summaryrefslogtreecommitdiffstats
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/CMakeLists.txt181
-rw-r--r--src/core/arm/arm_interface.cpp100
-rw-r--r--src/core/arm/arm_interface.h46
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic.h29
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_32.cpp97
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_32.h22
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_64.cpp76
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_64.h24
-rw-r--r--src/core/arm/dynarmic/dynarmic_cp15.cpp (renamed from src/core/arm/dynarmic/arm_dynarmic_cp15.cpp)2
-rw-r--r--src/core/arm/dynarmic/dynarmic_cp15.h (renamed from src/core/arm/dynarmic/arm_dynarmic_cp15.h)0
-rw-r--r--src/core/arm/dynarmic/dynarmic_exclusive_monitor.cpp (renamed from src/core/arm/dynarmic/arm_exclusive_monitor.cpp)2
-rw-r--r--src/core/arm/dynarmic/dynarmic_exclusive_monitor.h (renamed from src/core/arm/dynarmic/arm_exclusive_monitor.h)0
-rw-r--r--src/core/arm/exclusive_monitor.cpp2
-rw-r--r--src/core/constants.cpp27
-rw-r--r--src/core/constants.h2
-rw-r--r--src/core/core.cpp123
-rw-r--r--src/core/core.h46
-rw-r--r--src/core/core_timing.cpp85
-rw-r--r--src/core/core_timing.h12
-rw-r--r--src/core/core_timing_util.h58
-rw-r--r--src/core/cpu_manager.cpp2
-rw-r--r--src/core/crypto/ctr_encryption_layer.h2
-rw-r--r--src/core/crypto/key_manager.cpp8
-rw-r--r--src/core/crypto/key_manager.h5
-rw-r--r--src/core/crypto/xts_encryption_layer.h2
-rw-r--r--src/core/debugger/debugger.cpp7
-rw-r--r--src/core/debugger/gdbstub.cpp108
-rw-r--r--src/core/debugger/gdbstub_arch.cpp18
-rw-r--r--src/core/debugger/gdbstub_arch.h6
-rw-r--r--src/core/device_memory.cpp8
-rw-r--r--src/core/device_memory.h14
-rw-r--r--src/core/file_sys/content_archive.h2
-rw-r--r--src/core/file_sys/control_metadata.cpp12
-rw-r--r--src/core/file_sys/control_metadata.h4
-rw-r--r--src/core/file_sys/ips_layer.cpp8
-rw-r--r--src/core/file_sys/patch_manager.cpp47
-rw-r--r--src/core/file_sys/registered_cache.cpp2
-rw-r--r--src/core/file_sys/registered_cache.h2
-rw-r--r--src/core/file_sys/romfs.cpp6
-rw-r--r--src/core/file_sys/savedata_factory.cpp6
-rw-r--r--src/core/file_sys/submission_package.h1
-rw-r--r--src/core/file_sys/system_archive/time_zone_binary.cpp706
-rw-r--r--src/core/file_sys/vfs.h16
-rw-r--r--src/core/file_sys/vfs_cached.cpp63
-rw-r--r--src/core/file_sys/vfs_cached.h31
-rw-r--r--src/core/file_sys/vfs_concat.cpp167
-rw-r--r--src/core/file_sys/vfs_concat.h28
-rw-r--r--src/core/file_sys/vfs_layered.cpp9
-rw-r--r--src/core/file_sys/vfs_real.cpp232
-rw-r--r--src/core/file_sys/vfs_real.h46
-rw-r--r--src/core/frontend/applets/applet.h14
-rw-r--r--src/core/frontend/applets/cabinet.cpp4
-rw-r--r--src/core/frontend/applets/cabinet.h14
-rw-r--r--src/core/frontend/applets/controller.cpp4
-rw-r--r--src/core/frontend/applets/controller.h6
-rw-r--r--src/core/frontend/applets/error.cpp2
-rw-r--r--src/core/frontend/applets/error.h4
-rw-r--r--src/core/frontend/applets/general_frontend.cpp4
-rw-r--r--src/core/frontend/applets/general_frontend.h8
-rw-r--r--src/core/frontend/applets/mii_edit.cpp2
-rw-r--r--src/core/frontend/applets/mii_edit.h5
-rw-r--r--src/core/frontend/applets/profile_select.cpp5
-rw-r--r--src/core/frontend/applets/profile_select.h19
-rw-r--r--src/core/frontend/applets/software_keyboard.cpp2
-rw-r--r--src/core/frontend/applets/software_keyboard.h5
-rw-r--r--src/core/frontend/applets/web_browser.cpp2
-rw-r--r--src/core/frontend/applets/web_browser.h5
-rw-r--r--src/core/frontend/emu_window.cpp2
-rw-r--r--src/core/frontend/emu_window.h50
-rw-r--r--src/core/frontend/graphics_context.h62
-rw-r--r--src/core/hardware_properties.h28
-rw-r--r--src/core/hid/emulated_console.cpp35
-rw-r--r--src/core/hid/emulated_console.h4
-rw-r--r--src/core/hid/emulated_controller.cpp590
-rw-r--r--src/core/hid/emulated_controller.h114
-rw-r--r--src/core/hid/emulated_devices.cpp126
-rw-r--r--src/core/hid/emulated_devices.h51
-rw-r--r--src/core/hid/hid_types.h7
-rw-r--r--src/core/hid/input_converter.cpp32
-rw-r--r--src/core/hid/input_converter.h10
-rw-r--r--src/core/hid/motion_input.cpp83
-rw-r--r--src/core/hid/motion_input.h36
-rw-r--r--src/core/hle/kernel/board/nintendo/nx/k_memory_layout.cpp (renamed from src/core/hle/kernel/k_memory_layout.board.nintendo_nx.cpp)12
-rw-r--r--src/core/hle/kernel/board/nintendo/nx/k_memory_layout.h4
-rw-r--r--src/core/hle/kernel/board/nintendo/nx/k_system_control.cpp36
-rw-r--r--src/core/hle/kernel/board/nintendo/nx/k_system_control.h4
-rw-r--r--src/core/hle/kernel/code_set.h6
-rw-r--r--src/core/hle/kernel/global_scheduler_context.cpp33
-rw-r--r--src/core/hle/kernel/global_scheduler_context.h29
-rw-r--r--src/core/hle/kernel/init/init_slab_setup.cpp33
-rw-r--r--src/core/hle/kernel/initial_process.h2
-rw-r--r--src/core/hle/kernel/k_address_arbiter.cpp205
-rw-r--r--src/core/hle/kernel/k_address_arbiter.h45
-rw-r--r--src/core/hle/kernel/k_address_space_info.cpp84
-rw-r--r--src/core/hle/kernel/k_address_space_info.h2
-rw-r--r--src/core/hle/kernel/k_affinity_mask.h20
-rw-r--r--src/core/hle/kernel/k_auto_object.cpp4
-rw-r--r--src/core/hle/kernel/k_auto_object.h41
-rw-r--r--src/core/hle/kernel/k_capabilities.cpp358
-rw-r--r--src/core/hle/kernel/k_capabilities.h295
-rw-r--r--src/core/hle/kernel/k_client_port.cpp85
-rw-r--r--src/core/hle/kernel/k_client_port.h24
-rw-r--r--src/core/hle/kernel/k_client_session.cpp15
-rw-r--r--src/core/hle/kernel/k_client_session.h13
-rw-r--r--src/core/hle/kernel/k_code_memory.cpp41
-rw-r--r--src/core/hle/kernel/k_code_memory.h20
-rw-r--r--src/core/hle/kernel/k_condition_variable.cpp177
-rw-r--r--src/core/hle/kernel/k_condition_variable.h26
-rw-r--r--src/core/hle/kernel/k_debug.h4
-rw-r--r--src/core/hle/kernel/k_device_address_space.cpp150
-rw-r--r--src/core/hle/kernel/k_device_address_space.h61
-rw-r--r--src/core/hle/kernel/k_dynamic_page_manager.h19
-rw-r--r--src/core/hle/kernel/k_dynamic_slab_heap.h6
-rw-r--r--src/core/hle/kernel/k_event.cpp8
-rw-r--r--src/core/hle/kernel/k_event.h2
-rw-r--r--src/core/hle/kernel/k_event_info.h5
-rw-r--r--src/core/hle/kernel/k_handle_table.h3
-rw-r--r--src/core/hle/kernel/k_interrupt_manager.cpp2
-rw-r--r--src/core/hle/kernel/k_light_condition_variable.cpp18
-rw-r--r--src/core/hle/kernel/k_light_condition_variable.h6
-rw-r--r--src/core/hle/kernel/k_light_lock.cpp37
-rw-r--r--src/core/hle/kernel/k_light_lock.h8
-rw-r--r--src/core/hle/kernel/k_linked_list.h238
-rw-r--r--src/core/hle/kernel/k_memory_block.h52
-rw-r--r--src/core/hle/kernel/k_memory_block_manager.cpp68
-rw-r--r--src/core/hle/kernel/k_memory_block_manager.h40
-rw-r--r--src/core/hle/kernel/k_memory_layout.cpp28
-rw-r--r--src/core/hle/kernel/k_memory_layout.h112
-rw-r--r--src/core/hle/kernel/k_memory_manager.cpp51
-rw-r--r--src/core/hle/kernel/k_memory_manager.h48
-rw-r--r--src/core/hle/kernel/k_memory_region.h78
-rw-r--r--src/core/hle/kernel/k_object_name.cpp102
-rw-r--r--src/core/hle/kernel/k_object_name.h88
-rw-r--r--src/core/hle/kernel/k_page_buffer.cpp4
-rw-r--r--src/core/hle/kernel/k_page_buffer.h4
-rw-r--r--src/core/hle/kernel/k_page_group.h2
-rw-r--r--src/core/hle/kernel/k_page_heap.cpp40
-rw-r--r--src/core/hle/kernel/k_page_heap.h48
-rw-r--r--src/core/hle/kernel/k_page_table.cpp944
-rw-r--r--src/core/hle/kernel/k_page_table.h331
-rw-r--r--src/core/hle/kernel/k_page_table_manager.h14
-rw-r--r--src/core/hle/kernel/k_page_table_slab_heap.h15
-rw-r--r--src/core/hle/kernel/k_port.cpp48
-rw-r--r--src/core/hle/kernel/k_port.h28
-rw-r--r--src/core/hle/kernel/k_priority_queue.h168
-rw-r--r--src/core/hle/kernel/k_process.cpp419
-rw-r--r--src/core/hle/kernel/k_process.h242
-rw-r--r--src/core/hle/kernel/k_readable_event.cpp20
-rw-r--r--src/core/hle/kernel/k_readable_event.h2
-rw-r--r--src/core/hle/kernel/k_resource_limit.cpp105
-rw-r--r--src/core/hle/kernel/k_resource_limit.h22
-rw-r--r--src/core/hle/kernel/k_scheduler.cpp93
-rw-r--r--src/core/hle/kernel/k_scheduler.h14
-rw-r--r--src/core/hle/kernel/k_scheduler_lock.h64
-rw-r--r--src/core/hle/kernel/k_scoped_lock.h24
-rw-r--r--src/core/hle/kernel/k_scoped_resource_reservation.h36
-rw-r--r--src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h29
-rw-r--r--src/core/hle/kernel/k_server_port.cpp35
-rw-r--r--src/core/hle/kernel/k_server_port.h16
-rw-r--r--src/core/hle/kernel/k_server_session.cpp86
-rw-r--r--src/core/hle/kernel/k_server_session.h31
-rw-r--r--src/core/hle/kernel/k_session.cpp57
-rw-r--r--src/core/hle/kernel/k_session.h41
-rw-r--r--src/core/hle/kernel/k_session_request.cpp31
-rw-r--r--src/core/hle/kernel/k_session_request.h75
-rw-r--r--src/core/hle/kernel/k_shared_memory.cpp74
-rw-r--r--src/core/hle/kernel/k_shared_memory.h36
-rw-r--r--src/core/hle/kernel/k_shared_memory_info.h21
-rw-r--r--src/core/hle/kernel/k_slab_heap.h3
-rw-r--r--src/core/hle/kernel/k_spin_lock.cpp6
-rw-r--r--src/core/hle/kernel/k_spin_lock.h14
-rw-r--r--src/core/hle/kernel/k_synchronization_object.cpp40
-rw-r--r--src/core/hle/kernel/k_synchronization_object.h27
-rw-r--r--src/core/hle/kernel/k_system_resource.cpp9
-rw-r--r--src/core/hle/kernel/k_system_resource.h10
-rw-r--r--src/core/hle/kernel/k_thread.cpp953
-rw-r--r--src/core/hle/kernel/k_thread.h720
-rw-r--r--src/core/hle/kernel/k_thread_local_page.cpp8
-rw-r--r--src/core/hle/kernel/k_thread_local_page.h31
-rw-r--r--src/core/hle/kernel/k_thread_queue.cpp20
-rw-r--r--src/core/hle/kernel/k_thread_queue.h14
-rw-r--r--src/core/hle/kernel/k_transfer_memory.cpp27
-rw-r--r--src/core/hle/kernel/k_transfer_memory.h26
-rw-r--r--src/core/hle/kernel/k_typed_address.h12
-rw-r--r--src/core/hle/kernel/k_worker_task.h2
-rw-r--r--src/core/hle/kernel/k_worker_task_manager.cpp2
-rw-r--r--src/core/hle/kernel/k_worker_task_manager.h2
-rw-r--r--src/core/hle/kernel/kernel.cpp593
-rw-r--r--src/core/hle/kernel/kernel.h170
-rw-r--r--src/core/hle/kernel/memory_types.h4
-rw-r--r--src/core/hle/kernel/physical_core.cpp41
-rw-r--r--src/core/hle/kernel/physical_core.h37
-rw-r--r--src/core/hle/kernel/service_thread.cpp206
-rw-r--r--src/core/hle/kernel/service_thread.h29
-rw-r--r--src/core/hle/kernel/slab_helpers.h22
-rw-r--r--src/core/hle/kernel/svc.cpp6406
-rw-r--r--src/core/hle/kernel/svc.h528
-rw-r--r--src/core/hle/kernel/svc/svc_activity.cpp66
-rw-r--r--src/core/hle/kernel/svc/svc_address_arbiter.cpp105
-rw-r--r--src/core/hle/kernel/svc/svc_address_translation.cpp50
-rw-r--r--src/core/hle/kernel/svc/svc_cache.cpp98
-rw-r--r--src/core/hle/kernel/svc/svc_code_memory.cpp171
-rw-r--r--src/core/hle/kernel/svc/svc_condition_variable.cpp72
-rw-r--r--src/core/hle/kernel/svc/svc_debug.cpp194
-rw-r--r--src/core/hle/kernel/svc/svc_debug_string.cpp30
-rw-r--r--src/core/hle/kernel/svc/svc_device_address_space.cpp258
-rw-r--r--src/core/hle/kernel/svc/svc_event.cpp120
-rw-r--r--src/core/hle/kernel/svc/svc_exception.cpp137
-rw-r--r--src/core/hle/kernel/svc/svc_info.cpp277
-rw-r--r--src/core/hle/kernel/svc/svc_insecure_memory.cpp35
-rw-r--r--src/core/hle/kernel/svc/svc_interrupt_event.cpp25
-rw-r--r--src/core/hle/kernel/svc/svc_io_pool.cpp71
-rw-r--r--src/core/hle/kernel/svc/svc_ipc.cpp173
-rw-r--r--src/core/hle/kernel/svc/svc_kernel_debug.cpp35
-rw-r--r--src/core/hle/kernel/svc/svc_light_ipc.cpp73
-rw-r--r--src/core/hle/kernel/svc/svc_lock.cpp51
-rw-r--r--src/core/hle/kernel/svc/svc_memory.cpp216
-rw-r--r--src/core/hle/kernel/svc/svc_physical_memory.cpp183
-rw-r--r--src/core/hle/kernel/svc/svc_port.cpp159
-rw-r--r--src/core/hle/kernel/svc/svc_power_management.cpp21
-rw-r--r--src/core/hle/kernel/svc/svc_process.cpp194
-rw-r--r--src/core/hle/kernel/svc/svc_process_memory.cpp320
-rw-r--r--src/core/hle/kernel/svc/svc_processor.cpp25
-rw-r--r--src/core/hle/kernel/svc/svc_query_memory.cpp65
-rw-r--r--src/core/hle/kernel/svc/svc_register.cpp27
-rw-r--r--src/core/hle/kernel/svc/svc_resource_limit.cpp145
-rw-r--r--src/core/hle/kernel/svc/svc_secure_monitor_call.cpp53
-rw-r--r--src/core/hle/kernel/svc/svc_session.cpp127
-rw-r--r--src/core/hle/kernel/svc/svc_shared_memory.cpp130
-rw-r--r--src/core/hle/kernel/svc/svc_synchronization.cpp175
-rw-r--r--src/core/hle/kernel/svc/svc_thread.cpp412
-rw-r--r--src/core/hle/kernel/svc/svc_thread_profiler.cpp60
-rw-r--r--src/core/hle/kernel/svc/svc_tick.cpp27
-rw-r--r--src/core/hle/kernel/svc/svc_transfer_memory.cpp115
-rw-r--r--src/core/hle/kernel/svc_generator.py716
-rw-r--r--src/core/hle/kernel/svc_results.h1
-rw-r--r--src/core/hle/kernel/svc_types.h35
-rw-r--r--src/core/hle/kernel/svc_version.h58
-rw-r--r--src/core/hle/kernel/svc_wrap.h733
-rw-r--r--src/core/hle/service/acc/acc.cpp131
-rw-r--r--src/core/hle/service/acc/acc.h41
-rw-r--r--src/core/hle/service/acc/acc_su.cpp4
-rw-r--r--src/core/hle/service/acc/async_context.cpp10
-rw-r--r--src/core/hle/service/acc/async_context.h8
-rw-r--r--src/core/hle/service/acc/errors.h10
-rw-r--r--src/core/hle/service/acc/profile_manager.cpp7
-rw-r--r--src/core/hle/service/am/am.cpp363
-rw-r--r--src/core/hle/service/am/am.h198
-rw-r--r--src/core/hle/service/am/applet_ae.cpp82
-rw-r--r--src/core/hle/service/am/applet_ae.h14
-rw-r--r--src/core/hle/service/am/applet_oe.cpp42
-rw-r--r--src/core/hle/service/am/applet_oe.h10
-rw-r--r--src/core/hle/service/am/applets/applet_cabinet.cpp29
-rw-r--r--src/core/hle/service/am/applets/applet_cabinet.h7
-rw-r--r--src/core/hle/service/am/applets/applet_controller.cpp24
-rw-r--r--src/core/hle/service/am/applets/applet_controller.h10
-rw-r--r--src/core/hle/service/am/applets/applet_error.cpp7
-rw-r--r--src/core/hle/service/am/applets/applet_error.h1
-rw-r--r--src/core/hle/service/am/applets/applet_general_backend.cpp17
-rw-r--r--src/core/hle/service/am/applets/applet_general_backend.h3
-rw-r--r--src/core/hle/service/am/applets/applet_mii_edit.cpp5
-rw-r--r--src/core/hle/service/am/applets/applet_mii_edit.h1
-rw-r--r--src/core/hle/service/am/applets/applet_profile_select.cpp64
-rw-r--r--src/core/hle/service/am/applets/applet_profile_select.h103
-rw-r--r--src/core/hle/service/am/applets/applet_software_keyboard.cpp5
-rw-r--r--src/core/hle/service/am/applets/applet_software_keyboard.h1
-rw-r--r--src/core/hle/service/am/applets/applet_web_browser.cpp7
-rw-r--r--src/core/hle/service/am/applets/applet_web_browser.h1
-rw-r--r--src/core/hle/service/am/applets/applets.h1
-rw-r--r--src/core/hle/service/am/tcap.cpp22
-rw-r--r--src/core/hle/service/am/tcap.h20
-rw-r--r--src/core/hle/service/aoc/aoc_u.cpp46
-rw-r--r--src/core/hle/service/aoc/aoc_u.h25
-rw-r--r--src/core/hle/service/apm/apm.cpp22
-rw-r--r--src/core/hle/service/apm/apm.h3
-rw-r--r--src/core/hle/service/apm/apm_controller.cpp2
-rw-r--r--src/core/hle/service/apm/apm_interface.cpp20
-rw-r--r--src/core/hle/service/apm/apm_interface.h12
-rw-r--r--src/core/hle/service/audio/audctl.cpp6
-rw-r--r--src/core/hle/service/audio/audctl.h4
-rw-r--r--src/core/hle/service/audio/auddbg.cpp21
-rw-r--r--src/core/hle/service/audio/auddbg.h20
-rw-r--r--src/core/hle/service/audio/audin_a.cpp23
-rw-r--r--src/core/hle/service/audio/audin_a.h20
-rw-r--r--src/core/hle/service/audio/audin_u.cpp53
-rw-r--r--src/core/hle/service/audio/audin_u.h14
-rw-r--r--src/core/hle/service/audio/audio.cpp33
-rw-r--r--src/core/hle/service/audio/audio.h3
-rw-r--r--src/core/hle/service/audio/audout_a.cpp25
-rw-r--r--src/core/hle/service/audio/audout_a.h20
-rw-r--r--src/core/hle/service/audio/audout_u.cpp69
-rw-r--r--src/core/hle/service/audio/audout_u.h8
-rw-r--r--src/core/hle/service/audio/audren_a.cpp27
-rw-r--r--src/core/hle/service/audio/audren_a.h20
-rw-r--r--src/core/hle/service/audio/audren_u.cpp103
-rw-r--r--src/core/hle/service/audio/audren_u.h15
-rw-r--r--src/core/hle/service/audio/codecctl.cpp29
-rw-r--r--src/core/hle/service/audio/codecctl.h20
-rw-r--r--src/core/hle/service/audio/errors.h24
-rw-r--r--src/core/hle/service/audio/hwopus.cpp35
-rw-r--r--src/core/hle/service/audio/hwopus.h10
-rw-r--r--src/core/hle/service/bcat/bcat_module.cpp84
-rw-r--r--src/core/hle/service/bcat/bcat_module.h9
-rw-r--r--src/core/hle/service/bpc/bpc.cpp11
-rw-r--r--src/core/hle/service/bpc/bpc.h2
-rw-r--r--src/core/hle/service/btdrv/btdrv.cpp14
-rw-r--r--src/core/hle/service/btdrv/btdrv.h3
-rw-r--r--src/core/hle/service/btm/btm.cpp40
-rw-r--r--src/core/hle/service/btm/btm.h2
-rw-r--r--src/core/hle/service/caps/caps.cpp18
-rw-r--r--src/core/hle/service/caps/caps.h3
-rw-r--r--src/core/hle/service/caps/caps_a.h4
-rw-r--r--src/core/hle/service/caps/caps_c.cpp4
-rw-r--r--src/core/hle/service/caps/caps_c.h6
-rw-r--r--src/core/hle/service/caps/caps_su.cpp4
-rw-r--r--src/core/hle/service/caps/caps_su.h6
-rw-r--r--src/core/hle/service/caps/caps_u.cpp8
-rw-r--r--src/core/hle/service/caps/caps_u.h10
-rw-r--r--src/core/hle/service/erpt/erpt.cpp11
-rw-r--r--src/core/hle/service/erpt/erpt.h7
-rw-r--r--src/core/hle/service/es/es.cpp34
-rw-r--r--src/core/hle/service/es/es.h7
-rw-r--r--src/core/hle/service/eupld/eupld.cpp11
-rw-r--r--src/core/hle/service/eupld/eupld.h7
-rw-r--r--src/core/hle/service/fatal/fatal.cpp20
-rw-r--r--src/core/hle/service/fatal/fatal.h8
-rw-r--r--src/core/hle/service/fgm/fgm.cpp18
-rw-r--r--src/core/hle/service/fgm/fgm.h6
-rw-r--r--src/core/hle/service/filesystem/filesystem.cpp16
-rw-r--r--src/core/hle/service/filesystem/filesystem.h2
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.cpp161
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.h41
-rw-r--r--src/core/hle/service/friend/errors.h11
-rw-r--r--src/core/hle/service/friend/friend.cpp52
-rw-r--r--src/core/hle/service/friend/friend.h7
-rw-r--r--src/core/hle/service/glue/arp.cpp45
-rw-r--r--src/core/hle/service/glue/arp.h12
-rw-r--r--src/core/hle/service/glue/bgtc.cpp4
-rw-r--r--src/core/hle/service/glue/bgtc.h2
-rw-r--r--src/core/hle/service/glue/errors.h7
-rw-r--r--src/core/hle/service/glue/glue.cpp23
-rw-r--r--src/core/hle/service/glue/glue.h3
-rw-r--r--src/core/hle/service/glue/glue_manager.cpp16
-rw-r--r--src/core/hle/service/glue/glue_manager.h16
-rw-r--r--src/core/hle/service/glue/notif.cpp14
-rw-r--r--src/core/hle/service/glue/notif.h12
-rw-r--r--src/core/hle/service/grc/grc.cpp9
-rw-r--r--src/core/hle/service/grc/grc.h6
-rw-r--r--src/core/hle/service/hid/controllers/console_sixaxis.cpp15
-rw-r--r--src/core/hle/service/hid/controllers/console_sixaxis.h15
-rw-r--r--src/core/hle/service/hid/controllers/gesture.cpp7
-rw-r--r--src/core/hle/service/hid/controllers/mouse.cpp3
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp88
-rw-r--r--src/core/hle/service/hid/controllers/npad.h25
-rw-r--r--src/core/hle/service/hid/controllers/palma.cpp2
-rw-r--r--src/core/hle/service/hid/controllers/palma.h6
-rw-r--r--src/core/hle/service/hid/controllers/stubbed.cpp2
-rw-r--r--src/core/hle/service/hid/controllers/touchscreen.cpp13
-rw-r--r--src/core/hle/service/hid/errors.h1
-rw-r--r--src/core/hle/service/hid/hid.cpp355
-rw-r--r--src/core/hle/service/hid/hid.h235
-rw-r--r--src/core/hle/service/hid/hidbus.cpp81
-rw-r--r--src/core/hle/service/hid/hidbus.h33
-rw-r--r--src/core/hle/service/hid/hidbus/hidbus_base.cpp7
-rw-r--r--src/core/hle/service/hid/hidbus/hidbus_base.h17
-rw-r--r--src/core/hle/service/hid/hidbus/ringcon.cpp21
-rw-r--r--src/core/hle/service/hid/hidbus/ringcon.h10
-rw-r--r--src/core/hle/service/hid/hidbus/starlink.cpp8
-rw-r--r--src/core/hle/service/hid/hidbus/starlink.h5
-rw-r--r--src/core/hle/service/hid/hidbus/stubbed.cpp9
-rw-r--r--src/core/hle/service/hid/hidbus/stubbed.h5
-rw-r--r--src/core/hle/service/hid/irs.cpp72
-rw-r--r--src/core/hle/service/hid/irs.h44
-rw-r--r--src/core/hle/service/hid/irsensor/image_transfer_processor.cpp29
-rw-r--r--src/core/hle/service/hid/irsensor/image_transfer_processor.h14
-rw-r--r--src/core/hle/service/hle_ipc.cpp (renamed from src/core/hle/kernel/hle_ipc.cpp)90
-rw-r--r--src/core/hle/service/hle_ipc.h (renamed from src/core/hle/kernel/hle_ipc.h)132
-rw-r--r--src/core/hle/service/ipc_helpers.h (renamed from src/core/hle/ipc_helpers.h)29
-rw-r--r--src/core/hle/service/jit/jit.cpp38
-rw-r--r--src/core/hle/service/jit/jit.h7
-rw-r--r--src/core/hle/service/kernel_helpers.cpp14
-rw-r--r--src/core/hle/service/kernel_helpers.h1
-rw-r--r--src/core/hle/service/lbl/lbl.cpp60
-rw-r--r--src/core/hle/service/lbl/lbl.h6
-rw-r--r--src/core/hle/service/ldn/ldn.cpp96
-rw-r--r--src/core/hle/service/ldn/ldn.h9
-rw-r--r--src/core/hle/service/ldr/ldr.cpp56
-rw-r--r--src/core/hle/service/ldr/ldr.h7
-rw-r--r--src/core/hle/service/lm/lm.cpp16
-rw-r--r--src/core/hle/service/lm/lm.h3
-rw-r--r--src/core/hle/service/mig/mig.cpp9
-rw-r--r--src/core/hle/service/mig/mig.h6
-rw-r--r--src/core/hle/service/mii/mii.cpp38
-rw-r--r--src/core/hle/service/mii/mii.h6
-rw-r--r--src/core/hle/service/mii/mii_manager.cpp35
-rw-r--r--src/core/hle/service/mii/mii_manager.h7
-rw-r--r--src/core/hle/service/mii/types.h60
-rw-r--r--src/core/hle/service/mm/mm_u.cpp26
-rw-r--r--src/core/hle/service/mm/mm_u.h7
-rw-r--r--src/core/hle/service/mnpp/mnpp_app.cpp16
-rw-r--r--src/core/hle/service/mnpp/mnpp_app.h7
-rw-r--r--src/core/hle/service/mutex.cpp46
-rw-r--r--src/core/hle/service/mutex.h31
-rw-r--r--src/core/hle/service/ncm/ncm.cpp14
-rw-r--r--src/core/hle/service/ncm/ncm.h6
-rw-r--r--src/core/hle/service/nfc/common/amiibo_crypto.cpp (renamed from src/core/hle/service/nfp/amiibo_crypto.cpp)71
-rw-r--r--src/core/hle/service/nfc/common/amiibo_crypto.h (renamed from src/core/hle/service/nfp/amiibo_crypto.h)14
-rw-r--r--src/core/hle/service/nfc/common/device.cpp1483
-rw-r--r--src/core/hle/service/nfc/common/device.h146
-rw-r--r--src/core/hle/service/nfc/common/device_manager.cpp708
-rw-r--r--src/core/hle/service/nfc/common/device_manager.h100
-rw-r--r--src/core/hle/service/nfc/mifare_result.h17
-rw-r--r--src/core/hle/service/nfc/mifare_types.h64
-rw-r--r--src/core/hle/service/nfc/mifare_user.cpp400
-rw-r--r--src/core/hle/service/nfc/mifare_user.h52
-rw-r--r--src/core/hle/service/nfc/nfc.cpp176
-rw-r--r--src/core/hle/service/nfc/nfc.h6
-rw-r--r--src/core/hle/service/nfc/nfc_device.cpp273
-rw-r--r--src/core/hle/service/nfc/nfc_device.h77
-rw-r--r--src/core/hle/service/nfc/nfc_interface.cpp394
-rw-r--r--src/core/hle/service/nfc/nfc_interface.h49
-rw-r--r--src/core/hle/service/nfc/nfc_result.h36
-rw-r--r--src/core/hle/service/nfc/nfc_types.h91
-rw-r--r--src/core/hle/service/nfc/nfc_user.cpp365
-rw-r--r--src/core/hle/service/nfc/nfc_user.h52
-rw-r--r--src/core/hle/service/nfp/nfp.cpp191
-rw-r--r--src/core/hle/service/nfp/nfp.h2
-rw-r--r--src/core/hle/service/nfp/nfp_device.cpp719
-rw-r--r--src/core/hle/service/nfp/nfp_device.h101
-rw-r--r--src/core/hle/service/nfp/nfp_interface.cpp438
-rw-r--r--src/core/hle/service/nfp/nfp_interface.h50
-rw-r--r--src/core/hle/service/nfp/nfp_result.h31
-rw-r--r--src/core/hle/service/nfp/nfp_types.h231
-rw-r--r--src/core/hle/service/nfp/nfp_user.cpp672
-rw-r--r--src/core/hle/service/nfp/nfp_user.h63
-rw-r--r--src/core/hle/service/ngct/ngct.cpp14
-rw-r--r--src/core/hle/service/ngct/ngct.h7
-rw-r--r--src/core/hle/service/nifm/nifm.cpp65
-rw-r--r--src/core/hle/service/nifm/nifm.h31
-rw-r--r--src/core/hle/service/nim/nim.cpp43
-rw-r--r--src/core/hle/service/nim/nim.h6
-rw-r--r--src/core/hle/service/npns/npns.cpp11
-rw-r--r--src/core/hle/service/npns/npns.h6
-rw-r--r--src/core/hle/service/ns/errors.h5
-rw-r--r--src/core/hle/service/ns/iplatform_service_manager.cpp16
-rw-r--r--src/core/hle/service/ns/iplatform_service_manager.h12
-rw-r--r--src/core/hle/service/ns/ns.cpp73
-rw-r--r--src/core/hle/service/ns/ns.h17
-rw-r--r--src/core/hle/service/ns/pdm_qry.cpp4
-rw-r--r--src/core/hle/service/ns/pdm_qry.h2
-rw-r--r--src/core/hle/service/nvdrv/core/syncpoint_manager.cpp2
-rw-r--r--src/core/hle/service/nvdrv/core/syncpoint_manager.h2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdevice.h16
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp14
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdisp_disp0.h16
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp37
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h34
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp30
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl.h25
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp39
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h42
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp72
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_gpu.h42
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp16
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec.h12
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp24
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h14
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp14
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h14
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_vic.cpp12
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_vic.h12
-rw-r--r--src/core/hle/service/nvdrv/devices/nvmap.cpp30
-rw-r--r--src/core/hle/service/nvdrv/devices/nvmap.h24
-rw-r--r--src/core/hle/service/nvdrv/nvdrv.cpp39
-rw-r--r--src/core/hle/service/nvdrv/nvdrv.h24
-rw-r--r--src/core/hle/service/nvdrv/nvdrv_interface.cpp52
-rw-r--r--src/core/hle/service/nvdrv/nvdrv_interface.h29
-rw-r--r--src/core/hle/service/nvdrv/nvmemp.cpp4
-rw-r--r--src/core/hle/service/nvdrv/nvmemp.h4
-rw-r--r--src/core/hle/service/nvflinger/parcel.h172
-rw-r--r--src/core/hle/service/nvnflinger/binder.h (renamed from src/core/hle/service/nvflinger/binder.h)8
-rw-r--r--src/core/hle/service/nvnflinger/buffer_item.h (renamed from src/core/hle/service/nvflinger/buffer_item.h)4
-rw-r--r--src/core/hle/service/nvnflinger/buffer_item_consumer.cpp (renamed from src/core/hle/service/nvflinger/buffer_item_consumer.cpp)12
-rw-r--r--src/core/hle/service/nvnflinger/buffer_item_consumer.h (renamed from src/core/hle/service/nvflinger/buffer_item_consumer.h)4
-rw-r--r--src/core/hle/service/nvnflinger/buffer_queue_consumer.cpp (renamed from src/core/hle/service/nvflinger/buffer_queue_consumer.cpp)40
-rw-r--r--src/core/hle/service/nvnflinger/buffer_queue_consumer.h (renamed from src/core/hle/service/nvflinger/buffer_queue_consumer.h)4
-rw-r--r--src/core/hle/service/nvnflinger/buffer_queue_core.cpp (renamed from src/core/hle/service/nvflinger/buffer_queue_core.cpp)4
-rw-r--r--src/core/hle/service/nvnflinger/buffer_queue_core.h (renamed from src/core/hle/service/nvflinger/buffer_queue_core.h)10
-rw-r--r--src/core/hle/service/nvnflinger/buffer_queue_defs.h (renamed from src/core/hle/service/nvflinger/buffer_queue_defs.h)2
-rw-r--r--src/core/hle/service/nvnflinger/buffer_queue_producer.cpp (renamed from src/core/hle/service/nvflinger/buffer_queue_producer.cpp)149
-rw-r--r--src/core/hle/service/nvnflinger/buffer_queue_producer.h (renamed from src/core/hle/service/nvflinger/buffer_queue_producer.h)16
-rw-r--r--src/core/hle/service/nvnflinger/buffer_slot.h (renamed from src/core/hle/service/nvflinger/buffer_slot.h)2
-rw-r--r--src/core/hle/service/nvnflinger/buffer_transform_flags.h (renamed from src/core/hle/service/nvflinger/buffer_transform_flags.h)0
-rw-r--r--src/core/hle/service/nvnflinger/consumer_base.cpp (renamed from src/core/hle/service/nvflinger/consumer_base.cpp)24
-rw-r--r--src/core/hle/service/nvnflinger/consumer_base.h (renamed from src/core/hle/service/nvflinger/consumer_base.h)6
-rw-r--r--src/core/hle/service/nvnflinger/consumer_listener.h (renamed from src/core/hle/service/nvflinger/consumer_listener.h)0
-rw-r--r--src/core/hle/service/nvnflinger/graphic_buffer_producer.cpp (renamed from src/core/hle/service/nvflinger/graphic_buffer_producer.cpp)6
-rw-r--r--src/core/hle/service/nvnflinger/graphic_buffer_producer.h (renamed from src/core/hle/service/nvflinger/graphic_buffer_producer.h)8
-rw-r--r--src/core/hle/service/nvnflinger/hos_binder_driver_server.cpp (renamed from src/core/hle/service/nvflinger/hos_binder_driver_server.cpp)6
-rw-r--r--src/core/hle/service/nvnflinger/hos_binder_driver_server.h (renamed from src/core/hle/service/nvflinger/hos_binder_driver_server.h)6
-rw-r--r--src/core/hle/service/nvnflinger/nvnflinger.cpp (renamed from src/core/hle/service/nvflinger/nvflinger.cpp)77
-rw-r--r--src/core/hle/service/nvnflinger/nvnflinger.h (renamed from src/core/hle/service/nvflinger/nvflinger.h)13
-rw-r--r--src/core/hle/service/nvnflinger/parcel.h184
-rw-r--r--src/core/hle/service/nvnflinger/pixel_format.h (renamed from src/core/hle/service/nvflinger/pixel_format.h)0
-rw-r--r--src/core/hle/service/nvnflinger/producer_listener.h (renamed from src/core/hle/service/nvflinger/producer_listener.h)0
-rw-r--r--src/core/hle/service/nvnflinger/status.h (renamed from src/core/hle/service/nvflinger/status.h)0
-rw-r--r--src/core/hle/service/nvnflinger/ui/fence.h (renamed from src/core/hle/service/nvflinger/ui/fence.h)0
-rw-r--r--src/core/hle/service/nvnflinger/ui/graphic_buffer.h (renamed from src/core/hle/service/nvflinger/ui/graphic_buffer.h)2
-rw-r--r--src/core/hle/service/nvnflinger/window.h (renamed from src/core/hle/service/nvflinger/window.h)0
-rw-r--r--src/core/hle/service/olsc/olsc.cpp17
-rw-r--r--src/core/hle/service/olsc/olsc.h7
-rw-r--r--src/core/hle/service/pcie/pcie.cpp9
-rw-r--r--src/core/hle/service/pcie/pcie.h6
-rw-r--r--src/core/hle/service/pctl/pctl_module.cpp56
-rw-r--r--src/core/hle/service/pctl/pctl_module.h7
-rw-r--r--src/core/hle/service/pcv/pcv.cpp51
-rw-r--r--src/core/hle/service/pcv/pcv.h6
-rw-r--r--src/core/hle/service/pm/pm.cpp56
-rw-r--r--src/core/hle/service/pm/pm.h3
-rw-r--r--src/core/hle/service/prepo/prepo.cpp49
-rw-r--r--src/core/hle/service/prepo/prepo.h6
-rw-r--r--src/core/hle/service/psc/psc.cpp29
-rw-r--r--src/core/hle/service/psc/psc.h2
-rw-r--r--src/core/hle/service/ptm/psm.cpp18
-rw-r--r--src/core/hle/service/ptm/psm.h6
-rw-r--r--src/core/hle/service/ptm/ptm.cpp10
-rw-r--r--src/core/hle/service/ptm/ptm.h6
-rw-r--r--src/core/hle/service/ptm/ts.cpp6
-rw-r--r--src/core/hle/service/ptm/ts.h4
-rw-r--r--src/core/hle/service/server_manager.cpp451
-rw-r--r--src/core/hle/service/server_manager.h90
-rw-r--r--src/core/hle/service/service.cpp175
-rw-r--r--src/core/hle/service/service.h69
-rw-r--r--src/core/hle/service/set/set.cpp34
-rw-r--r--src/core/hle/service/set/set.h22
-rw-r--r--src/core/hle/service/set/set_sys.cpp18
-rw-r--r--src/core/hle/service/set/set_sys.h14
-rw-r--r--src/core/hle/service/set/settings.cpp15
-rw-r--r--src/core/hle/service/set/settings.h7
-rw-r--r--src/core/hle/service/sm/sm.cpp113
-rw-r--r--src/core/hle/service/sm/sm.h35
-rw-r--r--src/core/hle/service/sm/sm_controller.cpp22
-rw-r--r--src/core/hle/service/sm/sm_controller.h8
-rw-r--r--src/core/hle/service/sockets/bsd.cpp87
-rw-r--r--src/core/hle/service/sockets/bsd.h87
-rw-r--r--src/core/hle/service/sockets/ethc.cpp42
-rw-r--r--src/core/hle/service/sockets/ethc.h26
-rw-r--r--src/core/hle/service/sockets/sfdnsres.cpp10
-rw-r--r--src/core/hle/service/sockets/sfdnsres.h4
-rw-r--r--src/core/hle/service/sockets/sockets.cpp23
-rw-r--r--src/core/hle/service/sockets/sockets.h8
-rw-r--r--src/core/hle/service/sockets/sockets_translate.cpp2
-rw-r--r--src/core/hle/service/spl/spl_module.cpp36
-rw-r--r--src/core/hle/service/spl/spl_module.h17
-rw-r--r--src/core/hle/service/ssl/ssl.cpp115
-rw-r--r--src/core/hle/service/ssl/ssl.h7
-rw-r--r--src/core/hle/service/time/clock_types.h25
-rw-r--r--src/core/hle/service/time/standard_steady_clock_core.cpp2
-rw-r--r--src/core/hle/service/time/tick_based_steady_clock_core.cpp2
-rw-r--r--src/core/hle/service/time/time.cpp53
-rw-r--r--src/core/hle/service/time/time.h27
-rw-r--r--src/core/hle/service/time/time_manager.cpp34
-rw-r--r--src/core/hle/service/time/time_manager.h4
-rw-r--r--src/core/hle/service/time/time_sharedmemory.cpp24
-rw-r--r--src/core/hle/service/time/time_sharedmemory.h5
-rw-r--r--src/core/hle/service/time/time_zone_content_manager.cpp26
-rw-r--r--src/core/hle/service/time/time_zone_manager.cpp163
-rw-r--r--src/core/hle/service/time/time_zone_manager.h8
-rw-r--r--src/core/hle/service/time/time_zone_service.cpp81
-rw-r--r--src/core/hle/service/time/time_zone_service.h15
-rw-r--r--src/core/hle/service/usb/usb.cpp79
-rw-r--r--src/core/hle/service/usb/usb.h6
-rw-r--r--src/core/hle/service/vi/display/vi_display.cpp12
-rw-r--r--src/core/hle/service/vi/display/vi_display.h8
-rw-r--r--src/core/hle/service/vi/vi.cpp135
-rw-r--r--src/core/hle/service/vi/vi.h24
-rw-r--r--src/core/hle/service/vi/vi_m.cpp10
-rw-r--r--src/core/hle/service/vi/vi_m.h20
-rw-r--r--src/core/hle/service/vi/vi_s.cpp6
-rw-r--r--src/core/hle/service/vi/vi_s.h20
-rw-r--r--src/core/hle/service/vi/vi_u.cpp6
-rw-r--r--src/core/hle/service/vi/vi_u.h20
-rw-r--r--src/core/hle/service/wlan/wlan.cpp186
-rw-r--r--src/core/hle/service/wlan/wlan.h18
-rw-r--r--src/core/internal_network/network.cpp14
-rw-r--r--src/core/internal_network/network.h1
-rw-r--r--src/core/internal_network/network_interface.cpp2
-rw-r--r--src/core/internal_network/socket_proxy.cpp4
-rw-r--r--src/core/internal_network/socket_proxy.h8
-rw-r--r--src/core/internal_network/sockets.h22
-rw-r--r--src/core/loader/deconstructed_rom_directory.cpp2
-rw-r--r--src/core/loader/kip.cpp2
-rw-r--r--src/core/loader/nro.cpp13
-rw-r--r--src/core/loader/nro.h2
-rw-r--r--src/core/loader/nso.cpp4
-rw-r--r--src/core/memory.cpp354
-rw-r--r--src/core/memory.h122
-rw-r--r--src/core/memory/cheat_engine.cpp25
-rw-r--r--src/core/perf_stats.cpp4
-rw-r--r--src/core/reporter.cpp24
-rw-r--r--src/core/reporter.h10
-rw-r--r--src/core/telemetry_session.cpp19
602 files changed, 26447 insertions, 16633 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 5afdeb5ff..3655b8478 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -4,8 +4,6 @@
add_library(core STATIC
arm/arm_interface.h
arm/arm_interface.cpp
- arm/dynarmic/arm_exclusive_monitor.cpp
- arm/dynarmic/arm_exclusive_monitor.h
arm/exclusive_monitor.cpp
arm/exclusive_monitor.h
arm/symbols.cpp
@@ -16,7 +14,6 @@ add_library(core STATIC
core.h
core_timing.cpp
core_timing.h
- core_timing_util.h
cpu_manager.cpp
cpu_manager.h
crypto/aes_util.cpp
@@ -106,6 +103,8 @@ add_library(core STATIC
file_sys/system_archive/time_zone_binary.h
file_sys/vfs.cpp
file_sys/vfs.h
+ file_sys/vfs_cached.cpp
+ file_sys/vfs_cached.h
file_sys/vfs_concat.cpp
file_sys/vfs_concat.h
file_sys/vfs_layered.cpp
@@ -140,6 +139,7 @@ add_library(core STATIC
frontend/emu_window.h
frontend/framebuffer_layout.cpp
frontend/framebuffer_layout.h
+ frontend/graphics_context.h
hid/emulated_console.cpp
hid/emulated_console.h
hid/emulated_controller.cpp
@@ -158,7 +158,7 @@ add_library(core STATIC
hid/motion_input.h
hle/api_version.h
hle/ipc.h
- hle/ipc_helpers.h
+ hle/kernel/board/nintendo/nx/k_memory_layout.cpp
hle/kernel/board/nintendo/nx/k_memory_layout.h
hle/kernel/board/nintendo/nx/k_system_control.cpp
hle/kernel/board/nintendo/nx/k_system_control.h
@@ -168,8 +168,6 @@ add_library(core STATIC
hle/kernel/svc_results.h
hle/kernel/global_scheduler_context.cpp
hle/kernel/global_scheduler_context.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/initial_process.h
@@ -182,6 +180,8 @@ add_library(core STATIC
hle/kernel/k_auto_object_container.cpp
hle/kernel/k_auto_object_container.h
hle/kernel/k_affinity_mask.h
+ hle/kernel/k_capabilities.cpp
+ hle/kernel/k_capabilities.h
hle/kernel/k_class_token.cpp
hle/kernel/k_class_token.h
hle/kernel/k_client_port.cpp
@@ -193,6 +193,8 @@ add_library(core STATIC
hle/kernel/k_condition_variable.cpp
hle/kernel/k_condition_variable.h
hle/kernel/k_debug.h
+ hle/kernel/k_device_address_space.cpp
+ hle/kernel/k_device_address_space.h
hle/kernel/k_dynamic_page_manager.h
hle/kernel/k_dynamic_resource_manager.h
hle/kernel/k_dynamic_slab_heap.h
@@ -210,17 +212,17 @@ add_library(core STATIC
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
hle/kernel/k_memory_layout.cpp
- hle/kernel/k_memory_layout.board.nintendo_nx.cpp
hle/kernel/k_memory_layout.h
hle/kernel/k_memory_manager.cpp
hle/kernel/k_memory_manager.h
hle/kernel/k_memory_region.h
hle/kernel/k_memory_region_type.h
+ hle/kernel/k_object_name.cpp
+ hle/kernel/k_object_name.h
hle/kernel/k_page_bitmap.h
hle/kernel/k_page_buffer.cpp
hle/kernel/k_page_buffer.h
@@ -276,6 +278,7 @@ add_library(core STATIC
hle/kernel/k_trace.h
hle/kernel/k_transfer_memory.cpp
hle/kernel/k_transfer_memory.h
+ hle/kernel/k_typed_address.h
hle/kernel/k_worker_task.h
hle/kernel/k_worker_task_manager.cpp
hle/kernel/k_worker_task_manager.h
@@ -287,14 +290,48 @@ add_library(core STATIC
hle/kernel/physical_memory.h
hle/kernel/process_capability.cpp
hle/kernel/process_capability.h
- hle/kernel/service_thread.cpp
- hle/kernel/service_thread.h
hle/kernel/slab_helpers.h
hle/kernel/svc.cpp
hle/kernel/svc.h
hle/kernel/svc_common.h
hle/kernel/svc_types.h
- hle/kernel/svc_wrap.h
+ hle/kernel/svc/svc_activity.cpp
+ hle/kernel/svc/svc_address_arbiter.cpp
+ hle/kernel/svc/svc_address_translation.cpp
+ hle/kernel/svc/svc_cache.cpp
+ hle/kernel/svc/svc_code_memory.cpp
+ hle/kernel/svc/svc_condition_variable.cpp
+ hle/kernel/svc/svc_debug.cpp
+ hle/kernel/svc/svc_debug_string.cpp
+ hle/kernel/svc/svc_device_address_space.cpp
+ hle/kernel/svc/svc_event.cpp
+ hle/kernel/svc/svc_exception.cpp
+ hle/kernel/svc/svc_info.cpp
+ hle/kernel/svc/svc_insecure_memory.cpp
+ hle/kernel/svc/svc_interrupt_event.cpp
+ hle/kernel/svc/svc_io_pool.cpp
+ hle/kernel/svc/svc_ipc.cpp
+ hle/kernel/svc/svc_kernel_debug.cpp
+ hle/kernel/svc/svc_light_ipc.cpp
+ hle/kernel/svc/svc_lock.cpp
+ hle/kernel/svc/svc_memory.cpp
+ hle/kernel/svc/svc_physical_memory.cpp
+ hle/kernel/svc/svc_port.cpp
+ hle/kernel/svc/svc_power_management.cpp
+ hle/kernel/svc/svc_process.cpp
+ hle/kernel/svc/svc_process_memory.cpp
+ hle/kernel/svc/svc_processor.cpp
+ hle/kernel/svc/svc_query_memory.cpp
+ hle/kernel/svc/svc_register.cpp
+ hle/kernel/svc/svc_resource_limit.cpp
+ hle/kernel/svc/svc_secure_monitor_call.cpp
+ hle/kernel/svc/svc_session.cpp
+ hle/kernel/svc/svc_shared_memory.cpp
+ hle/kernel/svc/svc_synchronization.cpp
+ hle/kernel/svc/svc_thread.cpp
+ hle/kernel/svc/svc_thread_profiler.cpp
+ hle/kernel/svc/svc_tick.cpp
+ hle/kernel/svc/svc_transfer_memory.cpp
hle/result.h
hle/service/acc/acc.cpp
hle/service/acc/acc.h
@@ -344,8 +381,6 @@ add_library(core STATIC
hle/service/am/omm.h
hle/service/am/spsm.cpp
hle/service/am/spsm.h
- hle/service/am/tcap.cpp
- hle/service/am/tcap.h
hle/service/aoc/aoc_u.cpp
hle/service/aoc/aoc_u.h
hle/service/apm/apm.cpp
@@ -356,28 +391,18 @@ add_library(core STATIC
hle/service/apm/apm_interface.h
hle/service/audio/audctl.cpp
hle/service/audio/audctl.h
- hle/service/audio/auddbg.cpp
- hle/service/audio/auddbg.h
- hle/service/audio/audin_a.cpp
- hle/service/audio/audin_a.h
hle/service/audio/audin_u.cpp
hle/service/audio/audin_u.h
hle/service/audio/audio.cpp
hle/service/audio/audio.h
- hle/service/audio/audout_a.cpp
- hle/service/audio/audout_a.h
hle/service/audio/audout_u.cpp
hle/service/audio/audout_u.h
hle/service/audio/audrec_a.cpp
hle/service/audio/audrec_a.h
hle/service/audio/audrec_u.cpp
hle/service/audio/audrec_u.h
- hle/service/audio/audren_a.cpp
- hle/service/audio/audren_a.h
hle/service/audio/audren_u.cpp
hle/service/audio/audren_u.h
- hle/service/audio/codecctl.cpp
- hle/service/audio/codecctl.h
hle/service/audio/errors.h
hle/service/audio/hwopus.cpp
hle/service/audio/hwopus.h
@@ -429,7 +454,6 @@ add_library(core STATIC
hle/service/filesystem/fsp_srv.h
hle/service/fgm/fgm.cpp
hle/service/fgm/fgm.h
- hle/service/friend/errors.h
hle/service/friend/friend.cpp
hle/service/friend/friend.h
hle/service/friend/friend_interface.cpp
@@ -531,25 +555,26 @@ add_library(core STATIC
hle/service/mnpp/mnpp_app.h
hle/service/ncm/ncm.cpp
hle/service/ncm/ncm.h
- hle/service/nfc/mifare_user.cpp
- hle/service/nfc/mifare_user.h
+ hle/service/nfc/common/amiibo_crypto.cpp
+ hle/service/nfc/common/amiibo_crypto.h
+ hle/service/nfc/common/device.cpp
+ hle/service/nfc/common/device.h
+ hle/service/nfc/common/device_manager.cpp
+ hle/service/nfc/common/device_manager.h
+ hle/service/nfc/mifare_result.h
+ hle/service/nfc/mifare_types.h
hle/service/nfc/nfc.cpp
hle/service/nfc/nfc.h
- hle/service/nfc/nfc_device.cpp
- hle/service/nfc/nfc_device.h
+ hle/service/nfc/nfc_interface.cpp
+ hle/service/nfc/nfc_interface.h
hle/service/nfc/nfc_result.h
- hle/service/nfc/nfc_user.cpp
- hle/service/nfc/nfc_user.h
- hle/service/nfp/amiibo_crypto.cpp
- hle/service/nfp/amiibo_crypto.h
+ hle/service/nfc/nfc_types.h
hle/service/nfp/nfp.cpp
hle/service/nfp/nfp.h
- hle/service/nfp/nfp_device.cpp
- hle/service/nfp/nfp_device.h
+ hle/service/nfp/nfp_interface.cpp
+ hle/service/nfp/nfp_interface.h
hle/service/nfp/nfp_result.h
hle/service/nfp/nfp_types.h
- hle/service/nfp/nfp_user.cpp
- hle/service/nfp/nfp_user.h
hle/service/ngct/ngct.cpp
hle/service/ngct/ngct.h
hle/service/nifm/nifm.cpp
@@ -601,35 +626,35 @@ add_library(core STATIC
hle/service/nvdrv/nvdrv_interface.h
hle/service/nvdrv/nvmemp.cpp
hle/service/nvdrv/nvmemp.h
- hle/service/nvflinger/binder.h
- hle/service/nvflinger/buffer_item.h
- hle/service/nvflinger/buffer_item_consumer.cpp
- hle/service/nvflinger/buffer_item_consumer.h
- hle/service/nvflinger/buffer_queue_consumer.cpp
- hle/service/nvflinger/buffer_queue_consumer.h
- hle/service/nvflinger/buffer_queue_core.cpp
- hle/service/nvflinger/buffer_queue_core.h
- hle/service/nvflinger/buffer_queue_defs.h
- hle/service/nvflinger/buffer_queue_producer.cpp
- hle/service/nvflinger/buffer_queue_producer.h
- hle/service/nvflinger/buffer_slot.h
- hle/service/nvflinger/buffer_transform_flags.h
- hle/service/nvflinger/consumer_base.cpp
- hle/service/nvflinger/consumer_base.h
- hle/service/nvflinger/consumer_listener.h
- hle/service/nvflinger/graphic_buffer_producer.cpp
- hle/service/nvflinger/graphic_buffer_producer.h
- hle/service/nvflinger/hos_binder_driver_server.cpp
- hle/service/nvflinger/hos_binder_driver_server.h
- hle/service/nvflinger/nvflinger.cpp
- hle/service/nvflinger/nvflinger.h
- hle/service/nvflinger/parcel.h
- hle/service/nvflinger/pixel_format.h
- hle/service/nvflinger/producer_listener.h
- hle/service/nvflinger/status.h
- hle/service/nvflinger/ui/fence.h
- hle/service/nvflinger/ui/graphic_buffer.h
- hle/service/nvflinger/window.h
+ hle/service/nvnflinger/binder.h
+ hle/service/nvnflinger/buffer_item.h
+ hle/service/nvnflinger/buffer_item_consumer.cpp
+ hle/service/nvnflinger/buffer_item_consumer.h
+ hle/service/nvnflinger/buffer_queue_consumer.cpp
+ hle/service/nvnflinger/buffer_queue_consumer.h
+ hle/service/nvnflinger/buffer_queue_core.cpp
+ hle/service/nvnflinger/buffer_queue_core.h
+ hle/service/nvnflinger/buffer_queue_defs.h
+ hle/service/nvnflinger/buffer_queue_producer.cpp
+ hle/service/nvnflinger/buffer_queue_producer.h
+ hle/service/nvnflinger/buffer_slot.h
+ hle/service/nvnflinger/buffer_transform_flags.h
+ hle/service/nvnflinger/consumer_base.cpp
+ hle/service/nvnflinger/consumer_base.h
+ hle/service/nvnflinger/consumer_listener.h
+ hle/service/nvnflinger/graphic_buffer_producer.cpp
+ hle/service/nvnflinger/graphic_buffer_producer.h
+ hle/service/nvnflinger/hos_binder_driver_server.cpp
+ hle/service/nvnflinger/hos_binder_driver_server.h
+ hle/service/nvnflinger/nvnflinger.cpp
+ hle/service/nvnflinger/nvnflinger.h
+ hle/service/nvnflinger/parcel.h
+ hle/service/nvnflinger/pixel_format.h
+ hle/service/nvnflinger/producer_listener.h
+ hle/service/nvnflinger/status.h
+ hle/service/nvnflinger/ui/fence.h
+ hle/service/nvnflinger/ui/graphic_buffer.h
+ hle/service/nvnflinger/window.h
hle/service/olsc/olsc.cpp
hle/service/olsc/olsc.h
hle/service/pcie/pcie.cpp
@@ -652,8 +677,15 @@ add_library(core STATIC
hle/service/ptm/ptm.h
hle/service/ptm/ts.cpp
hle/service/ptm/ts.h
+ hle/service/hle_ipc.cpp
+ hle/service/hle_ipc.h
+ hle/service/ipc_helpers.h
hle/service/kernel_helpers.cpp
hle/service/kernel_helpers.h
+ hle/service/mutex.cpp
+ hle/service/mutex.h
+ hle/service/server_manager.cpp
+ hle/service/server_manager.h
hle/service/service.cpp
hle/service/service.h
hle/service/set/set.cpp
@@ -672,8 +704,6 @@ add_library(core STATIC
hle/service/sm/sm_controller.h
hle/service/sockets/bsd.cpp
hle/service/sockets/bsd.h
- hle/service/sockets/ethc.cpp
- hle/service/sockets/ethc.h
hle/service/sockets/nsd.cpp
hle/service/sockets/nsd.h
hle/service/sockets/sfdnsres.cpp
@@ -740,8 +770,6 @@ add_library(core STATIC
hle/service/vi/vi_s.h
hle/service/vi/vi_u.cpp
hle/service/vi/vi_u.h
- hle/service/wlan/wlan.cpp
- hle/service/wlan/wlan.h
internal_network/network.cpp
internal_network/network.h
internal_network/network_interface.cpp
@@ -805,8 +833,8 @@ endif()
create_target_directory_groups(core)
-target_link_libraries(core PUBLIC common PRIVATE audio_core network video_core)
-target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt::fmt nlohmann_json::nlohmann_json mbedtls Opus::opus)
+target_link_libraries(core PUBLIC common PRIVATE audio_core network video_core nx_tzdb)
+target_link_libraries(core PUBLIC Boost::headers PRIVATE fmt::fmt nlohmann_json::nlohmann_json mbedtls Opus::opus)
if (MINGW)
target_link_libraries(core PRIVATE ${MSWSOCK_LIBRARY})
endif()
@@ -818,12 +846,15 @@ endif()
if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64)
target_sources(core PRIVATE
+ arm/dynarmic/arm_dynarmic.h
arm/dynarmic/arm_dynarmic_64.cpp
arm/dynarmic/arm_dynarmic_64.h
arm/dynarmic/arm_dynarmic_32.cpp
arm/dynarmic/arm_dynarmic_32.h
- arm/dynarmic/arm_dynarmic_cp15.cpp
- arm/dynarmic/arm_dynarmic_cp15.h
+ arm/dynarmic/dynarmic_cp15.cpp
+ arm/dynarmic/dynarmic_cp15.h
+ arm/dynarmic/dynarmic_exclusive_monitor.cpp
+ arm/dynarmic/dynarmic_exclusive_monitor.h
hle/service/jit/jit_context.cpp
hle/service/jit/jit_context.h
hle/service/jit/jit.cpp
@@ -835,3 +866,7 @@ endif()
if (YUZU_USE_PRECOMPILED_HEADERS)
target_precompile_headers(core PRIVATE precompiled_headers.h)
endif()
+
+if (YUZU_ENABLE_LTO)
+ set_property(TARGET core PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE)
+endif()
diff --git a/src/core/arm/arm_interface.cpp b/src/core/arm/arm_interface.cpp
index 8aa7b9641..beaea64b3 100644
--- a/src/core/arm/arm_interface.cpp
+++ b/src/core/arm/arm_interface.cpp
@@ -13,25 +13,68 @@
#include "core/core.h"
#include "core/debugger/debugger.h"
#include "core/hle/kernel/k_process.h"
+#include "core/hle/kernel/k_thread.h"
#include "core/hle/kernel/svc.h"
#include "core/loader/loader.h"
#include "core/memory.h"
-#include "core/arm/dynarmic/arm_dynarmic_32.h"
-#include "core/arm/dynarmic/arm_dynarmic_64.h"
-
namespace Core {
constexpr u64 SEGMENT_BASE = 0x7100000000ull;
std::vector<ARM_Interface::BacktraceEntry> ARM_Interface::GetBacktraceFromContext(
Core::System& system, const ARM_Interface::ThreadContext32& ctx) {
- return ARM_Dynarmic_32::GetBacktraceFromContext(system, ctx);
+ std::vector<BacktraceEntry> out;
+ auto& memory = system.ApplicationMemory();
+
+ const auto& reg = ctx.cpu_registers;
+ u32 pc = reg[15], lr = reg[14], fp = reg[11];
+ out.push_back({"", 0, pc, 0, ""});
+
+ // fp (= r11) points to the last frame record.
+ // Frame records are two words long:
+ // fp+0 : pointer to previous frame record
+ // fp+4 : value of lr for frame
+ for (size_t i = 0; i < 256; i++) {
+ out.push_back({"", 0, lr, 0, ""});
+ if (!fp || (fp % 4 != 0) || !memory.IsValidVirtualAddressRange(fp, 8)) {
+ break;
+ }
+ lr = memory.Read32(fp + 4);
+ fp = memory.Read32(fp);
+ }
+
+ SymbolicateBacktrace(system, out);
+
+ return out;
}
std::vector<ARM_Interface::BacktraceEntry> ARM_Interface::GetBacktraceFromContext(
Core::System& system, const ARM_Interface::ThreadContext64& ctx) {
- return ARM_Dynarmic_64::GetBacktraceFromContext(system, ctx);
+ std::vector<BacktraceEntry> out;
+ auto& memory = system.ApplicationMemory();
+
+ const auto& reg = ctx.cpu_registers;
+ u64 pc = ctx.pc, lr = reg[30], fp = reg[29];
+
+ out.push_back({"", 0, pc, 0, ""});
+
+ // fp (= x29) points to the previous frame record.
+ // Frame records are two words long:
+ // fp+0 : pointer to previous frame record
+ // fp+8 : value of lr for frame
+ for (size_t i = 0; i < 256; i++) {
+ out.push_back({"", 0, lr, 0, ""});
+ if (!fp || (fp % 4 != 0) || !memory.IsValidVirtualAddressRange(fp, 16)) {
+ break;
+ }
+ lr = memory.Read64(fp + 8);
+ fp = memory.Read64(fp);
+ }
+
+ SymbolicateBacktrace(system, out);
+
+ return out;
}
void ARM_Interface::SymbolicateBacktrace(Core::System& system, std::vector<BacktraceEntry>& out) {
@@ -43,9 +86,9 @@ void ARM_Interface::SymbolicateBacktrace(Core::System& system, std::vector<Backt
std::map<std::string, Symbols::Symbols> symbols;
for (const auto& module : modules) {
- symbols.insert_or_assign(module.second,
- Symbols::GetSymbols(module.first, system.Memory(),
- system.CurrentProcess()->Is64BitProcess()));
+ symbols.insert_or_assign(
+ module.second, Symbols::GetSymbols(module.first, system.ApplicationMemory(),
+ system.ApplicationProcess()->Is64BitProcess()));
}
for (auto& entry : out) {
@@ -76,6 +119,18 @@ void ARM_Interface::SymbolicateBacktrace(Core::System& system, std::vector<Backt
}
}
+std::vector<ARM_Interface::BacktraceEntry> ARM_Interface::GetBacktrace() const {
+ if (GetArchitecture() == Architecture::Aarch64) {
+ ThreadContext64 ctx;
+ SaveContext(ctx);
+ return GetBacktraceFromContext(system, ctx);
+ } else {
+ ThreadContext32 ctx;
+ SaveContext(ctx);
+ return GetBacktraceFromContext(system, ctx);
+ }
+}
+
void ARM_Interface::LogBacktrace() const {
const VAddr sp = GetSP();
const VAddr pc = GetPC();
@@ -83,7 +138,6 @@ void ARM_Interface::LogBacktrace() const {
LOG_ERROR(Core_ARM, "{:20}{:20}{:20}{:20}{}", "Module Name", "Address", "Original Address",
"Offset", "Symbol");
LOG_ERROR(Core_ARM, "");
-
const auto backtrace = GetBacktrace();
for (const auto& entry : backtrace) {
LOG_ERROR(Core_ARM, "{:20}{:016X} {:016X} {:016X} {}", entry.module, entry.address,
@@ -97,7 +151,7 @@ void ARM_Interface::Run() {
while (true) {
Kernel::KThread* current_thread{Kernel::GetCurrentThreadPointer(system.Kernel())};
- Dynarmic::HaltReason hr{};
+ HaltReason hr{};
// Notify the debugger and go to sleep if a step was performed
// and this thread has been scheduled again.
@@ -108,17 +162,17 @@ void ARM_Interface::Run() {
}
// Otherwise, run the thread.
- system.EnterDynarmicProfile();
+ system.EnterCPUProfile();
if (current_thread->GetStepState() == StepState::StepPending) {
hr = StepJit();
- if (Has(hr, step_thread)) {
+ if (True(hr & HaltReason::StepThread)) {
current_thread->SetStepState(StepState::StepPerformed);
}
} else {
hr = RunJit();
}
- system.ExitDynarmicProfile();
+ system.ExitCPUProfile();
// If the thread is scheduled for termination, exit the thread.
if (current_thread->HasDpc()) {
@@ -130,8 +184,8 @@ void ARM_Interface::Run() {
// Notify the debugger and go to sleep if a breakpoint was hit,
// or if the thread is unable to continue for any reason.
- if (Has(hr, breakpoint) || Has(hr, no_execute)) {
- if (!Has(hr, no_execute)) {
+ if (True(hr & HaltReason::InstructionBreakpoint) || True(hr & HaltReason::PrefetchAbort)) {
+ if (!True(hr & HaltReason::InstructionBreakpoint)) {
RewindBreakpointInstruction();
}
if (system.DebuggerEnabled()) {
@@ -144,7 +198,7 @@ void ARM_Interface::Run() {
}
// Notify the debugger and go to sleep if a watchpoint was hit.
- if (Has(hr, watchpoint)) {
+ if (True(hr & HaltReason::DataAbort)) {
if (system.DebuggerEnabled()) {
system.GetDebugger().NotifyThreadWatchpoint(current_thread, *HaltedWatchpoint());
}
@@ -153,11 +207,11 @@ void ARM_Interface::Run() {
}
// Handle syscalls and scheduling (this may change the current thread/core)
- if (Has(hr, svc_call)) {
+ if (True(hr & HaltReason::SupervisorCall)) {
Kernel::Svc::Call(system, GetSvcNumber());
break;
}
- if (Has(hr, break_loop) || !uses_wall_clock) {
+ if (True(hr & HaltReason::BreakLoop) || !uses_wall_clock) {
break;
}
}
@@ -168,21 +222,21 @@ void ARM_Interface::LoadWatchpointArray(const WatchpointArray& wp) {
}
const Kernel::DebugWatchpoint* ARM_Interface::MatchingWatchpoint(
- VAddr addr, u64 size, Kernel::DebugWatchpointType access_type) const {
+ u64 addr, u64 size, Kernel::DebugWatchpointType access_type) const {
if (!watchpoints) {
return nullptr;
}
- const VAddr start_address{addr};
- const VAddr end_address{addr + size};
+ const u64 start_address{addr};
+ const u64 end_address{addr + size};
for (size_t i = 0; i < Core::Hardware::NUM_WATCHPOINTS; i++) {
const auto& watch{(*watchpoints)[i]};
- if (end_address <= watch.start_address) {
+ if (end_address <= GetInteger(watch.start_address)) {
continue;
}
- if (start_address >= watch.end_address) {
+ if (start_address >= GetInteger(watch.end_address)) {
continue;
}
if ((access_type & watch.type) == Kernel::DebugWatchpointType::None) {
diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h
index 7d62d030e..d5f2fa09a 100644
--- a/src/core/arm/arm_interface.h
+++ b/src/core/arm/arm_interface.h
@@ -5,10 +5,9 @@
#include <array>
#include <span>
+#include <string>
#include <vector>
-#include <dynarmic/interface/halt_reason.h>
-
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "core/hardware_properties.h"
@@ -29,6 +28,22 @@ class CPUInterruptHandler;
using WatchpointArray = std::array<Kernel::DebugWatchpoint, Core::Hardware::NUM_WATCHPOINTS>;
+// NOTE: these values match the HaltReason enum in Dynarmic
+enum class HaltReason : u64 {
+ StepThread = 0x00000001,
+ DataAbort = 0x00000004,
+ BreakLoop = 0x02000000,
+ SupervisorCall = 0x04000000,
+ InstructionBreakpoint = 0x08000000,
+ PrefetchAbort = 0x20000000,
+};
+DECLARE_ENUM_FLAG_OPERATORS(HaltReason);
+
+enum class Architecture {
+ Aarch32,
+ Aarch64,
+};
+
/// Generic ARMv8 CPU interface
class ARM_Interface {
public:
@@ -77,7 +92,7 @@ public:
* @param addr Start address of the cache range to clear
* @param size Size of the cache range to clear, starting at addr
*/
- virtual void InvalidateCacheRange(VAddr addr, std::size_t size) = 0;
+ virtual void InvalidateCacheRange(u64 addr, std::size_t size) = 0;
/**
* Notifies CPU emulation that the current page table has changed.
@@ -148,9 +163,9 @@ public:
*/
virtual void SetPSTATE(u32 pstate) = 0;
- virtual VAddr GetTlsAddress() const = 0;
+ virtual u64 GetTlsAddress() const = 0;
- virtual void SetTlsAddress(VAddr address) = 0;
+ virtual void SetTlsAddress(u64 address) = 0;
/**
* Gets the value within the TPIDR_EL0 (read/write software thread ID) register.
@@ -166,8 +181,9 @@ public:
*/
virtual void SetTPIDR_EL0(u64 value) = 0;
- virtual void SaveContext(ThreadContext32& ctx) = 0;
- virtual void SaveContext(ThreadContext64& ctx) = 0;
+ virtual Architecture GetArchitecture() const = 0;
+ virtual void SaveContext(ThreadContext32& ctx) const = 0;
+ virtual void SaveContext(ThreadContext64& ctx) const = 0;
virtual void LoadContext(const ThreadContext32& ctx) = 0;
virtual void LoadContext(const ThreadContext64& ctx) = 0;
void LoadWatchpointArray(const WatchpointArray& wp);
@@ -194,17 +210,9 @@ public:
static std::vector<BacktraceEntry> GetBacktraceFromContext(System& system,
const ThreadContext64& ctx);
- virtual std::vector<BacktraceEntry> GetBacktrace() const = 0;
-
+ std::vector<BacktraceEntry> GetBacktrace() const;
void LogBacktrace() const;
- static constexpr Dynarmic::HaltReason step_thread = Dynarmic::HaltReason::Step;
- static constexpr Dynarmic::HaltReason break_loop = Dynarmic::HaltReason::UserDefined2;
- static constexpr Dynarmic::HaltReason svc_call = Dynarmic::HaltReason::UserDefined3;
- static constexpr Dynarmic::HaltReason breakpoint = Dynarmic::HaltReason::UserDefined4;
- static constexpr Dynarmic::HaltReason watchpoint = Dynarmic::HaltReason::MemoryAbort;
- static constexpr Dynarmic::HaltReason no_execute = Dynarmic::HaltReason::UserDefined6;
-
protected:
/// System context that this ARM interface is running under.
System& system;
@@ -213,10 +221,10 @@ protected:
static void SymbolicateBacktrace(Core::System& system, std::vector<BacktraceEntry>& out);
const Kernel::DebugWatchpoint* MatchingWatchpoint(
- VAddr addr, u64 size, Kernel::DebugWatchpointType access_type) const;
+ u64 addr, u64 size, Kernel::DebugWatchpointType access_type) const;
- virtual Dynarmic::HaltReason RunJit() = 0;
- virtual Dynarmic::HaltReason StepJit() = 0;
+ virtual HaltReason RunJit() = 0;
+ virtual HaltReason StepJit() = 0;
virtual u32 GetSvcNumber() const = 0;
virtual const Kernel::DebugWatchpoint* HaltedWatchpoint() const = 0;
virtual void RewindBreakpointInstruction() = 0;
diff --git a/src/core/arm/dynarmic/arm_dynarmic.h b/src/core/arm/dynarmic/arm_dynarmic.h
new file mode 100644
index 000000000..eef7c3116
--- /dev/null
+++ b/src/core/arm/dynarmic/arm_dynarmic.h
@@ -0,0 +1,29 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <dynarmic/interface/halt_reason.h>
+
+#include "core/arm/arm_interface.h"
+
+namespace Core {
+
+constexpr Dynarmic::HaltReason StepThread = Dynarmic::HaltReason::Step;
+constexpr Dynarmic::HaltReason DataAbort = Dynarmic::HaltReason::MemoryAbort;
+constexpr Dynarmic::HaltReason BreakLoop = Dynarmic::HaltReason::UserDefined2;
+constexpr Dynarmic::HaltReason SupervisorCall = Dynarmic::HaltReason::UserDefined3;
+constexpr Dynarmic::HaltReason InstructionBreakpoint = Dynarmic::HaltReason::UserDefined4;
+constexpr Dynarmic::HaltReason PrefetchAbort = Dynarmic::HaltReason::UserDefined6;
+
+constexpr HaltReason TranslateHaltReason(Dynarmic::HaltReason hr) {
+ static_assert(static_cast<u64>(HaltReason::StepThread) == static_cast<u64>(StepThread));
+ static_assert(static_cast<u64>(HaltReason::DataAbort) == static_cast<u64>(DataAbort));
+ static_assert(static_cast<u64>(HaltReason::BreakLoop) == static_cast<u64>(BreakLoop));
+ static_assert(static_cast<u64>(HaltReason::SupervisorCall) == static_cast<u64>(SupervisorCall));
+ static_assert(static_cast<u64>(HaltReason::InstructionBreakpoint) ==
+ static_cast<u64>(InstructionBreakpoint));
+ static_assert(static_cast<u64>(HaltReason::PrefetchAbort) == static_cast<u64>(PrefetchAbort));
+
+ return static_cast<HaltReason>(hr);
+}
+
+} // namespace Core
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
index 2a7570073..5acf9008d 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
@@ -5,15 +5,15 @@
#include <memory>
#include <dynarmic/interface/A32/a32.h>
#include <dynarmic/interface/A32/config.h>
-#include <dynarmic/interface/A32/context.h>
#include "common/assert.h"
#include "common/literals.h"
#include "common/logging/log.h"
#include "common/page_table.h"
#include "common/settings.h"
+#include "core/arm/dynarmic/arm_dynarmic.h"
#include "core/arm/dynarmic/arm_dynarmic_32.h"
-#include "core/arm/dynarmic/arm_dynarmic_cp15.h"
-#include "core/arm/dynarmic/arm_exclusive_monitor.h"
+#include "core/arm/dynarmic/dynarmic_cp15.h"
+#include "core/arm/dynarmic/dynarmic_exclusive_monitor.h"
#include "core/core.h"
#include "core/core_timing.h"
#include "core/debugger/debugger.h"
@@ -28,8 +28,8 @@ using namespace Common::Literals;
class DynarmicCallbacks32 : public Dynarmic::A32::UserCallbacks {
public:
explicit DynarmicCallbacks32(ARM_Dynarmic_32& parent_)
- : parent{parent_},
- memory(parent.system.Memory()), debugger_enabled{parent.system.DebuggerEnabled()},
+ : parent{parent_}, memory(parent.system.ApplicationMemory()),
+ debugger_enabled{parent.system.DebuggerEnabled()},
check_memory_access{debugger_enabled ||
!Settings::values.cpuopt_ignore_memory_aborts.GetValue()} {}
@@ -105,11 +105,11 @@ public:
switch (exception) {
case Dynarmic::A32::Exception::NoExecuteFault:
LOG_CRITICAL(Core_ARM, "Cannot execute instruction at unmapped address {:#08x}", pc);
- ReturnException(pc, ARM_Interface::no_execute);
+ ReturnException(pc, PrefetchAbort);
return;
default:
if (debugger_enabled) {
- ReturnException(pc, ARM_Interface::breakpoint);
+ ReturnException(pc, InstructionBreakpoint);
return;
}
@@ -122,7 +122,7 @@ public:
void CallSVC(u32 swi) override {
parent.svc_swi = swi;
- parent.jit.load()->HaltExecution(ARM_Interface::svc_call);
+ parent.jit.load()->HaltExecution(SupervisorCall);
}
void AddTicks(u64 ticks) override {
@@ -155,7 +155,7 @@ public:
return std::max<s64>(parent.system.CoreTiming().GetDowncount(), 0);
}
- bool CheckMemoryAccess(VAddr addr, u64 size, Kernel::DebugWatchpointType type) {
+ bool CheckMemoryAccess(u64 addr, u64 size, Kernel::DebugWatchpointType type) {
if (!check_memory_access) {
return true;
}
@@ -163,7 +163,7 @@ public:
if (!memory.IsValidVirtualAddressRange(addr, size)) {
LOG_CRITICAL(Core_ARM, "Stopping execution due to unmapped memory access at {:#x}",
addr);
- parent.jit.load()->HaltExecution(ARM_Interface::no_execute);
+ parent.jit.load()->HaltExecution(PrefetchAbort);
return false;
}
@@ -174,7 +174,7 @@ public:
const auto match{parent.MatchingWatchpoint(addr, size, type)};
if (match) {
parent.halted_watchpoint = match;
- parent.jit.load()->HaltExecution(ARM_Interface::watchpoint);
+ parent.jit.load()->HaltExecution(DataAbort);
return false;
}
@@ -330,12 +330,12 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*
return std::make_unique<Dynarmic::A32::Jit>(config);
}
-Dynarmic::HaltReason ARM_Dynarmic_32::RunJit() {
- return jit.load()->Run();
+HaltReason ARM_Dynarmic_32::RunJit() {
+ return TranslateHaltReason(jit.load()->Run());
}
-Dynarmic::HaltReason ARM_Dynarmic_32::StepJit() {
- return jit.load()->Step();
+HaltReason ARM_Dynarmic_32::StepJit() {
+ return TranslateHaltReason(jit.load()->Step());
}
u32 ARM_Dynarmic_32::GetSvcNumber() const {
@@ -397,7 +397,7 @@ u64 ARM_Dynarmic_32::GetTlsAddress() const {
return cp15->uro;
}
-void ARM_Dynarmic_32::SetTlsAddress(VAddr address) {
+void ARM_Dynarmic_32::SetTlsAddress(u64 address) {
cp15->uro = static_cast<u32>(address);
}
@@ -409,37 +409,35 @@ void ARM_Dynarmic_32::SetTPIDR_EL0(u64 value) {
cp15->uprw = static_cast<u32>(value);
}
-void ARM_Dynarmic_32::SaveContext(ThreadContext32& ctx) {
- Dynarmic::A32::Context context;
- jit.load()->SaveContext(context);
- ctx.cpu_registers = context.Regs();
- ctx.extension_registers = context.ExtRegs();
- ctx.cpsr = context.Cpsr();
- ctx.fpscr = context.Fpscr();
+void ARM_Dynarmic_32::SaveContext(ThreadContext32& ctx) const {
+ Dynarmic::A32::Jit* j = jit.load();
+ ctx.cpu_registers = j->Regs();
+ ctx.extension_registers = j->ExtRegs();
+ ctx.cpsr = j->Cpsr();
+ ctx.fpscr = j->Fpscr();
}
void ARM_Dynarmic_32::LoadContext(const ThreadContext32& ctx) {
- Dynarmic::A32::Context context;
- context.Regs() = ctx.cpu_registers;
- context.ExtRegs() = ctx.extension_registers;
- context.SetCpsr(ctx.cpsr);
- context.SetFpscr(ctx.fpscr);
- jit.load()->LoadContext(context);
+ Dynarmic::A32::Jit* j = jit.load();
+ j->Regs() = ctx.cpu_registers;
+ j->ExtRegs() = ctx.extension_registers;
+ j->SetCpsr(ctx.cpsr);
+ j->SetFpscr(ctx.fpscr);
}
void ARM_Dynarmic_32::SignalInterrupt() {
- jit.load()->HaltExecution(break_loop);
+ jit.load()->HaltExecution(BreakLoop);
}
void ARM_Dynarmic_32::ClearInterrupt() {
- jit.load()->ClearHalt(break_loop);
+ jit.load()->ClearHalt(BreakLoop);
}
void ARM_Dynarmic_32::ClearInstructionCache() {
jit.load()->ClearCache();
}
-void ARM_Dynarmic_32::InvalidateCacheRange(VAddr addr, std::size_t size) {
+void ARM_Dynarmic_32::InvalidateCacheRange(u64 addr, std::size_t size) {
jit.load()->InvalidateCacheRange(static_cast<u32>(addr), size);
}
@@ -465,39 +463,4 @@ void ARM_Dynarmic_32::PageTableChanged(Common::PageTable& page_table,
jit_cache.emplace(key, std::move(new_jit));
}
-std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_32::GetBacktrace(Core::System& system,
- u64 fp, u64 lr, u64 pc) {
- std::vector<BacktraceEntry> out;
- auto& memory = system.Memory();
-
- out.push_back({"", 0, pc, 0, ""});
-
- // fp (= r11) points to the last frame record.
- // Frame records are two words long:
- // fp+0 : pointer to previous frame record
- // fp+4 : value of lr for frame
- for (size_t i = 0; i < 256; i++) {
- out.push_back({"", 0, lr, 0, ""});
- if (!fp || (fp % 4 != 0) || !memory.IsValidVirtualAddressRange(fp, 8)) {
- break;
- }
- lr = memory.Read32(fp + 4);
- fp = memory.Read32(fp);
- }
-
- SymbolicateBacktrace(system, out);
-
- return out;
-}
-
-std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_32::GetBacktraceFromContext(
- System& system, const ThreadContext32& ctx) {
- const auto& reg = ctx.cpu_registers;
- return GetBacktrace(system, reg[11], reg[14], reg[15]);
-}
-
-std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_32::GetBacktrace() const {
- return GetBacktrace(system, GetReg(11), GetReg(14), GetReg(15));
-}
-
} // namespace Core
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.h b/src/core/arm/dynarmic/arm_dynarmic_32.h
index d24ba2289..a990845cb 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_32.h
+++ b/src/core/arm/dynarmic/arm_dynarmic_32.h
@@ -41,8 +41,8 @@ public:
void SetVectorReg(int index, u128 value) override;
u32 GetPSTATE() const override;
void SetPSTATE(u32 pstate) override;
- VAddr GetTlsAddress() const override;
- void SetTlsAddress(VAddr address) override;
+ u64 GetTlsAddress() const override;
+ void SetTlsAddress(u64 address) override;
void SetTPIDR_EL0(u64 value) override;
u64 GetTPIDR_EL0() const override;
@@ -50,8 +50,11 @@ public:
return (GetPSTATE() & 0x20) != 0;
}
- void SaveContext(ThreadContext32& ctx) override;
- void SaveContext(ThreadContext64& ctx) override {}
+ Architecture GetArchitecture() const override {
+ return Architecture::Aarch32;
+ }
+ void SaveContext(ThreadContext32& ctx) const override;
+ void SaveContext(ThreadContext64& ctx) const override {}
void LoadContext(const ThreadContext32& ctx) override;
void LoadContext(const ThreadContext64& ctx) override {}
@@ -60,18 +63,13 @@ public:
void ClearExclusiveState() override;
void ClearInstructionCache() override;
- void InvalidateCacheRange(VAddr addr, std::size_t size) override;
+ void InvalidateCacheRange(u64 addr, std::size_t size) override;
void PageTableChanged(Common::PageTable& new_page_table,
std::size_t new_address_space_size_in_bits) override;
- static std::vector<BacktraceEntry> GetBacktraceFromContext(System& system,
- const ThreadContext32& ctx);
-
- std::vector<BacktraceEntry> GetBacktrace() const override;
-
protected:
- Dynarmic::HaltReason RunJit() override;
- Dynarmic::HaltReason StepJit() override;
+ HaltReason RunJit() override;
+ HaltReason StepJit() override;
u32 GetSvcNumber() const override;
const Kernel::DebugWatchpoint* HaltedWatchpoint() const override;
void RewindBreakpointInstruction() override;
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
index 7229fdc2a..bb97ed5bc 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
@@ -10,8 +10,9 @@
#include "common/logging/log.h"
#include "common/page_table.h"
#include "common/settings.h"
+#include "core/arm/dynarmic/arm_dynarmic.h"
#include "core/arm/dynarmic/arm_dynarmic_64.h"
-#include "core/arm/dynarmic/arm_exclusive_monitor.h"
+#include "core/arm/dynarmic/dynarmic_exclusive_monitor.h"
#include "core/core.h"
#include "core/core_timing.h"
#include "core/debugger/debugger.h"
@@ -28,8 +29,8 @@ using namespace Common::Literals;
class DynarmicCallbacks64 : public Dynarmic::A64::UserCallbacks {
public:
explicit DynarmicCallbacks64(ARM_Dynarmic_64& parent_)
- : parent{parent_},
- memory(parent.system.Memory()), debugger_enabled{parent.system.DebuggerEnabled()},
+ : parent{parent_}, memory(parent.system.ApplicationMemory()),
+ debugger_enabled{parent.system.DebuggerEnabled()},
check_memory_access{debugger_enabled ||
!Settings::values.cpuopt_ignore_memory_aborts.GetValue()} {}
@@ -113,11 +114,11 @@ public:
LOG_ERROR(Core_ARM,
"Unimplemented instruction @ 0x{:X} for {} instructions (instr = {:08X})", pc,
num_instructions, memory.Read32(pc));
- ReturnException(pc, ARM_Interface::no_execute);
+ ReturnException(pc, PrefetchAbort);
}
void InstructionCacheOperationRaised(Dynarmic::A64::InstructionCacheOperation op,
- VAddr value) override {
+ u64 value) override {
switch (op) {
case Dynarmic::A64::InstructionCacheOperation::InvalidateByVAToPoU: {
static constexpr u64 ICACHE_LINE_SIZE = 64;
@@ -148,11 +149,11 @@ public:
return;
case Dynarmic::A64::Exception::NoExecuteFault:
LOG_CRITICAL(Core_ARM, "Cannot execute instruction at unmapped address {:#016x}", pc);
- ReturnException(pc, ARM_Interface::no_execute);
+ ReturnException(pc, PrefetchAbort);
return;
default:
if (debugger_enabled) {
- ReturnException(pc, ARM_Interface::breakpoint);
+ ReturnException(pc, InstructionBreakpoint);
return;
}
@@ -164,7 +165,7 @@ public:
void CallSVC(u32 swi) override {
parent.svc_swi = swi;
- parent.jit.load()->HaltExecution(ARM_Interface::svc_call);
+ parent.jit.load()->HaltExecution(SupervisorCall);
}
void AddTicks(u64 ticks) override {
@@ -199,7 +200,7 @@ public:
return parent.system.CoreTiming().GetClockTicks();
}
- bool CheckMemoryAccess(VAddr addr, u64 size, Kernel::DebugWatchpointType type) {
+ bool CheckMemoryAccess(u64 addr, u64 size, Kernel::DebugWatchpointType type) {
if (!check_memory_access) {
return true;
}
@@ -207,7 +208,7 @@ public:
if (!memory.IsValidVirtualAddressRange(addr, size)) {
LOG_CRITICAL(Core_ARM, "Stopping execution due to unmapped memory access at {:#x}",
addr);
- parent.jit.load()->HaltExecution(ARM_Interface::no_execute);
+ parent.jit.load()->HaltExecution(PrefetchAbort);
return false;
}
@@ -218,7 +219,7 @@ public:
const auto match{parent.MatchingWatchpoint(addr, size, type)};
if (match) {
parent.halted_watchpoint = match;
- parent.jit.load()->HaltExecution(ARM_Interface::watchpoint);
+ parent.jit.load()->HaltExecution(DataAbort);
return false;
}
@@ -383,12 +384,12 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
return std::make_shared<Dynarmic::A64::Jit>(config);
}
-Dynarmic::HaltReason ARM_Dynarmic_64::RunJit() {
- return jit.load()->Run();
+HaltReason ARM_Dynarmic_64::RunJit() {
+ return TranslateHaltReason(jit.load()->Run());
}
-Dynarmic::HaltReason ARM_Dynarmic_64::StepJit() {
- return jit.load()->Step();
+HaltReason ARM_Dynarmic_64::StepJit() {
+ return TranslateHaltReason(jit.load()->Step());
}
u32 ARM_Dynarmic_64::GetSvcNumber() const {
@@ -452,7 +453,7 @@ u64 ARM_Dynarmic_64::GetTlsAddress() const {
return cb->tpidrro_el0;
}
-void ARM_Dynarmic_64::SetTlsAddress(VAddr address) {
+void ARM_Dynarmic_64::SetTlsAddress(u64 address) {
cb->tpidrro_el0 = address;
}
@@ -464,7 +465,7 @@ void ARM_Dynarmic_64::SetTPIDR_EL0(u64 value) {
cb->tpidr_el0 = value;
}
-void ARM_Dynarmic_64::SaveContext(ThreadContext64& ctx) {
+void ARM_Dynarmic_64::SaveContext(ThreadContext64& ctx) const {
Dynarmic::A64::Jit* j = jit.load();
ctx.cpu_registers = j->GetRegisters();
ctx.sp = j->GetSP();
@@ -489,18 +490,18 @@ void ARM_Dynarmic_64::LoadContext(const ThreadContext64& ctx) {
}
void ARM_Dynarmic_64::SignalInterrupt() {
- jit.load()->HaltExecution(break_loop);
+ jit.load()->HaltExecution(BreakLoop);
}
void ARM_Dynarmic_64::ClearInterrupt() {
- jit.load()->ClearHalt(break_loop);
+ jit.load()->ClearHalt(BreakLoop);
}
void ARM_Dynarmic_64::ClearInstructionCache() {
jit.load()->ClearCache();
}
-void ARM_Dynarmic_64::InvalidateCacheRange(VAddr addr, std::size_t size) {
+void ARM_Dynarmic_64::InvalidateCacheRange(u64 addr, std::size_t size) {
jit.load()->InvalidateCacheRange(addr, size);
}
@@ -526,39 +527,4 @@ void ARM_Dynarmic_64::PageTableChanged(Common::PageTable& page_table,
jit_cache.emplace(key, std::move(new_jit));
}
-std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_64::GetBacktrace(Core::System& system,
- u64 fp, u64 lr, u64 pc) {
- std::vector<BacktraceEntry> out;
- auto& memory = system.Memory();
-
- out.push_back({"", 0, pc, 0, ""});
-
- // fp (= x29) points to the previous frame record.
- // Frame records are two words long:
- // fp+0 : pointer to previous frame record
- // fp+8 : value of lr for frame
- for (size_t i = 0; i < 256; i++) {
- out.push_back({"", 0, lr, 0, ""});
- if (!fp || (fp % 4 != 0) || !memory.IsValidVirtualAddressRange(fp, 16)) {
- break;
- }
- lr = memory.Read64(fp + 8);
- fp = memory.Read64(fp);
- }
-
- SymbolicateBacktrace(system, out);
-
- return out;
-}
-
-std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_64::GetBacktraceFromContext(
- System& system, const ThreadContext64& ctx) {
- const auto& reg = ctx.cpu_registers;
- return GetBacktrace(system, reg[29], reg[30], ctx.pc);
-}
-
-std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_64::GetBacktrace() const {
- return GetBacktrace(system, GetReg(29), GetReg(30), GetPC());
-}
-
} // namespace Core
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.h b/src/core/arm/dynarmic/arm_dynarmic_64.h
index ed1a5eb96..af2aa1f1c 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_64.h
+++ b/src/core/arm/dynarmic/arm_dynarmic_64.h
@@ -38,13 +38,16 @@ public:
void SetVectorReg(int index, u128 value) override;
u32 GetPSTATE() const override;
void SetPSTATE(u32 pstate) override;
- VAddr GetTlsAddress() const override;
- void SetTlsAddress(VAddr address) override;
+ u64 GetTlsAddress() const override;
+ void SetTlsAddress(u64 address) override;
void SetTPIDR_EL0(u64 value) override;
u64 GetTPIDR_EL0() const override;
- void SaveContext(ThreadContext32& ctx) override {}
- void SaveContext(ThreadContext64& ctx) override;
+ Architecture GetArchitecture() const override {
+ return Architecture::Aarch64;
+ }
+ void SaveContext(ThreadContext32& ctx) const override {}
+ void SaveContext(ThreadContext64& ctx) const override;
void LoadContext(const ThreadContext32& ctx) override {}
void LoadContext(const ThreadContext64& ctx) override;
@@ -53,18 +56,13 @@ public:
void ClearExclusiveState() override;
void ClearInstructionCache() override;
- void InvalidateCacheRange(VAddr addr, std::size_t size) override;
+ void InvalidateCacheRange(u64 addr, std::size_t size) override;
void PageTableChanged(Common::PageTable& new_page_table,
std::size_t new_address_space_size_in_bits) override;
- static std::vector<BacktraceEntry> GetBacktraceFromContext(System& system,
- const ThreadContext64& ctx);
-
- std::vector<BacktraceEntry> GetBacktrace() const override;
-
protected:
- Dynarmic::HaltReason RunJit() override;
- Dynarmic::HaltReason StepJit() override;
+ HaltReason RunJit() override;
+ HaltReason StepJit() override;
u32 GetSvcNumber() const override;
const Kernel::DebugWatchpoint* HaltedWatchpoint() const override;
void RewindBreakpointInstruction() override;
@@ -73,8 +71,6 @@ private:
std::shared_ptr<Dynarmic::A64::Jit> MakeJit(Common::PageTable* page_table,
std::size_t address_space_bits) const;
- static std::vector<BacktraceEntry> GetBacktrace(Core::System& system, u64 fp, u64 lr, u64 pc);
-
using JitCacheKey = std::pair<Common::PageTable*, std::size_t>;
using JitCacheType =
std::unordered_map<JitCacheKey, std::shared_ptr<Dynarmic::A64::Jit>, Common::PairHash>;
diff --git a/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp b/src/core/arm/dynarmic/dynarmic_cp15.cpp
index 5a4eba3eb..92c548db0 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp
+++ b/src/core/arm/dynarmic/dynarmic_cp15.cpp
@@ -4,7 +4,7 @@
#include <fmt/format.h>
#include "common/logging/log.h"
#include "core/arm/dynarmic/arm_dynarmic_32.h"
-#include "core/arm/dynarmic/arm_dynarmic_cp15.h"
+#include "core/arm/dynarmic/dynarmic_cp15.h"
#include "core/core.h"
#include "core/core_timing.h"
diff --git a/src/core/arm/dynarmic/arm_dynarmic_cp15.h b/src/core/arm/dynarmic/dynarmic_cp15.h
index d90b3e568..d90b3e568 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_cp15.h
+++ b/src/core/arm/dynarmic/dynarmic_cp15.h
diff --git a/src/core/arm/dynarmic/arm_exclusive_monitor.cpp b/src/core/arm/dynarmic/dynarmic_exclusive_monitor.cpp
index fa0c48b25..b5c9c43c4 100644
--- a/src/core/arm/dynarmic/arm_exclusive_monitor.cpp
+++ b/src/core/arm/dynarmic/dynarmic_exclusive_monitor.cpp
@@ -1,7 +1,7 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
-#include "core/arm/dynarmic/arm_exclusive_monitor.h"
+#include "core/arm/dynarmic/dynarmic_exclusive_monitor.h"
#include "core/memory.h"
namespace Core {
diff --git a/src/core/arm/dynarmic/arm_exclusive_monitor.h b/src/core/arm/dynarmic/dynarmic_exclusive_monitor.h
index 57e6dd0d0..57e6dd0d0 100644
--- a/src/core/arm/dynarmic/arm_exclusive_monitor.h
+++ b/src/core/arm/dynarmic/dynarmic_exclusive_monitor.h
diff --git a/src/core/arm/exclusive_monitor.cpp b/src/core/arm/exclusive_monitor.cpp
index 20550faeb..6d9a862e1 100644
--- a/src/core/arm/exclusive_monitor.cpp
+++ b/src/core/arm/exclusive_monitor.cpp
@@ -2,7 +2,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#if defined(ARCHITECTURE_x86_64) || defined(ARCHITECTURE_arm64)
-#include "core/arm/dynarmic/arm_exclusive_monitor.h"
+#include "core/arm/dynarmic/dynarmic_exclusive_monitor.h"
#endif
#include "core/arm/exclusive_monitor.h"
#include "core/memory.h"
diff --git a/src/core/constants.cpp b/src/core/constants.cpp
index 4430173ef..760dc5f23 100644
--- a/src/core/constants.cpp
+++ b/src/core/constants.cpp
@@ -4,13 +4,24 @@
#include "core/constants.h"
namespace Core::Constants {
-const std::array<u8, 107> ACCOUNT_BACKUP_JPEG{{
- 0xff, 0xd8, 0xff, 0xdb, 0x00, 0x43, 0x00, 0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x02, 0x02,
- 0x02, 0x03, 0x03, 0x03, 0x03, 0x04, 0x06, 0x04, 0x04, 0x04, 0x04, 0x04, 0x08, 0x06, 0x06, 0x05,
- 0x06, 0x09, 0x08, 0x0a, 0x0a, 0x09, 0x08, 0x09, 0x09, 0x0a, 0x0c, 0x0f, 0x0c, 0x0a, 0x0b, 0x0e,
- 0x0b, 0x09, 0x09, 0x0d, 0x11, 0x0d, 0x0e, 0x0f, 0x10, 0x10, 0x11, 0x10, 0x0a, 0x0c, 0x12, 0x13,
- 0x12, 0x10, 0x13, 0x0f, 0x10, 0x10, 0x10, 0xff, 0xc9, 0x00, 0x0b, 0x08, 0x00, 0x01, 0x00, 0x01,
- 0x01, 0x01, 0x11, 0x00, 0xff, 0xcc, 0x00, 0x06, 0x00, 0x10, 0x10, 0x05, 0xff, 0xda, 0x00, 0x08,
- 0x01, 0x01, 0x00, 0x00, 0x3f, 0x00, 0xd2, 0xcf, 0x20, 0xff, 0xd9,
+const std::array<u8, 287> ACCOUNT_BACKUP_JPEG{{
+ 0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, 0x49, 0x46, 0x00, 0x01, 0x01, 0x01, 0x00, 0x48,
+ 0x00, 0x48, 0x00, 0x00, 0xff, 0xdb, 0x00, 0x43, 0x00, 0x06, 0x04, 0x04, 0x04, 0x05, 0x04, 0x06,
+ 0x05, 0x05, 0x06, 0x09, 0x06, 0x05, 0x06, 0x09, 0x0b, 0x08, 0x06, 0x06, 0x08, 0x0b, 0x0c, 0x0a,
+ 0x0a, 0x0b, 0x0a, 0x0a, 0x0c, 0x10, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x10, 0x0c, 0x0e, 0x0f,
+ 0x10, 0x0f, 0x0e, 0x0c, 0x13, 0x13, 0x14, 0x14, 0x13, 0x13, 0x1c, 0x1b, 0x1b, 0x1b, 0x1c, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0xff, 0xdb, 0x00, 0x43, 0x01, 0x07, 0x07,
+ 0x07, 0x0d, 0x0c, 0x0d, 0x18, 0x10, 0x10, 0x18, 0x1a, 0x15, 0x11, 0x15, 0x1a, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0xff, 0xc0,
+ 0x00, 0x11, 0x08, 0x00, 0x20, 0x00, 0x20, 0x03, 0x01, 0x22, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11,
+ 0x01, 0xff, 0xc4, 0x00, 0x14, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xc4, 0x00, 0x14, 0x10, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xc4, 0x00,
+ 0x14, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0xc4, 0x00, 0x14, 0x11, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01, 0x00,
+ 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xd9,
}};
}
diff --git a/src/core/constants.h b/src/core/constants.h
index f916ce0b6..f1f67d3b8 100644
--- a/src/core/constants.h
+++ b/src/core/constants.h
@@ -12,6 +12,6 @@
namespace Core::Constants {
// ACC Service - Blank JPEG used as user icon in absentia of real one.
-extern const std::array<u8, 107> ACCOUNT_BACKUP_JPEG;
+extern const std::array<u8, 287> ACCOUNT_BACKUP_JPEG;
} // namespace Core::Constants
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 47292cd78..b74fd0a58 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -54,10 +54,10 @@
#include "video_core/renderer_base.h"
#include "video_core/video_core.h"
-MICROPROFILE_DEFINE(ARM_Jit_Dynarmic_CPU0, "ARM JIT", "Dynarmic CPU 0", MP_RGB(255, 64, 64));
-MICROPROFILE_DEFINE(ARM_Jit_Dynarmic_CPU1, "ARM JIT", "Dynarmic CPU 1", MP_RGB(255, 64, 64));
-MICROPROFILE_DEFINE(ARM_Jit_Dynarmic_CPU2, "ARM JIT", "Dynarmic CPU 2", MP_RGB(255, 64, 64));
-MICROPROFILE_DEFINE(ARM_Jit_Dynarmic_CPU3, "ARM JIT", "Dynarmic CPU 3", MP_RGB(255, 64, 64));
+MICROPROFILE_DEFINE(ARM_CPU0, "ARM", "CPU 0", MP_RGB(255, 64, 64));
+MICROPROFILE_DEFINE(ARM_CPU1, "ARM", "CPU 1", MP_RGB(255, 64, 64));
+MICROPROFILE_DEFINE(ARM_CPU2, "ARM", "CPU 2", MP_RGB(255, 64, 64));
+MICROPROFILE_DEFINE(ARM_CPU3, "ARM", "CPU 3", MP_RGB(255, 64, 64));
namespace Core {
@@ -117,8 +117,7 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
return nullptr;
}
- return FileSys::ConcatenatedVfsFile::MakeConcatenatedFile(std::move(concat),
- dir->GetName());
+ return FileSys::ConcatenatedVfsFile::MakeConcatenatedFile(concat, dir->GetName());
}
if (Common::FS::IsDir(path)) {
@@ -137,7 +136,7 @@ struct System::Impl {
device_memory = std::make_unique<Core::DeviceMemory>();
is_multicore = Settings::values.use_multi_core.GetValue();
- extended_memory_layout = Settings::values.use_extended_memory_layout.GetValue();
+ extended_memory_layout = Settings::values.use_unsafe_extended_memory_layout.GetValue();
core_timing.SetMulticore(is_multicore);
core_timing.Initialize([&system]() { system.RegisterHostThread(); });
@@ -169,7 +168,7 @@ struct System::Impl {
void ReinitializeIfNecessary(System& system) {
const bool must_reinitialize =
is_multicore != Settings::values.use_multi_core.GetValue() ||
- extended_memory_layout != Settings::values.use_extended_memory_layout.GetValue();
+ extended_memory_layout != Settings::values.use_unsafe_extended_memory_layout.GetValue();
if (!must_reinitialize) {
return;
@@ -178,7 +177,7 @@ struct System::Impl {
LOG_DEBUG(Kernel, "Re-initializing");
is_multicore = Settings::values.use_multi_core.GetValue();
- extended_memory_layout = Settings::values.use_extended_memory_layout.GetValue();
+ extended_memory_layout = Settings::values.use_unsafe_extended_memory_layout.GetValue();
Initialize(system);
}
@@ -186,7 +185,7 @@ struct System::Impl {
void Run() {
std::unique_lock<std::mutex> lk(suspend_guard);
- kernel.Suspend(false);
+ kernel.SuspendApplication(false);
core_timing.SyncPause(false);
is_paused.store(false, std::memory_order_relaxed);
}
@@ -195,7 +194,7 @@ struct System::Impl {
std::unique_lock<std::mutex> lk(suspend_guard);
core_timing.SyncPause(true);
- kernel.Suspend(true);
+ kernel.SuspendApplication(true);
is_paused.store(true, std::memory_order_relaxed);
}
@@ -203,25 +202,33 @@ struct System::Impl {
return is_paused.load(std::memory_order_relaxed);
}
- std::unique_lock<std::mutex> StallProcesses() {
+ std::unique_lock<std::mutex> StallApplication() {
std::unique_lock<std::mutex> lk(suspend_guard);
- kernel.Suspend(true);
+ kernel.SuspendApplication(true);
core_timing.SyncPause(true);
return lk;
}
- void UnstallProcesses() {
+ void UnstallApplication() {
if (!IsPaused()) {
core_timing.SyncPause(false);
- kernel.Suspend(false);
+ kernel.SuspendApplication(false);
}
}
+ void SetNVDECActive(bool is_nvdec_active) {
+ nvdec_active = is_nvdec_active;
+ }
+
+ bool GetNVDECActive() {
+ return nvdec_active;
+ }
+
void InitializeDebugger(System& system, u16 port) {
debugger = std::make_unique<Debugger>(system, port);
}
- SystemResultStatus SetupForMainProcess(System& system, Frontend::EmuWindow& emu_window) {
+ SystemResultStatus SetupForApplicationProcess(System& system, Frontend::EmuWindow& emu_window) {
LOG_DEBUG(Core, "initialized OK");
// Setting changes may require a full system reinitialization (e.g., disabling multicore).
@@ -252,10 +259,10 @@ struct System::Impl {
is_powered_on = true;
exit_lock = false;
- microprofile_dynarmic[0] = MICROPROFILE_TOKEN(ARM_Jit_Dynarmic_CPU0);
- microprofile_dynarmic[1] = MICROPROFILE_TOKEN(ARM_Jit_Dynarmic_CPU1);
- microprofile_dynarmic[2] = MICROPROFILE_TOKEN(ARM_Jit_Dynarmic_CPU2);
- microprofile_dynarmic[3] = MICROPROFILE_TOKEN(ARM_Jit_Dynarmic_CPU3);
+ microprofile_cpu[0] = MICROPROFILE_TOKEN(ARM_CPU0);
+ microprofile_cpu[1] = MICROPROFILE_TOKEN(ARM_CPU1);
+ microprofile_cpu[2] = MICROPROFILE_TOKEN(ARM_CPU2);
+ microprofile_cpu[3] = MICROPROFILE_TOKEN(ARM_CPU3);
LOG_DEBUG(Core, "Initialized OK");
@@ -273,7 +280,7 @@ struct System::Impl {
return SystemResultStatus::ErrorGetLoader;
}
- SystemResultStatus init_result{SetupForMainProcess(system, emu_window)};
+ SystemResultStatus init_result{SetupForApplicationProcess(system, emu_window)};
if (init_result != SystemResultStatus::Success) {
LOG_CRITICAL(Core, "Failed to initialize system (Error {})!",
static_cast<int>(init_result));
@@ -293,6 +300,8 @@ struct System::Impl {
ASSERT(Kernel::KProcess::Initialize(main_process, system, "main",
Kernel::KProcess::ProcessType::Userland, resource_limit)
.IsSuccess());
+ Kernel::KProcess::Register(system.Kernel(), main_process);
+ kernel.MakeApplicationProcess(main_process);
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);
@@ -302,7 +311,6 @@ struct System::Impl {
static_cast<u32>(SystemResultStatus::ErrorLoader) + static_cast<u32>(load_result));
}
AddGlueRegistrationForProcess(*app_loader, *main_process);
- kernel.MakeCurrentProcess(main_process);
kernel.InitializeCores();
// Initialize cheat engine
@@ -358,7 +366,7 @@ struct System::Impl {
void ShutdownMainProcess() {
SetShuttingDown(true);
- // Log last frame performance stats if game was loded
+ // Log last frame performance stats if game was loaded
if (perf_stats) {
const auto perf_results = GetAndResetPerfStats();
constexpr auto performance = Common::Telemetry::FieldType::Performance;
@@ -380,9 +388,7 @@ struct System::Impl {
gpu_core->NotifyShutdown();
}
- kernel.ShutdownCores();
- cpu_manager.Shutdown();
- debugger.reset();
+ kernel.SuspendApplication(true);
if (services) {
services->KillNVNFlinger();
}
@@ -398,6 +404,9 @@ struct System::Impl {
gpu_core.reset();
host1x_core.reset();
perf_stats.reset();
+ kernel.ShutdownCores();
+ cpu_manager.Shutdown();
+ debugger.reset();
kernel.Shutdown();
memory.Reset();
@@ -433,7 +442,7 @@ struct System::Impl {
}
Service::Glue::ApplicationLaunchProperty launch{};
- launch.title_id = process.GetProgramID();
+ launch.title_id = process.GetProgramId();
FileSys::PatchManager pm{launch.title_id, fs_controller, *content_provider};
launch.version = pm.GetGameVersion().value_or(0);
@@ -484,6 +493,8 @@ struct System::Impl {
std::atomic_bool is_powered_on{};
bool exit_lock = false;
+ bool nvdec_active{};
+
Reporter reporter;
std::unique_ptr<Memory::CheatEngine> cheat_engine;
std::unique_ptr<Tools::Freezer> memory_freezer;
@@ -528,7 +539,7 @@ struct System::Impl {
ExitCallback exit_callback;
std::array<u64, Core::Hardware::NUM_CPU_CORES> dynarmic_ticks{};
- std::array<MicroProfileToken, Core::Hardware::NUM_CPU_CORES> microprofile_dynarmic{};
+ std::array<MicroProfileToken, Core::Hardware::NUM_CPU_CORES> microprofile_cpu{};
};
System::System() : impl{std::make_unique<Impl>(*this)} {}
@@ -563,7 +574,7 @@ void System::InvalidateCpuInstructionCaches() {
impl->kernel.InvalidateAllInstructionCaches();
}
-void System::InvalidateCpuInstructionCacheRange(VAddr addr, std::size_t size) {
+void System::InvalidateCpuInstructionCacheRange(u64 addr, std::size_t size) {
impl->kernel.InvalidateCpuInstructionCacheRange(addr, size);
}
@@ -585,12 +596,20 @@ void System::DetachDebugger() {
}
}
-std::unique_lock<std::mutex> System::StallProcesses() {
- return impl->StallProcesses();
+std::unique_lock<std::mutex> System::StallApplication() {
+ return impl->StallApplication();
+}
+
+void System::UnstallApplication() {
+ impl->UnstallApplication();
+}
+
+void System::SetNVDECActive(bool is_nvdec_active) {
+ impl->SetNVDECActive(is_nvdec_active);
}
-void System::UnstallProcesses() {
- impl->UnstallProcesses();
+bool System::GetNVDECActive() {
+ return impl->GetNVDECActive();
}
void System::InitializeDebugger() {
@@ -610,6 +629,10 @@ void System::PrepareReschedule(const u32 core_index) {
impl->kernel.PrepareReschedule(core_index);
}
+size_t System::GetCurrentHostThreadID() const {
+ return impl->kernel.GetCurrentHostThreadID();
+}
+
PerfStatsResults System::GetAndResetPerfStats() {
return impl->GetAndResetPerfStats();
}
@@ -648,8 +671,8 @@ const Kernel::GlobalSchedulerContext& System::GlobalSchedulerContext() const {
return impl->kernel.GlobalSchedulerContext();
}
-Kernel::KProcess* System::CurrentProcess() {
- return impl->kernel.CurrentProcess();
+Kernel::KProcess* System::ApplicationProcess() {
+ return impl->kernel.ApplicationProcess();
}
Core::DeviceMemory& System::DeviceMemory() {
@@ -660,8 +683,8 @@ const Core::DeviceMemory& System::DeviceMemory() const {
return *impl->device_memory;
}
-const Kernel::KProcess* System::CurrentProcess() const {
- return impl->kernel.CurrentProcess();
+const Kernel::KProcess* System::ApplicationProcess() const {
+ return impl->kernel.ApplicationProcess();
}
ARM_Interface& System::ArmInterface(std::size_t core_index) {
@@ -680,11 +703,11 @@ const ExclusiveMonitor& System::Monitor() const {
return impl->kernel.GetExclusiveMonitor();
}
-Memory::Memory& System::Memory() {
+Memory::Memory& System::ApplicationMemory() {
return impl->memory;
}
-const Core::Memory::Memory& System::Memory() const {
+const Core::Memory::Memory& System::ApplicationMemory() const {
return impl->memory;
}
@@ -760,8 +783,8 @@ const Core::SpeedLimiter& System::SpeedLimiter() const {
return impl->speed_limiter;
}
-u64 System::GetCurrentProcessProgramID() const {
- return impl->kernel.CurrentProcess()->GetProgramID();
+u64 System::GetApplicationProcessProgramID() const {
+ return impl->kernel.ApplicationProcess()->GetProgramId();
}
Loader::ResultStatus System::GetGameName(std::string& out) const {
@@ -793,7 +816,7 @@ FileSys::VirtualFilesystem System::GetFilesystem() const {
}
void System::RegisterCheatList(const std::vector<Memory::CheatEntry>& list,
- const std::array<u8, 32>& build_id, VAddr main_region_begin,
+ const std::array<u8, 32>& build_id, u64 main_region_begin,
u64 main_region_size) {
impl->cheat_engine = std::make_unique<Memory::CheatEngine>(*this, list, build_id);
impl->cheat_engine->SetMainMemoryParameters(main_region_begin, main_region_size);
@@ -880,11 +903,11 @@ bool System::GetExitLock() const {
return impl->exit_lock;
}
-void System::SetCurrentProcessBuildID(const CurrentBuildProcessID& id) {
+void System::SetApplicationProcessBuildID(const CurrentBuildProcessID& id) {
impl->build_id = id;
}
-const System::CurrentBuildProcessID& System::GetCurrentProcessBuildID() const {
+const System::CurrentBuildProcessID& System::GetApplicationProcessBuildID() const {
return impl->build_id;
}
@@ -904,14 +927,14 @@ void System::RegisterHostThread() {
impl->kernel.RegisterHostThread();
}
-void System::EnterDynarmicProfile() {
+void System::EnterCPUProfile() {
std::size_t core = impl->kernel.GetCurrentHostThreadID();
- impl->dynarmic_ticks[core] = MicroProfileEnter(impl->microprofile_dynarmic[core]);
+ impl->dynarmic_ticks[core] = MicroProfileEnter(impl->microprofile_cpu[core]);
}
-void System::ExitDynarmicProfile() {
+void System::ExitCPUProfile() {
std::size_t core = impl->kernel.GetCurrentHostThreadID();
- MicroProfileLeave(impl->microprofile_dynarmic[core], impl->dynarmic_ticks[core]);
+ MicroProfileLeave(impl->microprofile_cpu[core], impl->dynarmic_ticks[core]);
}
bool System::IsMulticore() const {
@@ -938,6 +961,10 @@ const Network::RoomNetwork& System::GetRoomNetwork() const {
return impl->room_network;
}
+void System::RunServer(std::unique_ptr<Service::ServerManager>&& server_manager) {
+ return impl->kernel.RunServer(std::move(server_manager));
+}
+
void System::RegisterExecuteProgramCallback(ExecuteProgramCallback&& callback) {
impl->execute_program_callback = std::move(callback);
}
diff --git a/src/core/core.h b/src/core/core.h
index fb5cda2f5..93afc9303 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -61,6 +61,8 @@ namespace Glue {
class ARPManager;
}
+class ServerManager;
+
namespace SM {
class ServiceManager;
} // namespace SM
@@ -144,7 +146,7 @@ public:
/**
* Initializes the system
- * This function will initialize core functionaility used for system emulation
+ * This function will initialize core functionality used for system emulation
*/
void Initialize();
@@ -170,7 +172,7 @@ public:
*/
void InvalidateCpuInstructionCaches();
- void InvalidateCpuInstructionCacheRange(VAddr addr, std::size_t size);
+ void InvalidateCpuInstructionCacheRange(u64 addr, std::size_t size);
/// Shutdown the main emulated process.
void ShutdownMainProcess();
@@ -184,8 +186,11 @@ public:
/// Forcibly detach the debugger if it is running.
void DetachDebugger();
- std::unique_lock<std::mutex> StallProcesses();
- void UnstallProcesses();
+ std::unique_lock<std::mutex> StallApplication();
+ void UnstallApplication();
+
+ void SetNVDECActive(bool is_nvdec_active);
+ [[nodiscard]] bool GetNVDECActive();
/**
* Initialize the debugger.
@@ -220,6 +225,8 @@ public:
/// Prepare the core emulation for a reschedule
void PrepareReschedule(u32 core_index);
+ [[nodiscard]] size_t GetCurrentHostThreadID() const;
+
/// Gets and resets core performance statistics
[[nodiscard]] PerfStatsResults GetAndResetPerfStats();
@@ -254,10 +261,10 @@ public:
[[nodiscard]] const ExclusiveMonitor& Monitor() const;
/// Gets a mutable reference to the system memory instance.
- [[nodiscard]] Core::Memory::Memory& Memory();
+ [[nodiscard]] Core::Memory::Memory& ApplicationMemory();
/// Gets a constant reference to the system memory instance.
- [[nodiscard]] const Core::Memory::Memory& Memory() const;
+ [[nodiscard]] const Core::Memory::Memory& ApplicationMemory() const;
/// Gets a mutable reference to the GPU interface
[[nodiscard]] Tegra::GPU& GPU();
@@ -295,11 +302,11 @@ public:
/// Gets the manager for the guest device memory
[[nodiscard]] const Core::DeviceMemory& DeviceMemory() const;
- /// Provides a pointer to the current process
- [[nodiscard]] Kernel::KProcess* CurrentProcess();
+ /// Provides a pointer to the application process
+ [[nodiscard]] Kernel::KProcess* ApplicationProcess();
- /// Provides a constant pointer to the current process.
- [[nodiscard]] const Kernel::KProcess* CurrentProcess() const;
+ /// Provides a constant pointer to the application process.
+ [[nodiscard]] const Kernel::KProcess* ApplicationProcess() const;
/// Provides a reference to the core timing instance.
[[nodiscard]] Timing::CoreTiming& CoreTiming();
@@ -331,7 +338,7 @@ public:
/// Provides a constant reference to the speed limiter
[[nodiscard]] const Core::SpeedLimiter& SpeedLimiter() const;
- [[nodiscard]] u64 GetCurrentProcessProgramID() const;
+ [[nodiscard]] u64 GetApplicationProcessProgramID() const;
/// Gets the name of the current game
[[nodiscard]] Loader::ResultStatus GetGameName(std::string& out) const;
@@ -351,7 +358,7 @@ public:
[[nodiscard]] FileSys::VirtualFilesystem GetFilesystem() const;
void RegisterCheatList(const std::vector<Memory::CheatEntry>& list,
- const std::array<u8, 0x20>& build_id, VAddr main_region_begin,
+ const std::array<u8, 0x20>& build_id, u64 main_region_begin,
u64 main_region_size);
void SetAppletFrontendSet(Service::AM::Applets::AppletFrontendSet&& set);
@@ -396,8 +403,8 @@ public:
void SetExitLock(bool locked);
[[nodiscard]] bool GetExitLock() const;
- void SetCurrentProcessBuildID(const CurrentBuildProcessID& id);
- [[nodiscard]] const CurrentBuildProcessID& GetCurrentProcessBuildID() const;
+ void SetApplicationProcessBuildID(const CurrentBuildProcessID& id);
+ [[nodiscard]] const CurrentBuildProcessID& GetApplicationProcessBuildID() const;
/// Register a host thread as an emulated CPU Core.
void RegisterCoreThread(std::size_t id);
@@ -405,11 +412,11 @@ public:
/// Register a host thread as an auxiliary thread.
void RegisterHostThread();
- /// Enter Dynarmic Microprofile
- void EnterDynarmicProfile();
+ /// Enter CPU Microprofile
+ void EnterCPUProfile();
- /// Exit Dynarmic Microprofile
- void ExitDynarmicProfile();
+ /// Exit CPU Microprofile
+ void ExitCPUProfile();
/// Tells if system is running on multicore.
[[nodiscard]] bool IsMulticore() const;
@@ -417,6 +424,9 @@ public:
/// Tells if the system debugger is enabled.
[[nodiscard]] bool DebuggerEnabled() const;
+ /// Runs a server instance until shutdown.
+ void RunServer(std::unique_ptr<Service::ServerManager>&& server_manager);
+
/// Type used for the frontend to designate a callback for System to re-launch the application
/// using a specified program index.
using ExecuteProgramCallback = std::function<void(std::size_t)>;
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp
index 6bac6722f..4f0a3f8ea 100644
--- a/src/core/core_timing.cpp
+++ b/src/core/core_timing.cpp
@@ -6,14 +6,21 @@
#include <string>
#include <tuple>
+#ifdef _WIN32
+#include "common/windows/timer_resolution.h"
+#endif
+
+#ifdef ARCHITECTURE_x86_64
+#include "common/x64/cpu_wait.h"
+#endif
+
#include "common/microprofile.h"
#include "core/core_timing.h"
-#include "core/core_timing_util.h"
#include "core/hardware_properties.h"
namespace Core::Timing {
-constexpr s64 MAX_SLICE_LENGTH = 4000;
+constexpr s64 MAX_SLICE_LENGTH = 10000;
std::shared_ptr<EventType> CreateEvent(std::string name, TimedCallback&& callback) {
return std::make_shared<EventType>(std::move(callback), std::move(name));
@@ -37,18 +44,17 @@ struct CoreTiming::Event {
}
};
-CoreTiming::CoreTiming()
- : clock{Common::CreateBestMatchingClock(Hardware::BASE_CLOCK_RATE, Hardware::CNTFREQ)} {}
+CoreTiming::CoreTiming() : clock{Common::CreateOptimalClock()} {}
CoreTiming::~CoreTiming() {
Reset();
}
void CoreTiming::ThreadEntry(CoreTiming& instance) {
- constexpr char name[] = "HostTiming";
+ static constexpr char name[] = "HostTiming";
MicroProfileOnThreadCreate(name);
Common::SetCurrentThreadName(name);
- Common::SetCurrentThreadPriority(Common::ThreadPriority::Critical);
+ Common::SetCurrentThreadPriority(Common::ThreadPriority::High);
instance.on_thread_init();
instance.ThreadLoop();
MicroProfileOnThreadExit();
@@ -59,7 +65,7 @@ void CoreTiming::Initialize(std::function<void()>&& on_thread_init_) {
on_thread_init = std::move(on_thread_init_);
event_fifo_id = 0;
shutting_down = false;
- ticks = 0;
+ cpu_ticks = 0;
const auto empty_timed_callback = [](std::uintptr_t, u64, std::chrono::nanoseconds)
-> std::optional<std::chrono::nanoseconds> { return std::nullopt; };
ev_lost = CreateEvent("_lost_event", empty_timed_callback);
@@ -164,38 +170,30 @@ void CoreTiming::UnscheduleEvent(const std::shared_ptr<EventType>& event_type,
}
void CoreTiming::AddTicks(u64 ticks_to_add) {
- ticks += ticks_to_add;
- downcount -= static_cast<s64>(ticks);
+ cpu_ticks += ticks_to_add;
+ downcount -= static_cast<s64>(cpu_ticks);
}
void CoreTiming::Idle() {
- if (!event_queue.empty()) {
- const u64 next_event_time = event_queue.front().time;
- const u64 next_ticks = nsToCycles(std::chrono::nanoseconds(next_event_time)) + 10U;
- if (next_ticks > ticks) {
- ticks = next_ticks;
- }
- return;
- }
- ticks += 1000U;
+ cpu_ticks += 1000U;
}
void CoreTiming::ResetTicks() {
downcount = MAX_SLICE_LENGTH;
}
-u64 CoreTiming::GetCPUTicks() const {
- if (is_multicore) {
- return clock->GetCPUCycles();
+u64 CoreTiming::GetClockTicks() const {
+ if (is_multicore) [[likely]] {
+ return clock->GetCNTPCT();
}
- return ticks;
+ return Common::WallClock::CPUTickToCNTPCT(cpu_ticks);
}
-u64 CoreTiming::GetClockTicks() const {
- if (is_multicore) {
- return clock->GetClockCycles();
+u64 CoreTiming::GetGPUTicks() const {
+ if (is_multicore) [[likely]] {
+ return clock->GetGPUTick();
}
- return CpuCyclesToClockCycles(ticks);
+ return Common::WallClock::CPUTickToGPUTick(cpu_ticks);
}
std::optional<s64> CoreTiming::Advance() {
@@ -252,21 +250,24 @@ void CoreTiming::ThreadLoop() {
const auto next_time = Advance();
if (next_time) {
// There are more events left in the queue, wait until the next event.
- const auto wait_time = *next_time - GetGlobalTimeNs().count();
+ auto wait_time = *next_time - GetGlobalTimeNs().count();
if (wait_time > 0) {
#ifdef _WIN32
- // Assume a timer resolution of 1ms.
- static constexpr s64 TimerResolutionNS = 1000000;
+ const auto timer_resolution_ns =
+ Common::Windows::GetCurrentTimerResolution().count();
- // Sleep in discrete intervals of the timer resolution, and spin the rest.
- const auto sleep_time = wait_time - (wait_time % TimerResolutionNS);
- if (sleep_time > 0) {
- event.WaitFor(std::chrono::nanoseconds(sleep_time));
- }
+ while (!paused && !event.IsSet() && wait_time > 0) {
+ wait_time = *next_time - GetGlobalTimeNs().count();
- while (!paused && !event.IsSet() && GetGlobalTimeNs().count() < *next_time) {
- // Yield to reduce thread starvation.
- std::this_thread::yield();
+ if (wait_time >= timer_resolution_ns) {
+ Common::Windows::SleepForOneTick();
+ } else {
+#ifdef ARCHITECTURE_x86_64
+ Common::X64::MicroSleep();
+#else
+ std::this_thread::yield();
+#endif
+ }
}
if (event.IsSet()) {
@@ -285,9 +286,7 @@ void CoreTiming::ThreadLoop() {
}
paused_set = true;
- clock->Pause(true);
pause_event.Wait();
- clock->Pause(false);
}
}
@@ -304,17 +303,17 @@ void CoreTiming::Reset() {
}
std::chrono::nanoseconds CoreTiming::GetGlobalTimeNs() const {
- if (is_multicore) {
+ if (is_multicore) [[likely]] {
return clock->GetTimeNS();
}
- return CyclesToNs(ticks);
+ return std::chrono::nanoseconds{Common::WallClock::CPUTickToNS(cpu_ticks)};
}
std::chrono::microseconds CoreTiming::GetGlobalTimeUs() const {
- if (is_multicore) {
+ if (is_multicore) [[likely]] {
return clock->GetTimeUS();
}
- return CyclesToUs(ticks);
+ return std::chrono::microseconds{Common::WallClock::CPUTickToUS(cpu_ticks)};
}
} // namespace Core::Timing
diff --git a/src/core/core_timing.h b/src/core/core_timing.h
index da366637b..10db1de55 100644
--- a/src/core/core_timing.h
+++ b/src/core/core_timing.h
@@ -116,12 +116,12 @@ public:
return downcount;
}
- /// Returns current time in emulated CPU cycles
- u64 GetCPUTicks() const;
-
- /// Returns current time in emulated in Clock cycles
+ /// Returns the current CNTPCT tick value.
u64 GetClockTicks() const;
+ /// Returns the current GPU tick value.
+ u64 GetGPUTicks() const;
+
/// Returns current time in microseconds.
std::chrono::microseconds GetGlobalTimeUs() const;
@@ -146,7 +146,7 @@ private:
// The queue is a min-heap using std::make_heap/push_heap/pop_heap.
// We don't use std::priority_queue because we need to be able to serialize, unserialize and
// erase arbitrary events (RemoveEvent()) regardless of the queue order. These aren't
- // accomodated by the standard adaptor class.
+ // accommodated by the standard adaptor class.
std::vector<Event> event_queue;
u64 event_fifo_id = 0;
@@ -167,7 +167,7 @@ private:
s64 pause_end_time{};
/// Cycle timing
- u64 ticks{};
+ u64 cpu_ticks{};
s64 downcount{};
};
diff --git a/src/core/core_timing_util.h b/src/core/core_timing_util.h
deleted file mode 100644
index fe5aaefc7..000000000
--- a/src/core/core_timing_util.h
+++ /dev/null
@@ -1,58 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#pragma once
-
-#include <chrono>
-
-#include "common/common_types.h"
-#include "core/hardware_properties.h"
-
-namespace Core::Timing {
-
-namespace detail {
-constexpr u64 CNTFREQ_ADJUSTED = Hardware::CNTFREQ / 1000;
-constexpr u64 BASE_CLOCK_RATE_ADJUSTED = Hardware::BASE_CLOCK_RATE / 1000;
-} // namespace detail
-
-[[nodiscard]] constexpr s64 msToCycles(std::chrono::milliseconds ms) {
- return ms.count() * detail::BASE_CLOCK_RATE_ADJUSTED;
-}
-
-[[nodiscard]] constexpr s64 usToCycles(std::chrono::microseconds us) {
- return us.count() * detail::BASE_CLOCK_RATE_ADJUSTED / 1000;
-}
-
-[[nodiscard]] constexpr s64 nsToCycles(std::chrono::nanoseconds ns) {
- return ns.count() * detail::BASE_CLOCK_RATE_ADJUSTED / 1000000;
-}
-
-[[nodiscard]] constexpr u64 msToClockCycles(std::chrono::milliseconds ms) {
- return static_cast<u64>(ms.count()) * detail::CNTFREQ_ADJUSTED;
-}
-
-[[nodiscard]] constexpr u64 usToClockCycles(std::chrono::microseconds us) {
- return us.count() * detail::CNTFREQ_ADJUSTED / 1000;
-}
-
-[[nodiscard]] constexpr u64 nsToClockCycles(std::chrono::nanoseconds ns) {
- return ns.count() * detail::CNTFREQ_ADJUSTED / 1000000;
-}
-
-[[nodiscard]] constexpr u64 CpuCyclesToClockCycles(u64 ticks) {
- return ticks * detail::CNTFREQ_ADJUSTED / detail::BASE_CLOCK_RATE_ADJUSTED;
-}
-
-[[nodiscard]] constexpr std::chrono::milliseconds CyclesToMs(s64 cycles) {
- return std::chrono::milliseconds(cycles / detail::BASE_CLOCK_RATE_ADJUSTED);
-}
-
-[[nodiscard]] constexpr std::chrono::nanoseconds CyclesToNs(s64 cycles) {
- return std::chrono::nanoseconds(cycles * 1000000 / detail::BASE_CLOCK_RATE_ADJUSTED);
-}
-
-[[nodiscard]] constexpr std::chrono::microseconds CyclesToUs(s64 cycles) {
- return std::chrono::microseconds(cycles * 1000 / detail::BASE_CLOCK_RATE_ADJUSTED);
-}
-
-} // namespace Core::Timing
diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp
index 04a11f444..980bb97f9 100644
--- a/src/core/cpu_manager.cpp
+++ b/src/core/cpu_manager.cpp
@@ -192,7 +192,7 @@ void CpuManager::RunThread(std::stop_token token, std::size_t core) {
}
MicroProfileOnThreadCreate(name.c_str());
Common::SetCurrentThreadName(name.c_str());
- Common::SetCurrentThreadPriority(Common::ThreadPriority::High);
+ Common::SetCurrentThreadPriority(Common::ThreadPriority::Critical);
auto& data = core_data[core];
data.host_context = Common::Fiber::ThreadToFiber();
diff --git a/src/core/crypto/ctr_encryption_layer.h b/src/core/crypto/ctr_encryption_layer.h
index 77f08d776..d85ad8f78 100644
--- a/src/core/crypto/ctr_encryption_layer.h
+++ b/src/core/crypto/ctr_encryption_layer.h
@@ -11,7 +11,7 @@
namespace Core::Crypto {
-// Sits on top of a VirtualFile and provides CTR-mode AES decription.
+// Sits on top of a VirtualFile and provides CTR-mode AES description.
class CTREncryptionLayer : public EncryptionLayer {
public:
using IVData = std::array<u8, 16>;
diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp
index 65a9fe802..4ff2c50e5 100644
--- a/src/core/crypto/key_manager.cpp
+++ b/src/core/crypto/key_manager.cpp
@@ -569,6 +569,10 @@ std::optional<std::pair<Key128, Key128>> ParseTicket(const Ticket& ticket,
}
KeyManager::KeyManager() {
+ ReloadKeys();
+}
+
+void KeyManager::ReloadKeys() {
// Initialize keys
const auto yuzu_keys_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::KeysDir);
@@ -702,6 +706,10 @@ void KeyManager::LoadFromFile(const std::filesystem::path& file_path, bool is_ti
}
}
+bool KeyManager::AreKeysLoaded() const {
+ return !s128_keys.empty() && !s256_keys.empty();
+}
+
bool KeyManager::BaseDeriveNecessary() const {
const auto check_key_existence = [this](auto key_type, u64 index1 = 0, u64 index2 = 0) {
return !HasKey(key_type, index1, index2);
diff --git a/src/core/crypto/key_manager.h b/src/core/crypto/key_manager.h
index dbf9ebfe4..8c864503b 100644
--- a/src/core/crypto/key_manager.h
+++ b/src/core/crypto/key_manager.h
@@ -249,7 +249,7 @@ public:
static bool KeyFileExists(bool title);
- // Call before using the sd seed to attempt to derive it if it dosen't exist. Needs system
+ // Call before using the sd seed to attempt to derive it if it doesn't exist. Needs system
// save 8*43 and the private file to exist.
void DeriveSDSeedLazy();
@@ -267,6 +267,9 @@ public:
bool AddTicketCommon(Ticket raw);
bool AddTicketPersonalized(Ticket raw);
+ void ReloadKeys();
+ bool AreKeysLoaded() const;
+
private:
KeyManager();
diff --git a/src/core/crypto/xts_encryption_layer.h b/src/core/crypto/xts_encryption_layer.h
index 735e660cb..68b5643b1 100644
--- a/src/core/crypto/xts_encryption_layer.h
+++ b/src/core/crypto/xts_encryption_layer.h
@@ -9,7 +9,7 @@
namespace Core::Crypto {
-// Sits on top of a VirtualFile and provides XTS-mode AES decription.
+// Sits on top of a VirtualFile and provides XTS-mode AES description.
class XTSEncryptionLayer : public EncryptionLayer {
public:
XTSEncryptionLayer(FileSys::VirtualFile base, Key256 key);
diff --git a/src/core/debugger/debugger.cpp b/src/core/debugger/debugger.cpp
index a9675df76..a1589fecb 100644
--- a/src/core/debugger/debugger.cpp
+++ b/src/core/debugger/debugger.cpp
@@ -16,6 +16,7 @@
#include "core/debugger/debugger_interface.h"
#include "core/debugger/gdbstub.h"
#include "core/hle/kernel/global_scheduler_context.h"
+#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_scheduler.h"
template <typename Readable, typename Buffer, typename Callback>
@@ -284,12 +285,12 @@ private:
void UpdateActiveThread() {
const auto& threads{ThreadList()};
if (std::find(threads.begin(), threads.end(), state->active_thread) == threads.end()) {
- state->active_thread = threads[0];
+ state->active_thread = threads.front();
}
}
- const std::vector<Kernel::KThread*>& ThreadList() {
- return system.GlobalSchedulerContext().GetThreadList();
+ const std::list<Kernel::KThread*>& ThreadList() {
+ return system.ApplicationProcess()->GetThreadList();
}
private:
diff --git a/src/core/debugger/gdbstub.cpp b/src/core/debugger/gdbstub.cpp
index 9c02b7b31..e2a13bbd2 100644
--- a/src/core/debugger/gdbstub.cpp
+++ b/src/core/debugger/gdbstub.cpp
@@ -96,7 +96,7 @@ static std::string EscapeXML(std::string_view data) {
GDBStub::GDBStub(DebuggerBackend& backend_, Core::System& system_)
: DebuggerFrontend(backend_), system{system_} {
- if (system.CurrentProcess()->Is64BitProcess()) {
+ if (system.ApplicationProcess()->Is64BitProcess()) {
arch = std::make_unique<GDBStubA64>();
} else {
arch = std::make_unique<GDBStubA32>();
@@ -118,14 +118,14 @@ void GDBStub::Watchpoint(Kernel::KThread* thread, const Kernel::DebugWatchpoint&
switch (watch.type) {
case Kernel::DebugWatchpointType::Read:
- SendReply(fmt::format("{}rwatch:{:x};", status, watch.start_address));
+ SendReply(fmt::format("{}rwatch:{:x};", status, GetInteger(watch.start_address)));
break;
case Kernel::DebugWatchpointType::Write:
- SendReply(fmt::format("{}watch:{:x};", status, watch.start_address));
+ SendReply(fmt::format("{}watch:{:x};", status, GetInteger(watch.start_address)));
break;
case Kernel::DebugWatchpointType::ReadOrWrite:
default:
- SendReply(fmt::format("{}awatch:{:x};", status, watch.start_address));
+ SendReply(fmt::format("{}awatch:{:x};", status, GetInteger(watch.start_address)));
break;
}
}
@@ -261,9 +261,9 @@ void GDBStub::ExecuteCommand(std::string_view packet, std::vector<DebuggerAction
const size_t addr{static_cast<size_t>(strtoll(command.data(), nullptr, 16))};
const size_t size{static_cast<size_t>(strtoll(command.data() + sep, nullptr, 16))};
- if (system.Memory().IsValidVirtualAddressRange(addr, size)) {
+ if (system.ApplicationMemory().IsValidVirtualAddressRange(addr, size)) {
std::vector<u8> mem(size);
- system.Memory().ReadBlock(addr, mem.data(), size);
+ system.ApplicationMemory().ReadBlock(addr, mem.data(), size);
SendReply(Common::HexToString(mem));
} else {
@@ -281,8 +281,8 @@ void GDBStub::ExecuteCommand(std::string_view packet, std::vector<DebuggerAction
const auto mem_substr{std::string_view(command).substr(mem_sep)};
const auto mem{Common::HexStringToVector(mem_substr, false)};
- if (system.Memory().IsValidVirtualAddressRange(addr, size)) {
- system.Memory().WriteBlock(addr, mem.data(), size);
+ if (system.ApplicationMemory().IsValidVirtualAddressRange(addr, size)) {
+ system.ApplicationMemory().WriteBlock(addr, mem.data(), size);
system.InvalidateCpuInstructionCacheRange(addr, size);
SendReply(GDB_STUB_REPLY_OK);
} else {
@@ -325,7 +325,7 @@ void GDBStub::HandleBreakpointInsert(std::string_view command) {
const size_t addr{static_cast<size_t>(strtoll(command.data() + addr_sep, nullptr, 16))};
const size_t size{static_cast<size_t>(strtoll(command.data() + size_sep, nullptr, 16))};
- if (!system.Memory().IsValidVirtualAddressRange(addr, size)) {
+ if (!system.ApplicationMemory().IsValidVirtualAddressRange(addr, size)) {
SendReply(GDB_STUB_REPLY_ERR);
return;
}
@@ -334,22 +334,22 @@ void GDBStub::HandleBreakpointInsert(std::string_view command) {
switch (type) {
case BreakpointType::Software:
- replaced_instructions[addr] = system.Memory().Read32(addr);
- system.Memory().Write32(addr, arch->BreakpointInstruction());
+ replaced_instructions[addr] = system.ApplicationMemory().Read32(addr);
+ system.ApplicationMemory().Write32(addr, arch->BreakpointInstruction());
system.InvalidateCpuInstructionCacheRange(addr, sizeof(u32));
success = true;
break;
case BreakpointType::WriteWatch:
- success = system.CurrentProcess()->InsertWatchpoint(system, addr, size,
- Kernel::DebugWatchpointType::Write);
+ success = system.ApplicationProcess()->InsertWatchpoint(addr, size,
+ Kernel::DebugWatchpointType::Write);
break;
case BreakpointType::ReadWatch:
- success = system.CurrentProcess()->InsertWatchpoint(system, addr, size,
- Kernel::DebugWatchpointType::Read);
+ success = system.ApplicationProcess()->InsertWatchpoint(addr, size,
+ Kernel::DebugWatchpointType::Read);
break;
case BreakpointType::AccessWatch:
- success = system.CurrentProcess()->InsertWatchpoint(
- system, addr, size, Kernel::DebugWatchpointType::ReadOrWrite);
+ success = system.ApplicationProcess()->InsertWatchpoint(
+ addr, size, Kernel::DebugWatchpointType::ReadOrWrite);
break;
case BreakpointType::Hardware:
default:
@@ -372,7 +372,7 @@ void GDBStub::HandleBreakpointRemove(std::string_view command) {
const size_t addr{static_cast<size_t>(strtoll(command.data() + addr_sep, nullptr, 16))};
const size_t size{static_cast<size_t>(strtoll(command.data() + size_sep, nullptr, 16))};
- if (!system.Memory().IsValidVirtualAddressRange(addr, size)) {
+ if (!system.ApplicationMemory().IsValidVirtualAddressRange(addr, size)) {
SendReply(GDB_STUB_REPLY_ERR);
return;
}
@@ -383,7 +383,7 @@ void GDBStub::HandleBreakpointRemove(std::string_view command) {
case BreakpointType::Software: {
const auto orig_insn{replaced_instructions.find(addr)};
if (orig_insn != replaced_instructions.end()) {
- system.Memory().Write32(addr, orig_insn->second);
+ system.ApplicationMemory().Write32(addr, orig_insn->second);
system.InvalidateCpuInstructionCacheRange(addr, sizeof(u32));
replaced_instructions.erase(addr);
success = true;
@@ -391,16 +391,16 @@ void GDBStub::HandleBreakpointRemove(std::string_view command) {
break;
}
case BreakpointType::WriteWatch:
- success = system.CurrentProcess()->RemoveWatchpoint(system, addr, size,
- Kernel::DebugWatchpointType::Write);
+ success = system.ApplicationProcess()->RemoveWatchpoint(addr, size,
+ Kernel::DebugWatchpointType::Write);
break;
case BreakpointType::ReadWatch:
- success = system.CurrentProcess()->RemoveWatchpoint(system, addr, size,
- Kernel::DebugWatchpointType::Read);
+ success = system.ApplicationProcess()->RemoveWatchpoint(addr, size,
+ Kernel::DebugWatchpointType::Read);
break;
case BreakpointType::AccessWatch:
- success = system.CurrentProcess()->RemoveWatchpoint(
- system, addr, size, Kernel::DebugWatchpointType::ReadOrWrite);
+ success = system.ApplicationProcess()->RemoveWatchpoint(
+ addr, size, Kernel::DebugWatchpointType::ReadOrWrite);
break;
case BreakpointType::Hardware:
default:
@@ -421,7 +421,7 @@ void GDBStub::HandleBreakpointRemove(std::string_view command) {
static std::optional<std::string> GetNameFromThreadType32(Core::Memory::Memory& memory,
const Kernel::KThread* thread) {
// Read thread type from TLS
- const VAddr tls_thread_type{memory.Read32(thread->GetTLSAddress() + 0x1fc)};
+ const VAddr tls_thread_type{memory.Read32(thread->GetTlsAddress() + 0x1fc)};
const VAddr argument_thread_type{thread->GetArgument()};
if (argument_thread_type && tls_thread_type != argument_thread_type) {
@@ -452,7 +452,7 @@ static std::optional<std::string> GetNameFromThreadType32(Core::Memory::Memory&
static std::optional<std::string> GetNameFromThreadType64(Core::Memory::Memory& memory,
const Kernel::KThread* thread) {
// Read thread type from TLS
- const VAddr tls_thread_type{memory.Read64(thread->GetTLSAddress() + 0x1f8)};
+ const VAddr tls_thread_type{memory.Read64(thread->GetTlsAddress() + 0x1f8)};
const VAddr argument_thread_type{thread->GetArgument()};
if (argument_thread_type && tls_thread_type != argument_thread_type) {
@@ -482,10 +482,10 @@ static std::optional<std::string> GetNameFromThreadType64(Core::Memory::Memory&
static std::optional<std::string> GetThreadName(Core::System& system,
const Kernel::KThread* thread) {
- if (system.CurrentProcess()->Is64BitProcess()) {
- return GetNameFromThreadType64(system.Memory(), thread);
+ if (system.ApplicationProcess()->Is64BitProcess()) {
+ return GetNameFromThreadType64(system.ApplicationMemory(), thread);
} else {
- return GetNameFromThreadType32(system.Memory(), thread);
+ return GetNameFromThreadType32(system.ApplicationMemory(), thread);
}
}
@@ -554,8 +554,9 @@ void GDBStub::HandleQuery(std::string_view command) {
if (main != modules.end()) {
SendReply(fmt::format("TextSeg={:x}", main->first));
} else {
- SendReply(fmt::format("TextSeg={:x}",
- system.CurrentProcess()->PageTable().GetCodeRegionStart()));
+ SendReply(fmt::format(
+ "TextSeg={:x}",
+ GetInteger(system.ApplicationProcess()->PageTable().GetCodeRegionStart())));
}
} else if (command.starts_with("Xfer:libraries:read::")) {
Loader::AppLoader::Modules modules;
@@ -573,10 +574,10 @@ void GDBStub::HandleQuery(std::string_view command) {
SendReply(PaginateBuffer(buffer, command.substr(21)));
} else if (command.starts_with("fThreadInfo")) {
// beginning of list
- const auto& threads = system.GlobalSchedulerContext().GetThreadList();
+ const auto& threads = system.ApplicationProcess()->GetThreadList();
std::vector<std::string> thread_ids;
for (const auto& thread : threads) {
- thread_ids.push_back(fmt::format("{:x}", thread->GetThreadID()));
+ thread_ids.push_back(fmt::format("{:x}", thread->GetThreadId()));
}
SendReply(fmt::format("m{}", fmt::join(thread_ids, ",")));
} else if (command.starts_with("sThreadInfo")) {
@@ -587,15 +588,15 @@ void GDBStub::HandleQuery(std::string_view command) {
buffer += R"(<?xml version="1.0"?>)";
buffer += "<threads>";
- const auto& threads = system.GlobalSchedulerContext().GetThreadList();
+ const auto& threads = system.ApplicationProcess()->GetThreadList();
for (const auto* thread : threads) {
auto thread_name{GetThreadName(system, thread)};
if (!thread_name) {
- thread_name = fmt::format("Thread {:d}", thread->GetThreadID());
+ thread_name = fmt::format("Thread {:d}", thread->GetThreadId());
}
buffer += fmt::format(R"(<thread id="{:x}" core="{:d}" name="{}">{}</thread>)",
- thread->GetThreadID(), thread->GetActiveCore(),
+ thread->GetThreadId(), thread->GetActiveCore(),
EscapeXML(*thread_name), GetThreadState(thread));
}
@@ -729,7 +730,7 @@ void GDBStub::HandleRcmd(const std::vector<u8>& command) {
std::string_view command_str{reinterpret_cast<const char*>(&command[0]), command.size()};
std::string reply;
- auto* process = system.CurrentProcess();
+ auto* process = system.ApplicationProcess();
auto& page_table = process->PageTable();
const char* commands = "Commands:\n"
@@ -756,18 +757,21 @@ void GDBStub::HandleRcmd(const std::vector<u8>& command) {
reply = fmt::format("Process: {:#x} ({})\n"
"Program Id: {:#018x}\n",
- process->GetProcessID(), process->GetName(), process->GetProgramID());
- reply +=
- fmt::format("Layout:\n"
- " Alias: {:#012x} - {:#012x}\n"
- " Heap: {:#012x} - {:#012x}\n"
- " Aslr: {:#012x} - {:#012x}\n"
- " Stack: {:#012x} - {:#012x}\n"
- "Modules:\n",
- page_table.GetAliasRegionStart(), page_table.GetAliasRegionEnd(),
- page_table.GetHeapRegionStart(), page_table.GetHeapRegionEnd(),
- page_table.GetAliasCodeRegionStart(), page_table.GetAliasCodeRegionEnd(),
- page_table.GetStackRegionStart(), page_table.GetStackRegionEnd());
+ process->GetProcessId(), process->GetName(), process->GetProgramId());
+ reply += fmt::format("Layout:\n"
+ " Alias: {:#012x} - {:#012x}\n"
+ " Heap: {:#012x} - {:#012x}\n"
+ " Aslr: {:#012x} - {:#012x}\n"
+ " Stack: {:#012x} - {:#012x}\n"
+ "Modules:\n",
+ GetInteger(page_table.GetAliasRegionStart()),
+ GetInteger(page_table.GetAliasRegionEnd()),
+ GetInteger(page_table.GetHeapRegionStart()),
+ GetInteger(page_table.GetHeapRegionEnd()),
+ GetInteger(page_table.GetAliasCodeRegionStart()),
+ GetInteger(page_table.GetAliasCodeRegionEnd()),
+ GetInteger(page_table.GetStackRegionStart()),
+ GetInteger(page_table.GetStackRegionEnd()));
for (const auto& [vaddr, name] : modules) {
reply += fmt::format(" {:#012x} - {:#012x} {}\n", vaddr,
@@ -817,9 +821,9 @@ void GDBStub::HandleRcmd(const std::vector<u8>& command) {
}
Kernel::KThread* GDBStub::GetThreadByID(u64 thread_id) {
- const auto& threads{system.GlobalSchedulerContext().GetThreadList()};
+ const auto& threads{system.ApplicationProcess()->GetThreadList()};
for (auto* thread : threads) {
- if (thread->GetThreadID() == thread_id) {
+ if (thread->GetThreadId() == thread_id) {
return thread;
}
}
diff --git a/src/core/debugger/gdbstub_arch.cpp b/src/core/debugger/gdbstub_arch.cpp
index 4bef09bd7..75c94a91a 100644
--- a/src/core/debugger/gdbstub_arch.cpp
+++ b/src/core/debugger/gdbstub_arch.cpp
@@ -41,9 +41,8 @@ static void PutSIMDRegister(std::array<u32, 64>& simd_regs, size_t offset, const
// For sample XML files see the GDB source /gdb/features
// This XML defines what the registers are for this specific ARM device
-std::string GDBStubA64::GetTargetXML() const {
- constexpr const char* target_xml =
- R"(<?xml version="1.0"?>
+std::string_view GDBStubA64::GetTargetXML() const {
+ return R"(<?xml version="1.0"?>
<!DOCTYPE target SYSTEM "gdb-target.dtd">
<target version="1.0">
<architecture>aarch64</architecture>
@@ -178,8 +177,6 @@ std::string GDBStubA64::GetTargetXML() const {
<reg name="fpcr" bitsize="32"/>
</feature>
</target>)";
-
- return target_xml;
}
std::string GDBStubA64::RegRead(const Kernel::KThread* thread, size_t id) const {
@@ -262,7 +259,7 @@ void GDBStubA64::WriteRegisters(Kernel::KThread* thread, std::string_view regist
std::string GDBStubA64::ThreadStatus(const Kernel::KThread* thread, u8 signal) const {
return fmt::format("T{:02x}{:02x}:{};{:02x}:{};{:02x}:{};thread:{:x};", signal, PC_REGISTER,
RegRead(thread, PC_REGISTER), SP_REGISTER, RegRead(thread, SP_REGISTER),
- LR_REGISTER, RegRead(thread, LR_REGISTER), thread->GetThreadID());
+ LR_REGISTER, RegRead(thread, LR_REGISTER), thread->GetThreadId());
}
u32 GDBStubA64::BreakpointInstruction() const {
@@ -270,9 +267,8 @@ u32 GDBStubA64::BreakpointInstruction() const {
return 0xd4200000;
}
-std::string GDBStubA32::GetTargetXML() const {
- constexpr const char* target_xml =
- R"(<?xml version="1.0"?>
+std::string_view GDBStubA32::GetTargetXML() const {
+ return R"(<?xml version="1.0"?>
<!DOCTYPE target SYSTEM "gdb-target.dtd">
<target version="1.0">
<architecture>arm</architecture>
@@ -378,8 +374,6 @@ std::string GDBStubA32::GetTargetXML() const {
<reg name="fpscr" bitsize="32" type="int" group="float" regnum="80"/>
</feature>
</target>)";
-
- return target_xml;
}
std::string GDBStubA32::RegRead(const Kernel::KThread* thread, size_t id) const {
@@ -475,7 +469,7 @@ void GDBStubA32::WriteRegisters(Kernel::KThread* thread, std::string_view regist
std::string GDBStubA32::ThreadStatus(const Kernel::KThread* thread, u8 signal) const {
return fmt::format("T{:02x}{:02x}:{};{:02x}:{};{:02x}:{};thread:{:x};", signal, PC_REGISTER,
RegRead(thread, PC_REGISTER), SP_REGISTER, RegRead(thread, SP_REGISTER),
- LR_REGISTER, RegRead(thread, LR_REGISTER), thread->GetThreadID());
+ LR_REGISTER, RegRead(thread, LR_REGISTER), thread->GetThreadId());
}
u32 GDBStubA32::BreakpointInstruction() const {
diff --git a/src/core/debugger/gdbstub_arch.h b/src/core/debugger/gdbstub_arch.h
index 2540d6456..34530c788 100644
--- a/src/core/debugger/gdbstub_arch.h
+++ b/src/core/debugger/gdbstub_arch.h
@@ -16,7 +16,7 @@ namespace Core {
class GDBStubArch {
public:
virtual ~GDBStubArch() = default;
- virtual std::string GetTargetXML() const = 0;
+ virtual std::string_view GetTargetXML() const = 0;
virtual std::string RegRead(const Kernel::KThread* thread, size_t id) const = 0;
virtual void RegWrite(Kernel::KThread* thread, size_t id, std::string_view value) const = 0;
virtual std::string ReadRegisters(const Kernel::KThread* thread) const = 0;
@@ -27,7 +27,7 @@ public:
class GDBStubA64 final : public GDBStubArch {
public:
- std::string GetTargetXML() const override;
+ std::string_view GetTargetXML() const override;
std::string RegRead(const Kernel::KThread* thread, size_t id) const override;
void RegWrite(Kernel::KThread* thread, size_t id, std::string_view value) const override;
std::string ReadRegisters(const Kernel::KThread* thread) const override;
@@ -47,7 +47,7 @@ private:
class GDBStubA32 final : public GDBStubArch {
public:
- std::string GetTargetXML() const override;
+ std::string_view GetTargetXML() const override;
std::string RegRead(const Kernel::KThread* thread, size_t id) const override;
void RegWrite(Kernel::KThread* thread, size_t id, std::string_view value) const override;
std::string ReadRegisters(const Kernel::KThread* thread) const override;
diff --git a/src/core/device_memory.cpp b/src/core/device_memory.cpp
index f8b5be2b4..de3f8ef8f 100644
--- a/src/core/device_memory.cpp
+++ b/src/core/device_memory.cpp
@@ -6,9 +6,15 @@
namespace Core {
+#ifdef ANDROID
+constexpr size_t VirtualReserveSize = 1ULL << 38;
+#else
+constexpr size_t VirtualReserveSize = 1ULL << 39;
+#endif
+
DeviceMemory::DeviceMemory()
: buffer{Kernel::Board::Nintendo::Nx::KSystemControl::Init::GetIntendedMemorySize(),
- 1ULL << 39} {}
+ VirtualReserveSize} {}
DeviceMemory::~DeviceMemory() = default;
} // namespace Core
diff --git a/src/core/device_memory.h b/src/core/device_memory.h
index 90510733c..13388b73e 100644
--- a/src/core/device_memory.h
+++ b/src/core/device_memory.h
@@ -3,8 +3,8 @@
#pragma once
-#include "common/common_types.h"
#include "common/host_memory.h"
+#include "common/typed_address.h"
namespace Core {
@@ -25,20 +25,22 @@ public:
DeviceMemory(const DeviceMemory&) = delete;
template <typename T>
- PAddr GetPhysicalAddr(const T* ptr) const {
+ Common::PhysicalAddress GetPhysicalAddr(const T* ptr) const {
return (reinterpret_cast<uintptr_t>(ptr) -
reinterpret_cast<uintptr_t>(buffer.BackingBasePointer())) +
DramMemoryMap::Base;
}
template <typename T>
- T* GetPointer(PAddr addr) {
- return reinterpret_cast<T*>(buffer.BackingBasePointer() + (addr - DramMemoryMap::Base));
+ T* GetPointer(Common::PhysicalAddress addr) {
+ return reinterpret_cast<T*>(buffer.BackingBasePointer() +
+ (GetInteger(addr) - DramMemoryMap::Base));
}
template <typename T>
- const T* GetPointer(PAddr addr) const {
- return reinterpret_cast<T*>(buffer.BackingBasePointer() + (addr - DramMemoryMap::Base));
+ const T* GetPointer(Common::PhysicalAddress addr) const {
+ return reinterpret_cast<T*>(buffer.BackingBasePointer() +
+ (GetInteger(addr) - DramMemoryMap::Base));
}
Common::HostMemory buffer;
diff --git a/src/core/file_sys/content_archive.h b/src/core/file_sys/content_archive.h
index 7fdc45ea7..20f524f80 100644
--- a/src/core/file_sys/content_archive.h
+++ b/src/core/file_sys/content_archive.h
@@ -93,7 +93,7 @@ inline bool IsDirectoryLogoPartition(const VirtualDir& pfs) {
pfs->GetFile("StartupMovie.gif") != nullptr;
}
-// An implementation of VfsDirectory that represents a Nintendo Content Archive (NCA) conatiner.
+// An implementation of VfsDirectory that represents a Nintendo Content Archive (NCA) container.
// After construction, use GetStatus to determine if the file is valid and ready to be used.
class NCA : public ReadOnlyVfsDirectory {
public:
diff --git a/src/core/file_sys/control_metadata.cpp b/src/core/file_sys/control_metadata.cpp
index 50f44f598..cd9ac2e75 100644
--- a/src/core/file_sys/control_metadata.cpp
+++ b/src/core/file_sys/control_metadata.cpp
@@ -23,8 +23,8 @@ const std::array<const char*, 16> LANGUAGE_NAMES{{
"Portuguese",
"Russian",
"Korean",
- "Taiwanese",
- "Chinese",
+ "TraditionalChinese",
+ "SimplifiedChinese",
"BrazilianPortuguese",
}};
@@ -45,17 +45,17 @@ constexpr std::array<Language, 18> language_to_codes = {{
Language::German,
Language::Italian,
Language::Spanish,
- Language::Chinese,
+ Language::SimplifiedChinese,
Language::Korean,
Language::Dutch,
Language::Portuguese,
Language::Russian,
- Language::Taiwanese,
+ Language::TraditionalChinese,
Language::BritishEnglish,
Language::CanadianFrench,
Language::LatinAmericanSpanish,
- Language::Chinese,
- Language::Taiwanese,
+ Language::SimplifiedChinese,
+ Language::TraditionalChinese,
Language::BrazilianPortuguese,
}};
diff --git a/src/core/file_sys/control_metadata.h b/src/core/file_sys/control_metadata.h
index 6a81873b1..c98efb00d 100644
--- a/src/core/file_sys/control_metadata.h
+++ b/src/core/file_sys/control_metadata.h
@@ -84,8 +84,8 @@ enum class Language : u8 {
Portuguese = 10,
Russian = 11,
Korean = 12,
- Taiwanese = 13,
- Chinese = 14,
+ TraditionalChinese = 13,
+ SimplifiedChinese = 14,
BrazilianPortuguese = 15,
Default = 255,
diff --git a/src/core/file_sys/ips_layer.cpp b/src/core/file_sys/ips_layer.cpp
index 5aab428bb..efdf18cee 100644
--- a/src/core/file_sys/ips_layer.cpp
+++ b/src/core/file_sys/ips_layer.cpp
@@ -41,12 +41,12 @@ static IPSFileType IdentifyMagic(const std::vector<u8>& magic) {
return IPSFileType::Error;
}
- constexpr std::array<u8, 5> patch_magic{{'P', 'A', 'T', 'C', 'H'}};
+ static constexpr std::array<u8, 5> patch_magic{{'P', 'A', 'T', 'C', 'H'}};
if (std::equal(magic.begin(), magic.end(), patch_magic.begin())) {
return IPSFileType::IPS;
}
- constexpr std::array<u8, 5> ips32_magic{{'I', 'P', 'S', '3', '2'}};
+ static constexpr std::array<u8, 5> ips32_magic{{'I', 'P', 'S', '3', '2'}};
if (std::equal(magic.begin(), magic.end(), ips32_magic.begin())) {
return IPSFileType::IPS32;
}
@@ -55,12 +55,12 @@ static IPSFileType IdentifyMagic(const std::vector<u8>& magic) {
}
static bool IsEOF(IPSFileType type, const std::vector<u8>& data) {
- constexpr std::array<u8, 3> eof{{'E', 'O', 'F'}};
+ static constexpr std::array<u8, 3> eof{{'E', 'O', 'F'}};
if (type == IPSFileType::IPS && std::equal(data.begin(), data.end(), eof.begin())) {
return true;
}
- constexpr std::array<u8, 4> eeof{{'E', 'E', 'O', 'F'}};
+ static constexpr std::array<u8, 4> eeof{{'E', 'E', 'O', 'F'}};
return type == IPSFileType::IPS32 && std::equal(data.begin(), data.end(), eeof.begin());
}
diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp
index 4c80e13a9..d3286b352 100644
--- a/src/core/file_sys/patch_manager.cpp
+++ b/src/core/file_sys/patch_manager.cpp
@@ -21,9 +21,12 @@
#include "core/file_sys/patch_manager.h"
#include "core/file_sys/registered_cache.h"
#include "core/file_sys/romfs.h"
+#include "core/file_sys/vfs_cached.h"
#include "core/file_sys/vfs_layered.h"
#include "core/file_sys/vfs_vector.h"
#include "core/hle/service/filesystem/filesystem.h"
+#include "core/hle/service/ns/language.h"
+#include "core/hle/service/set/set.h"
#include "core/loader/loader.h"
#include "core/loader/nso.h"
#include "core/memory/cheat_engine.h"
@@ -150,7 +153,7 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
const auto sdmc_load_dir = fs_controller.GetSDMCModificationLoadRoot(title_id);
std::vector<VirtualDir> patch_dirs = {sdmc_load_dir};
- if (load_dir != nullptr && load_dir->GetSize() > 0) {
+ if (load_dir != nullptr) {
const auto load_patch_dirs = load_dir->GetSubdirectories();
patch_dirs.insert(patch_dirs.end(), load_patch_dirs.begin(), load_patch_dirs.end());
}
@@ -351,8 +354,7 @@ static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType t
const auto load_dir = fs_controller.GetModificationLoadRoot(title_id);
const auto sdmc_load_dir = fs_controller.GetSDMCModificationLoadRoot(title_id);
if ((type != ContentRecordType::Program && type != ContentRecordType::Data) ||
- ((load_dir == nullptr || load_dir->GetSize() <= 0) &&
- (sdmc_load_dir == nullptr || sdmc_load_dir->GetSize() <= 0))) {
+ (load_dir == nullptr && sdmc_load_dir == nullptr)) {
return;
}
@@ -380,11 +382,11 @@ static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType t
auto romfs_dir = FindSubdirectoryCaseless(subdir, "romfs");
if (romfs_dir != nullptr)
- layers.push_back(std::move(romfs_dir));
+ layers.push_back(std::make_shared<CachedVfsDirectory>(romfs_dir));
auto ext_dir = FindSubdirectoryCaseless(subdir, "romfs_ext");
if (ext_dir != nullptr)
- layers_ext.push_back(std::move(ext_dir));
+ layers_ext.push_back(std::make_shared<CachedVfsDirectory>(ext_dir));
}
// When there are no layers to apply, return early as there is no need to rebuild the RomFS
@@ -493,7 +495,7 @@ PatchManager::PatchVersionNames PatchManager::GetPatchVersionNames(VirtualFile u
// General Mods (LayeredFS and IPS)
const auto mod_dir = fs_controller.GetModificationLoadRoot(title_id);
- if (mod_dir != nullptr && mod_dir->GetSize() > 0) {
+ if (mod_dir != nullptr) {
for (const auto& mod : mod_dir->GetSubdirectories()) {
std::string types;
@@ -537,7 +539,7 @@ PatchManager::PatchVersionNames PatchManager::GetPatchVersionNames(VirtualFile u
// SDMC mod directory (RomFS LayeredFS)
const auto sdmc_mod_dir = fs_controller.GetSDMCModificationLoadRoot(title_id);
- if (sdmc_mod_dir != nullptr && sdmc_mod_dir->GetSize() > 0) {
+ if (sdmc_mod_dir != nullptr) {
std::string types;
if (IsDirValidAndNonEmpty(FindSubdirectoryCaseless(sdmc_mod_dir, "exefs"))) {
AppendCommaIfNotEmpty(types, "LayeredExeFS");
@@ -623,8 +625,37 @@ PatchManager::Metadata PatchManager::ParseControlNCA(const NCA& nca) const {
auto nacp = nacp_file == nullptr ? nullptr : std::make_unique<NACP>(nacp_file);
+ // Get language code from settings
+ const auto language_code =
+ Service::Set::GetLanguageCodeFromIndex(Settings::values.language_index.GetValue());
+
+ // Convert to application language and get priority list
+ const auto application_language =
+ Service::NS::ConvertToApplicationLanguage(language_code)
+ .value_or(Service::NS::ApplicationLanguage::AmericanEnglish);
+ const auto language_priority_list =
+ Service::NS::GetApplicationLanguagePriorityList(application_language);
+
+ // Convert to language names
+ auto priority_language_names = FileSys::LANGUAGE_NAMES; // Copy
+ if (language_priority_list) {
+ for (size_t i = 0; i < priority_language_names.size(); ++i) {
+ // Relies on FileSys::LANGUAGE_NAMES being in the same order as
+ // Service::NS::ApplicationLanguage
+ const auto language_index = static_cast<u8>(language_priority_list->at(i));
+
+ if (language_index < FileSys::LANGUAGE_NAMES.size()) {
+ priority_language_names[i] = FileSys::LANGUAGE_NAMES[language_index];
+ } else {
+ // Not a catastrophe, unlikely to happen
+ LOG_WARNING(Loader, "Invalid language index {}", language_index);
+ }
+ }
+ }
+
+ // Get first matching icon
VirtualFile icon_file;
- for (const auto& language : FileSys::LANGUAGE_NAMES) {
+ for (const auto& language : priority_language_names) {
icon_file = extracted->GetFile(std::string("icon_").append(language).append(".dat"));
if (icon_file != nullptr) {
break;
diff --git a/src/core/file_sys/registered_cache.cpp b/src/core/file_sys/registered_cache.cpp
index 878d832c2..a6960170c 100644
--- a/src/core/file_sys/registered_cache.cpp
+++ b/src/core/file_sys/registered_cache.cpp
@@ -71,7 +71,7 @@ static std::string GetRelativePathFromNcaID(const std::array<u8, 16>& nca_id, bo
}
static std::string GetCNMTName(TitleType type, u64 title_id) {
- constexpr std::array<const char*, 9> TITLE_TYPE_NAMES{
+ static constexpr std::array<const char*, 9> TITLE_TYPE_NAMES{
"SystemProgram",
"SystemData",
"SystemUpdate",
diff --git a/src/core/file_sys/registered_cache.h b/src/core/file_sys/registered_cache.h
index 587f8cae8..bd7f53eaf 100644
--- a/src/core/file_sys/registered_cache.h
+++ b/src/core/file_sys/registered_cache.h
@@ -162,7 +162,7 @@ public:
InstallResult InstallEntry(const NSP& nsp, bool overwrite_if_exists = false,
const VfsCopyFunction& copy = &VfsRawCopy);
- // Due to the fact that we must use Meta-type NCAs to determine the existance of files, this
+ // Due to the fact that we must use Meta-type NCAs to determine the existence of files, this
// poses quite a challenge. Instead of creating a new meta NCA for this file, yuzu will create a
// dir inside the NAND called 'yuzu_meta' and store the raw CNMT there.
// TODO(DarkLordZach): Author real meta-type NCAs and install those.
diff --git a/src/core/file_sys/romfs.cpp b/src/core/file_sys/romfs.cpp
index ddcfe5980..614da2130 100644
--- a/src/core/file_sys/romfs.cpp
+++ b/src/core/file_sys/romfs.cpp
@@ -9,6 +9,7 @@
#include "core/file_sys/fsmitm_romfsbuild.h"
#include "core/file_sys/romfs.h"
#include "core/file_sys/vfs.h"
+#include "core/file_sys/vfs_cached.h"
#include "core/file_sys/vfs_concat.h"
#include "core/file_sys/vfs_offset.h"
#include "core/file_sys/vfs_vector.h"
@@ -132,7 +133,7 @@ VirtualDir ExtractRomFS(VirtualFile file, RomFSExtractionType type) {
out = out->GetSubdirectories().front();
}
- return out;
+ return std::make_shared<CachedVfsDirectory>(out);
}
VirtualFile CreateRomFS(VirtualDir dir, VirtualDir ext) {
@@ -140,7 +141,8 @@ VirtualFile CreateRomFS(VirtualDir dir, VirtualDir ext) {
return nullptr;
RomFSBuildContext ctx{dir, ext};
- return ConcatenatedVfsFile::MakeConcatenatedFile(0, ctx.Build(), dir->GetName());
+ auto file_map = ctx.Build();
+ return ConcatenatedVfsFile::MakeConcatenatedFile(0, file_map, dir->GetName());
}
} // namespace FileSys
diff --git a/src/core/file_sys/savedata_factory.cpp b/src/core/file_sys/savedata_factory.cpp
index 1567da231..70b36f170 100644
--- a/src/core/file_sys/savedata_factory.cpp
+++ b/src/core/file_sys/savedata_factory.cpp
@@ -82,9 +82,9 @@ std::string GetFutureSaveDataPath(SaveDataSpaceId space_id, SaveDataType type, u
// Only detect account/device saves from the future location.
switch (type) {
case SaveDataType::SaveData:
- return fmt::format("{}/account/{}/{:016X}/1", space_id_path, uuid.RawString(), title_id);
+ return fmt::format("{}/account/{}/{:016X}/0", space_id_path, uuid.RawString(), title_id);
case SaveDataType::DeviceSaveData:
- return fmt::format("{}/device/{:016X}/1", space_id_path, title_id);
+ return fmt::format("{}/device/{:016X}/0", space_id_path, title_id);
default:
return "";
}
@@ -172,7 +172,7 @@ std::string SaveDataFactory::GetFullPath(Core::System& system, VirtualDir dir,
// be interpreted as the title id of the current process.
if (type == SaveDataType::SaveData || type == SaveDataType::DeviceSaveData) {
if (title_id == 0) {
- title_id = system.GetCurrentProcessProgramID();
+ title_id = system.GetApplicationProcessProgramID();
}
}
diff --git a/src/core/file_sys/submission_package.h b/src/core/file_sys/submission_package.h
index 3226b884a..27f97c725 100644
--- a/src/core/file_sys/submission_package.h
+++ b/src/core/file_sys/submission_package.h
@@ -8,6 +8,7 @@
#include <set>
#include <vector>
#include "common/common_types.h"
+#include "core/file_sys/nca_metadata.h"
#include "core/file_sys/vfs.h"
namespace Core::Crypto {
diff --git a/src/core/file_sys/system_archive/time_zone_binary.cpp b/src/core/file_sys/system_archive/time_zone_binary.cpp
index 85383998d..7c17bbefa 100644
--- a/src/core/file_sys/system_archive/time_zone_binary.cpp
+++ b/src/core/file_sys/system_archive/time_zone_binary.cpp
@@ -1,7 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
-#include <array>
#include <vector>
#include "common/swap.h"
@@ -9,656 +8,79 @@
#include "core/file_sys/vfs_vector.h"
#include "core/hle/service/time/time_zone_types.h"
-namespace FileSys::SystemArchive {
-
-static constexpr std::array<u8, 9633> LOCATION_NAMES{
- 0x43, 0x45, 0x54, 0x0d, 0x0a, 0x43, 0x53, 0x54, 0x36, 0x43, 0x44, 0x54, 0x0d, 0x0a, 0x43, 0x75,
- 0x62, 0x61, 0x0d, 0x0a, 0x45, 0x45, 0x54, 0x0d, 0x0a, 0x45, 0x67, 0x79, 0x70, 0x74, 0x0d, 0x0a,
- 0x45, 0x69, 0x72, 0x65, 0x0d, 0x0a, 0x45, 0x53, 0x54, 0x0d, 0x0a, 0x45, 0x53, 0x54, 0x35, 0x45,
- 0x44, 0x54, 0x0d, 0x0a, 0x47, 0x42, 0x0d, 0x0a, 0x47, 0x42, 0x2d, 0x45, 0x69, 0x72, 0x65, 0x0d,
- 0x0a, 0x47, 0x4d, 0x54, 0x0d, 0x0a, 0x47, 0x4d, 0x54, 0x2b, 0x30, 0x0d, 0x0a, 0x47, 0x4d, 0x54,
- 0x2d, 0x30, 0x0d, 0x0a, 0x47, 0x4d, 0x54, 0x30, 0x0d, 0x0a, 0x47, 0x72, 0x65, 0x65, 0x6e, 0x77,
- 0x69, 0x63, 0x68, 0x0d, 0x0a, 0x48, 0x6f, 0x6e, 0x67, 0x6b, 0x6f, 0x6e, 0x67, 0x0d, 0x0a, 0x48,
- 0x53, 0x54, 0x0d, 0x0a, 0x49, 0x63, 0x65, 0x6c, 0x61, 0x6e, 0x64, 0x0d, 0x0a, 0x49, 0x72, 0x61,
- 0x6e, 0x0d, 0x0a, 0x49, 0x73, 0x72, 0x61, 0x65, 0x6c, 0x0d, 0x0a, 0x4a, 0x61, 0x6d, 0x61, 0x69,
- 0x63, 0x61, 0x0d, 0x0a, 0x4a, 0x61, 0x70, 0x61, 0x6e, 0x0d, 0x0a, 0x4b, 0x77, 0x61, 0x6a, 0x61,
- 0x6c, 0x65, 0x69, 0x6e, 0x0d, 0x0a, 0x4c, 0x69, 0x62, 0x79, 0x61, 0x0d, 0x0a, 0x4d, 0x45, 0x54,
- 0x0d, 0x0a, 0x4d, 0x53, 0x54, 0x0d, 0x0a, 0x4d, 0x53, 0x54, 0x37, 0x4d, 0x44, 0x54, 0x0d, 0x0a,
- 0x4e, 0x61, 0x76, 0x61, 0x6a, 0x6f, 0x0d, 0x0a, 0x4e, 0x5a, 0x0d, 0x0a, 0x4e, 0x5a, 0x2d, 0x43,
- 0x48, 0x41, 0x54, 0x0d, 0x0a, 0x50, 0x6f, 0x6c, 0x61, 0x6e, 0x64, 0x0d, 0x0a, 0x50, 0x6f, 0x72,
- 0x74, 0x75, 0x67, 0x61, 0x6c, 0x0d, 0x0a, 0x50, 0x52, 0x43, 0x0d, 0x0a, 0x50, 0x53, 0x54, 0x38,
- 0x50, 0x44, 0x54, 0x0d, 0x0a, 0x52, 0x4f, 0x43, 0x0d, 0x0a, 0x52, 0x4f, 0x4b, 0x0d, 0x0a, 0x53,
- 0x69, 0x6e, 0x67, 0x61, 0x70, 0x6f, 0x72, 0x65, 0x0d, 0x0a, 0x54, 0x75, 0x72, 0x6b, 0x65, 0x79,
- 0x0d, 0x0a, 0x55, 0x43, 0x54, 0x0d, 0x0a, 0x55, 0x6e, 0x69, 0x76, 0x65, 0x72, 0x73, 0x61, 0x6c,
- 0x0d, 0x0a, 0x55, 0x54, 0x43, 0x0d, 0x0a, 0x57, 0x2d, 0x53, 0x55, 0x0d, 0x0a, 0x57, 0x45, 0x54,
- 0x0d, 0x0a, 0x5a, 0x75, 0x6c, 0x75, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41,
- 0x62, 0x69, 0x64, 0x6a, 0x61, 0x6e, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41,
- 0x63, 0x63, 0x72, 0x61, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x64, 0x64,
- 0x69, 0x73, 0x5f, 0x41, 0x62, 0x61, 0x62, 0x61, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61,
- 0x2f, 0x41, 0x6c, 0x67, 0x69, 0x65, 0x72, 0x73, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61,
- 0x2f, 0x41, 0x73, 0x6d, 0x61, 0x72, 0x61, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f,
- 0x41, 0x73, 0x6d, 0x65, 0x72, 0x61, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42,
- 0x61, 0x6d, 0x61, 0x6b, 0x6f, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x61,
- 0x6e, 0x67, 0x75, 0x69, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x61, 0x6e,
- 0x6a, 0x75, 0x6c, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x69, 0x73, 0x73,
- 0x61, 0x75, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x6c, 0x61, 0x6e, 0x74,
- 0x79, 0x72, 0x65, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x72, 0x61, 0x7a,
- 0x7a, 0x61, 0x76, 0x69, 0x6c, 0x6c, 0x65, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f,
- 0x42, 0x75, 0x6a, 0x75, 0x6d, 0x62, 0x75, 0x72, 0x61, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63,
- 0x61, 0x2f, 0x43, 0x61, 0x69, 0x72, 0x6f, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f,
- 0x43, 0x61, 0x73, 0x61, 0x62, 0x6c, 0x61, 0x6e, 0x63, 0x61, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69,
- 0x63, 0x61, 0x2f, 0x43, 0x65, 0x75, 0x74, 0x61, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61,
- 0x2f, 0x43, 0x6f, 0x6e, 0x61, 0x6b, 0x72, 0x79, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61,
- 0x2f, 0x44, 0x61, 0x6b, 0x61, 0x72, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x44,
- 0x61, 0x72, 0x5f, 0x65, 0x73, 0x5f, 0x53, 0x61, 0x6c, 0x61, 0x61, 0x6d, 0x0d, 0x0a, 0x41, 0x66,
- 0x72, 0x69, 0x63, 0x61, 0x2f, 0x44, 0x6a, 0x69, 0x62, 0x6f, 0x75, 0x74, 0x69, 0x0d, 0x0a, 0x41,
- 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x44, 0x6f, 0x75, 0x61, 0x6c, 0x61, 0x0d, 0x0a, 0x41, 0x66,
- 0x72, 0x69, 0x63, 0x61, 0x2f, 0x45, 0x6c, 0x5f, 0x41, 0x61, 0x69, 0x75, 0x6e, 0x0d, 0x0a, 0x41,
- 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x46, 0x72, 0x65, 0x65, 0x74, 0x6f, 0x77, 0x6e, 0x0d, 0x0a,
- 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x47, 0x61, 0x62, 0x6f, 0x72, 0x6f, 0x6e, 0x65, 0x0d,
- 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x48, 0x61, 0x72, 0x61, 0x72, 0x65, 0x0d, 0x0a,
- 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4a, 0x6f, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x73, 0x62,
- 0x75, 0x72, 0x67, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4a, 0x75, 0x62, 0x61,
- 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4b, 0x61, 0x6d, 0x70, 0x61, 0x6c, 0x61,
- 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4b, 0x68, 0x61, 0x72, 0x74, 0x6f, 0x75,
- 0x6d, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4b, 0x69, 0x67, 0x61, 0x6c, 0x69,
- 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4b, 0x69, 0x6e, 0x73, 0x68, 0x61, 0x73,
- 0x61, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4c, 0x61, 0x67, 0x6f, 0x73, 0x0d,
- 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4c, 0x69, 0x62, 0x72, 0x65, 0x76, 0x69, 0x6c,
- 0x6c, 0x65, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4c, 0x6f, 0x6d, 0x65, 0x0d,
- 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4c, 0x75, 0x61, 0x6e, 0x64, 0x61, 0x0d, 0x0a,
- 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4c, 0x75, 0x62, 0x75, 0x6d, 0x62, 0x61, 0x73, 0x68,
- 0x69, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4c, 0x75, 0x73, 0x61, 0x6b, 0x61,
- 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x61, 0x6c, 0x61, 0x62, 0x6f, 0x0d,
- 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x61, 0x70, 0x75, 0x74, 0x6f, 0x0d, 0x0a,
- 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x61, 0x73, 0x65, 0x72, 0x75, 0x0d, 0x0a, 0x41,
- 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x62, 0x61, 0x62, 0x61, 0x6e, 0x65, 0x0d, 0x0a, 0x41,
- 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x6f, 0x67, 0x61, 0x64, 0x69, 0x73, 0x68, 0x75, 0x0d,
- 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x6f, 0x6e, 0x72, 0x6f, 0x76, 0x69, 0x61,
- 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4e, 0x61, 0x69, 0x72, 0x6f, 0x62, 0x69,
- 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4e, 0x64, 0x6a, 0x61, 0x6d, 0x65, 0x6e,
- 0x61, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4e, 0x69, 0x61, 0x6d, 0x65, 0x79,
- 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4e, 0x6f, 0x75, 0x61, 0x6b, 0x63, 0x68,
- 0x6f, 0x74, 0x74, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4f, 0x75, 0x61, 0x67,
- 0x61, 0x64, 0x6f, 0x75, 0x67, 0x6f, 0x75, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f,
- 0x50, 0x6f, 0x72, 0x74, 0x6f, 0x2d, 0x4e, 0x6f, 0x76, 0x6f, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69,
- 0x63, 0x61, 0x2f, 0x53, 0x61, 0x6f, 0x5f, 0x54, 0x6f, 0x6d, 0x65, 0x0d, 0x0a, 0x41, 0x66, 0x72,
- 0x69, 0x63, 0x61, 0x2f, 0x54, 0x69, 0x6d, 0x62, 0x75, 0x6b, 0x74, 0x75, 0x0d, 0x0a, 0x41, 0x66,
- 0x72, 0x69, 0x63, 0x61, 0x2f, 0x54, 0x72, 0x69, 0x70, 0x6f, 0x6c, 0x69, 0x0d, 0x0a, 0x41, 0x66,
- 0x72, 0x69, 0x63, 0x61, 0x2f, 0x54, 0x75, 0x6e, 0x69, 0x73, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69,
- 0x63, 0x61, 0x2f, 0x57, 0x69, 0x6e, 0x64, 0x68, 0x6f, 0x65, 0x6b, 0x0d, 0x0a, 0x41, 0x6d, 0x65,
- 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x64, 0x61, 0x6b, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69,
- 0x63, 0x61, 0x2f, 0x41, 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x0d, 0x0a, 0x41, 0x6d,
- 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x6e, 0x67, 0x75, 0x69, 0x6c, 0x6c, 0x61, 0x0d, 0x0a,
- 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x6e, 0x74, 0x69, 0x67, 0x75, 0x61, 0x0d,
- 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x72, 0x61, 0x67, 0x75, 0x61, 0x69,
- 0x6e, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x72, 0x75, 0x62,
- 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x73, 0x75, 0x6e, 0x63,
- 0x69, 0x6f, 0x6e, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x74, 0x69,
- 0x6b, 0x6f, 0x6b, 0x61, 0x6e, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41,
- 0x74, 0x6b, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x61, 0x68,
- 0x69, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x61, 0x68, 0x69,
- 0x61, 0x5f, 0x42, 0x61, 0x6e, 0x64, 0x65, 0x72, 0x61, 0x73, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72,
- 0x69, 0x63, 0x61, 0x2f, 0x42, 0x61, 0x72, 0x62, 0x61, 0x64, 0x6f, 0x73, 0x0d, 0x0a, 0x41, 0x6d,
- 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x65, 0x6c, 0x65, 0x6d, 0x0d, 0x0a, 0x41, 0x6d, 0x65,
- 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x65, 0x6c, 0x69, 0x7a, 0x65, 0x0d, 0x0a, 0x41, 0x6d, 0x65,
- 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x6c, 0x61, 0x6e, 0x63, 0x2d, 0x53, 0x61, 0x62, 0x6c, 0x6f,
- 0x6e, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x6f, 0x61, 0x5f, 0x56,
- 0x69, 0x73, 0x74, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x6f,
- 0x67, 0x6f, 0x74, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x6f,
- 0x69, 0x73, 0x65, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x75, 0x65,
- 0x6e, 0x6f, 0x73, 0x5f, 0x41, 0x69, 0x72, 0x65, 0x73, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69,
- 0x63, 0x61, 0x2f, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x5f, 0x42, 0x61, 0x79,
- 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x43, 0x61, 0x6d, 0x70, 0x6f, 0x5f,
- 0x47, 0x72, 0x61, 0x6e, 0x64, 0x65, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f,
- 0x43, 0x61, 0x6e, 0x63, 0x75, 0x6e, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f,
- 0x43, 0x61, 0x72, 0x61, 0x63, 0x61, 0x73, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61,
- 0x2f, 0x43, 0x61, 0x74, 0x61, 0x6d, 0x61, 0x72, 0x63, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72,
- 0x69, 0x63, 0x61, 0x2f, 0x43, 0x61, 0x79, 0x65, 0x6e, 0x6e, 0x65, 0x0d, 0x0a, 0x41, 0x6d, 0x65,
- 0x72, 0x69, 0x63, 0x61, 0x2f, 0x43, 0x61, 0x79, 0x6d, 0x61, 0x6e, 0x0d, 0x0a, 0x41, 0x6d, 0x65,
- 0x72, 0x69, 0x63, 0x61, 0x2f, 0x43, 0x68, 0x69, 0x63, 0x61, 0x67, 0x6f, 0x0d, 0x0a, 0x41, 0x6d,
- 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x43, 0x68, 0x69, 0x68, 0x75, 0x61, 0x68, 0x75, 0x61, 0x0d,
- 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x43, 0x6f, 0x72, 0x61, 0x6c, 0x5f, 0x48,
- 0x61, 0x72, 0x62, 0x6f, 0x75, 0x72, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f,
- 0x43, 0x6f, 0x72, 0x64, 0x6f, 0x62, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61,
- 0x2f, 0x43, 0x6f, 0x73, 0x74, 0x61, 0x5f, 0x52, 0x69, 0x63, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65,
- 0x72, 0x69, 0x63, 0x61, 0x2f, 0x43, 0x72, 0x65, 0x73, 0x74, 0x6f, 0x6e, 0x0d, 0x0a, 0x41, 0x6d,
- 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x43, 0x75, 0x69, 0x61, 0x62, 0x61, 0x0d, 0x0a, 0x41, 0x6d,
- 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x43, 0x75, 0x72, 0x61, 0x63, 0x61, 0x6f, 0x0d, 0x0a, 0x41,
- 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x44, 0x61, 0x6e, 0x6d, 0x61, 0x72, 0x6b, 0x73, 0x68,
- 0x61, 0x76, 0x6e, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x44, 0x61, 0x77,
- 0x73, 0x6f, 0x6e, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x44, 0x61, 0x77,
- 0x73, 0x6f, 0x6e, 0x5f, 0x43, 0x72, 0x65, 0x65, 0x6b, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69,
- 0x63, 0x61, 0x2f, 0x44, 0x65, 0x6e, 0x76, 0x65, 0x72, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69,
- 0x63, 0x61, 0x2f, 0x44, 0x65, 0x74, 0x72, 0x6f, 0x69, 0x74, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72,
- 0x69, 0x63, 0x61, 0x2f, 0x44, 0x6f, 0x6d, 0x69, 0x6e, 0x69, 0x63, 0x61, 0x0d, 0x0a, 0x41, 0x6d,
- 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x45, 0x64, 0x6d, 0x6f, 0x6e, 0x74, 0x6f, 0x6e, 0x0d, 0x0a,
- 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x45, 0x69, 0x72, 0x75, 0x6e, 0x65, 0x70, 0x65,
- 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x45, 0x6c, 0x5f, 0x53, 0x61, 0x6c,
- 0x76, 0x61, 0x64, 0x6f, 0x72, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x45,
- 0x6e, 0x73, 0x65, 0x6e, 0x61, 0x64, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61,
- 0x2f, 0x46, 0x6f, 0x72, 0x74, 0x61, 0x6c, 0x65, 0x7a, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72,
- 0x69, 0x63, 0x61, 0x2f, 0x46, 0x6f, 0x72, 0x74, 0x5f, 0x4e, 0x65, 0x6c, 0x73, 0x6f, 0x6e, 0x0d,
- 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x46, 0x6f, 0x72, 0x74, 0x5f, 0x57, 0x61,
- 0x79, 0x6e, 0x65, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x47, 0x6c, 0x61,
- 0x63, 0x65, 0x5f, 0x42, 0x61, 0x79, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f,
- 0x47, 0x6f, 0x64, 0x74, 0x68, 0x61, 0x62, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61,
- 0x2f, 0x47, 0x6f, 0x6f, 0x73, 0x65, 0x5f, 0x42, 0x61, 0x79, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72,
- 0x69, 0x63, 0x61, 0x2f, 0x47, 0x72, 0x61, 0x6e, 0x64, 0x5f, 0x54, 0x75, 0x72, 0x6b, 0x0d, 0x0a,
- 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x47, 0x72, 0x65, 0x6e, 0x61, 0x64, 0x61, 0x0d,
- 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x47, 0x75, 0x61, 0x64, 0x65, 0x6c, 0x6f,
- 0x75, 0x70, 0x65, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x47, 0x75, 0x61,
- 0x74, 0x65, 0x6d, 0x61, 0x6c, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f,
- 0x47, 0x75, 0x61, 0x79, 0x61, 0x71, 0x75, 0x69, 0x6c, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69,
- 0x63, 0x61, 0x2f, 0x47, 0x75, 0x79, 0x61, 0x6e, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69,
- 0x63, 0x61, 0x2f, 0x48, 0x61, 0x6c, 0x69, 0x66, 0x61, 0x78, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72,
- 0x69, 0x63, 0x61, 0x2f, 0x48, 0x61, 0x76, 0x61, 0x6e, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72,
- 0x69, 0x63, 0x61, 0x2f, 0x48, 0x65, 0x72, 0x6d, 0x6f, 0x73, 0x69, 0x6c, 0x6c, 0x6f, 0x0d, 0x0a,
- 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x61, 0x70,
- 0x6f, 0x6c, 0x69, 0x73, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x49, 0x6e,
- 0x75, 0x76, 0x69, 0x6b, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x49, 0x71,
- 0x61, 0x6c, 0x75, 0x69, 0x74, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4a,
- 0x61, 0x6d, 0x61, 0x69, 0x63, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f,
- 0x4a, 0x75, 0x6a, 0x75, 0x79, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4a,
- 0x75, 0x6e, 0x65, 0x61, 0x75, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4b,
- 0x6e, 0x6f, 0x78, 0x5f, 0x49, 0x4e, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f,
- 0x4b, 0x72, 0x61, 0x6c, 0x65, 0x6e, 0x64, 0x69, 0x6a, 0x6b, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72,
- 0x69, 0x63, 0x61, 0x2f, 0x4c, 0x61, 0x5f, 0x50, 0x61, 0x7a, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72,
- 0x69, 0x63, 0x61, 0x2f, 0x4c, 0x69, 0x6d, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63,
- 0x61, 0x2f, 0x4c, 0x6f, 0x73, 0x5f, 0x41, 0x6e, 0x67, 0x65, 0x6c, 0x65, 0x73, 0x0d, 0x0a, 0x41,
- 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4c, 0x6f, 0x75, 0x69, 0x73, 0x76, 0x69, 0x6c, 0x6c,
- 0x65, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4c, 0x6f, 0x77, 0x65, 0x72,
- 0x5f, 0x50, 0x72, 0x69, 0x6e, 0x63, 0x65, 0x73, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63,
- 0x61, 0x2f, 0x4d, 0x61, 0x63, 0x65, 0x69, 0x6f, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63,
- 0x61, 0x2f, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x75, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69,
- 0x63, 0x61, 0x2f, 0x4d, 0x61, 0x6e, 0x61, 0x75, 0x73, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69,
- 0x63, 0x61, 0x2f, 0x4d, 0x61, 0x72, 0x69, 0x67, 0x6f, 0x74, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72,
- 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x61, 0x72, 0x74, 0x69, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x0d, 0x0a,
- 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x61, 0x74, 0x61, 0x6d, 0x6f, 0x72, 0x6f,
- 0x73, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x61, 0x7a, 0x61, 0x74,
- 0x6c, 0x61, 0x6e, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x65, 0x6e,
- 0x64, 0x6f, 0x7a, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x65,
- 0x6e, 0x6f, 0x6d, 0x69, 0x6e, 0x65, 0x65, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61,
- 0x2f, 0x4d, 0x65, 0x72, 0x69, 0x64, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61,
- 0x2f, 0x4d, 0x65, 0x74, 0x6c, 0x61, 0x6b, 0x61, 0x74, 0x6c, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65,
- 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x65, 0x78, 0x69, 0x63, 0x6f, 0x5f, 0x43, 0x69, 0x74, 0x79,
- 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x69, 0x71, 0x75, 0x65, 0x6c,
- 0x6f, 0x6e, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x6f, 0x6e, 0x63,
- 0x74, 0x6f, 0x6e, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x6f, 0x6e,
- 0x74, 0x65, 0x72, 0x72, 0x65, 0x79, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f,
- 0x4d, 0x6f, 0x6e, 0x74, 0x65, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72,
- 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x6f, 0x6e, 0x74, 0x72, 0x65, 0x61, 0x6c, 0x0d, 0x0a, 0x41, 0x6d,
- 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x6f, 0x6e, 0x74, 0x73, 0x65, 0x72, 0x72, 0x61, 0x74,
- 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4e, 0x61, 0x73, 0x73, 0x61, 0x75,
- 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4e, 0x65, 0x77, 0x5f, 0x59, 0x6f,
- 0x72, 0x6b, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4e, 0x69, 0x70, 0x69,
- 0x67, 0x6f, 0x6e, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4e, 0x6f, 0x6d,
- 0x65, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4e, 0x6f, 0x72, 0x6f, 0x6e,
- 0x68, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4f, 0x6a, 0x69, 0x6e,
- 0x61, 0x67, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x50, 0x61, 0x6e,
- 0x61, 0x6d, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x50, 0x61, 0x6e,
- 0x67, 0x6e, 0x69, 0x72, 0x74, 0x75, 0x6e, 0x67, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63,
- 0x61, 0x2f, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x61, 0x72, 0x69, 0x62, 0x6f, 0x0d, 0x0a, 0x41, 0x6d,
- 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x50, 0x68, 0x6f, 0x65, 0x6e, 0x69, 0x78, 0x0d, 0x0a, 0x41,
- 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x50, 0x6f, 0x72, 0x74, 0x2d, 0x61, 0x75, 0x2d, 0x50,
- 0x72, 0x69, 0x6e, 0x63, 0x65, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x50,
- 0x6f, 0x72, 0x74, 0x6f, 0x5f, 0x41, 0x63, 0x72, 0x65, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69,
- 0x63, 0x61, 0x2f, 0x50, 0x6f, 0x72, 0x74, 0x6f, 0x5f, 0x56, 0x65, 0x6c, 0x68, 0x6f, 0x0d, 0x0a,
- 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x50, 0x6f, 0x72, 0x74, 0x5f, 0x6f, 0x66, 0x5f,
- 0x53, 0x70, 0x61, 0x69, 0x6e, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x50,
- 0x75, 0x65, 0x72, 0x74, 0x6f, 0x5f, 0x52, 0x69, 0x63, 0x6f, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72,
- 0x69, 0x63, 0x61, 0x2f, 0x50, 0x75, 0x6e, 0x74, 0x61, 0x5f, 0x41, 0x72, 0x65, 0x6e, 0x61, 0x73,
- 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x52, 0x61, 0x69, 0x6e, 0x79, 0x5f,
- 0x52, 0x69, 0x76, 0x65, 0x72, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x52,
- 0x61, 0x6e, 0x6b, 0x69, 0x6e, 0x5f, 0x49, 0x6e, 0x6c, 0x65, 0x74, 0x0d, 0x0a, 0x41, 0x6d, 0x65,
- 0x72, 0x69, 0x63, 0x61, 0x2f, 0x52, 0x65, 0x63, 0x69, 0x66, 0x65, 0x0d, 0x0a, 0x41, 0x6d, 0x65,
- 0x72, 0x69, 0x63, 0x61, 0x2f, 0x52, 0x65, 0x67, 0x69, 0x6e, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65,
- 0x72, 0x69, 0x63, 0x61, 0x2f, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x65, 0x0d, 0x0a, 0x41,
- 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x52, 0x69, 0x6f, 0x5f, 0x42, 0x72, 0x61, 0x6e, 0x63,
- 0x6f, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x52, 0x6f, 0x73, 0x61, 0x72,
- 0x69, 0x6f, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x53, 0x61, 0x6e, 0x74,
- 0x61, 0x72, 0x65, 0x6d, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x53, 0x61,
- 0x6e, 0x74, 0x61, 0x5f, 0x49, 0x73, 0x61, 0x62, 0x65, 0x6c, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72,
- 0x69, 0x63, 0x61, 0x2f, 0x53, 0x61, 0x6e, 0x74, 0x69, 0x61, 0x67, 0x6f, 0x0d, 0x0a, 0x41, 0x6d,
- 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x53, 0x61, 0x6e, 0x74, 0x6f, 0x5f, 0x44, 0x6f, 0x6d, 0x69,
- 0x6e, 0x67, 0x6f, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x53, 0x61, 0x6f,
- 0x5f, 0x50, 0x61, 0x75, 0x6c, 0x6f, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f,
- 0x53, 0x63, 0x6f, 0x72, 0x65, 0x73, 0x62, 0x79, 0x73, 0x75, 0x6e, 0x64, 0x0d, 0x0a, 0x41, 0x6d,
- 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x53, 0x68, 0x69, 0x70, 0x72, 0x6f, 0x63, 0x6b, 0x0d, 0x0a,
- 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x53, 0x69, 0x74, 0x6b, 0x61, 0x0d, 0x0a, 0x41,
- 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x53, 0x74, 0x5f, 0x42, 0x61, 0x72, 0x74, 0x68, 0x65,
- 0x6c, 0x65, 0x6d, 0x79, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x53, 0x74,
- 0x5f, 0x4a, 0x6f, 0x68, 0x6e, 0x73, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f,
- 0x53, 0x74, 0x5f, 0x4b, 0x69, 0x74, 0x74, 0x73, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63,
- 0x61, 0x2f, 0x53, 0x74, 0x5f, 0x4c, 0x75, 0x63, 0x69, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72,
- 0x69, 0x63, 0x61, 0x2f, 0x53, 0x74, 0x5f, 0x54, 0x68, 0x6f, 0x6d, 0x61, 0x73, 0x0d, 0x0a, 0x41,
- 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x53, 0x74, 0x5f, 0x56, 0x69, 0x6e, 0x63, 0x65, 0x6e,
- 0x74, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x53, 0x77, 0x69, 0x66, 0x74,
- 0x5f, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63,
- 0x61, 0x2f, 0x54, 0x65, 0x67, 0x75, 0x63, 0x69, 0x67, 0x61, 0x6c, 0x70, 0x61, 0x0d, 0x0a, 0x41,
- 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x54, 0x68, 0x75, 0x6c, 0x65, 0x0d, 0x0a, 0x41, 0x6d,
- 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x54, 0x68, 0x75, 0x6e, 0x64, 0x65, 0x72, 0x5f, 0x42, 0x61,
- 0x79, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x54, 0x69, 0x6a, 0x75, 0x61,
- 0x6e, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x54, 0x6f, 0x72, 0x6f,
- 0x6e, 0x74, 0x6f, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x54, 0x6f, 0x72,
- 0x74, 0x6f, 0x6c, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x56, 0x61,
- 0x6e, 0x63, 0x6f, 0x75, 0x76, 0x65, 0x72, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61,
- 0x2f, 0x56, 0x69, 0x72, 0x67, 0x69, 0x6e, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61,
- 0x2f, 0x57, 0x68, 0x69, 0x74, 0x65, 0x68, 0x6f, 0x72, 0x73, 0x65, 0x0d, 0x0a, 0x41, 0x6d, 0x65,
- 0x72, 0x69, 0x63, 0x61, 0x2f, 0x57, 0x69, 0x6e, 0x6e, 0x69, 0x70, 0x65, 0x67, 0x0d, 0x0a, 0x41,
- 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x59, 0x61, 0x6b, 0x75, 0x74, 0x61, 0x74, 0x0d, 0x0a,
- 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x59, 0x65, 0x6c, 0x6c, 0x6f, 0x77, 0x6b, 0x6e,
- 0x69, 0x66, 0x65, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x72, 0x67,
- 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x61, 0x2f, 0x42, 0x75, 0x65, 0x6e, 0x6f, 0x73, 0x5f, 0x41, 0x69,
- 0x72, 0x65, 0x73, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x72, 0x67,
- 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x61, 0x2f, 0x43, 0x61, 0x74, 0x61, 0x6d, 0x61, 0x72, 0x63, 0x61,
- 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x72, 0x67, 0x65, 0x6e, 0x74,
- 0x69, 0x6e, 0x61, 0x2f, 0x43, 0x6f, 0x6d, 0x6f, 0x64, 0x52, 0x69, 0x76, 0x61, 0x64, 0x61, 0x76,
- 0x69, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x72, 0x67, 0x65,
- 0x6e, 0x74, 0x69, 0x6e, 0x61, 0x2f, 0x43, 0x6f, 0x72, 0x64, 0x6f, 0x62, 0x61, 0x0d, 0x0a, 0x41,
- 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x72, 0x67, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x61,
- 0x2f, 0x4a, 0x75, 0x6a, 0x75, 0x79, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f,
- 0x41, 0x72, 0x67, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x61, 0x2f, 0x4c, 0x61, 0x5f, 0x52, 0x69, 0x6f,
- 0x6a, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x72, 0x67, 0x65,
- 0x6e, 0x74, 0x69, 0x6e, 0x61, 0x2f, 0x4d, 0x65, 0x6e, 0x64, 0x6f, 0x7a, 0x61, 0x0d, 0x0a, 0x41,
- 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x72, 0x67, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x61,
- 0x2f, 0x52, 0x69, 0x6f, 0x5f, 0x47, 0x61, 0x6c, 0x6c, 0x65, 0x67, 0x6f, 0x73, 0x0d, 0x0a, 0x41,
- 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x72, 0x67, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x61,
- 0x2f, 0x53, 0x61, 0x6c, 0x74, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f,
- 0x41, 0x72, 0x67, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x61, 0x2f, 0x53, 0x61, 0x6e, 0x5f, 0x4a, 0x75,
- 0x61, 0x6e, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x72, 0x67, 0x65,
- 0x6e, 0x74, 0x69, 0x6e, 0x61, 0x2f, 0x53, 0x61, 0x6e, 0x5f, 0x4c, 0x75, 0x69, 0x73, 0x0d, 0x0a,
- 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x72, 0x67, 0x65, 0x6e, 0x74, 0x69, 0x6e,
- 0x61, 0x2f, 0x54, 0x75, 0x63, 0x75, 0x6d, 0x61, 0x6e, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69,
- 0x63, 0x61, 0x2f, 0x41, 0x72, 0x67, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x61, 0x2f, 0x55, 0x73, 0x68,
- 0x75, 0x61, 0x69, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x49, 0x6e,
- 0x64, 0x69, 0x61, 0x6e, 0x61, 0x2f, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x61, 0x70, 0x6f, 0x6c,
- 0x69, 0x73, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x49, 0x6e, 0x64, 0x69,
- 0x61, 0x6e, 0x61, 0x2f, 0x4b, 0x6e, 0x6f, 0x78, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63,
- 0x61, 0x2f, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x61, 0x2f, 0x4d, 0x61, 0x72, 0x65, 0x6e, 0x67,
- 0x6f, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x49, 0x6e, 0x64, 0x69, 0x61,
- 0x6e, 0x61, 0x2f, 0x50, 0x65, 0x74, 0x65, 0x72, 0x73, 0x62, 0x75, 0x72, 0x67, 0x0d, 0x0a, 0x41,
- 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x61, 0x2f, 0x54,
- 0x65, 0x6c, 0x6c, 0x5f, 0x43, 0x69, 0x74, 0x79, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63,
- 0x61, 0x2f, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x61, 0x2f, 0x56, 0x65, 0x76, 0x61, 0x79, 0x0d,
- 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x61,
- 0x2f, 0x56, 0x69, 0x6e, 0x63, 0x65, 0x6e, 0x6e, 0x65, 0x73, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72,
- 0x69, 0x63, 0x61, 0x2f, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x61, 0x2f, 0x57, 0x69, 0x6e, 0x61,
- 0x6d, 0x61, 0x63, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4b, 0x65, 0x6e,
- 0x74, 0x75, 0x63, 0x6b, 0x79, 0x2f, 0x4c, 0x6f, 0x75, 0x69, 0x73, 0x76, 0x69, 0x6c, 0x6c, 0x65,
- 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4b, 0x65, 0x6e, 0x74, 0x75, 0x63,
- 0x6b, 0x79, 0x2f, 0x4d, 0x6f, 0x6e, 0x74, 0x69, 0x63, 0x65, 0x6c, 0x6c, 0x6f, 0x0d, 0x0a, 0x41,
- 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4e, 0x6f, 0x72, 0x74, 0x68, 0x5f, 0x44, 0x61, 0x6b,
- 0x6f, 0x74, 0x61, 0x2f, 0x42, 0x65, 0x75, 0x6c, 0x61, 0x68, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72,
- 0x69, 0x63, 0x61, 0x2f, 0x4e, 0x6f, 0x72, 0x74, 0x68, 0x5f, 0x44, 0x61, 0x6b, 0x6f, 0x74, 0x61,
- 0x2f, 0x43, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61,
- 0x2f, 0x4e, 0x6f, 0x72, 0x74, 0x68, 0x5f, 0x44, 0x61, 0x6b, 0x6f, 0x74, 0x61, 0x2f, 0x4e, 0x65,
- 0x77, 0x5f, 0x53, 0x61, 0x6c, 0x65, 0x6d, 0x0d, 0x0a, 0x41, 0x6e, 0x74, 0x61, 0x72, 0x63, 0x74,
- 0x69, 0x63, 0x61, 0x2f, 0x43, 0x61, 0x73, 0x65, 0x79, 0x0d, 0x0a, 0x41, 0x6e, 0x74, 0x61, 0x72,
- 0x63, 0x74, 0x69, 0x63, 0x61, 0x2f, 0x44, 0x61, 0x76, 0x69, 0x73, 0x0d, 0x0a, 0x41, 0x6e, 0x74,
- 0x61, 0x72, 0x63, 0x74, 0x69, 0x63, 0x61, 0x2f, 0x44, 0x75, 0x6d, 0x6f, 0x6e, 0x74, 0x44, 0x55,
- 0x72, 0x76, 0x69, 0x6c, 0x6c, 0x65, 0x0d, 0x0a, 0x41, 0x6e, 0x74, 0x61, 0x72, 0x63, 0x74, 0x69,
- 0x63, 0x61, 0x2f, 0x4d, 0x61, 0x63, 0x71, 0x75, 0x61, 0x72, 0x69, 0x65, 0x0d, 0x0a, 0x41, 0x6e,
- 0x74, 0x61, 0x72, 0x63, 0x74, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x61, 0x77, 0x73, 0x6f, 0x6e, 0x0d,
- 0x0a, 0x41, 0x6e, 0x74, 0x61, 0x72, 0x63, 0x74, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x63, 0x4d, 0x75,
- 0x72, 0x64, 0x6f, 0x0d, 0x0a, 0x41, 0x6e, 0x74, 0x61, 0x72, 0x63, 0x74, 0x69, 0x63, 0x61, 0x2f,
- 0x50, 0x61, 0x6c, 0x6d, 0x65, 0x72, 0x0d, 0x0a, 0x41, 0x6e, 0x74, 0x61, 0x72, 0x63, 0x74, 0x69,
- 0x63, 0x61, 0x2f, 0x52, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x61, 0x0d, 0x0a, 0x41, 0x6e, 0x74, 0x61,
- 0x72, 0x63, 0x74, 0x69, 0x63, 0x61, 0x2f, 0x53, 0x6f, 0x75, 0x74, 0x68, 0x5f, 0x50, 0x6f, 0x6c,
- 0x65, 0x0d, 0x0a, 0x41, 0x6e, 0x74, 0x61, 0x72, 0x63, 0x74, 0x69, 0x63, 0x61, 0x2f, 0x53, 0x79,
- 0x6f, 0x77, 0x61, 0x0d, 0x0a, 0x41, 0x6e, 0x74, 0x61, 0x72, 0x63, 0x74, 0x69, 0x63, 0x61, 0x2f,
- 0x54, 0x72, 0x6f, 0x6c, 0x6c, 0x0d, 0x0a, 0x41, 0x6e, 0x74, 0x61, 0x72, 0x63, 0x74, 0x69, 0x63,
- 0x61, 0x2f, 0x56, 0x6f, 0x73, 0x74, 0x6f, 0x6b, 0x0d, 0x0a, 0x41, 0x72, 0x63, 0x74, 0x69, 0x63,
- 0x2f, 0x4c, 0x6f, 0x6e, 0x67, 0x79, 0x65, 0x61, 0x72, 0x62, 0x79, 0x65, 0x6e, 0x0d, 0x0a, 0x41,
- 0x73, 0x69, 0x61, 0x2f, 0x41, 0x64, 0x65, 0x6e, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x41,
- 0x6c, 0x6d, 0x61, 0x74, 0x79, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x41, 0x6d, 0x6d, 0x61,
- 0x6e, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x41, 0x6e, 0x61, 0x64, 0x79, 0x72, 0x0d, 0x0a,
- 0x41, 0x73, 0x69, 0x61, 0x2f, 0x41, 0x71, 0x74, 0x61, 0x75, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61,
- 0x2f, 0x41, 0x71, 0x74, 0x6f, 0x62, 0x65, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x41, 0x73,
- 0x68, 0x67, 0x61, 0x62, 0x61, 0x74, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x41, 0x73, 0x68,
- 0x6b, 0x68, 0x61, 0x62, 0x61, 0x64, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x41, 0x74, 0x79,
- 0x72, 0x61, 0x75, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x42, 0x61, 0x67, 0x68, 0x64, 0x61,
- 0x64, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x42, 0x61, 0x68, 0x72, 0x61, 0x69, 0x6e, 0x0d,
- 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x42, 0x61, 0x6b, 0x75, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61,
- 0x2f, 0x42, 0x61, 0x6e, 0x67, 0x6b, 0x6f, 0x6b, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x42,
- 0x61, 0x72, 0x6e, 0x61, 0x75, 0x6c, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x42, 0x65, 0x69,
- 0x72, 0x75, 0x74, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x42, 0x69, 0x73, 0x68, 0x6b, 0x65,
- 0x6b, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x42, 0x72, 0x75, 0x6e, 0x65, 0x69, 0x0d, 0x0a,
- 0x41, 0x73, 0x69, 0x61, 0x2f, 0x43, 0x61, 0x6c, 0x63, 0x75, 0x74, 0x74, 0x61, 0x0d, 0x0a, 0x41,
- 0x73, 0x69, 0x61, 0x2f, 0x43, 0x68, 0x69, 0x74, 0x61, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f,
- 0x43, 0x68, 0x6f, 0x69, 0x62, 0x61, 0x6c, 0x73, 0x61, 0x6e, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61,
- 0x2f, 0x43, 0x68, 0x6f, 0x6e, 0x67, 0x71, 0x69, 0x6e, 0x67, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61,
- 0x2f, 0x43, 0x68, 0x75, 0x6e, 0x67, 0x6b, 0x69, 0x6e, 0x67, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61,
- 0x2f, 0x43, 0x6f, 0x6c, 0x6f, 0x6d, 0x62, 0x6f, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x44,
- 0x61, 0x63, 0x63, 0x61, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x44, 0x61, 0x6d, 0x61, 0x73,
- 0x63, 0x75, 0x73, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x44, 0x68, 0x61, 0x6b, 0x61, 0x0d,
- 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x44, 0x69, 0x6c, 0x69, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61,
- 0x2f, 0x44, 0x75, 0x62, 0x61, 0x69, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x44, 0x75, 0x73,
- 0x68, 0x61, 0x6e, 0x62, 0x65, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x46, 0x61, 0x6d, 0x61,
- 0x67, 0x75, 0x73, 0x74, 0x61, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x47, 0x61, 0x7a, 0x61,
- 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x48, 0x61, 0x72, 0x62, 0x69, 0x6e, 0x0d, 0x0a, 0x41,
- 0x73, 0x69, 0x61, 0x2f, 0x48, 0x65, 0x62, 0x72, 0x6f, 0x6e, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61,
- 0x2f, 0x48, 0x6f, 0x6e, 0x67, 0x5f, 0x4b, 0x6f, 0x6e, 0x67, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61,
- 0x2f, 0x48, 0x6f, 0x76, 0x64, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x48, 0x6f, 0x5f, 0x43,
- 0x68, 0x69, 0x5f, 0x4d, 0x69, 0x6e, 0x68, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x49, 0x72,
- 0x6b, 0x75, 0x74, 0x73, 0x6b, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x49, 0x73, 0x74, 0x61,
- 0x6e, 0x62, 0x75, 0x6c, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4a, 0x61, 0x6b, 0x61, 0x72,
- 0x74, 0x61, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4a, 0x61, 0x79, 0x61, 0x70, 0x75, 0x72,
- 0x61, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4a, 0x65, 0x72, 0x75, 0x73, 0x61, 0x6c, 0x65,
- 0x6d, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4b, 0x61, 0x62, 0x75, 0x6c, 0x0d, 0x0a, 0x41,
- 0x73, 0x69, 0x61, 0x2f, 0x4b, 0x61, 0x6d, 0x63, 0x68, 0x61, 0x74, 0x6b, 0x61, 0x0d, 0x0a, 0x41,
- 0x73, 0x69, 0x61, 0x2f, 0x4b, 0x61, 0x72, 0x61, 0x63, 0x68, 0x69, 0x0d, 0x0a, 0x41, 0x73, 0x69,
- 0x61, 0x2f, 0x4b, 0x61, 0x73, 0x68, 0x67, 0x61, 0x72, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f,
- 0x4b, 0x61, 0x74, 0x68, 0x6d, 0x61, 0x6e, 0x64, 0x75, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f,
- 0x4b, 0x61, 0x74, 0x6d, 0x61, 0x6e, 0x64, 0x75, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4b,
- 0x68, 0x61, 0x6e, 0x64, 0x79, 0x67, 0x61, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4b, 0x6f,
- 0x6c, 0x6b, 0x61, 0x74, 0x61, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4b, 0x72, 0x61, 0x73,
- 0x6e, 0x6f, 0x79, 0x61, 0x72, 0x73, 0x6b, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4b, 0x75,
- 0x61, 0x6c, 0x61, 0x5f, 0x4c, 0x75, 0x6d, 0x70, 0x75, 0x72, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61,
- 0x2f, 0x4b, 0x75, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4b,
- 0x75, 0x77, 0x61, 0x69, 0x74, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4d, 0x61, 0x63, 0x61,
- 0x6f, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4d, 0x61, 0x63, 0x61, 0x75, 0x0d, 0x0a, 0x41,
- 0x73, 0x69, 0x61, 0x2f, 0x4d, 0x61, 0x67, 0x61, 0x64, 0x61, 0x6e, 0x0d, 0x0a, 0x41, 0x73, 0x69,
- 0x61, 0x2f, 0x4d, 0x61, 0x6b, 0x61, 0x73, 0x73, 0x61, 0x72, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61,
- 0x2f, 0x4d, 0x61, 0x6e, 0x69, 0x6c, 0x61, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4d, 0x75,
- 0x73, 0x63, 0x61, 0x74, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4e, 0x69, 0x63, 0x6f, 0x73,
- 0x69, 0x61, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4e, 0x6f, 0x76, 0x6f, 0x6b, 0x75, 0x7a,
- 0x6e, 0x65, 0x74, 0x73, 0x6b, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4e, 0x6f, 0x76, 0x6f,
- 0x73, 0x69, 0x62, 0x69, 0x72, 0x73, 0x6b, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4f, 0x6d,
- 0x73, 0x6b, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4f, 0x72, 0x61, 0x6c, 0x0d, 0x0a, 0x41,
- 0x73, 0x69, 0x61, 0x2f, 0x50, 0x68, 0x6e, 0x6f, 0x6d, 0x5f, 0x50, 0x65, 0x6e, 0x68, 0x0d, 0x0a,
- 0x41, 0x73, 0x69, 0x61, 0x2f, 0x50, 0x6f, 0x6e, 0x74, 0x69, 0x61, 0x6e, 0x61, 0x6b, 0x0d, 0x0a,
- 0x41, 0x73, 0x69, 0x61, 0x2f, 0x50, 0x79, 0x6f, 0x6e, 0x67, 0x79, 0x61, 0x6e, 0x67, 0x0d, 0x0a,
- 0x41, 0x73, 0x69, 0x61, 0x2f, 0x51, 0x61, 0x74, 0x61, 0x72, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61,
- 0x2f, 0x51, 0x79, 0x7a, 0x79, 0x6c, 0x6f, 0x72, 0x64, 0x61, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61,
- 0x2f, 0x52, 0x61, 0x6e, 0x67, 0x6f, 0x6f, 0x6e, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x52,
- 0x69, 0x79, 0x61, 0x64, 0x68, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x53, 0x61, 0x69, 0x67,
- 0x6f, 0x6e, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x53, 0x61, 0x6b, 0x68, 0x61, 0x6c, 0x69,
- 0x6e, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x53, 0x61, 0x6d, 0x61, 0x72, 0x6b, 0x61, 0x6e,
- 0x64, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x53, 0x65, 0x6f, 0x75, 0x6c, 0x0d, 0x0a, 0x41,
- 0x73, 0x69, 0x61, 0x2f, 0x53, 0x68, 0x61, 0x6e, 0x67, 0x68, 0x61, 0x69, 0x0d, 0x0a, 0x41, 0x73,
- 0x69, 0x61, 0x2f, 0x53, 0x69, 0x6e, 0x67, 0x61, 0x70, 0x6f, 0x72, 0x65, 0x0d, 0x0a, 0x41, 0x73,
- 0x69, 0x61, 0x2f, 0x53, 0x72, 0x65, 0x64, 0x6e, 0x65, 0x6b, 0x6f, 0x6c, 0x79, 0x6d, 0x73, 0x6b,
- 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x54, 0x61, 0x69, 0x70, 0x65, 0x69, 0x0d, 0x0a, 0x41,
- 0x73, 0x69, 0x61, 0x2f, 0x54, 0x61, 0x73, 0x68, 0x6b, 0x65, 0x6e, 0x74, 0x0d, 0x0a, 0x41, 0x73,
- 0x69, 0x61, 0x2f, 0x54, 0x62, 0x69, 0x6c, 0x69, 0x73, 0x69, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61,
- 0x2f, 0x54, 0x65, 0x68, 0x72, 0x61, 0x6e, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x54, 0x65,
- 0x6c, 0x5f, 0x41, 0x76, 0x69, 0x76, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x54, 0x68, 0x69,
- 0x6d, 0x62, 0x75, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x54, 0x68, 0x69, 0x6d, 0x70, 0x68,
- 0x75, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x54, 0x6f, 0x6b, 0x79, 0x6f, 0x0d, 0x0a, 0x41,
- 0x73, 0x69, 0x61, 0x2f, 0x54, 0x6f, 0x6d, 0x73, 0x6b, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f,
- 0x55, 0x6a, 0x75, 0x6e, 0x67, 0x5f, 0x50, 0x61, 0x6e, 0x64, 0x61, 0x6e, 0x67, 0x0d, 0x0a, 0x41,
- 0x73, 0x69, 0x61, 0x2f, 0x55, 0x6c, 0x61, 0x61, 0x6e, 0x62, 0x61, 0x61, 0x74, 0x61, 0x72, 0x0d,
- 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x55, 0x6c, 0x61, 0x6e, 0x5f, 0x42, 0x61, 0x74, 0x6f, 0x72,
- 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x55, 0x72, 0x75, 0x6d, 0x71, 0x69, 0x0d, 0x0a, 0x41,
- 0x73, 0x69, 0x61, 0x2f, 0x55, 0x73, 0x74, 0x2d, 0x4e, 0x65, 0x72, 0x61, 0x0d, 0x0a, 0x41, 0x73,
- 0x69, 0x61, 0x2f, 0x56, 0x69, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6e, 0x65, 0x0d, 0x0a, 0x41, 0x73,
- 0x69, 0x61, 0x2f, 0x56, 0x6c, 0x61, 0x64, 0x69, 0x76, 0x6f, 0x73, 0x74, 0x6f, 0x6b, 0x0d, 0x0a,
- 0x41, 0x73, 0x69, 0x61, 0x2f, 0x59, 0x61, 0x6b, 0x75, 0x74, 0x73, 0x6b, 0x0d, 0x0a, 0x41, 0x73,
- 0x69, 0x61, 0x2f, 0x59, 0x61, 0x6e, 0x67, 0x6f, 0x6e, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f,
- 0x59, 0x65, 0x6b, 0x61, 0x74, 0x65, 0x72, 0x69, 0x6e, 0x62, 0x75, 0x72, 0x67, 0x0d, 0x0a, 0x41,
- 0x73, 0x69, 0x61, 0x2f, 0x59, 0x65, 0x72, 0x65, 0x76, 0x61, 0x6e, 0x0d, 0x0a, 0x41, 0x74, 0x6c,
- 0x61, 0x6e, 0x74, 0x69, 0x63, 0x2f, 0x41, 0x7a, 0x6f, 0x72, 0x65, 0x73, 0x0d, 0x0a, 0x41, 0x74,
- 0x6c, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x2f, 0x42, 0x65, 0x72, 0x6d, 0x75, 0x64, 0x61, 0x0d, 0x0a,
- 0x41, 0x74, 0x6c, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x2f, 0x43, 0x61, 0x6e, 0x61, 0x72, 0x79, 0x0d,
- 0x0a, 0x41, 0x74, 0x6c, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x2f, 0x43, 0x61, 0x70, 0x65, 0x5f, 0x56,
- 0x65, 0x72, 0x64, 0x65, 0x0d, 0x0a, 0x41, 0x74, 0x6c, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x2f, 0x46,
- 0x61, 0x65, 0x72, 0x6f, 0x65, 0x0d, 0x0a, 0x41, 0x74, 0x6c, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x2f,
- 0x46, 0x61, 0x72, 0x6f, 0x65, 0x0d, 0x0a, 0x41, 0x74, 0x6c, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x2f,
- 0x4a, 0x61, 0x6e, 0x5f, 0x4d, 0x61, 0x79, 0x65, 0x6e, 0x0d, 0x0a, 0x41, 0x74, 0x6c, 0x61, 0x6e,
- 0x74, 0x69, 0x63, 0x2f, 0x4d, 0x61, 0x64, 0x65, 0x69, 0x72, 0x61, 0x0d, 0x0a, 0x41, 0x74, 0x6c,
- 0x61, 0x6e, 0x74, 0x69, 0x63, 0x2f, 0x52, 0x65, 0x79, 0x6b, 0x6a, 0x61, 0x76, 0x69, 0x6b, 0x0d,
- 0x0a, 0x41, 0x74, 0x6c, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x2f, 0x53, 0x6f, 0x75, 0x74, 0x68, 0x5f,
- 0x47, 0x65, 0x6f, 0x72, 0x67, 0x69, 0x61, 0x0d, 0x0a, 0x41, 0x74, 0x6c, 0x61, 0x6e, 0x74, 0x69,
- 0x63, 0x2f, 0x53, 0x74, 0x61, 0x6e, 0x6c, 0x65, 0x79, 0x0d, 0x0a, 0x41, 0x74, 0x6c, 0x61, 0x6e,
- 0x74, 0x69, 0x63, 0x2f, 0x53, 0x74, 0x5f, 0x48, 0x65, 0x6c, 0x65, 0x6e, 0x61, 0x0d, 0x0a, 0x41,
- 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x41, 0x43, 0x54, 0x0d, 0x0a, 0x41, 0x75,
- 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x41, 0x64, 0x65, 0x6c, 0x61, 0x69, 0x64, 0x65,
- 0x0d, 0x0a, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x42, 0x72, 0x69, 0x73,
- 0x62, 0x61, 0x6e, 0x65, 0x0d, 0x0a, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f,
- 0x42, 0x72, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x48, 0x69, 0x6c, 0x6c, 0x0d, 0x0a, 0x41, 0x75, 0x73,
- 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x43, 0x61, 0x6e, 0x62, 0x65, 0x72, 0x72, 0x61, 0x0d,
- 0x0a, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x43, 0x75, 0x72, 0x72, 0x69,
- 0x65, 0x0d, 0x0a, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x44, 0x61, 0x72,
- 0x77, 0x69, 0x6e, 0x0d, 0x0a, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x45,
- 0x75, 0x63, 0x6c, 0x61, 0x0d, 0x0a, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f,
- 0x48, 0x6f, 0x62, 0x61, 0x72, 0x74, 0x0d, 0x0a, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69,
- 0x61, 0x2f, 0x4c, 0x48, 0x49, 0x0d, 0x0a, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61,
- 0x2f, 0x4c, 0x69, 0x6e, 0x64, 0x65, 0x6d, 0x61, 0x6e, 0x0d, 0x0a, 0x41, 0x75, 0x73, 0x74, 0x72,
- 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x4c, 0x6f, 0x72, 0x64, 0x5f, 0x48, 0x6f, 0x77, 0x65, 0x0d, 0x0a,
- 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x4d, 0x65, 0x6c, 0x62, 0x6f, 0x75,
- 0x72, 0x6e, 0x65, 0x0d, 0x0a, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x4e,
- 0x6f, 0x72, 0x74, 0x68, 0x0d, 0x0a, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f,
- 0x4e, 0x53, 0x57, 0x0d, 0x0a, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x50,
- 0x65, 0x72, 0x74, 0x68, 0x0d, 0x0a, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f,
- 0x51, 0x75, 0x65, 0x65, 0x6e, 0x73, 0x6c, 0x61, 0x6e, 0x64, 0x0d, 0x0a, 0x41, 0x75, 0x73, 0x74,
- 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x53, 0x6f, 0x75, 0x74, 0x68, 0x0d, 0x0a, 0x41, 0x75, 0x73,
- 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x53, 0x79, 0x64, 0x6e, 0x65, 0x79, 0x0d, 0x0a, 0x41,
- 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x54, 0x61, 0x73, 0x6d, 0x61, 0x6e, 0x69,
- 0x61, 0x0d, 0x0a, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x56, 0x69, 0x63,
- 0x74, 0x6f, 0x72, 0x69, 0x61, 0x0d, 0x0a, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61,
- 0x2f, 0x57, 0x65, 0x73, 0x74, 0x0d, 0x0a, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61,
- 0x2f, 0x59, 0x61, 0x6e, 0x63, 0x6f, 0x77, 0x69, 0x6e, 0x6e, 0x61, 0x0d, 0x0a, 0x42, 0x72, 0x61,
- 0x7a, 0x69, 0x6c, 0x2f, 0x41, 0x63, 0x72, 0x65, 0x0d, 0x0a, 0x42, 0x72, 0x61, 0x7a, 0x69, 0x6c,
- 0x2f, 0x44, 0x65, 0x4e, 0x6f, 0x72, 0x6f, 0x6e, 0x68, 0x61, 0x0d, 0x0a, 0x42, 0x72, 0x61, 0x7a,
- 0x69, 0x6c, 0x2f, 0x45, 0x61, 0x73, 0x74, 0x0d, 0x0a, 0x42, 0x72, 0x61, 0x7a, 0x69, 0x6c, 0x2f,
- 0x57, 0x65, 0x73, 0x74, 0x0d, 0x0a, 0x43, 0x61, 0x6e, 0x61, 0x64, 0x61, 0x2f, 0x41, 0x74, 0x6c,
- 0x61, 0x6e, 0x74, 0x69, 0x63, 0x0d, 0x0a, 0x43, 0x61, 0x6e, 0x61, 0x64, 0x61, 0x2f, 0x43, 0x65,
- 0x6e, 0x74, 0x72, 0x61, 0x6c, 0x0d, 0x0a, 0x43, 0x61, 0x6e, 0x61, 0x64, 0x61, 0x2f, 0x45, 0x61,
- 0x73, 0x74, 0x2d, 0x53, 0x61, 0x73, 0x6b, 0x61, 0x74, 0x63, 0x68, 0x65, 0x77, 0x61, 0x6e, 0x0d,
- 0x0a, 0x43, 0x61, 0x6e, 0x61, 0x64, 0x61, 0x2f, 0x45, 0x61, 0x73, 0x74, 0x65, 0x72, 0x6e, 0x0d,
- 0x0a, 0x43, 0x61, 0x6e, 0x61, 0x64, 0x61, 0x2f, 0x4d, 0x6f, 0x75, 0x6e, 0x74, 0x61, 0x69, 0x6e,
- 0x0d, 0x0a, 0x43, 0x61, 0x6e, 0x61, 0x64, 0x61, 0x2f, 0x4e, 0x65, 0x77, 0x66, 0x6f, 0x75, 0x6e,
- 0x64, 0x6c, 0x61, 0x6e, 0x64, 0x0d, 0x0a, 0x43, 0x61, 0x6e, 0x61, 0x64, 0x61, 0x2f, 0x50, 0x61,
- 0x63, 0x69, 0x66, 0x69, 0x63, 0x0d, 0x0a, 0x43, 0x61, 0x6e, 0x61, 0x64, 0x61, 0x2f, 0x53, 0x61,
- 0x73, 0x6b, 0x61, 0x74, 0x63, 0x68, 0x65, 0x77, 0x61, 0x6e, 0x0d, 0x0a, 0x43, 0x61, 0x6e, 0x61,
- 0x64, 0x61, 0x2f, 0x59, 0x75, 0x6b, 0x6f, 0x6e, 0x0d, 0x0a, 0x43, 0x68, 0x69, 0x6c, 0x65, 0x2f,
- 0x43, 0x6f, 0x6e, 0x74, 0x69, 0x6e, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x0d, 0x0a, 0x43, 0x68, 0x69,
- 0x6c, 0x65, 0x2f, 0x45, 0x61, 0x73, 0x74, 0x65, 0x72, 0x49, 0x73, 0x6c, 0x61, 0x6e, 0x64, 0x0d,
- 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d,
- 0x54, 0x2b, 0x30, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2b, 0x31, 0x0d, 0x0a,
- 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2b, 0x31, 0x30, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f,
- 0x47, 0x4d, 0x54, 0x2b, 0x31, 0x31, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2b,
- 0x31, 0x32, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2b, 0x32, 0x0d, 0x0a, 0x45,
- 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2b, 0x33, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d,
- 0x54, 0x2b, 0x34, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2b, 0x35, 0x0d, 0x0a,
- 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2b, 0x36, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47,
- 0x4d, 0x54, 0x2b, 0x37, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2b, 0x38, 0x0d,
- 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2b, 0x39, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f,
- 0x47, 0x4d, 0x54, 0x2d, 0x30, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2d, 0x31,
- 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2d, 0x31, 0x30, 0x0d, 0x0a, 0x45, 0x74,
- 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2d, 0x31, 0x31, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d,
- 0x54, 0x2d, 0x31, 0x32, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2d, 0x31, 0x33,
- 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2d, 0x31, 0x34, 0x0d, 0x0a, 0x45, 0x74,
- 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2d, 0x32, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54,
- 0x2d, 0x33, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2d, 0x34, 0x0d, 0x0a, 0x45,
- 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2d, 0x35, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d,
- 0x54, 0x2d, 0x36, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2d, 0x37, 0x0d, 0x0a,
- 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2d, 0x38, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47,
- 0x4d, 0x54, 0x2d, 0x39, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x30, 0x0d, 0x0a,
- 0x45, 0x74, 0x63, 0x2f, 0x47, 0x72, 0x65, 0x65, 0x6e, 0x77, 0x69, 0x63, 0x68, 0x0d, 0x0a, 0x45,
- 0x74, 0x63, 0x2f, 0x55, 0x43, 0x54, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x55, 0x6e, 0x69, 0x76,
- 0x65, 0x72, 0x73, 0x61, 0x6c, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x55, 0x54, 0x43, 0x0d, 0x0a,
- 0x45, 0x74, 0x63, 0x2f, 0x5a, 0x75, 0x6c, 0x75, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65,
- 0x2f, 0x41, 0x6d, 0x73, 0x74, 0x65, 0x72, 0x64, 0x61, 0x6d, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f,
- 0x70, 0x65, 0x2f, 0x41, 0x6e, 0x64, 0x6f, 0x72, 0x72, 0x61, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f,
- 0x70, 0x65, 0x2f, 0x41, 0x73, 0x74, 0x72, 0x61, 0x6b, 0x68, 0x61, 0x6e, 0x0d, 0x0a, 0x45, 0x75,
- 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x41, 0x74, 0x68, 0x65, 0x6e, 0x73, 0x0d, 0x0a, 0x45, 0x75, 0x72,
- 0x6f, 0x70, 0x65, 0x2f, 0x42, 0x65, 0x6c, 0x66, 0x61, 0x73, 0x74, 0x0d, 0x0a, 0x45, 0x75, 0x72,
- 0x6f, 0x70, 0x65, 0x2f, 0x42, 0x65, 0x6c, 0x67, 0x72, 0x61, 0x64, 0x65, 0x0d, 0x0a, 0x45, 0x75,
- 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x42, 0x65, 0x72, 0x6c, 0x69, 0x6e, 0x0d, 0x0a, 0x45, 0x75, 0x72,
- 0x6f, 0x70, 0x65, 0x2f, 0x42, 0x72, 0x61, 0x74, 0x69, 0x73, 0x6c, 0x61, 0x76, 0x61, 0x0d, 0x0a,
- 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x42, 0x72, 0x75, 0x73, 0x73, 0x65, 0x6c, 0x73, 0x0d,
- 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x42, 0x75, 0x63, 0x68, 0x61, 0x72, 0x65, 0x73,
- 0x74, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x42, 0x75, 0x64, 0x61, 0x70, 0x65,
- 0x73, 0x74, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x42, 0x75, 0x73, 0x69, 0x6e,
- 0x67, 0x65, 0x6e, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x43, 0x68, 0x69, 0x73,
- 0x69, 0x6e, 0x61, 0x75, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x43, 0x6f, 0x70,
- 0x65, 0x6e, 0x68, 0x61, 0x67, 0x65, 0x6e, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f,
- 0x44, 0x75, 0x62, 0x6c, 0x69, 0x6e, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x47,
- 0x69, 0x62, 0x72, 0x61, 0x6c, 0x74, 0x61, 0x72, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65,
- 0x2f, 0x47, 0x75, 0x65, 0x72, 0x6e, 0x73, 0x65, 0x79, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70,
- 0x65, 0x2f, 0x48, 0x65, 0x6c, 0x73, 0x69, 0x6e, 0x6b, 0x69, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f,
- 0x70, 0x65, 0x2f, 0x49, 0x73, 0x6c, 0x65, 0x5f, 0x6f, 0x66, 0x5f, 0x4d, 0x61, 0x6e, 0x0d, 0x0a,
- 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x49, 0x73, 0x74, 0x61, 0x6e, 0x62, 0x75, 0x6c, 0x0d,
- 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4a, 0x65, 0x72, 0x73, 0x65, 0x79, 0x0d, 0x0a,
- 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4b, 0x61, 0x6c, 0x69, 0x6e, 0x69, 0x6e, 0x67, 0x72,
- 0x61, 0x64, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4b, 0x69, 0x65, 0x76, 0x0d,
- 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4b, 0x69, 0x72, 0x6f, 0x76, 0x0d, 0x0a, 0x45,
- 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4c, 0x69, 0x73, 0x62, 0x6f, 0x6e, 0x0d, 0x0a, 0x45, 0x75,
- 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4c, 0x6a, 0x75, 0x62, 0x6c, 0x6a, 0x61, 0x6e, 0x61, 0x0d, 0x0a,
- 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4c, 0x6f, 0x6e, 0x64, 0x6f, 0x6e, 0x0d, 0x0a, 0x45,
- 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4c, 0x75, 0x78, 0x65, 0x6d, 0x62, 0x6f, 0x75, 0x72, 0x67,
- 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4d, 0x61, 0x64, 0x72, 0x69, 0x64, 0x0d,
- 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4d, 0x61, 0x6c, 0x74, 0x61, 0x0d, 0x0a, 0x45,
- 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4d, 0x61, 0x72, 0x69, 0x65, 0x68, 0x61, 0x6d, 0x6e, 0x0d,
- 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4d, 0x69, 0x6e, 0x73, 0x6b, 0x0d, 0x0a, 0x45,
- 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4d, 0x6f, 0x6e, 0x61, 0x63, 0x6f, 0x0d, 0x0a, 0x45, 0x75,
- 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4d, 0x6f, 0x73, 0x63, 0x6f, 0x77, 0x0d, 0x0a, 0x45, 0x75, 0x72,
- 0x6f, 0x70, 0x65, 0x2f, 0x4e, 0x69, 0x63, 0x6f, 0x73, 0x69, 0x61, 0x0d, 0x0a, 0x45, 0x75, 0x72,
- 0x6f, 0x70, 0x65, 0x2f, 0x4f, 0x73, 0x6c, 0x6f, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65,
- 0x2f, 0x50, 0x61, 0x72, 0x69, 0x73, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x50,
- 0x6f, 0x64, 0x67, 0x6f, 0x72, 0x69, 0x63, 0x61, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65,
- 0x2f, 0x50, 0x72, 0x61, 0x67, 0x75, 0x65, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f,
- 0x52, 0x69, 0x67, 0x61, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x52, 0x6f, 0x6d,
- 0x65, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x53, 0x61, 0x6d, 0x61, 0x72, 0x61,
- 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x53, 0x61, 0x6e, 0x5f, 0x4d, 0x61, 0x72,
- 0x69, 0x6e, 0x6f, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x53, 0x61, 0x72, 0x61,
- 0x6a, 0x65, 0x76, 0x6f, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x53, 0x61, 0x72,
- 0x61, 0x74, 0x6f, 0x76, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x53, 0x69, 0x6d,
- 0x66, 0x65, 0x72, 0x6f, 0x70, 0x6f, 0x6c, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f,
- 0x53, 0x6b, 0x6f, 0x70, 0x6a, 0x65, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x53,
- 0x6f, 0x66, 0x69, 0x61, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x53, 0x74, 0x6f,
- 0x63, 0x6b, 0x68, 0x6f, 0x6c, 0x6d, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x54,
- 0x61, 0x6c, 0x6c, 0x69, 0x6e, 0x6e, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x54,
- 0x69, 0x72, 0x61, 0x6e, 0x65, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x54, 0x69,
- 0x72, 0x61, 0x73, 0x70, 0x6f, 0x6c, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x55,
- 0x6c, 0x79, 0x61, 0x6e, 0x6f, 0x76, 0x73, 0x6b, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65,
- 0x2f, 0x55, 0x7a, 0x68, 0x67, 0x6f, 0x72, 0x6f, 0x64, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70,
- 0x65, 0x2f, 0x56, 0x61, 0x64, 0x75, 0x7a, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f,
- 0x56, 0x61, 0x74, 0x69, 0x63, 0x61, 0x6e, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f,
- 0x56, 0x69, 0x65, 0x6e, 0x6e, 0x61, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x56,
- 0x69, 0x6c, 0x6e, 0x69, 0x75, 0x73, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x56,
- 0x6f, 0x6c, 0x67, 0x6f, 0x67, 0x72, 0x61, 0x64, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65,
- 0x2f, 0x57, 0x61, 0x72, 0x73, 0x61, 0x77, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f,
- 0x5a, 0x61, 0x67, 0x72, 0x65, 0x62, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x5a,
- 0x61, 0x70, 0x6f, 0x72, 0x6f, 0x7a, 0x68, 0x79, 0x65, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70,
- 0x65, 0x2f, 0x5a, 0x75, 0x72, 0x69, 0x63, 0x68, 0x0d, 0x0a, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e,
- 0x2f, 0x41, 0x6e, 0x74, 0x61, 0x6e, 0x61, 0x6e, 0x61, 0x72, 0x69, 0x76, 0x6f, 0x0d, 0x0a, 0x49,
- 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x2f, 0x43, 0x68, 0x61, 0x67, 0x6f, 0x73, 0x0d, 0x0a, 0x49, 0x6e,
- 0x64, 0x69, 0x61, 0x6e, 0x2f, 0x43, 0x68, 0x72, 0x69, 0x73, 0x74, 0x6d, 0x61, 0x73, 0x0d, 0x0a,
- 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x2f, 0x43, 0x6f, 0x63, 0x6f, 0x73, 0x0d, 0x0a, 0x49, 0x6e,
- 0x64, 0x69, 0x61, 0x6e, 0x2f, 0x43, 0x6f, 0x6d, 0x6f, 0x72, 0x6f, 0x0d, 0x0a, 0x49, 0x6e, 0x64,
- 0x69, 0x61, 0x6e, 0x2f, 0x4b, 0x65, 0x72, 0x67, 0x75, 0x65, 0x6c, 0x65, 0x6e, 0x0d, 0x0a, 0x49,
- 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x2f, 0x4d, 0x61, 0x68, 0x65, 0x0d, 0x0a, 0x49, 0x6e, 0x64, 0x69,
- 0x61, 0x6e, 0x2f, 0x4d, 0x61, 0x6c, 0x64, 0x69, 0x76, 0x65, 0x73, 0x0d, 0x0a, 0x49, 0x6e, 0x64,
- 0x69, 0x61, 0x6e, 0x2f, 0x4d, 0x61, 0x75, 0x72, 0x69, 0x74, 0x69, 0x75, 0x73, 0x0d, 0x0a, 0x49,
- 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x2f, 0x4d, 0x61, 0x79, 0x6f, 0x74, 0x74, 0x65, 0x0d, 0x0a, 0x49,
- 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x2f, 0x52, 0x65, 0x75, 0x6e, 0x69, 0x6f, 0x6e, 0x0d, 0x0a, 0x4d,
- 0x65, 0x78, 0x69, 0x63, 0x6f, 0x2f, 0x42, 0x61, 0x6a, 0x61, 0x4e, 0x6f, 0x72, 0x74, 0x65, 0x0d,
- 0x0a, 0x4d, 0x65, 0x78, 0x69, 0x63, 0x6f, 0x2f, 0x42, 0x61, 0x6a, 0x61, 0x53, 0x75, 0x72, 0x0d,
- 0x0a, 0x4d, 0x65, 0x78, 0x69, 0x63, 0x6f, 0x2f, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c, 0x0d,
- 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x41, 0x70, 0x69, 0x61, 0x0d, 0x0a, 0x50,
- 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x41, 0x75, 0x63, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x0d,
- 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x42, 0x6f, 0x75, 0x67, 0x61, 0x69, 0x6e,
- 0x76, 0x69, 0x6c, 0x6c, 0x65, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x43,
- 0x68, 0x61, 0x74, 0x68, 0x61, 0x6d, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f,
- 0x43, 0x68, 0x75, 0x75, 0x6b, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x45,
- 0x61, 0x73, 0x74, 0x65, 0x72, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x45,
- 0x66, 0x61, 0x74, 0x65, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x45, 0x6e,
- 0x64, 0x65, 0x72, 0x62, 0x75, 0x72, 0x79, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63,
- 0x2f, 0x46, 0x61, 0x6b, 0x61, 0x6f, 0x66, 0x6f, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69,
- 0x63, 0x2f, 0x46, 0x69, 0x6a, 0x69, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f,
- 0x46, 0x75, 0x6e, 0x61, 0x66, 0x75, 0x74, 0x69, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69,
- 0x63, 0x2f, 0x47, 0x61, 0x6c, 0x61, 0x70, 0x61, 0x67, 0x6f, 0x73, 0x0d, 0x0a, 0x50, 0x61, 0x63,
- 0x69, 0x66, 0x69, 0x63, 0x2f, 0x47, 0x61, 0x6d, 0x62, 0x69, 0x65, 0x72, 0x0d, 0x0a, 0x50, 0x61,
- 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x47, 0x75, 0x61, 0x64, 0x61, 0x6c, 0x63, 0x61, 0x6e, 0x61,
- 0x6c, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x47, 0x75, 0x61, 0x6d, 0x0d,
- 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x48, 0x6f, 0x6e, 0x6f, 0x6c, 0x75, 0x6c,
- 0x75, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x4a, 0x6f, 0x68, 0x6e, 0x73,
- 0x74, 0x6f, 0x6e, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x4b, 0x69, 0x72,
- 0x69, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x69, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63,
- 0x2f, 0x4b, 0x6f, 0x73, 0x72, 0x61, 0x65, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63,
- 0x2f, 0x4b, 0x77, 0x61, 0x6a, 0x61, 0x6c, 0x65, 0x69, 0x6e, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69,
- 0x66, 0x69, 0x63, 0x2f, 0x4d, 0x61, 0x6a, 0x75, 0x72, 0x6f, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69,
- 0x66, 0x69, 0x63, 0x2f, 0x4d, 0x61, 0x72, 0x71, 0x75, 0x65, 0x73, 0x61, 0x73, 0x0d, 0x0a, 0x50,
- 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x4d, 0x69, 0x64, 0x77, 0x61, 0x79, 0x0d, 0x0a, 0x50,
- 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x4e, 0x61, 0x75, 0x72, 0x75, 0x0d, 0x0a, 0x50, 0x61,
- 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x4e, 0x69, 0x75, 0x65, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69,
- 0x66, 0x69, 0x63, 0x2f, 0x4e, 0x6f, 0x72, 0x66, 0x6f, 0x6c, 0x6b, 0x0d, 0x0a, 0x50, 0x61, 0x63,
- 0x69, 0x66, 0x69, 0x63, 0x2f, 0x4e, 0x6f, 0x75, 0x6d, 0x65, 0x61, 0x0d, 0x0a, 0x50, 0x61, 0x63,
- 0x69, 0x66, 0x69, 0x63, 0x2f, 0x50, 0x61, 0x67, 0x6f, 0x5f, 0x50, 0x61, 0x67, 0x6f, 0x0d, 0x0a,
- 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x50, 0x61, 0x6c, 0x61, 0x75, 0x0d, 0x0a, 0x50,
- 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x50, 0x69, 0x74, 0x63, 0x61, 0x69, 0x72, 0x6e, 0x0d,
- 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x50, 0x6f, 0x68, 0x6e, 0x70, 0x65, 0x69,
- 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x50, 0x6f, 0x6e, 0x61, 0x70, 0x65,
- 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x50, 0x6f, 0x72, 0x74, 0x5f, 0x4d,
- 0x6f, 0x72, 0x65, 0x73, 0x62, 0x79, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f,
- 0x52, 0x61, 0x72, 0x6f, 0x74, 0x6f, 0x6e, 0x67, 0x61, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66,
- 0x69, 0x63, 0x2f, 0x53, 0x61, 0x69, 0x70, 0x61, 0x6e, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66,
- 0x69, 0x63, 0x2f, 0x53, 0x61, 0x6d, 0x6f, 0x61, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69,
- 0x63, 0x2f, 0x54, 0x61, 0x68, 0x69, 0x74, 0x69, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69,
- 0x63, 0x2f, 0x54, 0x61, 0x72, 0x61, 0x77, 0x61, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69,
- 0x63, 0x2f, 0x54, 0x6f, 0x6e, 0x67, 0x61, 0x74, 0x61, 0x70, 0x75, 0x0d, 0x0a, 0x50, 0x61, 0x63,
- 0x69, 0x66, 0x69, 0x63, 0x2f, 0x54, 0x72, 0x75, 0x6b, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66,
- 0x69, 0x63, 0x2f, 0x57, 0x61, 0x6b, 0x65, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63,
- 0x2f, 0x57, 0x61, 0x6c, 0x6c, 0x69, 0x73, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63,
- 0x2f, 0x59, 0x61, 0x70, 0x0d, 0x0a, 0x55, 0x53, 0x2f, 0x41, 0x6c, 0x61, 0x73, 0x6b, 0x61, 0x0d,
- 0x0a, 0x55, 0x53, 0x2f, 0x41, 0x6c, 0x65, 0x75, 0x74, 0x69, 0x61, 0x6e, 0x0d, 0x0a, 0x55, 0x53,
- 0x2f, 0x41, 0x72, 0x69, 0x7a, 0x6f, 0x6e, 0x61, 0x0d, 0x0a, 0x55, 0x53, 0x2f, 0x43, 0x65, 0x6e,
- 0x74, 0x72, 0x61, 0x6c, 0x0d, 0x0a, 0x55, 0x53, 0x2f, 0x45, 0x61, 0x73, 0x74, 0x2d, 0x49, 0x6e,
- 0x64, 0x69, 0x61, 0x6e, 0x61, 0x0d, 0x0a, 0x55, 0x53, 0x2f, 0x45, 0x61, 0x73, 0x74, 0x65, 0x72,
- 0x6e, 0x0d, 0x0a, 0x55, 0x53, 0x2f, 0x48, 0x61, 0x77, 0x61, 0x69, 0x69, 0x0d, 0x0a, 0x55, 0x53,
- 0x2f, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x61, 0x2d, 0x53, 0x74, 0x61, 0x72, 0x6b, 0x65, 0x0d,
- 0x0a, 0x55, 0x53, 0x2f, 0x4d, 0x69, 0x63, 0x68, 0x69, 0x67, 0x61, 0x6e, 0x0d, 0x0a, 0x55, 0x53,
- 0x2f, 0x4d, 0x6f, 0x75, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x0d, 0x0a, 0x55, 0x53, 0x2f, 0x50, 0x61,
- 0x63, 0x69, 0x66, 0x69, 0x63, 0x0d, 0x0a, 0x55, 0x53, 0x2f, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69,
- 0x63, 0x2d, 0x4e, 0x65, 0x77, 0x0d, 0x0a, 0x55, 0x53, 0x2f, 0x53, 0x61, 0x6d, 0x6f, 0x61, 0x0d,
- 0x0a};
+#include "nx_tzdb.h"
-static VirtualFile GenerateDefaultTimeZoneFile() {
- struct TimeZoneInfo {
- s64_be at;
- std::array<u8, 7> padding1;
- std::array<char, 4> time_zone_chars;
- std::array<u8, 2> padding2;
- std::array<char, 6> time_zone_name;
- };
+namespace FileSys::SystemArchive {
- VirtualFile file{std::make_shared<VectorVfsFile>(
- std::vector<u8>(sizeof(Service::Time::TimeZone::TzifHeader) + sizeof(TimeZoneInfo)),
- "GMT")};
+const static std::map<std::string, const std::map<const char*, const std::vector<u8>>&>
+ tzdb_zoneinfo_dirs = {{"Africa", NxTzdb::africa},
+ {"America", NxTzdb::america},
+ {"Antarctica", NxTzdb::antarctica},
+ {"Arctic", NxTzdb::arctic},
+ {"Asia", NxTzdb::asia},
+ {"Atlantic", NxTzdb::atlantic},
+ {"Australia", NxTzdb::australia},
+ {"Brazil", NxTzdb::brazil},
+ {"Canada", NxTzdb::canada},
+ {"Chile", NxTzdb::chile},
+ {"Etc", NxTzdb::etc},
+ {"Europe", NxTzdb::europe},
+ {"Indian", NxTzdb::indian},
+ {"Mexico", NxTzdb::mexico},
+ {"Pacific", NxTzdb::pacific},
+ {"US", NxTzdb::us}};
- const Service::Time::TimeZone::TzifHeader header{
- .magic = 0x545a6966,
- .version = 0x32,
- .ttis_gmt_count = 1,
- .ttis_std_count = 1,
- .time_count = 1,
- .type_count = 1,
- .char_count = 4,
- };
- file->WriteObject(header, 0);
+const static std::map<std::string, const std::map<const char*, const std::vector<u8>>&>
+ tzdb_america_dirs = {{"Argentina", NxTzdb::america_argentina},
+ {"Indiana", NxTzdb::america_indiana},
+ {"Kentucky", NxTzdb::america_kentucky},
+ {"North_Dakota", NxTzdb::america_north_dakota}};
- const TimeZoneInfo time_zone_info{
- .at = 0xf8,
- .padding1 = {},
- .time_zone_chars = {'G', 'M', 'T', '\0'},
- .padding2 = {},
- .time_zone_name = {'\n', 'G', 'M', 'T', '0', '\n'},
- };
- file->WriteObject(time_zone_info, sizeof(Service::Time::TimeZone::TzifHeader));
+static void GenerateFiles(std::vector<VirtualFile>& directory,
+ const std::map<const char*, const std::vector<u8>>& files) {
+ for (const auto& [filename, data] : files) {
+ const auto data_copy{data};
+ const std::string filename_copy{filename};
+ VirtualFile file{
+ std::make_shared<VectorVfsFile>(std::move(data_copy), std::move(filename_copy))};
+ directory.push_back(file);
+ }
+}
- return file;
+static std::vector<VirtualFile> GenerateZoneinfoFiles() {
+ std::vector<VirtualFile> zoneinfo_files;
+ GenerateFiles(zoneinfo_files, NxTzdb::zoneinfo);
+ return zoneinfo_files;
}
VirtualDir TimeZoneBinary() {
- std::vector<VirtualDir> root_dirs{std::make_shared<VectorVfsDirectory>(
- std::vector<VirtualFile>{GenerateDefaultTimeZoneFile()}, std::vector<VirtualDir>{},
- "zoneinfo")};
- std::vector<VirtualFile> root_files{MakeArrayFile(LOCATION_NAMES, "binaryList.txt")};
+ std::vector<VirtualDir> america_sub_dirs;
+ for (const auto& [dir_name, files] : tzdb_america_dirs) {
+ std::vector<VirtualFile> vfs_files;
+ GenerateFiles(vfs_files, files);
+ america_sub_dirs.push_back(std::make_shared<VectorVfsDirectory>(
+ std::move(vfs_files), std::vector<VirtualDir>{}, dir_name));
+ }
+
+ std::vector<VirtualDir> zoneinfo_sub_dirs;
+ for (const auto& [dir_name, files] : tzdb_zoneinfo_dirs) {
+ std::vector<VirtualFile> vfs_files;
+ GenerateFiles(vfs_files, files);
+ if (dir_name == "America") {
+ zoneinfo_sub_dirs.push_back(std::make_shared<VectorVfsDirectory>(
+ std::move(vfs_files), std::move(america_sub_dirs), dir_name));
+ } else {
+ zoneinfo_sub_dirs.push_back(std::make_shared<VectorVfsDirectory>(
+ std::move(vfs_files), std::vector<VirtualDir>{}, dir_name));
+ }
+ }
+
+ std::vector<VirtualDir> zoneinfo_dir{std::make_shared<VectorVfsDirectory>(
+ GenerateZoneinfoFiles(), std::move(zoneinfo_sub_dirs), "zoneinfo")};
+ std::vector<VirtualFile> root_files;
+ GenerateFiles(root_files, NxTzdb::base);
- return std::make_shared<VectorVfsDirectory>(std::move(root_files), std::move(root_dirs),
+ return std::make_shared<VectorVfsDirectory>(std::move(root_files), std::move(zoneinfo_dir),
"data");
}
diff --git a/src/core/file_sys/vfs.h b/src/core/file_sys/vfs.h
index 8fc1738a4..a93e21f67 100644
--- a/src/core/file_sys/vfs.h
+++ b/src/core/file_sys/vfs.h
@@ -45,7 +45,7 @@ public:
// Return whether or not the user has write permission on this filesystem.
virtual bool IsWritable() const;
- // Determine if the entry at path is non-existant, a file, or a directory.
+ // Determine if the entry at path is non-existent, a file, or a directory.
virtual VfsEntryType GetEntryType(std::string_view path) const;
// Opens the file with path relative to root. If it doesn't exist, returns nullptr.
@@ -58,7 +58,7 @@ public:
// Moves the file from old_path to new_path, returning the moved file on success and nullptr on
// failure.
virtual VirtualFile MoveFile(std::string_view old_path, std::string_view new_path);
- // Deletes the file with path relative to root, returing true on success.
+ // Deletes the file with path relative to root, returning true on success.
virtual bool DeleteFile(std::string_view path);
// Opens the directory with path relative to root. If it doesn't exist, returns nullptr.
@@ -71,7 +71,7 @@ public:
// Moves the directory from old_path to new_path, returning the moved directory on success and
// nullptr on failure.
virtual VirtualDir MoveDirectory(std::string_view old_path, std::string_view new_path);
- // Deletes the directory with path relative to root, returing true on success.
+ // Deletes the directory with path relative to root, returning true on success.
virtual bool DeleteDirectory(std::string_view path);
protected:
@@ -144,7 +144,7 @@ public:
return Read(reinterpret_cast<u8*>(data), sizeof(T), offset);
}
- // Writes exactly one byte to offset in file and retuns whether or not the byte was written
+ // Writes exactly one byte to offset in file and returns whether or not the byte was written
// successfully.
virtual bool WriteByte(u8 data, std::size_t offset = 0);
// Writes a vector of bytes to offset in file and returns the number of bytes successfully
@@ -191,13 +191,13 @@ public:
VfsDirectory() = default;
virtual ~VfsDirectory();
- // Retrives the file located at path as if the current directory was root. Returns nullptr if
+ // Retrieves the file located at path as if the current directory was root. Returns nullptr if
// not found.
virtual VirtualFile GetFileRelative(std::string_view path) const;
// Calls GetFileRelative(path) on the root of the current directory.
virtual VirtualFile GetFileAbsolute(std::string_view path) const;
- // Retrives the directory located at path as if the current directory was root. Returns nullptr
+ // Retrieves the directory located at path as if the current directory was root. Returns nullptr
// if not found.
virtual VirtualDir GetDirectoryRelative(std::string_view path) const;
// Calls GetDirectoryRelative(path) on the root of the current directory.
@@ -205,7 +205,7 @@ public:
// Returns a vector containing all of the files in this directory.
virtual std::vector<VirtualFile> GetFiles() const = 0;
- // Returns the file with filename matching name. Returns nullptr if directory dosen't have a
+ // Returns the file with filename matching name. Returns nullptr if directory doesn't have a
// file with name.
virtual VirtualFile GetFile(std::string_view name) const;
@@ -214,7 +214,7 @@ public:
// Returns a vector containing all of the subdirectories in this directory.
virtual std::vector<VirtualDir> GetSubdirectories() const = 0;
- // Returns the directory with name matching name. Returns nullptr if directory dosen't have a
+ // Returns the directory with name matching name. Returns nullptr if directory doesn't have a
// directory with name.
virtual VirtualDir GetSubdirectory(std::string_view name) const;
diff --git a/src/core/file_sys/vfs_cached.cpp b/src/core/file_sys/vfs_cached.cpp
new file mode 100644
index 000000000..c3154ee81
--- /dev/null
+++ b/src/core/file_sys/vfs_cached.cpp
@@ -0,0 +1,63 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/file_sys/vfs_cached.h"
+#include "core/file_sys/vfs_types.h"
+
+namespace FileSys {
+
+CachedVfsDirectory::CachedVfsDirectory(VirtualDir& source_dir)
+ : name(source_dir->GetName()), parent(source_dir->GetParentDirectory()) {
+ for (auto& dir : source_dir->GetSubdirectories()) {
+ dirs.emplace(dir->GetName(), std::make_shared<CachedVfsDirectory>(dir));
+ }
+ for (auto& file : source_dir->GetFiles()) {
+ files.emplace(file->GetName(), file);
+ }
+}
+
+CachedVfsDirectory::~CachedVfsDirectory() = default;
+
+VirtualFile CachedVfsDirectory::GetFile(std::string_view file_name) const {
+ auto it = files.find(file_name);
+ if (it != files.end()) {
+ return it->second;
+ }
+
+ return nullptr;
+}
+
+VirtualDir CachedVfsDirectory::GetSubdirectory(std::string_view dir_name) const {
+ auto it = dirs.find(dir_name);
+ if (it != dirs.end()) {
+ return it->second;
+ }
+
+ return nullptr;
+}
+
+std::vector<VirtualFile> CachedVfsDirectory::GetFiles() const {
+ std::vector<VirtualFile> out;
+ for (auto& [file_name, file] : files) {
+ out.push_back(file);
+ }
+ return out;
+}
+
+std::vector<VirtualDir> CachedVfsDirectory::GetSubdirectories() const {
+ std::vector<VirtualDir> out;
+ for (auto& [dir_name, dir] : dirs) {
+ out.push_back(dir);
+ }
+ return out;
+}
+
+std::string CachedVfsDirectory::GetName() const {
+ return name;
+}
+
+VirtualDir CachedVfsDirectory::GetParentDirectory() const {
+ return parent;
+}
+
+} // namespace FileSys
diff --git a/src/core/file_sys/vfs_cached.h b/src/core/file_sys/vfs_cached.h
new file mode 100644
index 000000000..113acac12
--- /dev/null
+++ b/src/core/file_sys/vfs_cached.h
@@ -0,0 +1,31 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include <string_view>
+#include <vector>
+#include "core/file_sys/vfs.h"
+
+namespace FileSys {
+
+class CachedVfsDirectory : public ReadOnlyVfsDirectory {
+public:
+ CachedVfsDirectory(VirtualDir& source_directory);
+
+ ~CachedVfsDirectory() override;
+ VirtualFile GetFile(std::string_view file_name) const override;
+ VirtualDir GetSubdirectory(std::string_view dir_name) const override;
+ std::vector<VirtualFile> GetFiles() const override;
+ std::vector<VirtualDir> GetSubdirectories() const override;
+ std::string GetName() const override;
+ VirtualDir GetParentDirectory() const override;
+
+private:
+ std::string name;
+ VirtualDir parent;
+ std::map<std::string, VirtualDir, std::less<>> dirs;
+ std::map<std::string, VirtualFile, std::less<>> files;
+};
+
+} // namespace FileSys
diff --git a/src/core/file_sys/vfs_concat.cpp b/src/core/file_sys/vfs_concat.cpp
index d23623aa0..311a59e5f 100644
--- a/src/core/file_sys/vfs_concat.cpp
+++ b/src/core/file_sys/vfs_concat.cpp
@@ -10,84 +10,105 @@
namespace FileSys {
-static bool VerifyConcatenationMapContinuity(const std::multimap<u64, VirtualFile>& map) {
- const auto last_valid = --map.end();
- for (auto iter = map.begin(); iter != last_valid;) {
- const auto old = iter++;
- if (old->first + old->second->GetSize() != iter->first) {
+ConcatenatedVfsFile::ConcatenatedVfsFile(ConcatenationMap&& concatenation_map_, std::string&& name_)
+ : concatenation_map(std::move(concatenation_map_)), name(std::move(name_)) {
+ DEBUG_ASSERT(this->VerifyContinuity());
+}
+
+bool ConcatenatedVfsFile::VerifyContinuity() const {
+ u64 last_offset = 0;
+ for (auto& entry : concatenation_map) {
+ if (entry.offset != last_offset) {
return false;
}
- }
-
- return map.begin()->first == 0;
-}
-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);
- next_offset += file->GetSize();
+ last_offset = entry.offset + entry.file->GetSize();
}
-}
-ConcatenatedVfsFile::ConcatenatedVfsFile(std::multimap<u64, VirtualFile> files_, std::string name_)
- : files(std::move(files_)), name(std::move(name_)) {
- ASSERT(VerifyConcatenationMapContinuity(files));
+ return true;
}
ConcatenatedVfsFile::~ConcatenatedVfsFile() = default;
-VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(std::vector<VirtualFile> files,
- std::string name) {
- if (files.empty())
+VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(const std::vector<VirtualFile>& files,
+ std::string&& name) {
+ // Fold trivial cases.
+ if (files.empty()) {
return nullptr;
- if (files.size() == 1)
- return files[0];
+ }
+ if (files.size() == 1) {
+ return files.front();
+ }
+
+ // Make the concatenation map from the input.
+ std::vector<ConcatenationEntry> concatenation_map;
+ concatenation_map.reserve(files.size());
+ u64 last_offset = 0;
+
+ for (auto& file : files) {
+ concatenation_map.emplace_back(ConcatenationEntry{
+ .offset = last_offset,
+ .file = file,
+ });
+
+ last_offset += file->GetSize();
+ }
- return VirtualFile(new ConcatenatedVfsFile(std::move(files), std::move(name)));
+ return VirtualFile(new ConcatenatedVfsFile(std::move(concatenation_map), std::move(name)));
}
VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(u8 filler_byte,
- std::multimap<u64, VirtualFile> files,
- std::string name) {
- if (files.empty())
+ const std::multimap<u64, VirtualFile>& files,
+ std::string&& name) {
+ // Fold trivial cases.
+ if (files.empty()) {
return nullptr;
- if (files.size() == 1)
+ }
+ if (files.size() == 1) {
return files.begin()->second;
+ }
+
+ // Make the concatenation map from the input.
+ std::vector<ConcatenationEntry> concatenation_map;
- const auto last_valid = --files.end();
- for (auto iter = files.begin(); iter != last_valid;) {
- const auto old = iter++;
- if (old->first + old->second->GetSize() != iter->first) {
- files.emplace(old->first + old->second->GetSize(),
- std::make_shared<StaticVfsFile>(filler_byte, iter->first - old->first -
- old->second->GetSize()));
+ concatenation_map.reserve(files.size());
+ u64 last_offset = 0;
+
+ // Iteration of a multimap is ordered, so offset will be strictly non-decreasing.
+ for (auto& [offset, file] : files) {
+ if (offset > last_offset) {
+ concatenation_map.emplace_back(ConcatenationEntry{
+ .offset = last_offset,
+ .file = std::make_shared<StaticVfsFile>(filler_byte, offset - last_offset),
+ });
}
- }
- // Ensure the map starts at offset 0 (start of file), otherwise pad to fill.
- if (files.begin()->first != 0)
- files.emplace(0, std::make_shared<StaticVfsFile>(filler_byte, files.begin()->first));
+ concatenation_map.emplace_back(ConcatenationEntry{
+ .offset = offset,
+ .file = file,
+ });
- return VirtualFile(new ConcatenatedVfsFile(std::move(files), std::move(name)));
+ last_offset = offset + file->GetSize();
+ }
+
+ return VirtualFile(new ConcatenatedVfsFile(std::move(concatenation_map), std::move(name)));
}
std::string ConcatenatedVfsFile::GetName() const {
- if (files.empty()) {
+ if (concatenation_map.empty()) {
return "";
}
if (!name.empty()) {
return name;
}
- return files.begin()->second->GetName();
+ return concatenation_map.front().file->GetName();
}
std::size_t ConcatenatedVfsFile::GetSize() const {
- if (files.empty()) {
+ if (concatenation_map.empty()) {
return 0;
}
- return files.rbegin()->first + files.rbegin()->second->GetSize();
+ return concatenation_map.back().offset + concatenation_map.back().file->GetSize();
}
bool ConcatenatedVfsFile::Resize(std::size_t new_size) {
@@ -95,10 +116,10 @@ bool ConcatenatedVfsFile::Resize(std::size_t new_size) {
}
VirtualDir ConcatenatedVfsFile::GetContainingDirectory() const {
- if (files.empty()) {
+ if (concatenation_map.empty()) {
return nullptr;
}
- return files.begin()->second->GetContainingDirectory();
+ return concatenation_map.front().file->GetContainingDirectory();
}
bool ConcatenatedVfsFile::IsWritable() const {
@@ -110,25 +131,51 @@ bool ConcatenatedVfsFile::IsReadable() const {
}
std::size_t ConcatenatedVfsFile::Read(u8* data, std::size_t length, std::size_t offset) const {
- auto entry = --files.end();
- for (auto iter = files.begin(); iter != files.end(); ++iter) {
- if (iter->first > offset) {
- entry = --iter;
+ const ConcatenationEntry key{
+ .offset = offset,
+ .file = nullptr,
+ };
+
+ // Read nothing if the map is empty.
+ if (concatenation_map.empty()) {
+ return 0;
+ }
+
+ // Binary search to find the iterator to the first position we can check.
+ // It must exist, since we are not empty and are comparing unsigned integers.
+ auto it = std::prev(std::upper_bound(concatenation_map.begin(), concatenation_map.end(), key));
+ u64 cur_length = length;
+ u64 cur_offset = offset;
+
+ while (cur_length > 0 && it != concatenation_map.end()) {
+ // Check if we can read the file at this position.
+ const auto& file = it->file;
+ const u64 map_offset = it->offset;
+ const u64 file_size = file->GetSize();
+
+ if (cur_offset > map_offset + file_size) {
+ // Entirely out of bounds read.
break;
}
- }
- if (entry->first + entry->second->GetSize() <= offset)
- return 0;
+ // Read the file at this position.
+ const u64 file_seek = cur_offset - map_offset;
+ const u64 intended_read_size = std::min<u64>(cur_length, file_size - file_seek);
+ const u64 actual_read_size =
+ file->Read(data + (cur_offset - offset), intended_read_size, file_seek);
+
+ // Update tracking.
+ cur_offset += actual_read_size;
+ cur_length -= actual_read_size;
+ it++;
- const auto read_in =
- std::min<u64>(entry->first + entry->second->GetSize() - offset, entry->second->GetSize());
- if (length > read_in) {
- return entry->second->Read(data, read_in, offset - entry->first) +
- Read(data + read_in, length - read_in, offset + read_in);
+ // If we encountered a short read, we're done.
+ if (actual_read_size < intended_read_size) {
+ break;
+ }
}
- return entry->second->Read(data, std::min<u64>(read_in, length), offset - entry->first);
+ return cur_offset - offset;
}
std::size_t ConcatenatedVfsFile::Write(const u8* data, std::size_t length, std::size_t offset) {
diff --git a/src/core/file_sys/vfs_concat.h b/src/core/file_sys/vfs_concat.h
index 9be0261b6..6b329d545 100644
--- a/src/core/file_sys/vfs_concat.h
+++ b/src/core/file_sys/vfs_concat.h
@@ -3,6 +3,7 @@
#pragma once
+#include <compare>
#include <map>
#include <memory>
#include "core/file_sys/vfs.h"
@@ -12,19 +13,33 @@ namespace FileSys {
// Class that wraps multiple vfs files and concatenates them, making reads seamless. Currently
// read-only.
class ConcatenatedVfsFile : public VfsFile {
- explicit ConcatenatedVfsFile(std::vector<VirtualFile> files, std::string name_);
- explicit ConcatenatedVfsFile(std::multimap<u64, VirtualFile> files, std::string name_);
+private:
+ struct ConcatenationEntry {
+ u64 offset;
+ VirtualFile file;
+
+ auto operator<=>(const ConcatenationEntry& other) const {
+ return this->offset <=> other.offset;
+ }
+ };
+ using ConcatenationMap = std::vector<ConcatenationEntry>;
+
+ explicit ConcatenatedVfsFile(std::vector<ConcatenationEntry>&& concatenation_map,
+ std::string&& name);
+ bool VerifyContinuity() const;
public:
~ConcatenatedVfsFile() override;
/// Wrapper function to allow for more efficient handling of files.size() == 0, 1 cases.
- static VirtualFile MakeConcatenatedFile(std::vector<VirtualFile> files, std::string name);
+ static VirtualFile MakeConcatenatedFile(const std::vector<VirtualFile>& files,
+ std::string&& name);
/// Convenience function that turns a map of offsets to files into a concatenated file, filling
/// gaps with a given filler byte.
- static VirtualFile MakeConcatenatedFile(u8 filler_byte, std::multimap<u64, VirtualFile> files,
- std::string name);
+ static VirtualFile MakeConcatenatedFile(u8 filler_byte,
+ const std::multimap<u64, VirtualFile>& files,
+ std::string&& name);
std::string GetName() const override;
std::size_t GetSize() const override;
@@ -37,8 +52,7 @@ public:
bool Rename(std::string_view new_name) override;
private:
- // Maps starting offset to file -- more efficient.
- std::multimap<u64, VirtualFile> files;
+ ConcatenationMap concatenation_map;
std::string name;
};
diff --git a/src/core/file_sys/vfs_layered.cpp b/src/core/file_sys/vfs_layered.cpp
index da05dd395..3e6426afc 100644
--- a/src/core/file_sys/vfs_layered.cpp
+++ b/src/core/file_sys/vfs_layered.cpp
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include <algorithm>
+#include <set>
#include <utility>
#include "core/file_sys/vfs_layered.h"
@@ -58,11 +59,13 @@ std::string LayeredVfsDirectory::GetFullPath() const {
std::vector<VirtualFile> LayeredVfsDirectory::GetFiles() const {
std::vector<VirtualFile> out;
+ std::set<std::string, std::less<>> out_names;
+
for (const auto& layer : dirs) {
for (const auto& file : layer->GetFiles()) {
- if (std::find_if(out.begin(), out.end(), [&file](const VirtualFile& comp) {
- return comp->GetName() == file->GetName();
- }) == out.end()) {
+ auto file_name = file->GetName();
+ if (!out_names.contains(file_name)) {
+ out_names.emplace(std::move(file_name));
out.push_back(file);
}
}
diff --git a/src/core/file_sys/vfs_real.cpp b/src/core/file_sys/vfs_real.cpp
index cc0076238..b0515ec05 100644
--- a/src/core/file_sys/vfs_real.cpp
+++ b/src/core/file_sys/vfs_real.cpp
@@ -10,6 +10,7 @@
#include "common/fs/fs.h"
#include "common/fs/path_util.h"
#include "common/logging/log.h"
+#include "core/file_sys/vfs.h"
#include "core/file_sys/vfs_real.h"
// For FileTimeStampRaw
@@ -25,6 +26,8 @@ namespace FS = Common::FS;
namespace {
+constexpr size_t MaxOpenFiles = 512;
+
constexpr FS::FileAccessMode ModeFlagsToFileAccessMode(Mode mode) {
switch (mode) {
case Mode::Read:
@@ -70,31 +73,42 @@ VfsEntryType RealVfsFilesystem::GetEntryType(std::string_view path_) const {
return VfsEntryType::File;
}
-VirtualFile RealVfsFilesystem::OpenFile(std::string_view path_, Mode perms) {
+VirtualFile RealVfsFilesystem::OpenFileFromEntry(std::string_view path_, std::optional<u64> size,
+ Mode perms) {
const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault);
+ std::scoped_lock lk{list_lock};
- if (const auto weak_iter = cache.find(path); weak_iter != cache.cend()) {
- const auto& weak = weak_iter->second;
-
- if (!weak.expired()) {
- return std::shared_ptr<RealVfsFile>(new RealVfsFile(*this, weak.lock(), path, perms));
+ if (auto it = cache.find(path); it != cache.end()) {
+ if (auto file = it->second.lock(); file) {
+ return file;
}
}
- auto backing = FS::FileOpen(path, ModeFlagsToFileAccessMode(perms), FS::FileType::BinaryFile);
-
- if (!backing) {
+ if (!size && !FS::IsFile(path)) {
return nullptr;
}
- cache.insert_or_assign(path, std::move(backing));
+ auto reference = std::make_unique<FileReference>();
+ this->InsertReferenceIntoListLocked(*reference);
- // Cannot use make_shared as RealVfsFile constructor is private
- return std::shared_ptr<RealVfsFile>(new RealVfsFile(*this, backing, path, perms));
+ auto file = std::shared_ptr<RealVfsFile>(
+ new RealVfsFile(*this, std::move(reference), path, perms, size));
+ cache[path] = file;
+
+ return file;
+}
+
+VirtualFile RealVfsFilesystem::OpenFile(std::string_view path_, Mode perms) {
+ return OpenFileFromEntry(path_, {}, perms);
}
VirtualFile RealVfsFilesystem::CreateFile(std::string_view path_, Mode perms) {
const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault);
+ {
+ std::scoped_lock lk{list_lock};
+ cache.erase(path);
+ }
+
// Current usages of CreateFile expect to delete the contents of an existing file.
if (FS::IsFile(path)) {
FS::IOFile temp{path, FS::FileAccessMode::Write, FS::FileType::BinaryFile};
@@ -123,51 +137,28 @@ VirtualFile RealVfsFilesystem::CopyFile(std::string_view old_path_, std::string_
VirtualFile RealVfsFilesystem::MoveFile(std::string_view old_path_, std::string_view new_path_) {
const auto old_path = FS::SanitizePath(old_path_, FS::DirectorySeparator::PlatformDefault);
const auto new_path = FS::SanitizePath(new_path_, FS::DirectorySeparator::PlatformDefault);
- const auto cached_file_iter = cache.find(old_path);
-
- if (cached_file_iter != cache.cend()) {
- auto file = cached_file_iter->second.lock();
-
- if (!cached_file_iter->second.expired()) {
- file->Close();
- }
-
- if (!FS::RenameFile(old_path, new_path)) {
- return nullptr;
- }
-
+ {
+ std::scoped_lock lk{list_lock};
cache.erase(old_path);
- file->Open(new_path, FS::FileAccessMode::Read, FS::FileType::BinaryFile);
- if (file->IsOpen()) {
- cache.insert_or_assign(new_path, std::move(file));
- } else {
- LOG_ERROR(Service_FS, "Failed to open path {} in order to re-cache it", new_path);
- }
- } else {
- ASSERT(false);
+ cache.erase(new_path);
+ }
+ if (!FS::RenameFile(old_path, new_path)) {
return nullptr;
}
-
return OpenFile(new_path, Mode::ReadWrite);
}
bool RealVfsFilesystem::DeleteFile(std::string_view path_) {
const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault);
- const auto cached_iter = cache.find(path);
-
- if (cached_iter != cache.cend()) {
- if (!cached_iter->second.expired()) {
- cached_iter->second.lock()->Close();
- }
+ {
+ std::scoped_lock lk{list_lock};
cache.erase(path);
}
-
return FS::RemoveFile(path);
}
VirtualDir RealVfsFilesystem::OpenDirectory(std::string_view path_, Mode perms) {
const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault);
- // Cannot use make_shared as RealVfsDirectory constructor is private
return std::shared_ptr<RealVfsDirectory>(new RealVfsDirectory(*this, path, perms));
}
@@ -176,7 +167,6 @@ VirtualDir RealVfsFilesystem::CreateDirectory(std::string_view path_, Mode perms
if (!FS::CreateDirs(path)) {
return nullptr;
}
- // Cannot use make_shared as RealVfsDirectory constructor is private
return std::shared_ptr<RealVfsDirectory>(new RealVfsDirectory(*this, path, perms));
}
@@ -194,73 +184,112 @@ VirtualDir RealVfsFilesystem::MoveDirectory(std::string_view old_path_,
if (!FS::RenameDir(old_path, new_path)) {
return nullptr;
}
+ return OpenDirectory(new_path, Mode::ReadWrite);
+}
- for (auto& kv : cache) {
- // If the path in the cache doesn't start with old_path, then bail on this file.
- if (kv.first.rfind(old_path, 0) != 0) {
- continue;
- }
+bool RealVfsFilesystem::DeleteDirectory(std::string_view path_) {
+ const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault);
+ return FS::RemoveDirRecursively(path);
+}
- const auto file_old_path =
- FS::SanitizePath(kv.first, FS::DirectorySeparator::PlatformDefault);
- auto file_new_path = FS::SanitizePath(new_path + '/' + kv.first.substr(old_path.size()),
- FS::DirectorySeparator::PlatformDefault);
- const auto& cached = cache[file_old_path];
+std::unique_lock<std::mutex> RealVfsFilesystem::RefreshReference(const std::string& path,
+ Mode perms,
+ FileReference& reference) {
+ std::unique_lock lk{list_lock};
- if (cached.expired()) {
- continue;
- }
+ // Temporarily remove from list.
+ this->RemoveReferenceFromListLocked(reference);
+
+ // Restore file if needed.
+ if (!reference.file) {
+ this->EvictSingleReferenceLocked();
- auto file = cached.lock();
- cache.erase(file_old_path);
- file->Open(file_new_path, FS::FileAccessMode::Read, FS::FileType::BinaryFile);
- if (file->IsOpen()) {
- cache.insert_or_assign(std::move(file_new_path), std::move(file));
- } else {
- LOG_ERROR(Service_FS, "Failed to open path {} in order to re-cache it", file_new_path);
+ reference.file =
+ FS::FileOpen(path, ModeFlagsToFileAccessMode(perms), FS::FileType::BinaryFile);
+ if (reference.file) {
+ num_open_files++;
}
}
- return OpenDirectory(new_path, Mode::ReadWrite);
+ // Reinsert into list.
+ this->InsertReferenceIntoListLocked(reference);
+
+ return lk;
}
-bool RealVfsFilesystem::DeleteDirectory(std::string_view path_) {
- const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault);
+void RealVfsFilesystem::DropReference(std::unique_ptr<FileReference>&& reference) {
+ std::scoped_lock lk{list_lock};
- for (auto& kv : cache) {
- // If the path in the cache doesn't start with path, then bail on this file.
- if (kv.first.rfind(path, 0) != 0) {
- continue;
- }
+ // Remove from list.
+ this->RemoveReferenceFromListLocked(*reference);
- const auto& entry = cache[kv.first];
- if (!entry.expired()) {
- entry.lock()->Close();
- }
+ // Close the file.
+ if (reference->file) {
+ reference->file.reset();
+ num_open_files--;
+ }
+}
- cache.erase(kv.first);
+void RealVfsFilesystem::EvictSingleReferenceLocked() {
+ if (num_open_files < MaxOpenFiles || open_references.empty()) {
+ return;
}
- return FS::RemoveDirRecursively(path);
+ // Get and remove from list.
+ auto& reference = open_references.back();
+ this->RemoveReferenceFromListLocked(reference);
+
+ // Close the file.
+ if (reference.file) {
+ reference.file.reset();
+ num_open_files--;
+ }
+
+ // Reinsert into closed list.
+ this->InsertReferenceIntoListLocked(reference);
+}
+
+void RealVfsFilesystem::InsertReferenceIntoListLocked(FileReference& reference) {
+ if (reference.file) {
+ open_references.push_front(reference);
+ } else {
+ closed_references.push_front(reference);
+ }
}
-RealVfsFile::RealVfsFile(RealVfsFilesystem& base_, std::shared_ptr<FS::IOFile> backing_,
- const std::string& path_, Mode perms_)
- : base(base_), backing(std::move(backing_)), path(path_), parent_path(FS::GetParentPath(path_)),
- path_components(FS::SplitPathComponents(path_)), perms(perms_) {}
+void RealVfsFilesystem::RemoveReferenceFromListLocked(FileReference& reference) {
+ if (reference.file) {
+ open_references.erase(open_references.iterator_to(reference));
+ } else {
+ closed_references.erase(closed_references.iterator_to(reference));
+ }
+}
-RealVfsFile::~RealVfsFile() = default;
+RealVfsFile::RealVfsFile(RealVfsFilesystem& base_, std::unique_ptr<FileReference> reference_,
+ const std::string& path_, Mode perms_, std::optional<u64> size_)
+ : base(base_), reference(std::move(reference_)), path(path_),
+ parent_path(FS::GetParentPath(path_)), path_components(FS::SplitPathComponents(path_)),
+ size(size_), perms(perms_) {}
+
+RealVfsFile::~RealVfsFile() {
+ base.DropReference(std::move(reference));
+}
std::string RealVfsFile::GetName() const {
return path_components.back();
}
std::size_t RealVfsFile::GetSize() const {
- return backing->GetSize();
+ if (size) {
+ return *size;
+ }
+ return FS::GetSize(path);
}
bool RealVfsFile::Resize(std::size_t new_size) {
- return backing->SetSize(new_size);
+ size.reset();
+ auto lk = base.RefreshReference(path, perms, *reference);
+ return reference->file ? reference->file->SetSize(new_size) : false;
}
VirtualDir RealVfsFile::GetContainingDirectory() const {
@@ -276,27 +305,26 @@ bool RealVfsFile::IsReadable() const {
}
std::size_t RealVfsFile::Read(u8* data, std::size_t length, std::size_t offset) const {
- if (!backing->Seek(static_cast<s64>(offset))) {
+ auto lk = base.RefreshReference(path, perms, *reference);
+ if (!reference->file || !reference->file->Seek(static_cast<s64>(offset))) {
return 0;
}
- return backing->ReadSpan(std::span{data, length});
+ return reference->file->ReadSpan(std::span{data, length});
}
std::size_t RealVfsFile::Write(const u8* data, std::size_t length, std::size_t offset) {
- if (!backing->Seek(static_cast<s64>(offset))) {
+ size.reset();
+ auto lk = base.RefreshReference(path, perms, *reference);
+ if (!reference->file || !reference->file->Seek(static_cast<s64>(offset))) {
return 0;
}
- return backing->WriteSpan(std::span{data, length});
+ return reference->file->WriteSpan(std::span{data, length});
}
bool RealVfsFile::Rename(std::string_view name) {
return base.MoveFile(path, parent_path + '/' + std::string(name)) != nullptr;
}
-void RealVfsFile::Close() {
- backing->Close();
-}
-
// TODO(DarkLordZach): MSVC would not let me combine the following two functions using 'if
// constexpr' because there is a compile error in the branch not used.
@@ -308,10 +336,11 @@ std::vector<VirtualFile> RealVfsDirectory::IterateEntries<RealVfsFile, VfsFile>(
std::vector<VirtualFile> out;
- const FS::DirEntryCallable callback = [this, &out](const std::filesystem::path& full_path) {
- const auto full_path_string = FS::PathToUTF8String(full_path);
+ const FS::DirEntryCallable callback = [this,
+ &out](const std::filesystem::directory_entry& entry) {
+ const auto full_path_string = FS::PathToUTF8String(entry.path());
- out.emplace_back(base.OpenFile(full_path_string, perms));
+ out.emplace_back(base.OpenFileFromEntry(full_path_string, entry.file_size(), perms));
return true;
};
@@ -329,8 +358,9 @@ std::vector<VirtualDir> RealVfsDirectory::IterateEntries<RealVfsDirectory, VfsDi
std::vector<VirtualDir> out;
- const FS::DirEntryCallable callback = [this, &out](const std::filesystem::path& full_path) {
- const auto full_path_string = FS::PathToUTF8String(full_path);
+ const FS::DirEntryCallable callback = [this,
+ &out](const std::filesystem::directory_entry& entry) {
+ const auto full_path_string = FS::PathToUTF8String(entry.path());
out.emplace_back(base.OpenDirectory(full_path_string, perms));
@@ -482,12 +512,10 @@ std::map<std::string, VfsEntryType, std::less<>> RealVfsDirectory::GetEntries()
std::map<std::string, VfsEntryType, std::less<>> out;
- const FS::DirEntryCallable callback = [&out](const std::filesystem::path& full_path) {
- const auto filename = FS::PathToUTF8String(full_path.filename());
-
+ const FS::DirEntryCallable callback = [&out](const std::filesystem::directory_entry& entry) {
+ const auto filename = FS::PathToUTF8String(entry.path().filename());
out.insert_or_assign(filename,
- FS::IsDir(full_path) ? VfsEntryType::Directory : VfsEntryType::File);
-
+ entry.is_directory() ? VfsEntryType::Directory : VfsEntryType::File);
return true;
};
diff --git a/src/core/file_sys/vfs_real.h b/src/core/file_sys/vfs_real.h
index acde1ac89..26ea7df62 100644
--- a/src/core/file_sys/vfs_real.h
+++ b/src/core/file_sys/vfs_real.h
@@ -3,8 +3,11 @@
#pragma once
+#include <map>
+#include <mutex>
+#include <optional>
#include <string_view>
-#include <boost/container/flat_map.hpp>
+#include "common/intrusive_list.h"
#include "core/file_sys/mode.h"
#include "core/file_sys/vfs.h"
@@ -14,6 +17,13 @@ class IOFile;
namespace FileSys {
+struct FileReference : public Common::IntrusiveListBaseNode<FileReference> {
+ std::shared_ptr<Common::FS::IOFile> file{};
+};
+
+class RealVfsFile;
+class RealVfsDirectory;
+
class RealVfsFilesystem : public VfsFilesystem {
public:
RealVfsFilesystem();
@@ -35,10 +45,31 @@ public:
bool DeleteDirectory(std::string_view path) override;
private:
- boost::container::flat_map<std::string, std::weak_ptr<Common::FS::IOFile>> cache;
+ using ReferenceListType = Common::IntrusiveListBaseTraits<FileReference>::ListType;
+ std::map<std::string, std::weak_ptr<VfsFile>, std::less<>> cache;
+ ReferenceListType open_references;
+ ReferenceListType closed_references;
+ std::mutex list_lock;
+ size_t num_open_files{};
+
+private:
+ friend class RealVfsFile;
+ std::unique_lock<std::mutex> RefreshReference(const std::string& path, Mode perms,
+ FileReference& reference);
+ void DropReference(std::unique_ptr<FileReference>&& reference);
+
+private:
+ friend class RealVfsDirectory;
+ VirtualFile OpenFileFromEntry(std::string_view path, std::optional<u64> size,
+ Mode perms = Mode::Read);
+
+private:
+ void EvictSingleReferenceLocked();
+ void InsertReferenceIntoListLocked(FileReference& reference);
+ void RemoveReferenceFromListLocked(FileReference& reference);
};
-// An implmentation of VfsFile that represents a file on the user's computer.
+// An implementation of VfsFile that represents a file on the user's computer.
class RealVfsFile : public VfsFile {
friend class RealVfsDirectory;
friend class RealVfsFilesystem;
@@ -57,16 +88,15 @@ public:
bool Rename(std::string_view name) override;
private:
- RealVfsFile(RealVfsFilesystem& base, std::shared_ptr<Common::FS::IOFile> backing,
- const std::string& path, Mode perms = Mode::Read);
-
- void Close();
+ RealVfsFile(RealVfsFilesystem& base, std::unique_ptr<FileReference> reference,
+ const std::string& path, Mode perms = Mode::Read, std::optional<u64> size = {});
RealVfsFilesystem& base;
- std::shared_ptr<Common::FS::IOFile> backing;
+ std::unique_ptr<FileReference> reference;
std::string path;
std::string parent_path;
std::vector<std::string> path_components;
+ std::optional<u64> size;
Mode perms;
};
diff --git a/src/core/frontend/applets/applet.h b/src/core/frontend/applets/applet.h
new file mode 100644
index 000000000..77fffe306
--- /dev/null
+++ b/src/core/frontend/applets/applet.h
@@ -0,0 +1,14 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+namespace Core::Frontend {
+
+class Applet {
+public:
+ virtual ~Applet() = default;
+ virtual void Close() const = 0;
+};
+
+} // namespace Core::Frontend
diff --git a/src/core/frontend/applets/cabinet.cpp b/src/core/frontend/applets/cabinet.cpp
index 26c7fefe3..c33ce248b 100644
--- a/src/core/frontend/applets/cabinet.cpp
+++ b/src/core/frontend/applets/cabinet.cpp
@@ -10,9 +10,11 @@ namespace Core::Frontend {
CabinetApplet::~CabinetApplet() = default;
+void DefaultCabinetApplet::Close() const {}
+
void DefaultCabinetApplet::ShowCabinetApplet(
const CabinetCallback& callback, const CabinetParameters& parameters,
- std::shared_ptr<Service::NFP::NfpDevice> nfp_device) const {
+ std::shared_ptr<Service::NFC::NfcDevice> nfp_device) const {
LOG_WARNING(Service_AM, "(STUBBED) called");
callback(false, {});
}
diff --git a/src/core/frontend/applets/cabinet.h b/src/core/frontend/applets/cabinet.h
index c28a235c1..af3fc6c3d 100644
--- a/src/core/frontend/applets/cabinet.h
+++ b/src/core/frontend/applets/cabinet.h
@@ -4,11 +4,12 @@
#pragma once
#include <functional>
+#include "core/frontend/applets/applet.h"
#include "core/hle/service/nfp/nfp_types.h"
-namespace Service::NFP {
-class NfpDevice;
-} // namespace Service::NFP
+namespace Service::NFC {
+class NfcDevice;
+} // namespace Service::NFC
namespace Core::Frontend {
@@ -20,18 +21,19 @@ struct CabinetParameters {
using CabinetCallback = std::function<void(bool, const std::string&)>;
-class CabinetApplet {
+class CabinetApplet : public Applet {
public:
virtual ~CabinetApplet();
virtual void ShowCabinetApplet(const CabinetCallback& callback,
const CabinetParameters& parameters,
- std::shared_ptr<Service::NFP::NfpDevice> nfp_device) const = 0;
+ std::shared_ptr<Service::NFC::NfcDevice> nfp_device) const = 0;
};
class DefaultCabinetApplet final : public CabinetApplet {
public:
+ void Close() const override;
void ShowCabinetApplet(const CabinetCallback& callback, const CabinetParameters& parameters,
- std::shared_ptr<Service::NFP::NfpDevice> nfp_device) const override;
+ std::shared_ptr<Service::NFC::NfcDevice> nfp_device) const override;
};
} // namespace Core::Frontend
diff --git a/src/core/frontend/applets/controller.cpp b/src/core/frontend/applets/controller.cpp
index 52919484e..3300d4f79 100644
--- a/src/core/frontend/applets/controller.cpp
+++ b/src/core/frontend/applets/controller.cpp
@@ -16,6 +16,8 @@ DefaultControllerApplet::DefaultControllerApplet(HID::HIDCore& hid_core_) : hid_
DefaultControllerApplet::~DefaultControllerApplet() = default;
+void DefaultControllerApplet::Close() const {}
+
void DefaultControllerApplet::ReconfigureControllers(ReconfigureCallback callback,
const ControllerParameters& parameters) const {
LOG_INFO(Service_HID, "called, deducing the best configuration based on the given parameters!");
@@ -69,7 +71,7 @@ void DefaultControllerApplet::ReconfigureControllers(ReconfigureCallback callbac
}
}
- callback();
+ callback(true);
}
} // namespace Core::Frontend
diff --git a/src/core/frontend/applets/controller.h b/src/core/frontend/applets/controller.h
index adb2feefd..19a2db6bf 100644
--- a/src/core/frontend/applets/controller.h
+++ b/src/core/frontend/applets/controller.h
@@ -7,6 +7,7 @@
#include <vector>
#include "common/common_types.h"
+#include "core/frontend/applets/applet.h"
namespace Core::HID {
class HIDCore;
@@ -34,9 +35,9 @@ struct ControllerParameters {
bool allow_gamecube_controller{};
};
-class ControllerApplet {
+class ControllerApplet : public Applet {
public:
- using ReconfigureCallback = std::function<void()>;
+ using ReconfigureCallback = std::function<void(bool)>;
virtual ~ControllerApplet();
@@ -49,6 +50,7 @@ public:
explicit DefaultControllerApplet(HID::HIDCore& hid_core_);
~DefaultControllerApplet() override;
+ void Close() const override;
void ReconfigureControllers(ReconfigureCallback callback,
const ControllerParameters& parameters) const override;
diff --git a/src/core/frontend/applets/error.cpp b/src/core/frontend/applets/error.cpp
index 69c2b2b4d..2e6f7a3d9 100644
--- a/src/core/frontend/applets/error.cpp
+++ b/src/core/frontend/applets/error.cpp
@@ -8,6 +8,8 @@ namespace Core::Frontend {
ErrorApplet::~ErrorApplet() = default;
+void DefaultErrorApplet::Close() const {}
+
void DefaultErrorApplet::ShowError(Result error, FinishedCallback finished) const {
LOG_CRITICAL(Service_Fatal, "Application requested error display: {:04}-{:04} (raw={:08X})",
error.module.Value(), error.description.Value(), error.raw);
diff --git a/src/core/frontend/applets/error.h b/src/core/frontend/applets/error.h
index 884f2f653..3a12196ce 100644
--- a/src/core/frontend/applets/error.h
+++ b/src/core/frontend/applets/error.h
@@ -6,11 +6,12 @@
#include <chrono>
#include <functional>
+#include "core/frontend/applets/applet.h"
#include "core/hle/result.h"
namespace Core::Frontend {
-class ErrorApplet {
+class ErrorApplet : public Applet {
public:
using FinishedCallback = std::function<void()>;
@@ -28,6 +29,7 @@ public:
class DefaultErrorApplet final : public ErrorApplet {
public:
+ void Close() const override;
void ShowError(Result error, FinishedCallback finished) const override;
void ShowErrorWithTimestamp(Result error, std::chrono::seconds time,
FinishedCallback finished) const override;
diff --git a/src/core/frontend/applets/general_frontend.cpp b/src/core/frontend/applets/general_frontend.cpp
index 29a00fb6f..b4b213a31 100644
--- a/src/core/frontend/applets/general_frontend.cpp
+++ b/src/core/frontend/applets/general_frontend.cpp
@@ -10,6 +10,8 @@ ParentalControlsApplet::~ParentalControlsApplet() = default;
DefaultParentalControlsApplet::~DefaultParentalControlsApplet() = default;
+void DefaultParentalControlsApplet::Close() const {}
+
void DefaultParentalControlsApplet::VerifyPIN(std::function<void(bool)> finished,
bool suspend_future_verification_temporarily) {
LOG_INFO(Service_AM,
@@ -39,6 +41,8 @@ PhotoViewerApplet::~PhotoViewerApplet() = default;
DefaultPhotoViewerApplet::~DefaultPhotoViewerApplet() = default;
+void DefaultPhotoViewerApplet::Close() const {}
+
void DefaultPhotoViewerApplet::ShowPhotosForApplication(u64 title_id,
std::function<void()> finished) const {
LOG_INFO(Service_AM,
diff --git a/src/core/frontend/applets/general_frontend.h b/src/core/frontend/applets/general_frontend.h
index cbec8b4ad..319838ac7 100644
--- a/src/core/frontend/applets/general_frontend.h
+++ b/src/core/frontend/applets/general_frontend.h
@@ -6,9 +6,11 @@
#include <functional>
#include "common/common_types.h"
+#include "core/frontend/applets/applet.h"
+
namespace Core::Frontend {
-class ParentalControlsApplet {
+class ParentalControlsApplet : public Applet {
public:
virtual ~ParentalControlsApplet();
@@ -33,6 +35,7 @@ class DefaultParentalControlsApplet final : public ParentalControlsApplet {
public:
~DefaultParentalControlsApplet() override;
+ void Close() const override;
void VerifyPIN(std::function<void(bool)> finished,
bool suspend_future_verification_temporarily) override;
void VerifyPINForSettings(std::function<void(bool)> finished) override;
@@ -40,7 +43,7 @@ public:
void ChangePIN(std::function<void()> finished) override;
};
-class PhotoViewerApplet {
+class PhotoViewerApplet : public Applet {
public:
virtual ~PhotoViewerApplet();
@@ -52,6 +55,7 @@ class DefaultPhotoViewerApplet final : public PhotoViewerApplet {
public:
~DefaultPhotoViewerApplet() override;
+ void Close() const override;
void ShowPhotosForApplication(u64 title_id, std::function<void()> finished) const override;
void ShowAllPhotos(std::function<void()> finished) const override;
};
diff --git a/src/core/frontend/applets/mii_edit.cpp b/src/core/frontend/applets/mii_edit.cpp
index bc8c57067..2988c3e72 100644
--- a/src/core/frontend/applets/mii_edit.cpp
+++ b/src/core/frontend/applets/mii_edit.cpp
@@ -8,6 +8,8 @@ namespace Core::Frontend {
MiiEditApplet::~MiiEditApplet() = default;
+void DefaultMiiEditApplet::Close() const {}
+
void DefaultMiiEditApplet::ShowMiiEdit(const MiiEditCallback& callback) const {
LOG_WARNING(Service_AM, "(STUBBED) called");
diff --git a/src/core/frontend/applets/mii_edit.h b/src/core/frontend/applets/mii_edit.h
index d828f06ec..9d86ee658 100644
--- a/src/core/frontend/applets/mii_edit.h
+++ b/src/core/frontend/applets/mii_edit.h
@@ -5,9 +5,11 @@
#include <functional>
+#include "core/frontend/applets/applet.h"
+
namespace Core::Frontend {
-class MiiEditApplet {
+class MiiEditApplet : public Applet {
public:
using MiiEditCallback = std::function<void()>;
@@ -18,6 +20,7 @@ public:
class DefaultMiiEditApplet final : public MiiEditApplet {
public:
+ void Close() const override;
void ShowMiiEdit(const MiiEditCallback& callback) const override;
};
diff --git a/src/core/frontend/applets/profile_select.cpp b/src/core/frontend/applets/profile_select.cpp
index da4cfbf87..c18f17a36 100644
--- a/src/core/frontend/applets/profile_select.cpp
+++ b/src/core/frontend/applets/profile_select.cpp
@@ -9,7 +9,10 @@ namespace Core::Frontend {
ProfileSelectApplet::~ProfileSelectApplet() = default;
-void DefaultProfileSelectApplet::SelectProfile(SelectProfileCallback callback) const {
+void DefaultProfileSelectApplet::Close() const {}
+
+void DefaultProfileSelectApplet::SelectProfile(SelectProfileCallback callback,
+ const ProfileSelectParameters& parameters) const {
Service::Account::ProfileManager manager;
callback(manager.GetUser(Settings::values.current_user.GetValue()).value_or(Common::UUID{}));
LOG_INFO(Service_ACC, "called, selecting current user instead of prompting...");
diff --git a/src/core/frontend/applets/profile_select.h b/src/core/frontend/applets/profile_select.h
index 138429533..92e2737ea 100644
--- a/src/core/frontend/applets/profile_select.h
+++ b/src/core/frontend/applets/profile_select.h
@@ -5,22 +5,35 @@
#include <functional>
#include <optional>
+
#include "common/uuid.h"
+#include "core/frontend/applets/applet.h"
+#include "core/hle/service/am/applets/applet_profile_select.h"
namespace Core::Frontend {
-class ProfileSelectApplet {
+struct ProfileSelectParameters {
+ Service::AM::Applets::UiMode mode;
+ std::array<Common::UUID, 8> invalid_uid_list;
+ Service::AM::Applets::UiSettingsDisplayOptions display_options;
+ Service::AM::Applets::UserSelectionPurpose purpose;
+};
+
+class ProfileSelectApplet : public Applet {
public:
using SelectProfileCallback = std::function<void(std::optional<Common::UUID>)>;
virtual ~ProfileSelectApplet();
- virtual void SelectProfile(SelectProfileCallback callback) const = 0;
+ virtual void SelectProfile(SelectProfileCallback callback,
+ const ProfileSelectParameters& parameters) const = 0;
};
class DefaultProfileSelectApplet final : public ProfileSelectApplet {
public:
- void SelectProfile(SelectProfileCallback callback) const override;
+ void Close() const override;
+ void SelectProfile(SelectProfileCallback callback,
+ const ProfileSelectParameters& parameters) const override;
};
} // namespace Core::Frontend
diff --git a/src/core/frontend/applets/software_keyboard.cpp b/src/core/frontend/applets/software_keyboard.cpp
index a3720f4d7..7655d215b 100644
--- a/src/core/frontend/applets/software_keyboard.cpp
+++ b/src/core/frontend/applets/software_keyboard.cpp
@@ -13,6 +13,8 @@ SoftwareKeyboardApplet::~SoftwareKeyboardApplet() = default;
DefaultSoftwareKeyboardApplet::~DefaultSoftwareKeyboardApplet() = default;
+void DefaultSoftwareKeyboardApplet::Close() const {}
+
void DefaultSoftwareKeyboardApplet::InitializeKeyboard(
bool is_inline, KeyboardInitializeParameters initialize_parameters,
SubmitNormalCallback submit_normal_callback_, SubmitInlineCallback submit_inline_callback_) {
diff --git a/src/core/frontend/applets/software_keyboard.h b/src/core/frontend/applets/software_keyboard.h
index 8aef103d3..8ed96da24 100644
--- a/src/core/frontend/applets/software_keyboard.h
+++ b/src/core/frontend/applets/software_keyboard.h
@@ -7,6 +7,7 @@
#include "common/common_types.h"
+#include "core/frontend/applets/applet.h"
#include "core/hle/service/am/applets/applet_software_keyboard_types.h"
namespace Core::Frontend {
@@ -52,7 +53,7 @@ struct InlineTextParameters {
s32 cursor_position;
};
-class SoftwareKeyboardApplet {
+class SoftwareKeyboardApplet : public Applet {
public:
using SubmitInlineCallback =
std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)>;
@@ -84,6 +85,8 @@ class DefaultSoftwareKeyboardApplet final : public SoftwareKeyboardApplet {
public:
~DefaultSoftwareKeyboardApplet() override;
+ void Close() const override;
+
void InitializeKeyboard(bool is_inline, KeyboardInitializeParameters initialize_parameters,
SubmitNormalCallback submit_normal_callback_,
SubmitInlineCallback submit_inline_callback_) override;
diff --git a/src/core/frontend/applets/web_browser.cpp b/src/core/frontend/applets/web_browser.cpp
index b09cb7102..6e703ef06 100644
--- a/src/core/frontend/applets/web_browser.cpp
+++ b/src/core/frontend/applets/web_browser.cpp
@@ -10,6 +10,8 @@ WebBrowserApplet::~WebBrowserApplet() = default;
DefaultWebBrowserApplet::~DefaultWebBrowserApplet() = default;
+void DefaultWebBrowserApplet::Close() const {}
+
void DefaultWebBrowserApplet::OpenLocalWebPage(const std::string& local_url,
ExtractROMFSCallback extract_romfs_callback,
OpenWebPageCallback callback) const {
diff --git a/src/core/frontend/applets/web_browser.h b/src/core/frontend/applets/web_browser.h
index 4f72284ad..178bbdd3f 100644
--- a/src/core/frontend/applets/web_browser.h
+++ b/src/core/frontend/applets/web_browser.h
@@ -5,11 +5,12 @@
#include <functional>
+#include "core/frontend/applets/applet.h"
#include "core/hle/service/am/applets/applet_web_browser_types.h"
namespace Core::Frontend {
-class WebBrowserApplet {
+class WebBrowserApplet : public Applet {
public:
using ExtractROMFSCallback = std::function<void()>;
using OpenWebPageCallback =
@@ -29,6 +30,8 @@ class DefaultWebBrowserApplet final : public WebBrowserApplet {
public:
~DefaultWebBrowserApplet() override;
+ void Close() const override;
+
void OpenLocalWebPage(const std::string& local_url, ExtractROMFSCallback extract_romfs_callback,
OpenWebPageCallback callback) const override;
diff --git a/src/core/frontend/emu_window.cpp b/src/core/frontend/emu_window.cpp
index 1be2dccb0..d1f1ca8c9 100644
--- a/src/core/frontend/emu_window.cpp
+++ b/src/core/frontend/emu_window.cpp
@@ -6,8 +6,6 @@
namespace Core::Frontend {
-GraphicsContext::~GraphicsContext() = default;
-
EmuWindow::EmuWindow() {
// TODO: Find a better place to set this.
config.min_client_area_size =
diff --git a/src/core/frontend/emu_window.h b/src/core/frontend/emu_window.h
index cf85ba29e..a72df034e 100644
--- a/src/core/frontend/emu_window.h
+++ b/src/core/frontend/emu_window.h
@@ -5,11 +5,14 @@
#include <memory>
#include <utility>
+
#include "common/common_types.h"
#include "core/frontend/framebuffer_layout.h"
namespace Core::Frontend {
+class GraphicsContext;
+
/// Information for the Graphics Backends signifying what type of screen pointer is in
/// WindowInformation
enum class WindowSystemType {
@@ -22,51 +25,6 @@ enum class WindowSystemType {
};
/**
- * Represents a drawing context that supports graphics operations.
- */
-class GraphicsContext {
-public:
- virtual ~GraphicsContext();
-
- /// Inform the driver to swap the front/back buffers and present the current image
- virtual void SwapBuffers() {}
-
- /// Makes the graphics context current for the caller thread
- virtual void MakeCurrent() {}
-
- /// Releases (dunno if this is the "right" word) the context from the caller thread
- virtual void DoneCurrent() {}
-
- class Scoped {
- public:
- [[nodiscard]] explicit Scoped(GraphicsContext& context_) : context(context_) {
- context.MakeCurrent();
- }
- ~Scoped() {
- if (active) {
- context.DoneCurrent();
- }
- }
-
- /// In the event that context was destroyed before the Scoped is destroyed, this provides a
- /// mechanism to prevent calling a destroyed object's method during the deconstructor
- void Cancel() {
- active = false;
- }
-
- private:
- GraphicsContext& context;
- bool active{true};
- };
-
- /// Calls MakeCurrent on the context and calls DoneCurrent when the scope for the returned value
- /// ends
- [[nodiscard]] Scoped Acquire() {
- return Scoped{*this};
- }
-};
-
-/**
* Abstraction class used to provide an interface between emulation code and the frontend
* (e.g. SDL, QGLWidget, GLFW, etc...).
*
@@ -205,7 +163,7 @@ protected:
}
/**
- * Converts a screen postion into the equivalent touchscreen position.
+ * Converts a screen position into the equivalent touchscreen position.
*/
std::pair<f32, f32> MapToTouchScreen(u32 framebuffer_x, u32 framebuffer_y) const;
diff --git a/src/core/frontend/graphics_context.h b/src/core/frontend/graphics_context.h
new file mode 100644
index 000000000..7554c1583
--- /dev/null
+++ b/src/core/frontend/graphics_context.h
@@ -0,0 +1,62 @@
+// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include <memory>
+
+#include "common/dynamic_library.h"
+
+namespace Core::Frontend {
+
+/**
+ * Represents a drawing context that supports graphics operations.
+ */
+class GraphicsContext {
+public:
+ virtual ~GraphicsContext() = default;
+
+ /// Inform the driver to swap the front/back buffers and present the current image
+ virtual void SwapBuffers() {}
+
+ /// Makes the graphics context current for the caller thread
+ virtual void MakeCurrent() {}
+
+ /// Releases (dunno if this is the "right" word) the context from the caller thread
+ virtual void DoneCurrent() {}
+
+ /// Gets the GPU driver library (used by Android only)
+ virtual std::shared_ptr<Common::DynamicLibrary> GetDriverLibrary() {
+ return {};
+ }
+
+ class Scoped {
+ public:
+ [[nodiscard]] explicit Scoped(GraphicsContext& context_) : context(context_) {
+ context.MakeCurrent();
+ }
+ ~Scoped() {
+ if (active) {
+ context.DoneCurrent();
+ }
+ }
+
+ /// In the event that context was destroyed before the Scoped is destroyed, this provides a
+ /// mechanism to prevent calling a destroyed object's method during the deconstructor
+ void Cancel() {
+ active = false;
+ }
+
+ private:
+ GraphicsContext& context;
+ bool active{true};
+ };
+
+ /// Calls MakeCurrent on the context and calls DoneCurrent when the scope for the returned value
+ /// ends
+ [[nodiscard]] Scoped Acquire() {
+ return Scoped{*this};
+ }
+};
+
+} // namespace Core::Frontend
diff --git a/src/core/hardware_properties.h b/src/core/hardware_properties.h
index 13cbdb734..191c28bb4 100644
--- a/src/core/hardware_properties.h
+++ b/src/core/hardware_properties.h
@@ -13,11 +13,9 @@ namespace Core {
namespace Hardware {
-// The below clock rate is based on Switch's clockspeed being widely known as 1.020GHz
-// The exact value used is of course unverified.
-constexpr u64 BASE_CLOCK_RATE = 1019215872; // Switch cpu frequency is 1020MHz un/docked
-constexpr u64 CNTFREQ = 19200000; // Switch's hardware clock speed
-constexpr u32 NUM_CPU_CORES = 4; // Number of CPU Cores
+constexpr u64 BASE_CLOCK_RATE = 1'020'000'000; // Default CPU Frequency = 1020 MHz
+constexpr u64 CNTFREQ = 19'200'000; // CNTPCT_EL0 Frequency = 19.2 MHz
+constexpr u32 NUM_CPU_CORES = 4; // Number of CPU Cores
// Virtual to Physical core map.
constexpr std::array<s32, Common::BitSize<u64>()> VirtualToPhysicalCoreMap{
@@ -25,6 +23,26 @@ constexpr std::array<s32, Common::BitSize<u64>()> VirtualToPhysicalCoreMap{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,
};
+static constexpr inline size_t NumVirtualCores = Common::BitSize<u64>();
+
+static constexpr inline u64 VirtualCoreMask = [] {
+ u64 mask = 0;
+ for (size_t i = 0; i < NumVirtualCores; ++i) {
+ mask |= (UINT64_C(1) << i);
+ }
+ return mask;
+}();
+
+static constexpr inline u64 ConvertVirtualCoreMaskToPhysical(u64 v_core_mask) {
+ u64 p_core_mask = 0;
+ while (v_core_mask != 0) {
+ const u64 next = std::countr_zero(v_core_mask);
+ v_core_mask &= ~(static_cast<u64>(1) << next);
+ p_core_mask |= (static_cast<u64>(1) << VirtualToPhysicalCoreMap[next]);
+ }
+ return p_core_mask;
+}
+
// Cortex-A57 supports 4 memory watchpoints
constexpr u64 NUM_WATCHPOINTS = 4;
diff --git a/src/core/hid/emulated_console.cpp b/src/core/hid/emulated_console.cpp
index 1c91bbe40..b4afd930e 100644
--- a/src/core/hid/emulated_console.cpp
+++ b/src/core/hid/emulated_console.cpp
@@ -13,7 +13,7 @@ EmulatedConsole::~EmulatedConsole() = default;
void EmulatedConsole::ReloadFromSettings() {
// Using first motion device from player 1. No need to assign any unique config at the moment
const auto& player = Settings::values.players.GetValue()[0];
- motion_params = Common::ParamPackage(player.motions[0]);
+ motion_params[0] = Common::ParamPackage(player.motions[0]);
ReloadInput();
}
@@ -23,7 +23,8 @@ void EmulatedConsole::SetTouchParams() {
// We can't use mouse as touch if native mouse is enabled
if (!Settings::values.mouse_enabled) {
- touch_params[index++] = Common::ParamPackage{"engine:mouse,axis_x:10,axis_y:11,button:0"};
+ touch_params[index++] =
+ Common::ParamPackage{"engine:mouse,axis_x:0,axis_y:1,button:0,port:2"};
}
touch_params[index++] =
@@ -73,14 +74,30 @@ void EmulatedConsole::ReloadInput() {
// If you load any device here add the equivalent to the UnloadInput() function
SetTouchParams();
- motion_devices = Common::Input::CreateInputDevice(motion_params);
- if (motion_devices) {
- motion_devices->SetCallback({
+ motion_params[1] = Common::ParamPackage{"engine:virtual_gamepad,port:8,motion:0"};
+
+ for (std::size_t index = 0; index < motion_devices.size(); ++index) {
+ motion_devices[index] = Common::Input::CreateInputDevice(motion_params[index]);
+ if (!motion_devices[index]) {
+ continue;
+ }
+ motion_devices[index]->SetCallback({
.on_change =
[this](const Common::Input::CallbackStatus& callback) { SetMotion(callback); },
});
}
+ // Restore motion state
+ auto& emulated_motion = console.motion_values.emulated;
+ auto& motion = console.motion_state;
+ emulated_motion.ResetRotations();
+ emulated_motion.ResetQuaternion();
+ motion.accel = emulated_motion.GetAcceleration();
+ motion.gyro = emulated_motion.GetGyroscope();
+ motion.rotation = emulated_motion.GetRotations();
+ motion.orientation = emulated_motion.GetOrientation();
+ motion.is_at_rest = !emulated_motion.IsMoving(motion_sensitivity);
+
// Unique index for identifying touch device source
std::size_t index = 0;
for (auto& touch_device : touch_devices) {
@@ -99,7 +116,9 @@ void EmulatedConsole::ReloadInput() {
}
void EmulatedConsole::UnloadInput() {
- motion_devices.reset();
+ for (auto& motion : motion_devices) {
+ motion.reset();
+ }
for (auto& touch : touch_devices) {
touch.reset();
}
@@ -132,11 +151,11 @@ void EmulatedConsole::RestoreConfig() {
}
Common::ParamPackage EmulatedConsole::GetMotionParam() const {
- return motion_params;
+ return motion_params[0];
}
void EmulatedConsole::SetMotionParam(Common::ParamPackage param) {
- motion_params = std::move(param);
+ motion_params[0] = std::move(param);
ReloadInput();
}
diff --git a/src/core/hid/emulated_console.h b/src/core/hid/emulated_console.h
index 697ecd2d6..79114bb6d 100644
--- a/src/core/hid/emulated_console.h
+++ b/src/core/hid/emulated_console.h
@@ -29,10 +29,10 @@ struct ConsoleMotionInfo {
MotionInput emulated{};
};
-using ConsoleMotionDevices = std::unique_ptr<Common::Input::InputDevice>;
+using ConsoleMotionDevices = std::array<std::unique_ptr<Common::Input::InputDevice>, 2>;
using TouchDevices = std::array<std::unique_ptr<Common::Input::InputDevice>, MaxTouchDevices>;
-using ConsoleMotionParams = Common::ParamPackage;
+using ConsoleMotionParams = std::array<Common::ParamPackage, 2>;
using TouchParams = std::array<Common::ParamPackage, MaxTouchDevices>;
using ConsoleMotionValues = ConsoleMotionInfo;
diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp
index a959c9db9..1ebc32c1e 100644
--- a/src/core/hid/emulated_controller.cpp
+++ b/src/core/hid/emulated_controller.cpp
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include <algorithm>
+#include <common/scope_exit.h>
#include "common/polyfill_ranges.h"
#include "common/thread.h"
@@ -10,8 +11,8 @@
namespace Core::HID {
constexpr s32 HID_JOYSTICK_MAX = 0x7fff;
-constexpr s32 HID_JOYSTICK_MIN = 0x7ffe;
constexpr s32 HID_TRIGGER_MAX = 0x7fff;
+constexpr u32 TURBO_BUTTON_DELAY = 4;
// Use a common UUID for TAS and Virtual Gamepad
constexpr Common::UUID TAS_UUID =
Common::UUID{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xA5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}};
@@ -94,6 +95,7 @@ void EmulatedController::ReloadFromSettings() {
motion_params[index] = Common::ParamPackage(player.motions[index]);
}
+ controller.color_values = {};
controller.colors_state.fullkey = {
.body = GetNpadColor(player.body_color_left),
.button = GetNpadColor(player.button_color_left),
@@ -107,6 +109,8 @@ void EmulatedController::ReloadFromSettings() {
.button = GetNpadColor(player.button_color_right),
};
+ ring_params[0] = Common::ParamPackage(Settings::values.ringcon_analogs);
+
// Other or debug controller should always be a pro controller
if (npad_id_type != NpadIdType::Other) {
SetNpadStyleIndex(MapSettingsTypeToNPad(player.controller_type));
@@ -133,18 +137,32 @@ void EmulatedController::LoadDevices() {
trigger_params[LeftIndex] = button_params[Settings::NativeButton::ZL];
trigger_params[RightIndex] = button_params[Settings::NativeButton::ZR];
+ color_params[LeftIndex] = left_joycon;
+ color_params[RightIndex] = right_joycon;
+ color_params[LeftIndex].Set("color", true);
+ color_params[RightIndex].Set("color", true);
+
battery_params[LeftIndex] = left_joycon;
battery_params[RightIndex] = right_joycon;
battery_params[LeftIndex].Set("battery", true);
battery_params[RightIndex].Set("battery", true);
- camera_params = Common::ParamPackage{"engine:camera,camera:1"};
- nfc_params = Common::ParamPackage{"engine:virtual_amiibo,nfc:1"};
+ camera_params[0] = right_joycon;
+ camera_params[0].Set("camera", true);
+ nfc_params[1] = right_joycon;
+ nfc_params[1].Set("nfc", true);
+
+ // Only map virtual devices to the first controller
+ if (npad_id_type == NpadIdType::Player1 || npad_id_type == NpadIdType::Handheld) {
+ camera_params[1] = Common::ParamPackage{"engine:camera,camera:1"};
+ ring_params[1] = Common::ParamPackage{"engine:joycon,axis_x:100,axis_y:101"};
+ nfc_params[0] = Common::ParamPackage{"engine:virtual_amiibo,nfc:1"};
+ }
output_params[LeftIndex] = left_joycon;
output_params[RightIndex] = right_joycon;
- output_params[2] = camera_params;
- output_params[3] = nfc_params;
+ output_params[2] = camera_params[1];
+ output_params[3] = nfc_params[0];
output_params[LeftIndex].Set("output", true);
output_params[RightIndex].Set("output", true);
output_params[2].Set("output", true);
@@ -160,8 +178,11 @@ void EmulatedController::LoadDevices() {
Common::Input::CreateInputDevice);
std::ranges::transform(battery_params, battery_devices.begin(),
Common::Input::CreateInputDevice);
- camera_devices = Common::Input::CreateInputDevice(camera_params);
- nfc_devices = Common::Input::CreateInputDevice(nfc_params);
+ std::ranges::transform(color_params, color_devices.begin(), Common::Input::CreateInputDevice);
+ std::ranges::transform(camera_params, camera_devices.begin(), Common::Input::CreateInputDevice);
+ std::ranges::transform(ring_params, ring_analog_devices.begin(),
+ Common::Input::CreateInputDevice);
+ std::ranges::transform(nfc_params, nfc_devices.begin(), Common::Input::CreateInputDevice);
std::ranges::transform(output_params, output_devices.begin(),
Common::Input::CreateOutputDevice);
@@ -176,6 +197,8 @@ void EmulatedController::LoadDevices() {
Common::Input::CreateInputDevice);
std::ranges::transform(virtual_stick_params, virtual_stick_devices.begin(),
Common::Input::CreateInputDevice);
+ std::ranges::transform(virtual_motion_params, virtual_motion_devices.begin(),
+ Common::Input::CreateInputDevice);
}
void EmulatedController::LoadTASParams() {
@@ -236,6 +259,12 @@ void EmulatedController::LoadVirtualGamepadParams() {
for (auto& param : virtual_stick_params) {
param = common_params;
}
+ for (auto& param : virtual_stick_params) {
+ param = common_params;
+ }
+ for (auto& param : virtual_motion_params) {
+ param = common_params;
+ }
// TODO(german77): Replace this with an input profile or something better
virtual_button_params[Settings::NativeButton::A].Set("button", 0);
@@ -263,6 +292,13 @@ void EmulatedController::LoadVirtualGamepadParams() {
virtual_stick_params[Settings::NativeAnalog::LStick].Set("axis_y", 1);
virtual_stick_params[Settings::NativeAnalog::RStick].Set("axis_x", 2);
virtual_stick_params[Settings::NativeAnalog::RStick].Set("axis_y", 3);
+ virtual_stick_params[Settings::NativeAnalog::LStick].Set("deadzone", 0.0f);
+ virtual_stick_params[Settings::NativeAnalog::LStick].Set("range", 1.0f);
+ virtual_stick_params[Settings::NativeAnalog::RStick].Set("deadzone", 0.0f);
+ virtual_stick_params[Settings::NativeAnalog::RStick].Set("range", 1.0f);
+
+ virtual_motion_params[Settings::NativeMotion::MotionLeft].Set("motion", 0);
+ virtual_motion_params[Settings::NativeMotion::MotionRight].Set("motion", 0);
}
void EmulatedController::ReloadInput() {
@@ -323,6 +359,19 @@ void EmulatedController::ReloadInput() {
battery_devices[index]->ForceUpdate();
}
+ for (std::size_t index = 0; index < color_devices.size(); ++index) {
+ if (!color_devices[index]) {
+ continue;
+ }
+ color_devices[index]->SetCallback({
+ .on_change =
+ [this, index](const Common::Input::CallbackStatus& callback) {
+ SetColors(callback, index);
+ },
+ });
+ color_devices[index]->ForceUpdate();
+ }
+
for (std::size_t index = 0; index < motion_devices.size(); ++index) {
if (!motion_devices[index]) {
continue;
@@ -333,25 +382,51 @@ void EmulatedController::ReloadInput() {
SetMotion(callback, index);
},
});
- motion_devices[index]->ForceUpdate();
- }
- if (camera_devices) {
- camera_devices->SetCallback({
+ // Restore motion state
+ auto& emulated_motion = controller.motion_values[index].emulated;
+ auto& motion = controller.motion_state[index];
+ emulated_motion.ResetRotations();
+ emulated_motion.ResetQuaternion();
+ motion.accel = emulated_motion.GetAcceleration();
+ motion.gyro = emulated_motion.GetGyroscope();
+ motion.rotation = emulated_motion.GetRotations();
+ motion.euler = emulated_motion.GetEulerAngles();
+ motion.orientation = emulated_motion.GetOrientation();
+ motion.is_at_rest = !emulated_motion.IsMoving(motion_sensitivity);
+ }
+
+ for (std::size_t index = 0; index < camera_devices.size(); ++index) {
+ if (!camera_devices[index]) {
+ continue;
+ }
+ camera_devices[index]->SetCallback({
.on_change =
[this](const Common::Input::CallbackStatus& callback) { SetCamera(callback); },
});
- camera_devices->ForceUpdate();
+ camera_devices[index]->ForceUpdate();
}
- if (nfc_devices) {
- if (npad_id_type == NpadIdType::Handheld || npad_id_type == NpadIdType::Player1) {
- nfc_devices->SetCallback({
- .on_change =
- [this](const Common::Input::CallbackStatus& callback) { SetNfc(callback); },
- });
- nfc_devices->ForceUpdate();
+ for (std::size_t index = 0; index < ring_analog_devices.size(); ++index) {
+ if (!ring_analog_devices[index]) {
+ continue;
}
+ ring_analog_devices[index]->SetCallback({
+ .on_change =
+ [this](const Common::Input::CallbackStatus& callback) { SetRingAnalog(callback); },
+ });
+ ring_analog_devices[index]->ForceUpdate();
+ }
+
+ for (std::size_t index = 0; index < nfc_devices.size(); ++index) {
+ if (!nfc_devices[index]) {
+ continue;
+ }
+ nfc_devices[index]->SetCallback({
+ .on_change =
+ [this](const Common::Input::CallbackStatus& callback) { SetNfc(callback); },
+ });
+ nfc_devices[index]->ForceUpdate();
}
// Register TAS devices. No need to force update
@@ -403,6 +478,19 @@ void EmulatedController::ReloadInput() {
},
});
}
+
+ for (std::size_t index = 0; index < virtual_motion_devices.size(); ++index) {
+ if (!virtual_motion_devices[index]) {
+ continue;
+ }
+ virtual_motion_devices[index]->SetCallback({
+ .on_change =
+ [this, index](const Common::Input::CallbackStatus& callback) {
+ SetMotion(callback, index);
+ },
+ });
+ }
+ turbo_button_state = 0;
}
void EmulatedController::UnloadInput() {
@@ -421,6 +509,9 @@ void EmulatedController::UnloadInput() {
for (auto& battery : battery_devices) {
battery.reset();
}
+ for (auto& color : color_devices) {
+ color.reset();
+ }
for (auto& output : output_devices) {
output.reset();
}
@@ -436,8 +527,18 @@ void EmulatedController::UnloadInput() {
for (auto& stick : virtual_stick_devices) {
stick.reset();
}
- camera_devices.reset();
- nfc_devices.reset();
+ for (auto& motion : virtual_motion_devices) {
+ motion.reset();
+ }
+ for (auto& camera : camera_devices) {
+ camera.reset();
+ }
+ for (auto& ring : ring_analog_devices) {
+ ring.reset();
+ }
+ for (auto& nfc : nfc_devices) {
+ nfc.reset();
+ }
}
void EmulatedController::EnableConfiguration() {
@@ -449,6 +550,11 @@ void EmulatedController::EnableConfiguration() {
void EmulatedController::DisableConfiguration() {
is_configuring = false;
+ // Get Joycon colors before turning on the controller
+ for (const auto& color_device : color_devices) {
+ color_device->ForceUpdate();
+ }
+
// Apply temporary npad type to the real controller
if (tmp_npad_type != npad_type) {
if (is_connected) {
@@ -476,6 +582,8 @@ void EmulatedController::EnableSystemButtons() {
void EmulatedController::DisableSystemButtons() {
std::scoped_lock lock{mutex};
system_buttons_enabled = false;
+ controller.home_button_state.raw = 0;
+ controller.capture_button_state.raw = 0;
}
void EmulatedController::ResetSystemButtons() {
@@ -502,6 +610,9 @@ void EmulatedController::SaveCurrentConfig() {
for (std::size_t index = 0; index < player.motions.size(); ++index) {
player.motions[index] = motion_params[index].Serialize();
}
+ if (npad_id_type == NpadIdType::Player1) {
+ Settings::values.ringcon_analogs = ring_params[0].Serialize();
+ }
}
void EmulatedController::RestoreConfig() {
@@ -607,6 +718,12 @@ void EmulatedController::SetMotionParam(std::size_t index, Common::ParamPackage
ReloadInput();
}
+void EmulatedController::StartMotionCalibration() {
+ for (ControllerMotionInfo& motion : controller.motion_values) {
+ motion.emulated.Calibrate();
+ }
+}
+
void EmulatedController::SetButton(const Common::Input::CallbackStatus& callback, std::size_t index,
Common::UUID uuid) {
if (index >= controller.button_values.size()) {
@@ -625,6 +742,7 @@ void EmulatedController::SetButton(const Common::Input::CallbackStatus& callback
}
current_status.toggle = new_status.toggle;
+ current_status.turbo = new_status.turbo;
current_status.uuid = uuid;
// Update button status with current
@@ -655,6 +773,8 @@ void EmulatedController::SetButton(const Common::Input::CallbackStatus& callback
if (is_configuring) {
controller.npad_button_state.raw = NpadButton::None;
controller.debug_pad_button_state.raw = 0;
+ controller.home_button_state.raw = 0;
+ controller.capture_button_state.raw = 0;
lock.unlock();
TriggerOnChange(ControllerTriggerType::Button, false);
return;
@@ -773,17 +893,21 @@ void EmulatedController::SetStick(const Common::Input::CallbackStatus& callback,
if (index >= controller.stick_values.size()) {
return;
}
- std::unique_lock lock{mutex};
+ auto trigger_guard =
+ SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Stick, !is_configuring); });
+ std::scoped_lock lock{mutex};
const auto stick_value = TransformToStick(callback);
// Only read stick values that have the same uuid or are over the threshold to avoid flapping
if (controller.stick_values[index].uuid != uuid) {
const bool is_tas = uuid == TAS_UUID;
if (is_tas && stick_value.x.value == 0 && stick_value.y.value == 0) {
+ trigger_guard.Cancel();
return;
}
if (!is_tas && !stick_value.down && !stick_value.up && !stick_value.left &&
!stick_value.right) {
+ trigger_guard.Cancel();
return;
}
}
@@ -794,21 +918,12 @@ void EmulatedController::SetStick(const Common::Input::CallbackStatus& callback,
if (is_configuring) {
controller.analog_stick_state.left = {};
controller.analog_stick_state.right = {};
- lock.unlock();
- TriggerOnChange(ControllerTriggerType::Stick, false);
return;
}
- const auto FloatToShort = [](float a) {
- if (a > 0) {
- return static_cast<s32>(a * HID_JOYSTICK_MAX);
- }
- return static_cast<s32>(a * HID_JOYSTICK_MIN);
- };
-
const AnalogStickState stick{
- .x = FloatToShort(controller.stick_values[index].x.value),
- .y = FloatToShort(controller.stick_values[index].y.value),
+ .x = static_cast<s32>(controller.stick_values[index].x.value * HID_JOYSTICK_MAX),
+ .y = static_cast<s32>(controller.stick_values[index].y.value * HID_JOYSTICK_MAX),
};
switch (index) {
@@ -827,9 +942,6 @@ void EmulatedController::SetStick(const Common::Input::CallbackStatus& callback,
controller.npad_button_state.stick_r_down.Assign(controller.stick_values[index].down);
break;
}
-
- lock.unlock();
- TriggerOnChange(ControllerTriggerType::Stick, true);
}
void EmulatedController::SetTrigger(const Common::Input::CallbackStatus& callback,
@@ -837,7 +949,9 @@ void EmulatedController::SetTrigger(const Common::Input::CallbackStatus& callbac
if (index >= controller.trigger_values.size()) {
return;
}
- std::unique_lock lock{mutex};
+ auto trigger_guard =
+ SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Trigger, !is_configuring); });
+ std::scoped_lock lock{mutex};
const auto trigger_value = TransformToTrigger(callback);
// Only read trigger values that have the same uuid or are pressed once
@@ -853,13 +967,12 @@ void EmulatedController::SetTrigger(const Common::Input::CallbackStatus& callbac
if (is_configuring) {
controller.gc_trigger_state.left = 0;
controller.gc_trigger_state.right = 0;
- lock.unlock();
- TriggerOnChange(ControllerTriggerType::Trigger, false);
return;
}
// Only GC controllers have analog triggers
if (npad_type != NpadStyleIndex::GameCube) {
+ trigger_guard.Cancel();
return;
}
@@ -876,9 +989,6 @@ void EmulatedController::SetTrigger(const Common::Input::CallbackStatus& callbac
controller.npad_button_state.zr.Assign(trigger.pressed.value);
break;
}
-
- lock.unlock();
- TriggerOnChange(ControllerTriggerType::Trigger, true);
}
void EmulatedController::SetMotion(const Common::Input::CallbackStatus& callback,
@@ -886,7 +996,8 @@ void EmulatedController::SetMotion(const Common::Input::CallbackStatus& callback
if (index >= controller.motion_values.size()) {
return;
}
- std::unique_lock lock{mutex};
+ SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::Motion, !is_configuring); });
+ std::scoped_lock lock{mutex};
auto& raw_status = controller.motion_values[index].raw_status;
auto& emulated = controller.motion_values[index].emulated;
@@ -901,26 +1012,67 @@ void EmulatedController::SetMotion(const Common::Input::CallbackStatus& callback
raw_status.gyro.y.value,
raw_status.gyro.z.value,
});
- emulated.SetGyroThreshold(raw_status.gyro.x.properties.threshold);
+ emulated.SetUserGyroThreshold(raw_status.gyro.x.properties.threshold);
emulated.UpdateRotation(raw_status.delta_timestamp);
emulated.UpdateOrientation(raw_status.delta_timestamp);
- force_update_motion = raw_status.force_update;
-
- if (is_configuring) {
- lock.unlock();
- TriggerOnChange(ControllerTriggerType::Motion, false);
- return;
- }
auto& motion = controller.motion_state[index];
motion.accel = emulated.GetAcceleration();
motion.gyro = emulated.GetGyroscope();
motion.rotation = emulated.GetRotations();
+ motion.euler = emulated.GetEulerAngles();
motion.orientation = emulated.GetOrientation();
motion.is_at_rest = !emulated.IsMoving(motion_sensitivity);
+}
- lock.unlock();
- TriggerOnChange(ControllerTriggerType::Motion, true);
+void EmulatedController::SetColors(const Common::Input::CallbackStatus& callback,
+ std::size_t index) {
+ if (index >= controller.color_values.size()) {
+ return;
+ }
+ auto trigger_guard =
+ SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Color, !is_configuring); });
+ std::scoped_lock lock{mutex};
+ controller.color_values[index] = TransformToColor(callback);
+
+ if (is_configuring) {
+ return;
+ }
+
+ if (controller.color_values[index].body == 0) {
+ trigger_guard.Cancel();
+ return;
+ }
+
+ controller.colors_state.fullkey = {
+ .body = GetNpadColor(controller.color_values[index].body),
+ .button = GetNpadColor(controller.color_values[index].buttons),
+ };
+ if (npad_type == NpadStyleIndex::ProController) {
+ controller.colors_state.left = {
+ .body = GetNpadColor(controller.color_values[index].left_grip),
+ .button = GetNpadColor(controller.color_values[index].buttons),
+ };
+ controller.colors_state.right = {
+ .body = GetNpadColor(controller.color_values[index].right_grip),
+ .button = GetNpadColor(controller.color_values[index].buttons),
+ };
+ } else {
+ switch (index) {
+ case LeftIndex:
+ controller.colors_state.left = {
+ .body = GetNpadColor(controller.color_values[index].body),
+ .button = GetNpadColor(controller.color_values[index].buttons),
+ };
+ break;
+ case RightIndex:
+ controller.colors_state.right = {
+ .body = GetNpadColor(controller.color_values[index].body),
+ .button = GetNpadColor(controller.color_values[index].buttons),
+ };
+ break;
+ }
+ }
}
void EmulatedController::SetBattery(const Common::Input::CallbackStatus& callback,
@@ -928,12 +1080,11 @@ void EmulatedController::SetBattery(const Common::Input::CallbackStatus& callbac
if (index >= controller.battery_values.size()) {
return;
}
- std::unique_lock lock{mutex};
+ SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::Battery, !is_configuring); });
+ std::scoped_lock lock{mutex};
controller.battery_values[index] = TransformToBattery(callback);
if (is_configuring) {
- lock.unlock();
- TriggerOnChange(ControllerTriggerType::Battery, false);
return;
}
@@ -989,18 +1140,14 @@ void EmulatedController::SetBattery(const Common::Input::CallbackStatus& callbac
};
break;
}
-
- lock.unlock();
- TriggerOnChange(ControllerTriggerType::Battery, true);
}
void EmulatedController::SetCamera(const Common::Input::CallbackStatus& callback) {
- std::unique_lock lock{mutex};
+ SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::IrSensor, !is_configuring); });
+ std::scoped_lock lock{mutex};
controller.camera_values = TransformToCamera(callback);
if (is_configuring) {
- lock.unlock();
- TriggerOnChange(ControllerTriggerType::IrSensor, false);
return;
}
@@ -1008,28 +1155,32 @@ void EmulatedController::SetCamera(const Common::Input::CallbackStatus& callback
controller.camera_state.format =
static_cast<Core::IrSensor::ImageTransferProcessorFormat>(controller.camera_values.format);
controller.camera_state.data = controller.camera_values.data;
+}
- lock.unlock();
- TriggerOnChange(ControllerTriggerType::IrSensor, true);
+void EmulatedController::SetRingAnalog(const Common::Input::CallbackStatus& callback) {
+ SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::RingController, !is_configuring); });
+ std::scoped_lock lock{mutex};
+ const auto force_value = TransformToStick(callback);
+
+ controller.ring_analog_value = force_value.x;
+
+ if (is_configuring) {
+ return;
+ }
+
+ controller.ring_analog_state.force = force_value.x.value;
}
void EmulatedController::SetNfc(const Common::Input::CallbackStatus& callback) {
- std::unique_lock lock{mutex};
+ SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::Nfc, !is_configuring); });
+ std::scoped_lock lock{mutex};
controller.nfc_values = TransformToNfc(callback);
if (is_configuring) {
- lock.unlock();
- TriggerOnChange(ControllerTriggerType::Nfc, false);
return;
}
- controller.nfc_state = {
- controller.nfc_values.state,
- controller.nfc_values.data,
- };
-
- lock.unlock();
- TriggerOnChange(ControllerTriggerType::Nfc, true);
+ controller.nfc_state = controller.nfc_values;
}
bool EmulatedController::SetVibration(std::size_t device_index, VibrationValue vibration) {
@@ -1061,7 +1212,7 @@ bool EmulatedController::SetVibration(std::size_t device_index, VibrationValue v
.type = type,
};
return output_devices[device_index]->SetVibration(status) ==
- Common::Input::VibrationError::None;
+ Common::Input::DriverResult::Success;
}
bool EmulatedController::IsVibrationEnabled(std::size_t device_index) {
@@ -1083,16 +1234,37 @@ bool EmulatedController::IsVibrationEnabled(std::size_t device_index) {
return output_devices[device_index]->IsVibrationEnabled();
}
-bool EmulatedController::SetPollingMode(Common::Input::PollingMode polling_mode) {
- LOG_INFO(Service_HID, "Set polling mode {}", polling_mode);
- auto& output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)];
+Common::Input::DriverResult EmulatedController::SetPollingMode(
+ EmulatedDeviceIndex device_index, Common::Input::PollingMode polling_mode) {
+ LOG_INFO(Service_HID, "Set polling mode {}, device_index={}", polling_mode, device_index);
+
+ auto& left_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Left)];
+ auto& right_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)];
auto& nfc_output_device = output_devices[3];
- const auto virtual_nfc_result = nfc_output_device->SetPollingMode(polling_mode);
- const auto mapped_nfc_result = output_device->SetPollingMode(polling_mode);
+ if (device_index == EmulatedDeviceIndex::LeftIndex) {
+ return left_output_device->SetPollingMode(polling_mode);
+ }
+
+ if (device_index == EmulatedDeviceIndex::RightIndex) {
+ const auto virtual_nfc_result = nfc_output_device->SetPollingMode(polling_mode);
+ const auto mapped_nfc_result = right_output_device->SetPollingMode(polling_mode);
+
+ // Restore previous state
+ if (mapped_nfc_result != Common::Input::DriverResult::Success) {
+ right_output_device->SetPollingMode(Common::Input::PollingMode::Active);
+ }
- return virtual_nfc_result == Common::Input::PollingError::None ||
- mapped_nfc_result == Common::Input::PollingError::None;
+ if (virtual_nfc_result == Common::Input::DriverResult::Success) {
+ return virtual_nfc_result;
+ }
+ return mapped_nfc_result;
+ }
+
+ left_output_device->SetPollingMode(polling_mode);
+ right_output_device->SetPollingMode(polling_mode);
+ nfc_output_device->SetPollingMode(polling_mode);
+ return Common::Input::DriverResult::Success;
}
bool EmulatedController::SetCameraFormat(
@@ -1103,13 +1275,22 @@ bool EmulatedController::SetCameraFormat(
auto& camera_output_device = output_devices[2];
if (right_output_device->SetCameraFormat(static_cast<Common::Input::CameraFormat>(
- camera_format)) == Common::Input::CameraError::None) {
+ camera_format)) == Common::Input::DriverResult::Success) {
return true;
}
// Fallback to Qt camera if native device doesn't have support
return camera_output_device->SetCameraFormat(static_cast<Common::Input::CameraFormat>(
- camera_format)) == Common::Input::CameraError::None;
+ camera_format)) == Common::Input::DriverResult::Success;
+}
+
+Common::ParamPackage EmulatedController::GetRingParam() const {
+ return ring_params[0];
+}
+
+void EmulatedController::SetRingParam(Common::ParamPackage param) {
+ ring_params[0] = std::move(param);
+ ReloadInput();
}
bool EmulatedController::HasNfc() const {
@@ -1133,10 +1314,88 @@ bool EmulatedController::HasNfc() const {
return is_connected && (has_virtual_nfc && is_virtual_nfc_supported);
}
+bool EmulatedController::AddNfcHandle() {
+ nfc_handles++;
+ return SetPollingMode(EmulatedDeviceIndex::RightIndex, Common::Input::PollingMode::NFC) ==
+ Common::Input::DriverResult::Success;
+}
+
+bool EmulatedController::RemoveNfcHandle() {
+ nfc_handles--;
+ if (nfc_handles <= 0) {
+ return SetPollingMode(EmulatedDeviceIndex::RightIndex,
+ Common::Input::PollingMode::Active) ==
+ Common::Input::DriverResult::Success;
+ }
+ return true;
+}
+
+bool EmulatedController::StartNfcPolling() {
+ auto& nfc_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)];
+ auto& nfc_virtual_output_device = output_devices[3];
+
+ const auto device_result = nfc_output_device->StartNfcPolling();
+ const auto virtual_device_result = nfc_virtual_output_device->StartNfcPolling();
+
+ return device_result == Common::Input::NfcState::Success ||
+ virtual_device_result == Common::Input::NfcState::Success;
+}
+
+bool EmulatedController::StopNfcPolling() {
+ auto& nfc_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)];
+ auto& nfc_virtual_output_device = output_devices[3];
+
+ const auto device_result = nfc_output_device->StopNfcPolling();
+ const auto virtual_device_result = nfc_virtual_output_device->StopNfcPolling();
+
+ return device_result == Common::Input::NfcState::Success ||
+ virtual_device_result == Common::Input::NfcState::Success;
+}
+
+bool EmulatedController::ReadAmiiboData(std::vector<u8>& data) {
+ auto& nfc_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)];
+ auto& nfc_virtual_output_device = output_devices[3];
+
+ if (nfc_output_device->ReadAmiiboData(data) == Common::Input::NfcState::Success) {
+ return true;
+ }
+
+ return nfc_virtual_output_device->ReadAmiiboData(data) == Common::Input::NfcState::Success;
+}
+
+bool EmulatedController::ReadMifareData(const Common::Input::MifareRequest& request,
+ Common::Input::MifareRequest& out_data) {
+ auto& nfc_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)];
+ auto& nfc_virtual_output_device = output_devices[3];
+
+ if (nfc_output_device->ReadMifareData(request, out_data) == Common::Input::NfcState::Success) {
+ return true;
+ }
+
+ return nfc_virtual_output_device->ReadMifareData(request, out_data) ==
+ Common::Input::NfcState::Success;
+}
+
+bool EmulatedController::WriteMifareData(const Common::Input::MifareRequest& request) {
+ auto& nfc_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)];
+ auto& nfc_virtual_output_device = output_devices[3];
+
+ if (nfc_output_device->WriteMifareData(request) == Common::Input::NfcState::Success) {
+ return true;
+ }
+
+ return nfc_virtual_output_device->WriteMifareData(request) == Common::Input::NfcState::Success;
+}
+
bool EmulatedController::WriteNfc(const std::vector<u8>& data) {
- auto& nfc_output_device = output_devices[3];
+ auto& nfc_output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)];
+ auto& nfc_virtual_output_device = output_devices[3];
- return nfc_output_device->WriteNfcData(data) == Common::Input::NfcState::Success;
+ if (nfc_output_device->SupportsNfc() != Common::Input::NfcState::NotSupported) {
+ return nfc_output_device->WriteNfcData(data) == Common::Input::NfcState::Success;
+ }
+
+ return nfc_virtual_output_device->WriteNfcData(data) == Common::Input::NfcState::Success;
}
void EmulatedController::SetLedPattern() {
@@ -1156,6 +1415,26 @@ void EmulatedController::SetLedPattern() {
}
}
+void EmulatedController::SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode mode) {
+ for (auto& motion : controller.motion_values) {
+ switch (mode) {
+ case GyroscopeZeroDriftMode::Loose:
+ motion_sensitivity = motion.emulated.IsAtRestLoose;
+ motion.emulated.SetGyroThreshold(motion.emulated.ThresholdLoose);
+ break;
+ case GyroscopeZeroDriftMode::Tight:
+ motion_sensitivity = motion.emulated.IsAtRestThight;
+ motion.emulated.SetGyroThreshold(motion.emulated.ThresholdThight);
+ break;
+ case GyroscopeZeroDriftMode::Standard:
+ default:
+ motion_sensitivity = motion.emulated.IsAtRestStandard;
+ motion.emulated.SetGyroThreshold(motion.emulated.ThresholdStandard);
+ break;
+ }
+ }
+}
+
void EmulatedController::SetSupportedNpadStyleTag(NpadStyleTag supported_styles) {
supported_style_tag = supported_styles;
if (!is_connected) {
@@ -1263,39 +1542,35 @@ void EmulatedController::Connect(bool use_temporary_value) {
return;
}
- std::unique_lock lock{mutex};
+ auto trigger_guard =
+ SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Connected, !is_configuring); });
+ std::scoped_lock lock{mutex};
if (is_configuring) {
tmp_is_connected = true;
- lock.unlock();
- TriggerOnChange(ControllerTriggerType::Connected, false);
return;
}
if (is_connected) {
+ trigger_guard.Cancel();
return;
}
is_connected = true;
-
- lock.unlock();
- TriggerOnChange(ControllerTriggerType::Connected, true);
}
void EmulatedController::Disconnect() {
- std::unique_lock lock{mutex};
+ auto trigger_guard =
+ SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Disconnected, !is_configuring); });
+ std::scoped_lock lock{mutex};
if (is_configuring) {
tmp_is_connected = false;
- lock.unlock();
- TriggerOnChange(ControllerTriggerType::Disconnected, false);
return;
}
if (!is_connected) {
+ trigger_guard.Cancel();
return;
}
is_connected = false;
-
- lock.unlock();
- TriggerOnChange(ControllerTriggerType::Disconnected, true);
}
bool EmulatedController::IsConnected(bool get_temporary_value) const {
@@ -1320,19 +1595,21 @@ NpadStyleIndex EmulatedController::GetNpadStyleIndex(bool get_temporary_value) c
}
void EmulatedController::SetNpadStyleIndex(NpadStyleIndex npad_type_) {
- std::unique_lock lock{mutex};
+ auto trigger_guard =
+ SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Type, !is_configuring); });
+ std::scoped_lock lock{mutex};
if (is_configuring) {
if (tmp_npad_type == npad_type_) {
+ trigger_guard.Cancel();
return;
}
tmp_npad_type = npad_type_;
- lock.unlock();
- TriggerOnChange(ControllerTriggerType::Type, false);
return;
}
if (npad_type == npad_type_) {
+ trigger_guard.Cancel();
return;
}
if (is_connected) {
@@ -1340,9 +1617,6 @@ void EmulatedController::SetNpadStyleIndex(NpadStyleIndex npad_type_) {
NpadIdTypeToIndex(npad_id_type));
}
npad_type = npad_type_;
-
- lock.unlock();
- TriggerOnChange(ControllerTriggerType::Type, true);
}
LedPattern EmulatedController::GetLedPattern() const {
@@ -1403,6 +1677,10 @@ CameraValues EmulatedController::GetCameraValues() const {
return controller.camera_values;
}
+RingAnalogValue EmulatedController::GetRingSensorValues() const {
+ return controller.ring_analog_value;
+}
+
HomeButtonState EmulatedController::GetHomeButtons() const {
std::scoped_lock lock{mutex};
if (is_configuring) {
@@ -1424,7 +1702,7 @@ NpadButtonState EmulatedController::GetNpadButtons() const {
if (is_configuring) {
return {};
}
- return controller.npad_button_state;
+ return {controller.npad_button_state.raw & GetTurboButtonMask()};
}
DebugPadButton EmulatedController::GetDebugPadButtons() const {
@@ -1436,7 +1714,7 @@ DebugPadButton EmulatedController::GetDebugPadButtons() const {
}
AnalogSticks EmulatedController::GetSticks() const {
- std::unique_lock lock{mutex};
+ std::scoped_lock lock{mutex};
if (is_configuring) {
return {};
@@ -1455,19 +1733,6 @@ NpadGcTriggerState EmulatedController::GetTriggers() const {
MotionState EmulatedController::GetMotions() const {
std::unique_lock lock{mutex};
-
- // Some drivers like mouse motion need constant refreshing
- if (force_update_motion) {
- for (auto& device : motion_devices) {
- if (!device) {
- continue;
- }
- lock.unlock();
- device->ForceUpdate();
- lock.lock();
- }
- }
-
return controller.motion_state;
}
@@ -1486,6 +1751,10 @@ const CameraState& EmulatedController::GetCamera() const {
return controller.camera_state;
}
+RingSensorForce EmulatedController::GetRingSensorForce() const {
+ return controller.ring_analog_state;
+}
+
const NfcState& EmulatedController::GetNfc() const {
std::scoped_lock lock{mutex};
return controller.nfc_state;
@@ -1528,4 +1797,87 @@ void EmulatedController::DeleteCallback(int key) {
}
callback_list.erase(iterator);
}
+
+void EmulatedController::StatusUpdate() {
+ turbo_button_state = (turbo_button_state + 1) % (TURBO_BUTTON_DELAY * 2);
+
+ // Some drivers like key motion need constant refreshing
+ for (std::size_t index = 0; index < motion_devices.size(); ++index) {
+ const auto& raw_status = controller.motion_values[index].raw_status;
+ auto& device = motion_devices[index];
+ if (!raw_status.force_update) {
+ continue;
+ }
+ if (!device) {
+ continue;
+ }
+ device->ForceUpdate();
+ }
+}
+
+NpadButton EmulatedController::GetTurboButtonMask() const {
+ // Apply no mask when disabled
+ if (turbo_button_state < TURBO_BUTTON_DELAY) {
+ return {NpadButton::All};
+ }
+
+ NpadButtonState button_mask{};
+ for (std::size_t index = 0; index < controller.button_values.size(); ++index) {
+ if (!controller.button_values[index].turbo) {
+ continue;
+ }
+
+ switch (index) {
+ case Settings::NativeButton::A:
+ button_mask.a.Assign(1);
+ break;
+ case Settings::NativeButton::B:
+ button_mask.b.Assign(1);
+ break;
+ case Settings::NativeButton::X:
+ button_mask.x.Assign(1);
+ break;
+ case Settings::NativeButton::Y:
+ button_mask.y.Assign(1);
+ break;
+ case Settings::NativeButton::L:
+ button_mask.l.Assign(1);
+ break;
+ case Settings::NativeButton::R:
+ button_mask.r.Assign(1);
+ break;
+ case Settings::NativeButton::ZL:
+ button_mask.zl.Assign(1);
+ break;
+ case Settings::NativeButton::ZR:
+ button_mask.zr.Assign(1);
+ break;
+ case Settings::NativeButton::DLeft:
+ button_mask.left.Assign(1);
+ break;
+ case Settings::NativeButton::DUp:
+ button_mask.up.Assign(1);
+ break;
+ case Settings::NativeButton::DRight:
+ button_mask.right.Assign(1);
+ break;
+ case Settings::NativeButton::DDown:
+ button_mask.down.Assign(1);
+ break;
+ case Settings::NativeButton::SL:
+ button_mask.left_sl.Assign(1);
+ button_mask.right_sl.Assign(1);
+ break;
+ case Settings::NativeButton::SR:
+ button_mask.left_sr.Assign(1);
+ button_mask.right_sr.Assign(1);
+ break;
+ default:
+ break;
+ }
+ }
+
+ return static_cast<NpadButton>(~button_mask.raw);
+}
+
} // namespace Core::HID
diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h
index a398543a6..d511e5fac 100644
--- a/src/core/hid/emulated_controller.h
+++ b/src/core/hid/emulated_controller.h
@@ -35,19 +35,27 @@ using ControllerMotionDevices =
std::array<std::unique_ptr<Common::Input::InputDevice>, Settings::NativeMotion::NumMotions>;
using TriggerDevices =
std::array<std::unique_ptr<Common::Input::InputDevice>, Settings::NativeTrigger::NumTriggers>;
+using ColorDevices =
+ std::array<std::unique_ptr<Common::Input::InputDevice>, max_emulated_controllers>;
using BatteryDevices =
std::array<std::unique_ptr<Common::Input::InputDevice>, max_emulated_controllers>;
-using CameraDevices = std::unique_ptr<Common::Input::InputDevice>;
-using NfcDevices = std::unique_ptr<Common::Input::InputDevice>;
+using CameraDevices =
+ std::array<std::unique_ptr<Common::Input::InputDevice>, max_emulated_controllers>;
+using RingAnalogDevices =
+ std::array<std::unique_ptr<Common::Input::InputDevice>, max_emulated_controllers>;
+using NfcDevices =
+ std::array<std::unique_ptr<Common::Input::InputDevice>, max_emulated_controllers>;
using OutputDevices = std::array<std::unique_ptr<Common::Input::OutputDevice>, output_devices_size>;
using ButtonParams = std::array<Common::ParamPackage, Settings::NativeButton::NumButtons>;
using StickParams = std::array<Common::ParamPackage, Settings::NativeAnalog::NumAnalogs>;
using ControllerMotionParams = std::array<Common::ParamPackage, Settings::NativeMotion::NumMotions>;
using TriggerParams = std::array<Common::ParamPackage, Settings::NativeTrigger::NumTriggers>;
+using ColorParams = std::array<Common::ParamPackage, max_emulated_controllers>;
using BatteryParams = std::array<Common::ParamPackage, max_emulated_controllers>;
-using CameraParams = Common::ParamPackage;
-using NfcParams = Common::ParamPackage;
+using CameraParams = std::array<Common::ParamPackage, max_emulated_controllers>;
+using RingAnalogParams = std::array<Common::ParamPackage, max_emulated_controllers>;
+using NfcParams = std::array<Common::ParamPackage, max_emulated_controllers>;
using OutputParams = std::array<Common::ParamPackage, output_devices_size>;
using ButtonValues = std::array<Common::Input::ButtonStatus, Settings::NativeButton::NumButtons>;
@@ -58,6 +66,7 @@ using ControllerMotionValues = std::array<ControllerMotionInfo, Settings::Native
using ColorValues = std::array<Common::Input::BodyColorStatus, max_emulated_controllers>;
using BatteryValues = std::array<Common::Input::BatteryStatus, max_emulated_controllers>;
using CameraValues = Common::Input::CameraStatus;
+using RingAnalogValue = Common::Input::AnalogStatus;
using NfcValues = Common::Input::NfcStatus;
using VibrationValues = std::array<Common::Input::VibrationStatus, max_emulated_controllers>;
@@ -84,15 +93,17 @@ struct CameraState {
std::size_t sample{};
};
-struct NfcState {
- Common::Input::NfcState state{};
- std::vector<u8> data{};
+struct RingSensorForce {
+ f32 force;
};
+using NfcState = Common::Input::NfcStatus;
+
struct ControllerMotion {
Common::Vec3f accel{};
Common::Vec3f gyro{};
Common::Vec3f rotation{};
+ Common::Vec3f euler{};
std::array<Common::Vec3f, 3> orientation{};
bool is_at_rest{};
};
@@ -116,9 +127,10 @@ struct ControllerStatus {
BatteryValues battery_values{};
VibrationValues vibration_values{};
CameraValues camera_values{};
+ RingAnalogValue ring_analog_value{};
NfcValues nfc_values{};
- // Data for HID serices
+ // Data for HID services
HomeButtonState home_button_state{};
CaptureButtonState capture_button_state{};
NpadButtonState npad_button_state{};
@@ -129,6 +141,7 @@ struct ControllerStatus {
ControllerColors colors_state{};
BatteryLevelState battery_state{};
CameraState camera_state{};
+ RingSensorForce ring_analog_state{};
NfcState nfc_state{};
};
@@ -141,6 +154,7 @@ enum class ControllerTriggerType {
Battery,
Vibration,
IrSensor,
+ RingController,
Nfc,
Connected,
Disconnected,
@@ -273,6 +287,9 @@ public:
*/
void SetMotionParam(std::size_t index, Common::ParamPackage param);
+ /// Auto calibrates the current motion devices
+ void StartMotionCalibration();
+
/// Returns the latest button status from the controller with parameters
ButtonValues GetButtonsValues() const;
@@ -294,6 +311,9 @@ public:
/// Returns the latest camera status from the controller with parameters
CameraValues GetCameraValues() const;
+ /// Returns the latest status of analog input from the ring sensor with parameters
+ RingAnalogValue GetRingSensorValues() const;
+
/// Returns the latest status of button input for the hid::HomeButton service
HomeButtonState GetHomeButtons() const;
@@ -324,6 +344,9 @@ public:
/// Returns the latest camera status from the controller
const CameraState& GetCamera() const;
+ /// Returns the latest ringcon force sensor value
+ RingSensorForce GetRingSensorForce() const;
+
/// Returns the latest ntag status from the controller
const NfcState& GetNfc() const;
@@ -335,36 +358,72 @@ public:
/**
* Sends a small vibration to the output device
- * @return true if SetVibration was successfull
+ * @return true if SetVibration was successful
*/
bool IsVibrationEnabled(std::size_t device_index);
/**
* Sets the desired data to be polled from a controller
+ * @param device_index index of the controller to set the polling mode
* @param polling_mode type of input desired buttons, gyro, nfc, ir, etc.
- * @return true if SetPollingMode was successfull
+ * @return driver result from this command
*/
- bool SetPollingMode(Common::Input::PollingMode polling_mode);
+ Common::Input::DriverResult SetPollingMode(EmulatedDeviceIndex device_index,
+ Common::Input::PollingMode polling_mode);
/**
* Sets the desired camera format to be polled from a controller
* @param camera_format size of each frame
- * @return true if SetCameraFormat was successfull
+ * @return true if SetCameraFormat was successful
*/
bool SetCameraFormat(Core::IrSensor::ImageTransferProcessorFormat camera_format);
+ // Returns the current mapped ring device
+ Common::ParamPackage GetRingParam() const;
+
+ /**
+ * Updates the current mapped ring device
+ * @param param ParamPackage with ring sensor data to be mapped
+ */
+ void SetRingParam(Common::ParamPackage param);
+
/// Returns true if the device has nfc support
bool HasNfc() const;
+ /// Sets the joycon in nfc mode and increments the handle count
+ bool AddNfcHandle();
+
+ /// Decrements the handle count if zero sets the joycon in active mode
+ bool RemoveNfcHandle();
+
+ /// Start searching for nfc tags
+ bool StartNfcPolling();
+
+ /// Stop searching for nfc tags
+ bool StopNfcPolling();
+
+ /// Returns true if the nfc tag was readable
+ bool ReadAmiiboData(std::vector<u8>& data);
+
/// Returns true if the nfc tag was written
bool WriteNfc(const std::vector<u8>& data);
+ /// Returns true if the nfc tag was readable
+ bool ReadMifareData(const Common::Input::MifareRequest& request,
+ Common::Input::MifareRequest& out_data);
+
+ /// Returns true if the nfc tag was written
+ bool WriteMifareData(const Common::Input::MifareRequest& request);
+
/// Returns the led pattern corresponding to this emulated controller
LedPattern GetLedPattern() const;
/// Asks the output device to change the player led pattern
void SetLedPattern();
+ /// Changes sensitivity of the motion sensor
+ void SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode mode);
+
/**
* Adds a callback to the list of events
* @param update_callback A ConsoleUpdateCallback that will be triggered
@@ -378,6 +437,9 @@ public:
*/
void DeleteCallback(int key);
+ /// Swaps the state of the turbo buttons and updates motion input
+ void StatusUpdate();
+
private:
/// creates input devices from params
void LoadDevices();
@@ -433,9 +495,16 @@ private:
void SetMotion(const Common::Input::CallbackStatus& callback, std::size_t index);
/**
+ * Updates the color status of the controller
+ * @param callback A CallbackStatus containing the color status
+ * @param index color ID of the to be updated
+ */
+ void SetColors(const Common::Input::CallbackStatus& callback, std::size_t index);
+
+ /**
* Updates the battery status of the controller
* @param callback A CallbackStatus containing the battery status
- * @param index Button ID of the to be updated
+ * @param index battery ID of the to be updated
*/
void SetBattery(const Common::Input::CallbackStatus& callback, std::size_t index);
@@ -446,6 +515,12 @@ private:
void SetCamera(const Common::Input::CallbackStatus& callback);
/**
+ * Updates the ring analog sensor status of the ring controller
+ * @param callback A CallbackStatus containing the force status
+ */
+ void SetRingAnalog(const Common::Input::CallbackStatus& callback);
+
+ /**
* Updates the nfc status of the controller
* @param callback A CallbackStatus containing the nfc status
*/
@@ -465,6 +540,8 @@ private:
*/
void TriggerOnChange(ControllerTriggerType type, bool is_service_update);
+ NpadButton GetTurboButtonMask() const;
+
const NpadIdType npad_id_type;
NpadStyleIndex npad_type{NpadStyleIndex::None};
NpadStyleIndex original_npad_type{NpadStyleIndex::None};
@@ -472,8 +549,9 @@ private:
bool is_connected{false};
bool is_configuring{false};
bool system_buttons_enabled{true};
- f32 motion_sensitivity{0.01f};
- bool force_update_motion{false};
+ f32 motion_sensitivity{Core::HID::MotionInput::IsAtRestStandard};
+ u32 turbo_button_state{0};
+ std::size_t nfc_handles{0};
// Temporary values to avoid doing changes while the controller is in configuring mode
NpadStyleIndex tmp_npad_type{NpadStyleIndex::None};
@@ -484,7 +562,9 @@ private:
ControllerMotionParams motion_params;
TriggerParams trigger_params;
BatteryParams battery_params;
+ ColorParams color_params;
CameraParams camera_params;
+ RingAnalogParams ring_params;
NfcParams nfc_params;
OutputParams output_params;
@@ -493,7 +573,9 @@ private:
ControllerMotionDevices motion_devices;
TriggerDevices trigger_devices;
BatteryDevices battery_devices;
+ ColorDevices color_devices;
CameraDevices camera_devices;
+ RingAnalogDevices ring_analog_devices;
NfcDevices nfc_devices;
OutputDevices output_devices;
@@ -506,8 +588,10 @@ private:
// Virtual gamepad related variables
ButtonParams virtual_button_params;
StickParams virtual_stick_params;
+ ControllerMotionParams virtual_motion_params;
ButtonDevices virtual_button_devices;
StickDevices virtual_stick_devices;
+ ControllerMotionDevices virtual_motion_devices;
mutable std::mutex mutex;
mutable std::mutex callback_mutex;
diff --git a/src/core/hid/emulated_devices.cpp b/src/core/hid/emulated_devices.cpp
index e421828d2..8e165dded 100644
--- a/src/core/hid/emulated_devices.cpp
+++ b/src/core/hid/emulated_devices.cpp
@@ -14,60 +14,61 @@ EmulatedDevices::EmulatedDevices() = default;
EmulatedDevices::~EmulatedDevices() = default;
void EmulatedDevices::ReloadFromSettings() {
- ring_params = Common::ParamPackage(Settings::values.ringcon_analogs);
ReloadInput();
}
void EmulatedDevices::ReloadInput() {
// If you load any device here add the equivalent to the UnloadInput() function
+
+ // Native Mouse is mapped on port 1, pad 0
+ const Common::ParamPackage mouse_params{"engine:mouse,port:1,pad:0"};
+
+ // Keyboard keys is mapped on port 1, pad 0 for normal keys, pad 1 for moddifier keys
+ const Common::ParamPackage keyboard_params{"engine:keyboard,port:1"};
+
std::size_t key_index = 0;
for (auto& mouse_device : mouse_button_devices) {
- Common::ParamPackage mouse_params;
- mouse_params.Set("engine", "mouse");
- mouse_params.Set("button", static_cast<int>(key_index));
- mouse_device = Common::Input::CreateInputDevice(mouse_params);
+ Common::ParamPackage mouse_button_params = mouse_params;
+ mouse_button_params.Set("button", static_cast<int>(key_index));
+ mouse_device = Common::Input::CreateInputDevice(mouse_button_params);
key_index++;
}
- mouse_stick_device =
- Common::Input::CreateInputDeviceFromString("engine:mouse,axis_x:0,axis_y:1");
+ Common::ParamPackage mouse_position_params = mouse_params;
+ mouse_position_params.Set("axis_x", 0);
+ mouse_position_params.Set("axis_y", 1);
+ mouse_position_params.Set("deadzone", 0.0f);
+ mouse_position_params.Set("range", 1.0f);
+ mouse_position_params.Set("threshold", 0.0f);
+ mouse_stick_device = Common::Input::CreateInputDevice(mouse_position_params);
// First two axis are reserved for mouse position
key_index = 2;
- for (auto& mouse_device : mouse_analog_devices) {
- Common::ParamPackage mouse_params;
- mouse_params.Set("engine", "mouse");
- mouse_params.Set("axis", static_cast<int>(key_index));
- mouse_device = Common::Input::CreateInputDevice(mouse_params);
+ for (auto& mouse_device : mouse_wheel_devices) {
+ Common::ParamPackage mouse_wheel_params = mouse_params;
+ mouse_wheel_params.Set("axis", static_cast<int>(key_index));
+ mouse_device = Common::Input::CreateInputDevice(mouse_wheel_params);
key_index++;
}
key_index = 0;
for (auto& keyboard_device : keyboard_devices) {
- // Keyboard keys are only mapped on port 1, pad 0
- Common::ParamPackage keyboard_params;
- keyboard_params.Set("engine", "keyboard");
- keyboard_params.Set("button", static_cast<int>(key_index));
- keyboard_params.Set("port", 1);
- keyboard_params.Set("pad", 0);
- keyboard_device = Common::Input::CreateInputDevice(keyboard_params);
+ Common::ParamPackage keyboard_key_params = keyboard_params;
+ keyboard_key_params.Set("button", static_cast<int>(key_index));
+ keyboard_key_params.Set("pad", 0);
+ keyboard_device = Common::Input::CreateInputDevice(keyboard_key_params);
key_index++;
}
key_index = 0;
for (auto& keyboard_device : keyboard_modifier_devices) {
- // Keyboard moddifiers are only mapped on port 1, pad 1
- Common::ParamPackage keyboard_params;
- keyboard_params.Set("engine", "keyboard");
- keyboard_params.Set("button", static_cast<int>(key_index));
- keyboard_params.Set("port", 1);
- keyboard_params.Set("pad", 1);
- keyboard_device = Common::Input::CreateInputDevice(keyboard_params);
+ Common::ParamPackage keyboard_moddifier_params = keyboard_params;
+ keyboard_moddifier_params.Set("button", static_cast<int>(key_index));
+ keyboard_moddifier_params.Set("pad", 1);
+ keyboard_device = Common::Input::CreateInputDevice(keyboard_moddifier_params);
key_index++;
}
- ring_analog_device = Common::Input::CreateInputDevice(ring_params);
-
for (std::size_t index = 0; index < mouse_button_devices.size(); ++index) {
if (!mouse_button_devices[index]) {
continue;
@@ -80,14 +81,14 @@ void EmulatedDevices::ReloadInput() {
});
}
- for (std::size_t index = 0; index < mouse_analog_devices.size(); ++index) {
- if (!mouse_analog_devices[index]) {
+ for (std::size_t index = 0; index < mouse_wheel_devices.size(); ++index) {
+ if (!mouse_wheel_devices[index]) {
continue;
}
- mouse_analog_devices[index]->SetCallback({
+ mouse_wheel_devices[index]->SetCallback({
.on_change =
[this, index](const Common::Input::CallbackStatus& callback) {
- SetMouseAnalog(callback, index);
+ SetMouseWheel(callback, index);
},
});
}
@@ -95,7 +96,9 @@ void EmulatedDevices::ReloadInput() {
if (mouse_stick_device) {
mouse_stick_device->SetCallback({
.on_change =
- [this](const Common::Input::CallbackStatus& callback) { SetMouseStick(callback); },
+ [this](const Common::Input::CallbackStatus& callback) {
+ SetMousePosition(callback);
+ },
});
}
@@ -122,20 +125,13 @@ void EmulatedDevices::ReloadInput() {
},
});
}
-
- if (ring_analog_device) {
- ring_analog_device->SetCallback({
- .on_change =
- [this](const Common::Input::CallbackStatus& callback) { SetRingAnalog(callback); },
- });
- }
}
void EmulatedDevices::UnloadInput() {
for (auto& button : mouse_button_devices) {
button.reset();
}
- for (auto& analog : mouse_analog_devices) {
+ for (auto& analog : mouse_wheel_devices) {
analog.reset();
}
mouse_stick_device.reset();
@@ -145,7 +141,6 @@ void EmulatedDevices::UnloadInput() {
for (auto& button : keyboard_modifier_devices) {
button.reset();
}
- ring_analog_device.reset();
}
void EmulatedDevices::EnableConfiguration() {
@@ -165,7 +160,6 @@ void EmulatedDevices::SaveCurrentConfig() {
if (!is_configuring) {
return;
}
- Settings::values.ringcon_analogs = ring_params.Serialize();
}
void EmulatedDevices::RestoreConfig() {
@@ -175,15 +169,6 @@ void EmulatedDevices::RestoreConfig() {
ReloadFromSettings();
}
-Common::ParamPackage EmulatedDevices::GetRingParam() const {
- return ring_params;
-}
-
-void EmulatedDevices::SetRingParam(Common::ParamPackage param) {
- ring_params = std::move(param);
- ReloadInput();
-}
-
void EmulatedDevices::SetKeyboardButton(const Common::Input::CallbackStatus& callback,
std::size_t index) {
if (index >= device_status.keyboard_values.size()) {
@@ -380,18 +365,18 @@ void EmulatedDevices::SetMouseButton(const Common::Input::CallbackStatus& callba
TriggerOnChange(DeviceTriggerType::Mouse);
}
-void EmulatedDevices::SetMouseAnalog(const Common::Input::CallbackStatus& callback,
- std::size_t index) {
- if (index >= device_status.mouse_analog_values.size()) {
+void EmulatedDevices::SetMouseWheel(const Common::Input::CallbackStatus& callback,
+ std::size_t index) {
+ if (index >= device_status.mouse_wheel_values.size()) {
return;
}
std::unique_lock lock{mutex};
const auto analog_value = TransformToAnalog(callback);
- device_status.mouse_analog_values[index] = analog_value;
+ device_status.mouse_wheel_values[index] = analog_value;
if (is_configuring) {
- device_status.mouse_position_state = {};
+ device_status.mouse_wheel_state = {};
lock.unlock();
TriggerOnChange(DeviceTriggerType::Mouse);
return;
@@ -410,7 +395,7 @@ void EmulatedDevices::SetMouseAnalog(const Common::Input::CallbackStatus& callba
TriggerOnChange(DeviceTriggerType::Mouse);
}
-void EmulatedDevices::SetMouseStick(const Common::Input::CallbackStatus& callback) {
+void EmulatedDevices::SetMousePosition(const Common::Input::CallbackStatus& callback) {
std::unique_lock lock{mutex};
const auto touch_value = TransformToTouch(callback);
@@ -430,23 +415,6 @@ void EmulatedDevices::SetMouseStick(const Common::Input::CallbackStatus& callbac
TriggerOnChange(DeviceTriggerType::Mouse);
}
-void EmulatedDevices::SetRingAnalog(const Common::Input::CallbackStatus& callback) {
- std::lock_guard lock{mutex};
- const auto force_value = TransformToStick(callback);
-
- device_status.ring_analog_value = force_value.x;
-
- if (is_configuring) {
- device_status.ring_analog_value = {};
- TriggerOnChange(DeviceTriggerType::RingController);
- return;
- }
-
- device_status.ring_analog_state.force = force_value.x.value;
-
- TriggerOnChange(DeviceTriggerType::RingController);
-}
-
KeyboardValues EmulatedDevices::GetKeyboardValues() const {
std::scoped_lock lock{mutex};
return device_status.keyboard_values;
@@ -462,10 +430,6 @@ MouseButtonValues EmulatedDevices::GetMouseButtonsValues() const {
return device_status.mouse_button_values;
}
-RingAnalogValue EmulatedDevices::GetRingSensorValues() const {
- return device_status.ring_analog_value;
-}
-
KeyboardKey EmulatedDevices::GetKeyboard() const {
std::scoped_lock lock{mutex};
return device_status.keyboard_state;
@@ -491,10 +455,6 @@ AnalogStickState EmulatedDevices::GetMouseWheel() const {
return device_status.mouse_wheel_state;
}
-RingSensorForce EmulatedDevices::GetRingSensorForce() const {
- return device_status.ring_analog_state;
-}
-
void EmulatedDevices::TriggerOnChange(DeviceTriggerType type) {
std::scoped_lock lock{callback_mutex};
for (const auto& poller_pair : callback_list) {
diff --git a/src/core/hid/emulated_devices.h b/src/core/hid/emulated_devices.h
index 4cdbf9dc6..5eab693e4 100644
--- a/src/core/hid/emulated_devices.h
+++ b/src/core/hid/emulated_devices.h
@@ -23,14 +23,12 @@ using KeyboardModifierDevices = std::array<std::unique_ptr<Common::Input::InputD
Settings::NativeKeyboard::NumKeyboardMods>;
using MouseButtonDevices = std::array<std::unique_ptr<Common::Input::InputDevice>,
Settings::NativeMouseButton::NumMouseButtons>;
-using MouseAnalogDevices = std::array<std::unique_ptr<Common::Input::InputDevice>,
- Settings::NativeMouseWheel::NumMouseWheels>;
+using MouseWheelDevices = std::array<std::unique_ptr<Common::Input::InputDevice>,
+ Settings::NativeMouseWheel::NumMouseWheels>;
using MouseStickDevice = std::unique_ptr<Common::Input::InputDevice>;
-using RingAnalogDevice = std::unique_ptr<Common::Input::InputDevice>;
using MouseButtonParams =
std::array<Common::ParamPackage, Settings::NativeMouseButton::NumMouseButtons>;
-using RingAnalogParams = Common::ParamPackage;
using KeyboardValues =
std::array<Common::Input::ButtonStatus, Settings::NativeKeyboard::NumKeyboardKeys>;
@@ -38,36 +36,29 @@ using KeyboardModifierValues =
std::array<Common::Input::ButtonStatus, Settings::NativeKeyboard::NumKeyboardMods>;
using MouseButtonValues =
std::array<Common::Input::ButtonStatus, Settings::NativeMouseButton::NumMouseButtons>;
-using MouseAnalogValues =
+using MouseWheelValues =
std::array<Common::Input::AnalogStatus, Settings::NativeMouseWheel::NumMouseWheels>;
using MouseStickValue = Common::Input::TouchStatus;
-using RingAnalogValue = Common::Input::AnalogStatus;
struct MousePosition {
f32 x;
f32 y;
};
-struct RingSensorForce {
- f32 force;
-};
-
struct DeviceStatus {
// Data from input_common
KeyboardValues keyboard_values{};
KeyboardModifierValues keyboard_moddifier_values{};
MouseButtonValues mouse_button_values{};
- MouseAnalogValues mouse_analog_values{};
+ MouseWheelValues mouse_wheel_values{};
MouseStickValue mouse_stick_value{};
- RingAnalogValue ring_analog_value{};
- // Data for HID serices
+ // Data for HID services
KeyboardKey keyboard_state{};
KeyboardModifier keyboard_moddifier_state{};
MouseButton mouse_button_state{};
MousePosition mouse_position_state{};
AnalogStickState mouse_wheel_state{};
- RingSensorForce ring_analog_state{};
};
enum class DeviceTriggerType {
@@ -84,7 +75,7 @@ struct InterfaceUpdateCallback {
class EmulatedDevices {
public:
/**
- * Contains all input data related to external devices that aren't necesarily a controller
+ * Contains all input data related to external devices that aren't necessarily a controller
* This includes devices such as the keyboard or mouse
*/
explicit EmulatedDevices();
@@ -120,15 +111,6 @@ public:
/// Reverts any mapped changes made that weren't saved
void RestoreConfig();
- // Returns the current mapped ring device
- Common::ParamPackage GetRingParam() const;
-
- /**
- * Updates the current mapped ring device
- * @param param ParamPackage with ring sensor data to be mapped
- */
- void SetRingParam(Common::ParamPackage param);
-
/// Returns the latest status of button input from the keyboard with parameters
KeyboardValues GetKeyboardValues() const;
@@ -138,9 +120,6 @@ public:
/// Returns the latest status of button input from the mouse with parameters
MouseButtonValues GetMouseButtonsValues() const;
- /// Returns the latest status of analog input from the ring sensor with parameters
- RingAnalogValue GetRingSensorValues() const;
-
/// Returns the latest status of button input from the keyboard
KeyboardKey GetKeyboard() const;
@@ -156,9 +135,6 @@ public:
/// Returns the latest mouse wheel change
AnalogStickState GetMouseWheel() const;
- /// Returns the latest ringcon force sensor value
- RingSensorForce GetRingSensorForce() const;
-
/**
* Adds a callback to the list of events
* @param update_callback InterfaceUpdateCallback that will be triggered
@@ -202,19 +178,13 @@ private:
* @param callback A CallbackStatus containing the wheel status
* @param index wheel ID to be updated
*/
- void SetMouseAnalog(const Common::Input::CallbackStatus& callback, std::size_t index);
+ void SetMouseWheel(const Common::Input::CallbackStatus& callback, std::size_t index);
/**
* Updates the mouse position status of the mouse device
* @param callback A CallbackStatus containing the position status
*/
- void SetMouseStick(const Common::Input::CallbackStatus& callback);
-
- /**
- * Updates the ring analog sensor status of the ring controller
- * @param callback A CallbackStatus containing the force status
- */
- void SetRingAnalog(const Common::Input::CallbackStatus& callback);
+ void SetMousePosition(const Common::Input::CallbackStatus& callback);
/**
* Triggers a callback that something has changed on the device status
@@ -224,14 +194,11 @@ private:
bool is_configuring{false};
- RingAnalogParams ring_params;
-
KeyboardDevices keyboard_devices;
KeyboardModifierDevices keyboard_modifier_devices;
MouseButtonDevices mouse_button_devices;
- MouseAnalogDevices mouse_analog_devices;
+ MouseWheelDevices mouse_wheel_devices;
MouseStickDevice mouse_stick_device;
- RingAnalogDevice ring_analog_device;
mutable std::mutex mutex;
mutable std::mutex callback_mutex;
diff --git a/src/core/hid/hid_types.h b/src/core/hid/hid_types.h
index e3b1cfbc6..6b35f448c 100644
--- a/src/core/hid/hid_types.h
+++ b/src/core/hid/hid_types.h
@@ -282,6 +282,13 @@ enum class VibrationGcErmCommand : u64 {
StopHard = 2,
};
+// This is nn::hid::GyroscopeZeroDriftMode
+enum class GyroscopeZeroDriftMode : u32 {
+ Loose = 0,
+ Standard = 1,
+ Tight = 2,
+};
+
// This is nn::hid::NpadStyleTag
struct NpadStyleTag {
union {
diff --git a/src/core/hid/input_converter.cpp b/src/core/hid/input_converter.cpp
index 502692875..a05716fd8 100644
--- a/src/core/hid/input_converter.cpp
+++ b/src/core/hid/input_converter.cpp
@@ -54,6 +54,7 @@ Common::Input::ButtonStatus TransformToButton(const Common::Input::CallbackStatu
case Common::Input::InputType::Analog:
status.value = TransformToTrigger(callback).pressed.value;
status.toggle = callback.analog_status.properties.toggle;
+ status.inverted = callback.analog_status.properties.inverted_button;
break;
case Common::Input::InputType::Trigger:
status.value = TransformToTrigger(callback).pressed.value;
@@ -61,6 +62,9 @@ Common::Input::ButtonStatus TransformToButton(const Common::Input::CallbackStatu
case Common::Input::InputType::Button:
status = callback.button_status;
break;
+ case Common::Input::InputType::Motion:
+ status.value = std::abs(callback.motion_status.gyro.x.raw_value) > 1.0f;
+ break;
default:
LOG_ERROR(Input, "Conversion from type {} to button not implemented", callback.type);
break;
@@ -82,7 +86,7 @@ Common::Input::MotionStatus TransformToMotion(const Common::Input::CallbackStatu
.range = 1.0f,
.offset = 0.0f,
};
- status.delta_timestamp = 5000;
+ status.delta_timestamp = 1000;
status.force_update = true;
status.accel.x = {
.value = 0.0f,
@@ -226,6 +230,10 @@ Common::Input::TriggerStatus TransformToTrigger(const Common::Input::CallbackSta
status = callback.trigger_status;
calculate_button_value = false;
break;
+ case Common::Input::InputType::Motion:
+ status.analog.properties.range = 1.0f;
+ raw_value = callback.motion_status.accel.x.raw_value;
+ break;
default:
LOG_ERROR(Input, "Conversion from type {} to trigger not implemented", callback.type);
break;
@@ -291,11 +299,7 @@ Common::Input::NfcStatus TransformToNfc(const Common::Input::CallbackStatus& cal
Common::Input::NfcStatus nfc{};
switch (callback.type) {
case Common::Input::InputType::Nfc:
- nfc = {
- .state = callback.nfc_status,
- .data = callback.raw_data,
- };
- break;
+ return callback.nfc_status;
default:
LOG_ERROR(Input, "Conversion from type {} to NFC not implemented", callback.type);
break;
@@ -304,6 +308,18 @@ Common::Input::NfcStatus TransformToNfc(const Common::Input::CallbackStatus& cal
return nfc;
}
+Common::Input::BodyColorStatus TransformToColor(const Common::Input::CallbackStatus& callback) {
+ switch (callback.type) {
+ case Common::Input::InputType::Color:
+ return callback.color_status;
+ break;
+ default:
+ LOG_ERROR(Input, "Conversion from type {} to color not implemented", callback.type);
+ return {};
+ break;
+ }
+}
+
void SanitizeAnalog(Common::Input::AnalogStatus& analog, bool clamp_value) {
const auto& properties = analog.properties;
float& raw_value = analog.raw_value;
@@ -316,7 +332,7 @@ void SanitizeAnalog(Common::Input::AnalogStatus& analog, bool clamp_value) {
// Apply center offset
raw_value -= properties.offset;
- // Set initial values to be formated
+ // Set initial values to be formatted
value = raw_value;
// Calculate vector size
@@ -386,7 +402,7 @@ void SanitizeStick(Common::Input::AnalogStatus& analog_x, Common::Input::AnalogS
raw_x = properties_x.inverted ? -raw_x : raw_x;
raw_y = properties_y.inverted ? -raw_y : raw_y;
- // Set initial values to be formated
+ // Set initial values to be formatted
x = raw_x;
y = raw_y;
diff --git a/src/core/hid/input_converter.h b/src/core/hid/input_converter.h
index b7eb6e660..c51c03e57 100644
--- a/src/core/hid/input_converter.h
+++ b/src/core/hid/input_converter.h
@@ -88,11 +88,19 @@ Common::Input::CameraStatus TransformToCamera(const Common::Input::CallbackStatu
* Converts raw input data into a valid nfc status.
*
* @param callback Supported callbacks: Nfc.
- * @return A valid CameraObject object.
+ * @return A valid data tag vector.
*/
Common::Input::NfcStatus TransformToNfc(const Common::Input::CallbackStatus& callback);
/**
+ * Converts raw input data into a valid color status.
+ *
+ * @param callback Supported callbacks: Color.
+ * @return A valid Color object.
+ */
+Common::Input::BodyColorStatus TransformToColor(const Common::Input::CallbackStatus& callback);
+
+/**
* Converts raw analog data into a valid analog value
* @param analog An analog object containing raw data and properties
* @param clamp_value determines if the value needs to be clamped between -1.0f and 1.0f.
diff --git a/src/core/hid/motion_input.cpp b/src/core/hid/motion_input.cpp
index b1f658e62..f56f2ae1d 100644
--- a/src/core/hid/motion_input.cpp
+++ b/src/core/hid/motion_input.cpp
@@ -1,6 +1,8 @@
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
+#include <cmath>
+
#include "common/math_util.h"
#include "core/hid/motion_input.h"
@@ -9,7 +11,9 @@ namespace Core::HID {
MotionInput::MotionInput() {
// Initialize PID constants with default values
SetPID(0.3f, 0.005f, 0.0f);
- SetGyroThreshold(0.007f);
+ SetGyroThreshold(ThresholdStandard);
+ ResetQuaternion();
+ ResetRotations();
}
void MotionInput::SetPID(f32 new_kp, f32 new_ki, f32 new_kd) {
@@ -20,17 +24,31 @@ void MotionInput::SetPID(f32 new_kp, f32 new_ki, f32 new_kd) {
void MotionInput::SetAcceleration(const Common::Vec3f& acceleration) {
accel = acceleration;
+
+ accel.x = std::clamp(accel.x, -AccelMaxValue, AccelMaxValue);
+ accel.y = std::clamp(accel.y, -AccelMaxValue, AccelMaxValue);
+ accel.z = std::clamp(accel.z, -AccelMaxValue, AccelMaxValue);
}
void MotionInput::SetGyroscope(const Common::Vec3f& gyroscope) {
gyro = gyroscope - gyro_bias;
- // Auto adjust drift to minimize drift
- if (!IsMoving(0.1f)) {
+ gyro.x = std::clamp(gyro.x, -GyroMaxValue, GyroMaxValue);
+ gyro.y = std::clamp(gyro.y, -GyroMaxValue, GyroMaxValue);
+ gyro.z = std::clamp(gyro.z, -GyroMaxValue, GyroMaxValue);
+
+ // Auto adjust gyro_bias to minimize drift
+ if (!IsMoving(IsAtRestRelaxed)) {
gyro_bias = (gyro_bias * 0.9999f) + (gyroscope * 0.0001f);
}
- if (gyro.Length() < gyro_threshold) {
+ // Adjust drift when calibration mode is enabled
+ if (calibration_mode) {
+ gyro_bias = (gyro_bias * 0.99f) + (gyroscope * 0.01f);
+ StopCalibration();
+ }
+
+ if (gyro.Length() < gyro_threshold * user_gyro_threshold) {
gyro = {};
} else {
only_accelerometer = false;
@@ -41,6 +59,20 @@ void MotionInput::SetQuaternion(const Common::Quaternion<f32>& quaternion) {
quat = quaternion;
}
+void MotionInput::SetEulerAngles(const Common::Vec3f& euler_angles) {
+ const float cr = std::cos(euler_angles.x * 0.5f);
+ const float sr = std::sin(euler_angles.x * 0.5f);
+ const float cp = std::cos(euler_angles.y * 0.5f);
+ const float sp = std::sin(euler_angles.y * 0.5f);
+ const float cy = std::cos(euler_angles.z * 0.5f);
+ const float sy = std::sin(euler_angles.z * 0.5f);
+
+ quat.w = cr * cp * cy + sr * sp * sy;
+ quat.xyz.x = sr * cp * cy - cr * sp * sy;
+ quat.xyz.y = cr * sp * cy + sr * cp * sy;
+ quat.xyz.z = cr * cp * sy - sr * sp * cy;
+}
+
void MotionInput::SetGyroBias(const Common::Vec3f& bias) {
gyro_bias = bias;
}
@@ -49,6 +81,10 @@ void MotionInput::SetGyroThreshold(f32 threshold) {
gyro_threshold = threshold;
}
+void MotionInput::SetUserGyroThreshold(f32 threshold) {
+ user_gyro_threshold = threshold / ThresholdStandard;
+}
+
void MotionInput::EnableReset(bool reset) {
reset_enabled = reset;
}
@@ -57,6 +93,10 @@ void MotionInput::ResetRotations() {
rotations = {};
}
+void MotionInput::ResetQuaternion() {
+ quat = {{0.0f, 0.0f, -1.0f}, 0.0f};
+}
+
bool MotionInput::IsMoving(f32 sensitivity) const {
return gyro.Length() >= sensitivity || accel.Length() <= 0.9f || accel.Length() >= 1.1f;
}
@@ -73,6 +113,19 @@ void MotionInput::UpdateRotation(u64 elapsed_time) {
rotations += gyro * sample_period;
}
+void MotionInput::Calibrate() {
+ calibration_mode = true;
+ calibration_counter = 0;
+}
+
+void MotionInput::StopCalibration() {
+ if (calibration_counter++ > CalibrationSamples) {
+ calibration_mode = false;
+ ResetQuaternion();
+ ResetRotations();
+ }
+}
+
// Based on Madgwick's implementation of Mayhony's AHRS algorithm.
// https://github.com/xioTechnologies/Open-Source-AHRS-With-x-IMU/blob/master/x-IMU%20IMU%20and%20AHRS%20Algorithms/x-IMU%20IMU%20and%20AHRS%20Algorithms/AHRS/MahonyAHRS.cs
void MotionInput::UpdateOrientation(u64 elapsed_time) {
@@ -204,11 +257,31 @@ Common::Vec3f MotionInput::GetRotations() const {
return rotations;
}
+Common::Vec3f MotionInput::GetEulerAngles() const {
+ // roll (x-axis rotation)
+ const float sinr_cosp = 2 * (quat.w * quat.xyz.x + quat.xyz.y * quat.xyz.z);
+ const float cosr_cosp = 1 - 2 * (quat.xyz.x * quat.xyz.x + quat.xyz.y * quat.xyz.y);
+
+ // pitch (y-axis rotation)
+ const float sinp = std::sqrt(1 + 2 * (quat.w * quat.xyz.y - quat.xyz.x * quat.xyz.z));
+ const float cosp = std::sqrt(1 - 2 * (quat.w * quat.xyz.y - quat.xyz.x * quat.xyz.z));
+
+ // yaw (z-axis rotation)
+ const float siny_cosp = 2 * (quat.w * quat.xyz.z + quat.xyz.x * quat.xyz.y);
+ const float cosy_cosp = 1 - 2 * (quat.xyz.y * quat.xyz.y + quat.xyz.z * quat.xyz.z);
+
+ return {
+ std::atan2(sinr_cosp, cosr_cosp),
+ 2 * std::atan2(sinp, cosp) - Common::PI / 2,
+ std::atan2(siny_cosp, cosy_cosp),
+ };
+}
+
void MotionInput::ResetOrientation() {
if (!reset_enabled || only_accelerometer) {
return;
}
- if (!IsMoving(0.5f) && accel.z <= -0.9f) {
+ if (!IsMoving(IsAtRestRelaxed) && accel.z <= -0.9f) {
++reset_counter;
if (reset_counter > 900) {
quat.w = 0;
diff --git a/src/core/hid/motion_input.h b/src/core/hid/motion_input.h
index f5fd90db5..11678983d 100644
--- a/src/core/hid/motion_input.h
+++ b/src/core/hid/motion_input.h
@@ -11,6 +11,20 @@ namespace Core::HID {
class MotionInput {
public:
+ static constexpr float ThresholdLoose = 0.01f;
+ static constexpr float ThresholdStandard = 0.007f;
+ static constexpr float ThresholdThight = 0.002f;
+
+ static constexpr float IsAtRestRelaxed = 0.05f;
+ static constexpr float IsAtRestLoose = 0.02f;
+ static constexpr float IsAtRestStandard = 0.01f;
+ static constexpr float IsAtRestThight = 0.005f;
+
+ static constexpr float GyroMaxValue = 5.0f;
+ static constexpr float AccelMaxValue = 7.0f;
+
+ static constexpr std::size_t CalibrationSamples = 300;
+
explicit MotionInput();
MotionInput(const MotionInput&) = default;
@@ -23,26 +37,35 @@ public:
void SetAcceleration(const Common::Vec3f& acceleration);
void SetGyroscope(const Common::Vec3f& gyroscope);
void SetQuaternion(const Common::Quaternion<f32>& quaternion);
+ void SetEulerAngles(const Common::Vec3f& euler_angles);
void SetGyroBias(const Common::Vec3f& bias);
void SetGyroThreshold(f32 threshold);
+ /// Applies a modifier on top of the normal gyro threshold
+ void SetUserGyroThreshold(f32 threshold);
+
void EnableReset(bool reset);
void ResetRotations();
+ void ResetQuaternion();
void UpdateRotation(u64 elapsed_time);
void UpdateOrientation(u64 elapsed_time);
+ void Calibrate();
+
[[nodiscard]] std::array<Common::Vec3f, 3> GetOrientation() const;
[[nodiscard]] Common::Vec3f GetAcceleration() const;
[[nodiscard]] Common::Vec3f GetGyroscope() const;
[[nodiscard]] Common::Vec3f GetGyroBias() const;
[[nodiscard]] Common::Vec3f GetRotations() const;
[[nodiscard]] Common::Quaternion<f32> GetQuaternion() const;
+ [[nodiscard]] Common::Vec3f GetEulerAngles() const;
[[nodiscard]] bool IsMoving(f32 sensitivity) const;
[[nodiscard]] bool IsCalibrated(f32 sensitivity) const;
private:
+ void StopCalibration();
void ResetOrientation();
void SetOrientationFromAccelerometer();
@@ -57,7 +80,7 @@ private:
Common::Vec3f derivative_error;
// Quaternion containing the device orientation
- Common::Quaternion<f32> quat{{0.0f, 0.0f, -1.0f}, 0.0f};
+ Common::Quaternion<f32> quat;
// Number of full rotations in each axis
Common::Vec3f rotations;
@@ -68,12 +91,15 @@ private:
// Gyroscope vector measurement in radians/s.
Common::Vec3f gyro;
- // Vector to be substracted from gyro measurements
+ // Vector to be subtracted from gyro measurements
Common::Vec3f gyro_bias;
// Minimum gyro amplitude to detect if the device is moving
f32 gyro_threshold = 0.0f;
+ // Multiplies gyro_threshold by this value
+ f32 user_gyro_threshold = 0.0f;
+
// Number of invalid sequential data
u32 reset_counter = 0;
@@ -82,6 +108,12 @@ private:
// Use accelerometer values to calculate position
bool only_accelerometer = true;
+
+ // When enabled it will aggressively adjust for gyro drift
+ bool calibration_mode = false;
+
+ // Used to auto disable calibration mode
+ std::size_t calibration_counter = 0;
};
} // namespace Core::HID
diff --git a/src/core/hle/kernel/k_memory_layout.board.nintendo_nx.cpp b/src/core/hle/kernel/board/nintendo/nx/k_memory_layout.cpp
index 098ba6eac..24eb3f886 100644
--- a/src/core/hle/kernel/k_memory_layout.board.nintendo_nx.cpp
+++ b/src/core/hle/kernel/board/nintendo/nx/k_memory_layout.cpp
@@ -76,22 +76,24 @@ void SetupDevicePhysicalMemoryRegions(KMemoryLayout& memory_layout) {
void SetupDramPhysicalMemoryRegions(KMemoryLayout& memory_layout) {
const size_t intended_memory_size = KSystemControl::Init::GetIntendedMemorySize();
- const PAddr physical_memory_base_address =
+ const KPhysicalAddress physical_memory_base_address =
KSystemControl::Init::GetKernelPhysicalBaseAddress(DramPhysicalAddress);
// Insert blocks into the tree.
ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
- physical_memory_base_address, intended_memory_size, KMemoryRegionType_Dram));
+ GetInteger(physical_memory_base_address), intended_memory_size, KMemoryRegionType_Dram));
ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
- physical_memory_base_address, ReservedEarlyDramSize, KMemoryRegionType_DramReservedEarly));
+ GetInteger(physical_memory_base_address), ReservedEarlyDramSize,
+ KMemoryRegionType_DramReservedEarly));
// Insert the KTrace block at the end of Dram, if KTrace is enabled.
static_assert(!IsKTraceEnabled || KTraceBufferSize > 0);
if constexpr (IsKTraceEnabled) {
- const PAddr ktrace_buffer_phys_addr =
+ const KPhysicalAddress ktrace_buffer_phys_addr =
physical_memory_base_address + intended_memory_size - KTraceBufferSize;
ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
- ktrace_buffer_phys_addr, KTraceBufferSize, KMemoryRegionType_KernelTraceBuffer));
+ GetInteger(ktrace_buffer_phys_addr), KTraceBufferSize,
+ KMemoryRegionType_KernelTraceBuffer));
}
}
diff --git a/src/core/hle/kernel/board/nintendo/nx/k_memory_layout.h b/src/core/hle/kernel/board/nintendo/nx/k_memory_layout.h
index d02ee61c3..f8fee4f5b 100644
--- a/src/core/hle/kernel/board/nintendo/nx/k_memory_layout.h
+++ b/src/core/hle/kernel/board/nintendo/nx/k_memory_layout.h
@@ -3,10 +3,10 @@
#pragma once
-#include "common/common_types.h"
+#include "core/hle/kernel/k_typed_address.h"
namespace Kernel {
-constexpr inline PAddr MainMemoryAddress = 0x80000000;
+constexpr inline KPhysicalAddress MainMemoryAddress = 0x80000000;
} // namespace Kernel
diff --git a/src/core/hle/kernel/board/nintendo/nx/k_system_control.cpp b/src/core/hle/kernel/board/nintendo/nx/k_system_control.cpp
index c10b7bf30..49bdc671e 100644
--- a/src/core/hle/kernel/board/nintendo/nx/k_system_control.cpp
+++ b/src/core/hle/kernel/board/nintendo/nx/k_system_control.cpp
@@ -14,9 +14,12 @@ namespace Kernel::Board::Nintendo::Nx {
namespace impl {
-constexpr const std::size_t RequiredNonSecureSystemMemorySizeVi = 0x2238 * 4 * 1024;
-constexpr const std::size_t RequiredNonSecureSystemMemorySizeNvservices = 0x710 * 4 * 1024;
-constexpr const std::size_t RequiredNonSecureSystemMemorySizeMisc = 0x80 * 4 * 1024;
+using namespace Common::Literals;
+
+constexpr const std::size_t RequiredNonSecureSystemMemorySizeVi = 0x2280 * 4_KiB;
+constexpr const std::size_t RequiredNonSecureSystemMemorySizeViFatal = 0x200 * 4_KiB;
+constexpr const std::size_t RequiredNonSecureSystemMemorySizeNvservices = 0x704 * 4_KiB;
+constexpr const std::size_t RequiredNonSecureSystemMemorySizeMisc = 0x80 * 4_KiB;
} // namespace impl
@@ -24,17 +27,21 @@ constexpr const std::size_t RequiredNonSecureSystemMemorySize =
impl::RequiredNonSecureSystemMemorySizeVi + impl::RequiredNonSecureSystemMemorySizeNvservices +
impl::RequiredNonSecureSystemMemorySizeMisc;
+constexpr const std::size_t RequiredNonSecureSystemMemorySizeWithFatal =
+ RequiredNonSecureSystemMemorySize + impl::RequiredNonSecureSystemMemorySizeViFatal;
+
namespace {
using namespace Common::Literals;
u32 GetMemorySizeForInit() {
- return Settings::values.use_extended_memory_layout ? Smc::MemorySize_6GB : Smc::MemorySize_4GB;
+ return Settings::values.use_unsafe_extended_memory_layout ? Smc::MemorySize_8GB
+ : Smc::MemorySize_4GB;
}
Smc::MemoryArrangement GetMemoryArrangeForInit() {
- return Settings::values.use_extended_memory_layout ? Smc::MemoryArrangement_6GB
- : Smc::MemoryArrangement_4GB;
+ return Settings::values.use_unsafe_extended_memory_layout ? Smc::MemoryArrangement_8GB
+ : Smc::MemoryArrangement_4GB;
}
} // namespace
@@ -55,7 +62,7 @@ size_t KSystemControl::Init::GetIntendedMemorySize() {
}
}
-PAddr KSystemControl::Init::GetKernelPhysicalBaseAddress(u64 base_address) {
+KPhysicalAddress KSystemControl::Init::GetKernelPhysicalBaseAddress(KPhysicalAddress base_address) {
const size_t real_dram_size = KSystemControl::Init::GetRealMemorySize();
const size_t intended_dram_size = KSystemControl::Init::GetIntendedMemorySize();
if (intended_dram_size * 2 < real_dram_size) {
@@ -85,7 +92,8 @@ std::size_t KSystemControl::Init::GetApplicationPoolSize() {
case Smc::MemoryArrangement_6GBForAppletDev:
return 3285_MiB;
case Smc::MemoryArrangement_8GB:
- return 4916_MiB;
+ // Real kernel sets this to 4916_MiB. We are not debugging applets.
+ return 6547_MiB;
}
}();
@@ -109,7 +117,8 @@ size_t KSystemControl::Init::GetAppletPoolSize() {
case Smc::MemoryArrangement_6GBForAppletDev:
return 2193_MiB;
case Smc::MemoryArrangement_8GB:
- return 2193_MiB;
+ //! Real kernel sets this to 2193_MiB. We are not debugging applets.
+ return 562_MiB;
}
}();
@@ -120,10 +129,13 @@ size_t KSystemControl::Init::GetAppletPoolSize() {
size_t KSystemControl::Init::GetMinimumNonSecureSystemPoolSize() {
// Verify that our minimum is at least as large as Nintendo's.
- constexpr size_t MinimumSize = RequiredNonSecureSystemMemorySize;
- static_assert(MinimumSize >= 0x29C8000);
+ constexpr size_t MinimumSizeWithFatal = RequiredNonSecureSystemMemorySizeWithFatal;
+ static_assert(MinimumSizeWithFatal >= 0x2C04000);
+
+ constexpr size_t MinimumSizeWithoutFatal = RequiredNonSecureSystemMemorySize;
+ static_assert(MinimumSizeWithoutFatal >= 0x2A00000);
- return MinimumSize;
+ return MinimumSizeWithFatal;
}
namespace {
diff --git a/src/core/hle/kernel/board/nintendo/nx/k_system_control.h b/src/core/hle/kernel/board/nintendo/nx/k_system_control.h
index 4b717d091..b477e8193 100644
--- a/src/core/hle/kernel/board/nintendo/nx/k_system_control.h
+++ b/src/core/hle/kernel/board/nintendo/nx/k_system_control.h
@@ -3,7 +3,7 @@
#pragma once
-#include "common/common_types.h"
+#include "core/hle/kernel/k_typed_address.h"
namespace Kernel::Board::Nintendo::Nx {
@@ -18,7 +18,7 @@ public:
// Initialization.
static std::size_t GetRealMemorySize();
static std::size_t GetIntendedMemorySize();
- static PAddr GetKernelPhysicalBaseAddress(u64 base_address);
+ static KPhysicalAddress GetKernelPhysicalBaseAddress(KPhysicalAddress base_address);
static bool ShouldIncreaseThreadResourceLimit();
static std::size_t GetApplicationPoolSize();
static std::size_t GetAppletPoolSize();
diff --git a/src/core/hle/kernel/code_set.h b/src/core/hle/kernel/code_set.h
index 5220dbcb6..af1af2b78 100644
--- a/src/core/hle/kernel/code_set.h
+++ b/src/core/hle/kernel/code_set.h
@@ -5,7 +5,7 @@
#include <cstddef>
-#include "common/common_types.h"
+#include "core/hle/kernel/k_typed_address.h"
#include "core/hle/kernel/physical_memory.h"
namespace Kernel {
@@ -36,7 +36,7 @@ struct CodeSet final {
std::size_t offset = 0;
/// The address to map this segment to.
- VAddr addr = 0;
+ KProcessAddress addr = 0;
/// The size of this segment in bytes.
u32 size = 0;
@@ -82,7 +82,7 @@ struct CodeSet final {
std::array<Segment, 3> segments;
/// The entry point address for this code set.
- VAddr entrypoint = 0;
+ KProcessAddress entrypoint = 0;
};
} // namespace Kernel
diff --git a/src/core/hle/kernel/global_scheduler_context.cpp b/src/core/hle/kernel/global_scheduler_context.cpp
index fd911a3a5..7b090ccb5 100644
--- a/src/core/hle/kernel/global_scheduler_context.cpp
+++ b/src/core/hle/kernel/global_scheduler_context.cpp
@@ -12,20 +12,19 @@
namespace Kernel {
-GlobalSchedulerContext::GlobalSchedulerContext(KernelCore& kernel_)
- : kernel{kernel_}, scheduler_lock{kernel_} {}
+GlobalSchedulerContext::GlobalSchedulerContext(KernelCore& kernel)
+ : m_kernel{kernel}, m_scheduler_lock{kernel} {}
GlobalSchedulerContext::~GlobalSchedulerContext() = default;
void GlobalSchedulerContext::AddThread(KThread* thread) {
- std::scoped_lock lock{global_list_guard};
- thread_list.push_back(thread);
+ std::scoped_lock lock{m_global_list_guard};
+ m_thread_list.push_back(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());
+ std::scoped_lock lock{m_global_list_guard};
+ std::erase(m_thread_list, thread);
}
void GlobalSchedulerContext::PreemptThreads() {
@@ -38,37 +37,37 @@ void GlobalSchedulerContext::PreemptThreads() {
63,
};
- ASSERT(IsLocked());
+ ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(m_kernel));
for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) {
const u32 priority = preemption_priorities[core_id];
- KScheduler::RotateScheduledQueue(kernel, core_id, priority);
+ KScheduler::RotateScheduledQueue(m_kernel, core_id, priority);
}
}
bool GlobalSchedulerContext::IsLocked() const {
- return scheduler_lock.IsLockedByCurrentThread();
+ return m_scheduler_lock.IsLockedByCurrentThread();
}
void GlobalSchedulerContext::RegisterDummyThreadForWakeup(KThread* thread) {
- ASSERT(IsLocked());
+ ASSERT(this->IsLocked());
- woken_dummy_threads.insert(thread);
+ m_woken_dummy_threads.insert(thread);
}
void GlobalSchedulerContext::UnregisterDummyThreadForWakeup(KThread* thread) {
- ASSERT(IsLocked());
+ ASSERT(this->IsLocked());
- woken_dummy_threads.erase(thread);
+ m_woken_dummy_threads.erase(thread);
}
void GlobalSchedulerContext::WakeupWaitingDummyThreads() {
- ASSERT(IsLocked());
+ ASSERT(this->IsLocked());
- for (auto* thread : woken_dummy_threads) {
+ for (auto* thread : m_woken_dummy_threads) {
thread->DummyThreadEndWait();
}
- woken_dummy_threads.clear();
+ m_woken_dummy_threads.clear();
}
} // namespace Kernel
diff --git a/src/core/hle/kernel/global_scheduler_context.h b/src/core/hle/kernel/global_scheduler_context.h
index 220ed6192..c48e8cd12 100644
--- a/src/core/hle/kernel/global_scheduler_context.h
+++ b/src/core/hle/kernel/global_scheduler_context.h
@@ -33,7 +33,7 @@ class GlobalSchedulerContext final {
public:
using LockType = KAbstractSchedulerLock<KScheduler>;
- explicit GlobalSchedulerContext(KernelCore& kernel_);
+ explicit GlobalSchedulerContext(KernelCore& kernel);
~GlobalSchedulerContext();
/// Adds a new thread to the scheduler
@@ -43,8 +43,9 @@ public:
void RemoveThread(KThread* thread);
/// Returns a list of all threads managed by the scheduler
- [[nodiscard]] const std::vector<KThread*>& GetThreadList() const {
- return thread_list;
+ /// This is only safe to iterate while holding the scheduler lock
+ const std::vector<KThread*>& GetThreadList() const {
+ return m_thread_list;
}
/**
@@ -63,30 +64,26 @@ public:
void RegisterDummyThreadForWakeup(KThread* thread);
void WakeupWaitingDummyThreads();
- [[nodiscard]] LockType& SchedulerLock() {
- return scheduler_lock;
- }
-
- [[nodiscard]] const LockType& SchedulerLock() const {
- return scheduler_lock;
+ LockType& SchedulerLock() {
+ return m_scheduler_lock;
}
private:
friend class KScopedSchedulerLock;
friend class KScopedSchedulerLockAndSleep;
- KernelCore& kernel;
+ KernelCore& m_kernel;
- std::atomic_bool scheduler_update_needed{};
- KSchedulerPriorityQueue priority_queue;
- LockType scheduler_lock;
+ std::atomic_bool m_scheduler_update_needed{};
+ KSchedulerPriorityQueue m_priority_queue;
+ LockType m_scheduler_lock;
/// Lists dummy threads pending wakeup on lock release
- std::set<KThread*> woken_dummy_threads;
+ std::set<KThread*> m_woken_dummy_threads;
/// Lists all thread ids that aren't deleted/etc.
- std::vector<KThread*> thread_list;
- std::mutex global_list_guard;
+ std::vector<KThread*> m_thread_list;
+ std::mutex m_global_list_guard;
};
} // namespace Kernel
diff --git a/src/core/hle/kernel/init/init_slab_setup.cpp b/src/core/hle/kernel/init/init_slab_setup.cpp
index 7b363eb1e..1f2db673c 100644
--- a/src/core/hle/kernel/init/init_slab_setup.cpp
+++ b/src/core/hle/kernel/init/init_slab_setup.cpp
@@ -4,17 +4,18 @@
#include "common/alignment.h"
#include "common/assert.h"
#include "common/common_funcs.h"
-#include "common/common_types.h"
#include "core/core.h"
#include "core/device_memory.h"
#include "core/hardware_properties.h"
#include "core/hle/kernel/init/init_slab_setup.h"
#include "core/hle/kernel/k_code_memory.h"
#include "core/hle/kernel/k_debug.h"
+#include "core/hle/kernel/k_device_address_space.h"
#include "core/hle/kernel/k_event.h"
#include "core/hle/kernel/k_event_info.h"
#include "core/hle/kernel/k_memory_layout.h"
#include "core/hle/kernel/k_memory_manager.h"
+#include "core/hle/kernel/k_object_name.h"
#include "core/hle/kernel/k_page_buffer.h"
#include "core/hle/kernel/k_port.h"
#include "core/hle/kernel/k_process.h"
@@ -28,9 +29,13 @@
#include "core/hle/kernel/k_thread.h"
#include "core/hle/kernel/k_thread_local_page.h"
#include "core/hle/kernel/k_transfer_memory.h"
+#include "core/hle/kernel/k_typed_address.h"
namespace Kernel::Init {
+// For macro convenience.
+using KThreadLockInfo = KThread::LockWithPriorityInheritanceInfo;
+
#define SLAB_COUNT(CLASS) kernel.SlabResourceCounts().num_##CLASS
#define FOREACH_SLAB_TYPE(HANDLER, ...) \
@@ -43,14 +48,17 @@ namespace Kernel::Init {
HANDLER(KSharedMemoryInfo, (SLAB_COUNT(KSharedMemory) * 8), ##__VA_ARGS__) \
HANDLER(KTransferMemory, (SLAB_COUNT(KTransferMemory)), ##__VA_ARGS__) \
HANDLER(KCodeMemory, (SLAB_COUNT(KCodeMemory)), ##__VA_ARGS__) \
+ HANDLER(KDeviceAddressSpace, (SLAB_COUNT(KDeviceAddressSpace)), ##__VA_ARGS__) \
HANDLER(KSession, (SLAB_COUNT(KSession)), ##__VA_ARGS__) \
HANDLER(KThreadLocalPage, \
(SLAB_COUNT(KProcess) + (SLAB_COUNT(KProcess) + SLAB_COUNT(KThread)) / 8), \
##__VA_ARGS__) \
+ HANDLER(KObjectName, (SLAB_COUNT(KObjectName)), ##__VA_ARGS__) \
HANDLER(KResourceLimit, (SLAB_COUNT(KResourceLimit)), ##__VA_ARGS__) \
HANDLER(KEventInfo, (SLAB_COUNT(KThread) + SLAB_COUNT(KDebug)), ##__VA_ARGS__) \
HANDLER(KDebug, (SLAB_COUNT(KDebug)), ##__VA_ARGS__) \
- HANDLER(KSecureSystemResource, (SLAB_COUNT(KProcess)), ##__VA_ARGS__)
+ HANDLER(KSecureSystemResource, (SLAB_COUNT(KProcess)), ##__VA_ARGS__) \
+ HANDLER(KThreadLockInfo, (SLAB_COUNT(KThread)), ##__VA_ARGS__)
namespace {
@@ -96,17 +104,18 @@ static_assert(KernelPageBufferAdditionalSize ==
/// Helper function to translate from the slab virtual address to the reserved location in physical
/// memory.
-static PAddr TranslateSlabAddrToPhysical(KMemoryLayout& memory_layout, VAddr slab_addr) {
- slab_addr -= memory_layout.GetSlabRegionAddress();
- return slab_addr + Core::DramMemoryMap::SlabHeapBase;
+static KPhysicalAddress TranslateSlabAddrToPhysical(KMemoryLayout& memory_layout,
+ KVirtualAddress slab_addr) {
+ slab_addr -= GetInteger(memory_layout.GetSlabRegionAddress());
+ return GetInteger(slab_addr) + Core::DramMemoryMap::SlabHeapBase;
}
template <typename T>
-VAddr InitializeSlabHeap(Core::System& system, KMemoryLayout& memory_layout, VAddr address,
- size_t num_objects) {
+KVirtualAddress InitializeSlabHeap(Core::System& system, KMemoryLayout& memory_layout,
+ KVirtualAddress address, size_t num_objects) {
const size_t size = Common::AlignUp(sizeof(T) * num_objects, alignof(void*));
- VAddr start = Common::AlignUp(address, alignof(T));
+ KVirtualAddress start = Common::AlignUp(GetInteger(address), alignof(T));
// This should use the virtual memory address passed in, but currently, we do not setup the
// kernel virtual memory layout. Instead, we simply map these at a region of physical memory
@@ -127,7 +136,7 @@ VAddr InitializeSlabHeap(Core::System& system, KMemoryLayout& memory_layout, VAd
}
size_t CalculateSlabHeapGapSize() {
- constexpr size_t KernelSlabHeapGapSize = 2_MiB - 320_KiB;
+ constexpr size_t KernelSlabHeapGapSize = 2_MiB - 356_KiB;
static_assert(KernelSlabHeapGapSize <= KernelSlabHeapGapsSizeMax);
return KernelSlabHeapGapSize;
}
@@ -187,7 +196,7 @@ 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();
+ KVirtualAddress address = memory_layout.GetSlabRegionAddress();
// Initialize slab type array to be in sorted order.
std::array<KSlabType, KSlabType_Count> slab_types;
@@ -220,7 +229,7 @@ void InitializeSlabHeaps(Core::System& system, KMemoryLayout& memory_layout) {
}
// Track the gaps, so that we can free them to the unused slab tree.
- VAddr gap_start = address;
+ KVirtualAddress gap_start = address;
size_t gap_size = 0;
for (size_t i = 0; i < slab_gaps.size(); i++) {
@@ -272,7 +281,7 @@ void KPageBufferSlabHeap::Initialize(Core::System& system) {
// Allocate memory for the slab.
constexpr auto AllocateOption = KMemoryManager::EncodeOption(
KMemoryManager::Pool::System, KMemoryManager::Direction::FromFront);
- const PAddr slab_address =
+ const KPhysicalAddress slab_address =
kernel.MemoryManager().AllocateAndOpenContinuous(num_pages, 1, AllocateOption);
ASSERT(slab_address != 0);
diff --git a/src/core/hle/kernel/initial_process.h b/src/core/hle/kernel/initial_process.h
index af0fb23b6..82195f4f7 100644
--- a/src/core/hle/kernel/initial_process.h
+++ b/src/core/hle/kernel/initial_process.h
@@ -14,7 +14,7 @@ using namespace Common::Literals;
constexpr std::size_t InitialProcessBinarySizeMax = 12_MiB;
-static inline PAddr GetInitialProcessBinaryPhysicalAddress() {
+static inline KPhysicalAddress GetInitialProcessBinaryPhysicalAddress() {
return Kernel::Board::Nintendo::Nx::KSystemControl::Init::GetKernelPhysicalBaseAddress(
MainMemoryAddress);
}
diff --git a/src/core/hle/kernel/k_address_arbiter.cpp b/src/core/hle/kernel/k_address_arbiter.cpp
index a442a3b98..78d43d729 100644
--- a/src/core/hle/kernel/k_address_arbiter.cpp
+++ b/src/core/hle/kernel/k_address_arbiter.cpp
@@ -8,46 +8,57 @@
#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/k_typed_address.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/svc_results.h"
#include "core/memory.h"
namespace Kernel {
-KAddressArbiter::KAddressArbiter(Core::System& system_)
- : system{system_}, kernel{system.Kernel()} {}
+KAddressArbiter::KAddressArbiter(Core::System& system)
+ : m_system{system}, m_kernel{system.Kernel()} {}
KAddressArbiter::~KAddressArbiter() = default;
namespace {
-bool ReadFromUser(Core::System& system, s32* out, VAddr address) {
- *out = system.Memory().Read32(address);
+bool ReadFromUser(KernelCore& kernel, s32* out, KProcessAddress address) {
+ *out = GetCurrentMemory(kernel).Read32(GetInteger(address));
return true;
}
-bool DecrementIfLessThan(Core::System& system, s32* out, VAddr address, s32 value) {
+bool DecrementIfLessThan(Core::System& system, s32* out, KProcessAddress address, s32 value) {
auto& monitor = system.Monitor();
const auto current_core = system.Kernel().CurrentPhysicalCoreIndex();
- // TODO(bunnei): We should disable interrupts here via KScopedInterruptDisable.
+ // NOTE: If scheduler lock is not held here, interrupt disable is required.
+ // KScopedInterruptDisable di;
+
// TODO(bunnei): We should call CanAccessAtomic(..) here.
- // Load the value from the address.
- const s32 current_value = static_cast<s32>(monitor.ExclusiveRead32(current_core, address));
+ s32 current_value{};
+
+ while (true) {
+ // Load the value from the address.
+ current_value =
+ static_cast<s32>(monitor.ExclusiveRead32(current_core, GetInteger(address)));
+
+ // Compare it to the desired one.
+ if (current_value < value) {
+ // If less than, we want to try to decrement.
+ const s32 decrement_value = current_value - 1;
- // Compare it to the desired one.
- if (current_value < value) {
- // If less than, we want to try to decrement.
- const s32 decrement_value = current_value - 1;
+ // Decrement and try to store.
+ if (monitor.ExclusiveWrite32(current_core, GetInteger(address),
+ static_cast<u32>(decrement_value))) {
+ break;
+ }
- // Decrement and try to store.
- if (!monitor.ExclusiveWrite32(current_core, address, static_cast<u32>(decrement_value))) {
// If we failed to store, try again.
- DecrementIfLessThan(system, out, address, value);
+ } else {
+ // Otherwise, clear our exclusive hold and finish
+ monitor.ClearExclusive(current_core);
+ break;
}
- } else {
- // Otherwise, clear our exclusive hold and finish
- monitor.ClearExclusive(current_core);
}
// We're done.
@@ -55,28 +66,39 @@ bool DecrementIfLessThan(Core::System& system, s32* out, VAddr address, s32 valu
return true;
}
-bool UpdateIfEqual(Core::System& system, s32* out, VAddr address, s32 value, s32 new_value) {
+bool UpdateIfEqual(Core::System& system, s32* out, KProcessAddress address, s32 value,
+ s32 new_value) {
auto& monitor = system.Monitor();
const auto current_core = system.Kernel().CurrentPhysicalCoreIndex();
- // TODO(bunnei): We should disable interrupts here via KScopedInterruptDisable.
+ // NOTE: If scheduler lock is not held here, interrupt disable is required.
+ // KScopedInterruptDisable di;
+
// TODO(bunnei): We should call CanAccessAtomic(..) here.
- // Load the value from the address.
- const s32 current_value = static_cast<s32>(monitor.ExclusiveRead32(current_core, address));
+ s32 current_value{};
- // Compare it to the desired one.
- if (current_value == value) {
- // If equal, we want to try to write the new value.
+ // Load the value from the address.
+ while (true) {
+ current_value =
+ static_cast<s32>(monitor.ExclusiveRead32(current_core, GetInteger(address)));
+
+ // Compare it to the desired one.
+ if (current_value == value) {
+ // If equal, we want to try to write the new value.
+
+ // Try to store.
+ if (monitor.ExclusiveWrite32(current_core, GetInteger(address),
+ static_cast<u32>(new_value))) {
+ break;
+ }
- // Try to store.
- if (!monitor.ExclusiveWrite32(current_core, address, static_cast<u32>(new_value))) {
// If we failed to store, try again.
- UpdateIfEqual(system, out, address, value, new_value);
+ } else {
+ // Otherwise, clear our exclusive hold and finish.
+ monitor.ClearExclusive(current_core);
+ break;
}
- } else {
- // Otherwise, clear our exclusive hold and finish.
- monitor.ClearExclusive(current_core);
}
// We're done.
@@ -86,8 +108,8 @@ bool UpdateIfEqual(Core::System& system, s32* out, VAddr address, s32 value, s32
class ThreadQueueImplForKAddressArbiter final : public KThreadQueue {
public:
- explicit ThreadQueueImplForKAddressArbiter(KernelCore& kernel_, KAddressArbiter::ThreadTree* t)
- : KThreadQueue(kernel_), m_tree(t) {}
+ explicit ThreadQueueImplForKAddressArbiter(KernelCore& kernel, KAddressArbiter::ThreadTree* t)
+ : KThreadQueue(kernel), m_tree(t) {}
void CancelWait(KThread* waiting_thread, Result wait_result, bool cancel_timer_task) override {
// If the thread is waiting on an address arbiter, remove it from the tree.
@@ -101,19 +123,19 @@ public:
}
private:
- KAddressArbiter::ThreadTree* m_tree;
+ KAddressArbiter::ThreadTree* m_tree{};
};
} // namespace
-Result KAddressArbiter::Signal(VAddr addr, s32 count) {
+Result KAddressArbiter::Signal(uint64_t addr, s32 count) {
// Perform signaling.
s32 num_waiters{};
{
- KScopedSchedulerLock sl(kernel);
+ KScopedSchedulerLock sl(m_kernel);
- auto it = thread_tree.nfind_key({addr, -1});
- while ((it != thread_tree.end()) && (count <= 0 || num_waiters < count) &&
+ auto it = m_tree.nfind_key({addr, -1});
+ while ((it != m_tree.end()) && (count <= 0 || num_waiters < count) &&
(it->GetAddressArbiterKey() == addr)) {
// End the thread's wait.
KThread* target_thread = std::addressof(*it);
@@ -122,31 +144,27 @@ Result KAddressArbiter::Signal(VAddr addr, s32 count) {
ASSERT(target_thread->IsWaitingForAddressArbiter());
target_thread->ClearAddressArbiter();
- it = thread_tree.erase(it);
+ it = m_tree.erase(it);
++num_waiters;
}
}
- return ResultSuccess;
+ R_SUCCEED();
}
-Result KAddressArbiter::SignalAndIncrementIfEqual(VAddr addr, s32 value, s32 count) {
+Result KAddressArbiter::SignalAndIncrementIfEqual(uint64_t addr, s32 value, s32 count) {
// Perform signaling.
s32 num_waiters{};
{
- KScopedSchedulerLock sl(kernel);
+ KScopedSchedulerLock sl(m_kernel);
// Check the userspace value.
s32 user_value{};
- if (!UpdateIfEqual(system, &user_value, addr, value, value + 1)) {
- LOG_ERROR(Kernel, "Invalid current memory!");
- return ResultInvalidCurrentMemory;
- }
- if (user_value != value) {
- return ResultInvalidState;
- }
+ R_UNLESS(UpdateIfEqual(m_system, std::addressof(user_value), addr, value, value + 1),
+ ResultInvalidCurrentMemory);
+ R_UNLESS(user_value == value, ResultInvalidState);
- auto it = thread_tree.nfind_key({addr, -1});
- while ((it != thread_tree.end()) && (count <= 0 || num_waiters < count) &&
+ auto it = m_tree.nfind_key({addr, -1});
+ while ((it != m_tree.end()) && (count <= 0 || num_waiters < count) &&
(it->GetAddressArbiterKey() == addr)) {
// End the thread's wait.
KThread* target_thread = std::addressof(*it);
@@ -155,33 +173,33 @@ Result KAddressArbiter::SignalAndIncrementIfEqual(VAddr addr, s32 value, s32 cou
ASSERT(target_thread->IsWaitingForAddressArbiter());
target_thread->ClearAddressArbiter();
- it = thread_tree.erase(it);
+ it = m_tree.erase(it);
++num_waiters;
}
}
- return ResultSuccess;
+ R_SUCCEED();
}
-Result KAddressArbiter::SignalAndModifyByWaitingCountIfEqual(VAddr addr, s32 value, s32 count) {
+Result KAddressArbiter::SignalAndModifyByWaitingCountIfEqual(uint64_t addr, s32 value, s32 count) {
// Perform signaling.
s32 num_waiters{};
{
- [[maybe_unused]] const KScopedSchedulerLock sl(kernel);
+ KScopedSchedulerLock sl(m_kernel);
- auto it = thread_tree.nfind_key({addr, -1});
+ auto it = m_tree.nfind_key({addr, -1});
// Determine the updated value.
s32 new_value{};
if (count <= 0) {
- if (it != thread_tree.end() && it->GetAddressArbiterKey() == addr) {
+ if (it != m_tree.end() && it->GetAddressArbiterKey() == addr) {
new_value = value - 2;
} else {
new_value = value + 1;
}
} else {
- if (it != thread_tree.end() && it->GetAddressArbiterKey() == addr) {
+ if (it != m_tree.end() && it->GetAddressArbiterKey() == addr) {
auto tmp_it = it;
s32 tmp_num_waiters{};
- while (++tmp_it != thread_tree.end() && tmp_it->GetAddressArbiterKey() == addr) {
+ while (++tmp_it != m_tree.end() && tmp_it->GetAddressArbiterKey() == addr) {
if (tmp_num_waiters++ >= count) {
break;
}
@@ -201,20 +219,15 @@ Result KAddressArbiter::SignalAndModifyByWaitingCountIfEqual(VAddr addr, s32 val
s32 user_value{};
bool succeeded{};
if (value != new_value) {
- succeeded = UpdateIfEqual(system, &user_value, addr, value, new_value);
+ succeeded = UpdateIfEqual(m_system, std::addressof(user_value), addr, value, new_value);
} else {
- succeeded = ReadFromUser(system, &user_value, addr);
+ succeeded = ReadFromUser(m_kernel, std::addressof(user_value), addr);
}
- if (!succeeded) {
- LOG_ERROR(Kernel, "Invalid current memory!");
- return ResultInvalidCurrentMemory;
- }
- if (user_value != value) {
- return ResultInvalidState;
- }
+ R_UNLESS(succeeded, ResultInvalidCurrentMemory);
+ R_UNLESS(user_value == value, ResultInvalidState);
- while ((it != thread_tree.end()) && (count <= 0 || num_waiters < count) &&
+ while ((it != m_tree.end()) && (count <= 0 || num_waiters < count) &&
(it->GetAddressArbiterKey() == addr)) {
// End the thread's wait.
KThread* target_thread = std::addressof(*it);
@@ -223,58 +236,60 @@ Result KAddressArbiter::SignalAndModifyByWaitingCountIfEqual(VAddr addr, s32 val
ASSERT(target_thread->IsWaitingForAddressArbiter());
target_thread->ClearAddressArbiter();
- it = thread_tree.erase(it);
+ it = m_tree.erase(it);
++num_waiters;
}
}
- return ResultSuccess;
+ R_SUCCEED();
}
-Result KAddressArbiter::WaitIfLessThan(VAddr addr, s32 value, bool decrement, s64 timeout) {
+Result KAddressArbiter::WaitIfLessThan(uint64_t addr, s32 value, bool decrement, s64 timeout) {
// Prepare to wait.
- KThread* cur_thread = GetCurrentThreadPointer(kernel);
- ThreadQueueImplForKAddressArbiter wait_queue(kernel, std::addressof(thread_tree));
+ KThread* cur_thread = GetCurrentThreadPointer(m_kernel);
+ KHardwareTimer* timer{};
+ ThreadQueueImplForKAddressArbiter wait_queue(m_kernel, std::addressof(m_tree));
{
- KScopedSchedulerLockAndSleep slp{kernel, cur_thread, timeout};
+ KScopedSchedulerLockAndSleep slp{m_kernel, std::addressof(timer), cur_thread, timeout};
// Check that the thread isn't terminating.
if (cur_thread->IsTerminationRequested()) {
slp.CancelSleep();
- return ResultTerminationRequested;
+ R_THROW(ResultTerminationRequested);
}
// Read the value from userspace.
s32 user_value{};
bool succeeded{};
if (decrement) {
- succeeded = DecrementIfLessThan(system, &user_value, addr, value);
+ succeeded = DecrementIfLessThan(m_system, std::addressof(user_value), addr, value);
} else {
- succeeded = ReadFromUser(system, &user_value, addr);
+ succeeded = ReadFromUser(m_kernel, std::addressof(user_value), addr);
}
if (!succeeded) {
slp.CancelSleep();
- return ResultInvalidCurrentMemory;
+ R_THROW(ResultInvalidCurrentMemory);
}
// Check that the value is less than the specified one.
if (user_value >= value) {
slp.CancelSleep();
- return ResultInvalidState;
+ R_THROW(ResultInvalidState);
}
// Check that the timeout is non-zero.
if (timeout == 0) {
slp.CancelSleep();
- return ResultTimedOut;
+ R_THROW(ResultTimedOut);
}
// Set the arbiter.
- cur_thread->SetAddressArbiter(&thread_tree, addr);
- thread_tree.insert(*cur_thread);
+ cur_thread->SetAddressArbiter(std::addressof(m_tree), addr);
+ m_tree.insert(*cur_thread);
// Wait for the thread to finish.
+ wait_queue.SetHardwareTimer(timer);
cur_thread->BeginWait(std::addressof(wait_queue));
cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Arbitration);
}
@@ -283,44 +298,46 @@ Result KAddressArbiter::WaitIfLessThan(VAddr addr, s32 value, bool decrement, s6
return cur_thread->GetWaitResult();
}
-Result KAddressArbiter::WaitIfEqual(VAddr addr, s32 value, s64 timeout) {
+Result KAddressArbiter::WaitIfEqual(uint64_t addr, s32 value, s64 timeout) {
// Prepare to wait.
- KThread* cur_thread = GetCurrentThreadPointer(kernel);
- ThreadQueueImplForKAddressArbiter wait_queue(kernel, std::addressof(thread_tree));
+ KThread* cur_thread = GetCurrentThreadPointer(m_kernel);
+ KHardwareTimer* timer{};
+ ThreadQueueImplForKAddressArbiter wait_queue(m_kernel, std::addressof(m_tree));
{
- KScopedSchedulerLockAndSleep slp{kernel, cur_thread, timeout};
+ KScopedSchedulerLockAndSleep slp{m_kernel, std::addressof(timer), cur_thread, timeout};
// Check that the thread isn't terminating.
if (cur_thread->IsTerminationRequested()) {
slp.CancelSleep();
- return ResultTerminationRequested;
+ R_THROW(ResultTerminationRequested);
}
// Read the value from userspace.
s32 user_value{};
- if (!ReadFromUser(system, &user_value, addr)) {
+ if (!ReadFromUser(m_kernel, std::addressof(user_value), addr)) {
slp.CancelSleep();
- return ResultInvalidCurrentMemory;
+ R_THROW(ResultInvalidCurrentMemory);
}
// Check that the value is equal.
if (value != user_value) {
slp.CancelSleep();
- return ResultInvalidState;
+ R_THROW(ResultInvalidState);
}
// Check that the timeout is non-zero.
if (timeout == 0) {
slp.CancelSleep();
- return ResultTimedOut;
+ R_THROW(ResultTimedOut);
}
// Set the arbiter.
- cur_thread->SetAddressArbiter(&thread_tree, addr);
- thread_tree.insert(*cur_thread);
+ cur_thread->SetAddressArbiter(std::addressof(m_tree), addr);
+ m_tree.insert(*cur_thread);
// Wait for the thread to finish.
+ wait_queue.SetHardwareTimer(timer);
cur_thread->BeginWait(std::addressof(wait_queue));
cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Arbitration);
}
diff --git a/src/core/hle/kernel/k_address_arbiter.h b/src/core/hle/kernel/k_address_arbiter.h
index e4085ae22..3b70e1ab2 100644
--- a/src/core/hle/kernel/k_address_arbiter.h
+++ b/src/core/hle/kernel/k_address_arbiter.h
@@ -22,47 +22,46 @@ class KAddressArbiter {
public:
using ThreadTree = KConditionVariable::ThreadTree;
- explicit KAddressArbiter(Core::System& system_);
+ explicit KAddressArbiter(Core::System& system);
~KAddressArbiter();
- [[nodiscard]] Result SignalToAddress(VAddr addr, Svc::SignalType type, s32 value, s32 count) {
+ Result SignalToAddress(uint64_t addr, Svc::SignalType type, s32 value, s32 count) {
switch (type) {
case Svc::SignalType::Signal:
- return Signal(addr, count);
+ R_RETURN(this->Signal(addr, count));
case Svc::SignalType::SignalAndIncrementIfEqual:
- return SignalAndIncrementIfEqual(addr, value, count);
+ R_RETURN(this->SignalAndIncrementIfEqual(addr, value, count));
case Svc::SignalType::SignalAndModifyByWaitingCountIfEqual:
- return SignalAndModifyByWaitingCountIfEqual(addr, value, count);
+ R_RETURN(this->SignalAndModifyByWaitingCountIfEqual(addr, value, count));
+ default:
+ UNREACHABLE();
}
- ASSERT(false);
- return ResultUnknown;
}
- [[nodiscard]] Result WaitForAddress(VAddr addr, Svc::ArbitrationType type, s32 value,
- s64 timeout) {
+ Result WaitForAddress(uint64_t addr, Svc::ArbitrationType type, s32 value, s64 timeout) {
switch (type) {
case Svc::ArbitrationType::WaitIfLessThan:
- return WaitIfLessThan(addr, value, false, timeout);
+ R_RETURN(WaitIfLessThan(addr, value, false, timeout));
case Svc::ArbitrationType::DecrementAndWaitIfLessThan:
- return WaitIfLessThan(addr, value, true, timeout);
+ R_RETURN(WaitIfLessThan(addr, value, true, timeout));
case Svc::ArbitrationType::WaitIfEqual:
- return WaitIfEqual(addr, value, timeout);
+ R_RETURN(WaitIfEqual(addr, value, timeout));
+ default:
+ UNREACHABLE();
}
- ASSERT(false);
- return ResultUnknown;
}
private:
- [[nodiscard]] Result Signal(VAddr addr, s32 count);
- [[nodiscard]] Result SignalAndIncrementIfEqual(VAddr addr, s32 value, s32 count);
- [[nodiscard]] Result SignalAndModifyByWaitingCountIfEqual(VAddr addr, s32 value, s32 count);
- [[nodiscard]] Result WaitIfLessThan(VAddr addr, s32 value, bool decrement, s64 timeout);
- [[nodiscard]] Result WaitIfEqual(VAddr addr, s32 value, s64 timeout);
+ Result Signal(uint64_t addr, s32 count);
+ Result SignalAndIncrementIfEqual(uint64_t addr, s32 value, s32 count);
+ Result SignalAndModifyByWaitingCountIfEqual(uint64_t addr, s32 value, s32 count);
+ Result WaitIfLessThan(uint64_t addr, s32 value, bool decrement, s64 timeout);
+ Result WaitIfEqual(uint64_t addr, s32 value, s64 timeout);
- ThreadTree thread_tree;
-
- Core::System& system;
- KernelCore& kernel;
+private:
+ ThreadTree m_tree;
+ Core::System& m_system;
+ KernelCore& m_kernel;
};
} // namespace Kernel
diff --git a/src/core/hle/kernel/k_address_space_info.cpp b/src/core/hle/kernel/k_address_space_info.cpp
index 3e612a207..32173e52b 100644
--- a/src/core/hle/kernel/k_address_space_info.cpp
+++ b/src/core/hle/kernel/k_address_space_info.cpp
@@ -23,86 +23,38 @@ constexpr std::array<KAddressSpaceInfo, 13> AddressSpaceInfos{{
{ .bit_width = 32, .address = Size_Invalid, .size = 1_GiB , .type = KAddressSpaceInfo::Type::Heap, },
{ .bit_width = 36, .address = 128_MiB , .size = 2_GiB - 128_MiB, .type = KAddressSpaceInfo::Type::MapSmall, },
{ .bit_width = 36, .address = 2_GiB , .size = 64_GiB - 2_GiB , .type = KAddressSpaceInfo::Type::MapLarge, },
- { .bit_width = 36, .address = Size_Invalid, .size = 6_GiB , .type = KAddressSpaceInfo::Type::Heap, },
+ { .bit_width = 36, .address = Size_Invalid, .size = 8_GiB , .type = KAddressSpaceInfo::Type::Heap, },
{ .bit_width = 36, .address = Size_Invalid, .size = 6_GiB , .type = KAddressSpaceInfo::Type::Alias, },
+#ifdef ANDROID
+ // With Android, we use a 38-bit address space due to memory limitations. This should (safely) truncate ASLR region.
+ { .bit_width = 39, .address = 128_MiB , .size = 256_GiB - 128_MiB, .type = KAddressSpaceInfo::Type::Map39Bit, },
+#else
{ .bit_width = 39, .address = 128_MiB , .size = 512_GiB - 128_MiB, .type = KAddressSpaceInfo::Type::Map39Bit, },
+#endif
{ .bit_width = 39, .address = Size_Invalid, .size = 64_GiB , .type = KAddressSpaceInfo::Type::MapSmall },
- { .bit_width = 39, .address = Size_Invalid, .size = 6_GiB , .type = KAddressSpaceInfo::Type::Heap, },
+ { .bit_width = 39, .address = Size_Invalid, .size = 8_GiB , .type = KAddressSpaceInfo::Type::Heap, },
{ .bit_width = 39, .address = Size_Invalid, .size = 64_GiB , .type = KAddressSpaceInfo::Type::Alias, },
{ .bit_width = 39, .address = Size_Invalid, .size = 2_GiB , .type = KAddressSpaceInfo::Type::Stack, },
}};
// clang-format on
-constexpr bool IsAllowedIndexForAddress(std::size_t index) {
- return index < AddressSpaceInfos.size() && AddressSpaceInfos[index].address != Size_Invalid;
-}
-
-using IndexArray =
- std::array<std::size_t, static_cast<std::size_t>(KAddressSpaceInfo::Type::Count)>;
-
-constexpr IndexArray AddressSpaceIndices32Bit{
- 0, 1, 0, 2, 0, 3,
-};
-
-constexpr IndexArray AddressSpaceIndices36Bit{
- 4, 5, 4, 6, 4, 7,
-};
-
-constexpr IndexArray AddressSpaceIndices39Bit{
- 9, 8, 8, 10, 12, 11,
-};
-
-constexpr bool IsAllowed32BitType(KAddressSpaceInfo::Type type) {
- return type < KAddressSpaceInfo::Type::Count && type != KAddressSpaceInfo::Type::Map39Bit &&
- type != KAddressSpaceInfo::Type::Stack;
-}
-
-constexpr bool IsAllowed36BitType(KAddressSpaceInfo::Type type) {
- return type < KAddressSpaceInfo::Type::Count && type != KAddressSpaceInfo::Type::Map39Bit &&
- type != KAddressSpaceInfo::Type::Stack;
-}
-
-constexpr bool IsAllowed39BitType(KAddressSpaceInfo::Type type) {
- return type < KAddressSpaceInfo::Type::Count && type != KAddressSpaceInfo::Type::MapLarge;
+const KAddressSpaceInfo& GetAddressSpaceInfo(size_t width, KAddressSpaceInfo::Type type) {
+ for (auto& info : AddressSpaceInfos) {
+ if (info.bit_width == width && info.type == type) {
+ return info;
+ }
+ }
+ UNREACHABLE_MSG("Could not find AddressSpaceInfo");
}
} // namespace
-u64 KAddressSpaceInfo::GetAddressSpaceStart(std::size_t width, Type type) {
- const std::size_t index{static_cast<std::size_t>(type)};
- switch (width) {
- case 32:
- ASSERT(IsAllowed32BitType(type));
- ASSERT(IsAllowedIndexForAddress(AddressSpaceIndices32Bit[index]));
- return AddressSpaceInfos[AddressSpaceIndices32Bit[index]].address;
- case 36:
- ASSERT(IsAllowed36BitType(type));
- ASSERT(IsAllowedIndexForAddress(AddressSpaceIndices36Bit[index]));
- return AddressSpaceInfos[AddressSpaceIndices36Bit[index]].address;
- case 39:
- ASSERT(IsAllowed39BitType(type));
- ASSERT(IsAllowedIndexForAddress(AddressSpaceIndices39Bit[index]));
- return AddressSpaceInfos[AddressSpaceIndices39Bit[index]].address;
- }
- ASSERT(false);
- return 0;
+std::size_t KAddressSpaceInfo::GetAddressSpaceStart(size_t width, KAddressSpaceInfo::Type type) {
+ return GetAddressSpaceInfo(width, type).address;
}
-std::size_t KAddressSpaceInfo::GetAddressSpaceSize(std::size_t width, Type type) {
- const std::size_t index{static_cast<std::size_t>(type)};
- switch (width) {
- case 32:
- ASSERT(IsAllowed32BitType(type));
- return AddressSpaceInfos[AddressSpaceIndices32Bit[index]].size;
- case 36:
- ASSERT(IsAllowed36BitType(type));
- return AddressSpaceInfos[AddressSpaceIndices36Bit[index]].size;
- case 39:
- ASSERT(IsAllowed39BitType(type));
- return AddressSpaceInfos[AddressSpaceIndices39Bit[index]].size;
- }
- ASSERT(false);
- return 0;
+std::size_t KAddressSpaceInfo::GetAddressSpaceSize(size_t width, KAddressSpaceInfo::Type type) {
+ return GetAddressSpaceInfo(width, type).size;
}
} // namespace Kernel
diff --git a/src/core/hle/kernel/k_address_space_info.h b/src/core/hle/kernel/k_address_space_info.h
index 69e9d77f2..9a26f6b90 100644
--- a/src/core/hle/kernel/k_address_space_info.h
+++ b/src/core/hle/kernel/k_address_space_info.h
@@ -18,7 +18,7 @@ struct KAddressSpaceInfo final {
Count,
};
- static u64 GetAddressSpaceStart(std::size_t width, Type type);
+ static std::size_t GetAddressSpaceStart(std::size_t width, Type type);
static std::size_t GetAddressSpaceSize(std::size_t width, Type type);
const std::size_t bit_width{};
diff --git a/src/core/hle/kernel/k_affinity_mask.h b/src/core/hle/kernel/k_affinity_mask.h
index b58716e90..07a5a822c 100644
--- a/src/core/hle/kernel/k_affinity_mask.h
+++ b/src/core/hle/kernel/k_affinity_mask.h
@@ -13,40 +13,40 @@ class KAffinityMask {
public:
constexpr KAffinityMask() = default;
- [[nodiscard]] constexpr u64 GetAffinityMask() const {
- return this->mask;
+ constexpr u64 GetAffinityMask() const {
+ return m_mask;
}
constexpr void SetAffinityMask(u64 new_mask) {
ASSERT((new_mask & ~AllowedAffinityMask) == 0);
- this->mask = new_mask;
+ m_mask = new_mask;
}
- [[nodiscard]] constexpr bool GetAffinity(s32 core) const {
- return (this->mask & GetCoreBit(core)) != 0;
+ constexpr bool GetAffinity(s32 core) const {
+ return (m_mask & GetCoreBit(core)) != 0;
}
constexpr void SetAffinity(s32 core, bool set) {
if (set) {
- this->mask |= GetCoreBit(core);
+ m_mask |= GetCoreBit(core);
} else {
- this->mask &= ~GetCoreBit(core);
+ m_mask &= ~GetCoreBit(core);
}
}
constexpr void SetAll() {
- this->mask = AllowedAffinityMask;
+ m_mask = AllowedAffinityMask;
}
private:
- [[nodiscard]] static constexpr u64 GetCoreBit(s32 core) {
+ static constexpr u64 GetCoreBit(s32 core) {
ASSERT(0 <= core && core < static_cast<s32>(Core::Hardware::NUM_CPU_CORES));
return (1ULL << core);
}
static constexpr u64 AllowedAffinityMask = (1ULL << Core::Hardware::NUM_CPU_CORES) - 1;
- u64 mask{};
+ u64 m_mask{};
};
} // namespace Kernel
diff --git a/src/core/hle/kernel/k_auto_object.cpp b/src/core/hle/kernel/k_auto_object.cpp
index 691af8ccb..0ae42c95c 100644
--- a/src/core/hle/kernel/k_auto_object.cpp
+++ b/src/core/hle/kernel/k_auto_object.cpp
@@ -12,11 +12,11 @@ KAutoObject* KAutoObject::Create(KAutoObject* obj) {
}
void KAutoObject::RegisterWithKernel() {
- kernel.RegisterKernelObject(this);
+ m_kernel.RegisterKernelObject(this);
}
void KAutoObject::UnregisterWithKernel() {
- kernel.UnregisterKernelObject(this);
+ m_kernel.UnregisterKernelObject(this);
}
} // namespace Kernel
diff --git a/src/core/hle/kernel/k_auto_object.h b/src/core/hle/kernel/k_auto_object.h
index 2827763d5..f384b1568 100644
--- a/src/core/hle/kernel/k_auto_object.h
+++ b/src/core/hle/kernel/k_auto_object.h
@@ -24,9 +24,7 @@ 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>; \
- } \
+ static constexpr inline ClassTokenType ClassToken() { return ::Kernel::ClassToken<CLASS>; } \
\
public: \
YUZU_NON_COPYABLE(CLASS); \
@@ -37,15 +35,9 @@ public:
constexpr ClassTokenType Token = ClassToken(); \
return TypeObj(TypeName, Token); \
} \
- static constexpr const char* GetStaticTypeName() { \
- return TypeName; \
- } \
- virtual TypeObj GetTypeObj() ATTRIBUTE { \
- return GetStaticTypeObj(); \
- } \
- virtual const char* GetTypeName() ATTRIBUTE { \
- return GetStaticTypeName(); \
- } \
+ static constexpr const char* GetStaticTypeName() { return TypeName; } \
+ virtual TypeObj GetTypeObj() ATTRIBUTE { return GetStaticTypeObj(); } \
+ virtual const char* GetTypeName() ATTRIBUTE { return GetStaticTypeName(); } \
\
private: \
constexpr bool operator!=(const TypeObj& rhs)
@@ -88,7 +80,7 @@ private:
KERNEL_AUTOOBJECT_TRAITS_IMPL(KAutoObject, KAutoObject, const);
public:
- explicit KAutoObject(KernelCore& kernel_) : kernel(kernel_) {
+ explicit KAutoObject(KernelCore& kernel) : m_kernel(kernel) {
RegisterWithKernel();
}
virtual ~KAutoObject() = default;
@@ -172,17 +164,12 @@ public:
}
}
- const std::string& GetName() const {
- return name;
- }
-
private:
void RegisterWithKernel();
void UnregisterWithKernel();
protected:
- KernelCore& kernel;
- std::string name;
+ KernelCore& m_kernel;
private:
std::atomic<u32> m_ref_count{};
@@ -192,11 +179,11 @@ class KAutoObjectWithListContainer;
class KAutoObjectWithList : public KAutoObject, public boost::intrusive::set_base_hook<> {
public:
- explicit KAutoObjectWithList(KernelCore& kernel_) : KAutoObject(kernel_) {}
+ 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();
+ const uintptr_t lid = reinterpret_cast<uintptr_t>(std::addressof(lhs));
+ const uintptr_t rid = reinterpret_cast<uintptr_t>(std::addressof(rhs));
if (lid < rid) {
return -1;
@@ -208,7 +195,7 @@ public:
}
friend bool operator<(const KAutoObjectWithList& left, const KAutoObjectWithList& right) {
- return &left < &right;
+ return KAutoObjectWithList::Compare(left, right) < 0;
}
public:
@@ -216,10 +203,6 @@ public:
return reinterpret_cast<u64>(this);
}
- virtual const std::string& GetName() const {
- return name;
- }
-
private:
friend class KAutoObjectWithListContainer;
};
@@ -245,8 +228,8 @@ public:
}
template <typename U>
- requires(std::derived_from<T, U> ||
- std::derived_from<U, T>) constexpr KScopedAutoObject(KScopedAutoObject<U>&& rhs) {
+ 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;
diff --git a/src/core/hle/kernel/k_capabilities.cpp b/src/core/hle/kernel/k_capabilities.cpp
new file mode 100644
index 000000000..90e4e8fb0
--- /dev/null
+++ b/src/core/hle/kernel/k_capabilities.cpp
@@ -0,0 +1,358 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hardware_properties.h"
+#include "core/hle/kernel/k_capabilities.h"
+#include "core/hle/kernel/k_memory_layout.h"
+#include "core/hle/kernel/k_page_table.h"
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/svc_results.h"
+#include "core/hle/kernel/svc_version.h"
+
+namespace Kernel {
+
+Result KCapabilities::InitializeForKip(std::span<const u32> kern_caps, KPageTable* page_table) {
+ // We're initializing an initial process.
+ m_svc_access_flags.reset();
+ m_irq_access_flags.reset();
+ m_debug_capabilities = 0;
+ m_handle_table_size = 0;
+ m_intended_kernel_version = 0;
+ m_program_type = 0;
+
+ // Initial processes may run on all cores.
+ constexpr u64 VirtMask = Core::Hardware::VirtualCoreMask;
+ constexpr u64 PhysMask = Core::Hardware::ConvertVirtualCoreMaskToPhysical(VirtMask);
+
+ m_core_mask = VirtMask;
+ m_phys_core_mask = PhysMask;
+
+ // Initial processes may use any user priority they like.
+ m_priority_mask = ~0xFULL;
+
+ // Here, Nintendo sets the kernel version to the current kernel version.
+ // We will follow suit and set the version to the highest supported kernel version.
+ KernelVersion intended_kernel_version{};
+ intended_kernel_version.major_version.Assign(Svc::SupportedKernelMajorVersion);
+ intended_kernel_version.minor_version.Assign(Svc::SupportedKernelMinorVersion);
+ m_intended_kernel_version = intended_kernel_version.raw;
+
+ // Parse the capabilities array.
+ R_RETURN(this->SetCapabilities(kern_caps, page_table));
+}
+
+Result KCapabilities::InitializeForUser(std::span<const u32> user_caps, KPageTable* page_table) {
+ // We're initializing a user process.
+ m_svc_access_flags.reset();
+ m_irq_access_flags.reset();
+ m_debug_capabilities = 0;
+ m_handle_table_size = 0;
+ m_intended_kernel_version = 0;
+ m_program_type = 0;
+
+ // User processes must specify what cores/priorities they can use.
+ m_core_mask = 0;
+ m_priority_mask = 0;
+
+ // Parse the user capabilities array.
+ R_RETURN(this->SetCapabilities(user_caps, page_table));
+}
+
+Result KCapabilities::SetCorePriorityCapability(const u32 cap) {
+ // We can't set core/priority if we've already set them.
+ R_UNLESS(m_core_mask == 0, ResultInvalidArgument);
+ R_UNLESS(m_priority_mask == 0, ResultInvalidArgument);
+
+ // Validate the core/priority.
+ CorePriority pack{cap};
+ const u32 min_core = pack.minimum_core_id;
+ const u32 max_core = pack.maximum_core_id;
+ const u32 max_prio = pack.lowest_thread_priority;
+ const u32 min_prio = pack.highest_thread_priority;
+
+ R_UNLESS(min_core <= max_core, ResultInvalidCombination);
+ R_UNLESS(min_prio <= max_prio, ResultInvalidCombination);
+ R_UNLESS(max_core < Core::Hardware::NumVirtualCores, ResultInvalidCoreId);
+
+ ASSERT(max_prio < Common::BitSize<u64>());
+
+ // Set core mask.
+ for (auto core_id = min_core; core_id <= max_core; core_id++) {
+ m_core_mask |= (1ULL << core_id);
+ }
+ ASSERT((m_core_mask & Core::Hardware::VirtualCoreMask) == m_core_mask);
+
+ // Set physical core mask.
+ m_phys_core_mask = Core::Hardware::ConvertVirtualCoreMaskToPhysical(m_core_mask);
+
+ // Set priority mask.
+ for (auto prio = min_prio; prio <= max_prio; prio++) {
+ m_priority_mask |= (1ULL << prio);
+ }
+
+ // We must have some core/priority we can use.
+ R_UNLESS(m_core_mask != 0, ResultInvalidArgument);
+ R_UNLESS(m_priority_mask != 0, ResultInvalidArgument);
+
+ // Processes must not have access to kernel thread priorities.
+ R_UNLESS((m_priority_mask & 0xF) == 0, ResultInvalidArgument);
+
+ R_SUCCEED();
+}
+
+Result KCapabilities::SetSyscallMaskCapability(const u32 cap, u32& set_svc) {
+ // Validate the index.
+ SyscallMask pack{cap};
+ const u32 mask = pack.mask;
+ const u32 index = pack.index;
+
+ const u32 index_flag = (1U << index);
+ R_UNLESS((set_svc & index_flag) == 0, ResultInvalidCombination);
+ set_svc |= index_flag;
+
+ // Set SVCs.
+ for (size_t i = 0; i < decltype(SyscallMask::mask)::bits; i++) {
+ const u32 svc_id = static_cast<u32>(decltype(SyscallMask::mask)::bits * index + i);
+ if (mask & (1U << i)) {
+ R_UNLESS(this->SetSvcAllowed(svc_id), ResultOutOfRange);
+ }
+ }
+
+ R_SUCCEED();
+}
+
+Result KCapabilities::MapRange_(const u32 cap, const u32 size_cap, KPageTable* page_table) {
+ const auto range_pack = MapRange{cap};
+ const auto size_pack = MapRangeSize{size_cap};
+
+ // Get/validate address/size
+ const u64 phys_addr = range_pack.address.Value() * PageSize;
+
+ // Validate reserved bits are unused.
+ R_UNLESS(size_pack.reserved.Value() == 0, ResultOutOfRange);
+
+ const size_t num_pages = size_pack.pages;
+ const size_t size = num_pages * PageSize;
+ R_UNLESS(num_pages != 0, ResultInvalidSize);
+ R_UNLESS(phys_addr < phys_addr + size, ResultInvalidAddress);
+ R_UNLESS(((phys_addr + size - 1) & ~PhysicalMapAllowedMask) == 0, ResultInvalidAddress);
+
+ // Do the mapping.
+ [[maybe_unused]] const KMemoryPermission perm = range_pack.read_only.Value()
+ ? KMemoryPermission::UserRead
+ : KMemoryPermission::UserReadWrite;
+ if (MapRangeSize{size_cap}.normal) {
+ // R_RETURN(page_table->MapStatic(phys_addr, size, perm));
+ } else {
+ // R_RETURN(page_table->MapIo(phys_addr, size, perm));
+ }
+
+ UNIMPLEMENTED();
+ R_SUCCEED();
+}
+
+Result KCapabilities::MapIoPage_(const u32 cap, KPageTable* page_table) {
+ // Get/validate address/size
+ const u64 phys_addr = MapIoPage{cap}.address.Value() * PageSize;
+ const size_t num_pages = 1;
+ const size_t size = num_pages * PageSize;
+ R_UNLESS(num_pages != 0, ResultInvalidSize);
+ R_UNLESS(phys_addr < phys_addr + size, ResultInvalidAddress);
+ R_UNLESS(((phys_addr + size - 1) & ~PhysicalMapAllowedMask) == 0, ResultInvalidAddress);
+
+ // Do the mapping.
+ // R_RETURN(page_table->MapIo(phys_addr, size, KMemoryPermission_UserReadWrite));
+
+ UNIMPLEMENTED();
+ R_SUCCEED();
+}
+
+template <typename F>
+Result KCapabilities::ProcessMapRegionCapability(const u32 cap, F f) {
+ // Define the allowed memory regions.
+ constexpr std::array<KMemoryRegionType, 4> MemoryRegions{
+ KMemoryRegionType_None,
+ KMemoryRegionType_KernelTraceBuffer,
+ KMemoryRegionType_OnMemoryBootImage,
+ KMemoryRegionType_DTB,
+ };
+
+ // Extract regions/read only.
+ const MapRegion pack{cap};
+ const std::array<RegionType, 3> types{pack.region0, pack.region1, pack.region2};
+ const std::array<u32, 3> ro{pack.read_only0, pack.read_only1, pack.read_only2};
+
+ for (size_t i = 0; i < types.size(); i++) {
+ const auto type = types[i];
+ const auto perm = ro[i] ? KMemoryPermission::UserRead : KMemoryPermission::UserReadWrite;
+ switch (type) {
+ case RegionType::NoMapping:
+ break;
+ case RegionType::KernelTraceBuffer:
+ case RegionType::OnMemoryBootImage:
+ case RegionType::DTB:
+ R_TRY(f(MemoryRegions[static_cast<u32>(type)], perm));
+ break;
+ default:
+ R_THROW(ResultNotFound);
+ }
+ }
+
+ R_SUCCEED();
+}
+
+Result KCapabilities::MapRegion_(const u32 cap, KPageTable* page_table) {
+ // Map each region into the process's page table.
+ return ProcessMapRegionCapability(
+ cap, [](KMemoryRegionType region_type, KMemoryPermission perm) -> Result {
+ // R_RETURN(page_table->MapRegion(region_type, perm));
+ UNIMPLEMENTED();
+ R_SUCCEED();
+ });
+}
+
+Result KCapabilities::CheckMapRegion(KernelCore& kernel, const u32 cap) {
+ // Check that each region has a physical backing store.
+ return ProcessMapRegionCapability(
+ cap, [&](KMemoryRegionType region_type, KMemoryPermission perm) -> Result {
+ R_UNLESS(kernel.MemoryLayout().GetPhysicalMemoryRegionTree().FindFirstDerived(
+ region_type) != nullptr,
+ ResultOutOfRange);
+ R_SUCCEED();
+ });
+}
+
+Result KCapabilities::SetInterruptPairCapability(const u32 cap) {
+ // Extract interrupts.
+ const InterruptPair pack{cap};
+ const std::array<u32, 2> ids{pack.interrupt_id0, pack.interrupt_id1};
+
+ for (size_t i = 0; i < ids.size(); i++) {
+ if (ids[i] != PaddingInterruptId) {
+ UNIMPLEMENTED();
+ // R_UNLESS(Kernel::GetInterruptManager().IsInterruptDefined(ids[i]), ResultOutOfRange);
+ // R_UNLESS(this->SetInterruptPermitted(ids[i]), ResultOutOfRange);
+ }
+ }
+
+ R_SUCCEED();
+}
+
+Result KCapabilities::SetProgramTypeCapability(const u32 cap) {
+ // Validate.
+ const ProgramType pack{cap};
+ R_UNLESS(pack.reserved == 0, ResultReservedUsed);
+
+ m_program_type = pack.type;
+ R_SUCCEED();
+}
+
+Result KCapabilities::SetKernelVersionCapability(const u32 cap) {
+ // Ensure we haven't set our version before.
+ R_UNLESS(KernelVersion{m_intended_kernel_version}.major_version == 0, ResultInvalidArgument);
+
+ // Set, ensure that we set a valid version.
+ m_intended_kernel_version = cap;
+ R_UNLESS(KernelVersion{m_intended_kernel_version}.major_version != 0, ResultInvalidArgument);
+
+ R_SUCCEED();
+}
+
+Result KCapabilities::SetHandleTableCapability(const u32 cap) {
+ // Validate.
+ const HandleTable pack{cap};
+ R_UNLESS(pack.reserved == 0, ResultReservedUsed);
+
+ m_handle_table_size = pack.size;
+ R_SUCCEED();
+}
+
+Result KCapabilities::SetDebugFlagsCapability(const u32 cap) {
+ // Validate.
+ const DebugFlags pack{cap};
+ R_UNLESS(pack.reserved == 0, ResultReservedUsed);
+
+ DebugFlags debug_capabilities{m_debug_capabilities};
+ debug_capabilities.allow_debug.Assign(pack.allow_debug);
+ debug_capabilities.force_debug.Assign(pack.force_debug);
+ m_debug_capabilities = debug_capabilities.raw;
+
+ R_SUCCEED();
+}
+
+Result KCapabilities::SetCapability(const u32 cap, u32& set_flags, u32& set_svc,
+ KPageTable* page_table) {
+ // Validate this is a capability we can act on.
+ const auto type = GetCapabilityType(cap);
+ R_UNLESS(type != CapabilityType::Invalid, ResultInvalidArgument);
+
+ // If the type is padding, we have no work to do.
+ R_SUCCEED_IF(type == CapabilityType::Padding);
+
+ // Check that we haven't already processed this capability.
+ const auto flag = GetCapabilityFlag(type);
+ R_UNLESS(((set_flags & InitializeOnceFlags) & flag) == 0, ResultInvalidCombination);
+ set_flags |= flag;
+
+ // Process the capability.
+ switch (type) {
+ case CapabilityType::CorePriority:
+ R_RETURN(this->SetCorePriorityCapability(cap));
+ case CapabilityType::SyscallMask:
+ R_RETURN(this->SetSyscallMaskCapability(cap, set_svc));
+ case CapabilityType::MapIoPage:
+ R_RETURN(this->MapIoPage_(cap, page_table));
+ case CapabilityType::MapRegion:
+ R_RETURN(this->MapRegion_(cap, page_table));
+ case CapabilityType::InterruptPair:
+ R_RETURN(this->SetInterruptPairCapability(cap));
+ case CapabilityType::ProgramType:
+ R_RETURN(this->SetProgramTypeCapability(cap));
+ case CapabilityType::KernelVersion:
+ R_RETURN(this->SetKernelVersionCapability(cap));
+ case CapabilityType::HandleTable:
+ R_RETURN(this->SetHandleTableCapability(cap));
+ case CapabilityType::DebugFlags:
+ R_RETURN(this->SetDebugFlagsCapability(cap));
+ default:
+ R_THROW(ResultInvalidArgument);
+ }
+}
+
+Result KCapabilities::SetCapabilities(std::span<const u32> caps, KPageTable* page_table) {
+ u32 set_flags = 0, set_svc = 0;
+
+ for (size_t i = 0; i < caps.size(); i++) {
+ const u32 cap{caps[i]};
+
+ if (GetCapabilityType(cap) == CapabilityType::MapRange) {
+ // Check that the pair cap exists.
+ R_UNLESS((++i) < caps.size(), ResultInvalidCombination);
+
+ // Check the pair cap is a map range cap.
+ const u32 size_cap{caps[i]};
+ R_UNLESS(GetCapabilityType(size_cap) == CapabilityType::MapRange,
+ ResultInvalidCombination);
+
+ // Map the range.
+ R_TRY(this->MapRange_(cap, size_cap, page_table));
+ } else {
+ R_TRY(this->SetCapability(cap, set_flags, set_svc, page_table));
+ }
+ }
+
+ R_SUCCEED();
+}
+
+Result KCapabilities::CheckCapabilities(KernelCore& kernel, std::span<const u32> caps) {
+ for (auto cap : caps) {
+ // Check the capability refers to a valid region.
+ if (GetCapabilityType(cap) == CapabilityType::MapRegion) {
+ R_TRY(CheckMapRegion(kernel, cap));
+ }
+ }
+
+ R_SUCCEED();
+}
+
+} // namespace Kernel
diff --git a/src/core/hle/kernel/k_capabilities.h b/src/core/hle/kernel/k_capabilities.h
new file mode 100644
index 000000000..de766c811
--- /dev/null
+++ b/src/core/hle/kernel/k_capabilities.h
@@ -0,0 +1,295 @@
+
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include <bitset>
+#include <span>
+
+#include "common/bit_field.h"
+#include "common/common_types.h"
+
+#include "core/hle/kernel/svc_types.h"
+#include "core/hle/result.h"
+
+namespace Kernel {
+
+class KPageTable;
+class KernelCore;
+
+class KCapabilities {
+public:
+ constexpr explicit KCapabilities() = default;
+
+ Result InitializeForKip(std::span<const u32> kern_caps, KPageTable* page_table);
+ Result InitializeForUser(std::span<const u32> user_caps, KPageTable* page_table);
+
+ static Result CheckCapabilities(KernelCore& kernel, std::span<const u32> user_caps);
+
+ constexpr u64 GetCoreMask() const {
+ return m_core_mask;
+ }
+
+ constexpr u64 GetPhysicalCoreMask() const {
+ return m_phys_core_mask;
+ }
+
+ constexpr u64 GetPriorityMask() const {
+ return m_priority_mask;
+ }
+
+ constexpr s32 GetHandleTableSize() const {
+ return m_handle_table_size;
+ }
+
+ constexpr const Svc::SvcAccessFlagSet& GetSvcPermissions() const {
+ return m_svc_access_flags;
+ }
+
+ constexpr bool IsPermittedSvc(u32 id) const {
+ return (id < m_svc_access_flags.size()) && m_svc_access_flags[id];
+ }
+
+ constexpr bool IsPermittedInterrupt(u32 id) const {
+ return (id < m_irq_access_flags.size()) && m_irq_access_flags[id];
+ }
+
+ constexpr bool IsPermittedDebug() const {
+ return DebugFlags{m_debug_capabilities}.allow_debug.Value() != 0;
+ }
+
+ constexpr bool CanForceDebug() const {
+ return DebugFlags{m_debug_capabilities}.force_debug.Value() != 0;
+ }
+
+ constexpr u32 GetIntendedKernelMajorVersion() const {
+ return KernelVersion{m_intended_kernel_version}.major_version;
+ }
+
+ constexpr u32 GetIntendedKernelMinorVersion() const {
+ return KernelVersion{m_intended_kernel_version}.minor_version;
+ }
+
+private:
+ static constexpr size_t InterruptIdCount = 0x400;
+ using InterruptFlagSet = std::bitset<InterruptIdCount>;
+
+ enum class CapabilityType : u32 {
+ CorePriority = (1U << 3) - 1,
+ SyscallMask = (1U << 4) - 1,
+ MapRange = (1U << 6) - 1,
+ MapIoPage = (1U << 7) - 1,
+ MapRegion = (1U << 10) - 1,
+ InterruptPair = (1U << 11) - 1,
+ ProgramType = (1U << 13) - 1,
+ KernelVersion = (1U << 14) - 1,
+ HandleTable = (1U << 15) - 1,
+ DebugFlags = (1U << 16) - 1,
+
+ Invalid = 0U,
+ Padding = ~0U,
+ };
+
+ using RawCapabilityValue = u32;
+
+ static constexpr CapabilityType GetCapabilityType(const RawCapabilityValue value) {
+ return static_cast<CapabilityType>((~value & (value + 1)) - 1);
+ }
+
+ static constexpr u32 GetCapabilityFlag(CapabilityType type) {
+ return static_cast<u32>(type) + 1;
+ }
+
+ template <CapabilityType Type>
+ static constexpr inline u32 CapabilityFlag = static_cast<u32>(Type) + 1;
+
+ template <CapabilityType Type>
+ static constexpr inline u32 CapabilityId = std::countr_zero(CapabilityFlag<Type>);
+
+ union CorePriority {
+ static_assert(CapabilityId<CapabilityType::CorePriority> + 1 == 4);
+
+ RawCapabilityValue raw;
+ BitField<0, 4, CapabilityType> id;
+ BitField<4, 6, u32> lowest_thread_priority;
+ BitField<10, 6, u32> highest_thread_priority;
+ BitField<16, 8, u32> minimum_core_id;
+ BitField<24, 8, u32> maximum_core_id;
+ };
+
+ union SyscallMask {
+ static_assert(CapabilityId<CapabilityType::SyscallMask> + 1 == 5);
+
+ RawCapabilityValue raw;
+ BitField<0, 5, CapabilityType> id;
+ BitField<5, 24, u32> mask;
+ BitField<29, 3, u32> index;
+ };
+
+ // #undef MESOSPHERE_ENABLE_LARGE_PHYSICAL_ADDRESS_CAPABILITIES
+ static constexpr u64 PhysicalMapAllowedMask = (1ULL << 36) - 1;
+
+ union MapRange {
+ static_assert(CapabilityId<CapabilityType::MapRange> + 1 == 7);
+
+ RawCapabilityValue raw;
+ BitField<0, 7, CapabilityType> id;
+ BitField<7, 24, u32> address;
+ BitField<31, 1, u32> read_only;
+ };
+
+ union MapRangeSize {
+ static_assert(CapabilityId<CapabilityType::MapRange> + 1 == 7);
+
+ RawCapabilityValue raw;
+ BitField<0, 7, CapabilityType> id;
+ BitField<7, 20, u32> pages;
+ BitField<27, 4, u32> reserved;
+ BitField<31, 1, u32> normal;
+ };
+
+ union MapIoPage {
+ static_assert(CapabilityId<CapabilityType::MapIoPage> + 1 == 8);
+
+ RawCapabilityValue raw;
+ BitField<0, 8, CapabilityType> id;
+ BitField<8, 24, u32> address;
+ };
+
+ enum class RegionType : u32 {
+ NoMapping = 0,
+ KernelTraceBuffer = 1,
+ OnMemoryBootImage = 2,
+ DTB = 3,
+ };
+
+ union MapRegion {
+ static_assert(CapabilityId<CapabilityType::MapRegion> + 1 == 11);
+
+ RawCapabilityValue raw;
+ BitField<0, 11, CapabilityType> id;
+ BitField<11, 6, RegionType> region0;
+ BitField<17, 1, u32> read_only0;
+ BitField<18, 6, RegionType> region1;
+ BitField<24, 1, u32> read_only1;
+ BitField<25, 6, RegionType> region2;
+ BitField<31, 1, u32> read_only2;
+ };
+
+ union InterruptPair {
+ static_assert(CapabilityId<CapabilityType::InterruptPair> + 1 == 12);
+
+ RawCapabilityValue raw;
+ BitField<0, 12, CapabilityType> id;
+ BitField<12, 10, u32> interrupt_id0;
+ BitField<22, 10, u32> interrupt_id1;
+ };
+
+ union ProgramType {
+ static_assert(CapabilityId<CapabilityType::ProgramType> + 1 == 14);
+
+ RawCapabilityValue raw;
+ BitField<0, 14, CapabilityType> id;
+ BitField<14, 3, u32> type;
+ BitField<17, 15, u32> reserved;
+ };
+
+ union KernelVersion {
+ static_assert(CapabilityId<CapabilityType::KernelVersion> + 1 == 15);
+
+ RawCapabilityValue raw;
+ BitField<0, 15, CapabilityType> id;
+ BitField<15, 4, u32> major_version;
+ BitField<19, 13, u32> minor_version;
+ };
+
+ union HandleTable {
+ static_assert(CapabilityId<CapabilityType::HandleTable> + 1 == 16);
+
+ RawCapabilityValue raw;
+ BitField<0, 16, CapabilityType> id;
+ BitField<16, 10, u32> size;
+ BitField<26, 6, u32> reserved;
+ };
+
+ union DebugFlags {
+ static_assert(CapabilityId<CapabilityType::DebugFlags> + 1 == 17);
+
+ RawCapabilityValue raw;
+ BitField<0, 17, CapabilityType> id;
+ BitField<17, 1, u32> allow_debug;
+ BitField<18, 1, u32> force_debug;
+ BitField<19, 13, u32> reserved;
+ };
+
+ static_assert(sizeof(CorePriority) == 4);
+ static_assert(sizeof(SyscallMask) == 4);
+ static_assert(sizeof(MapRange) == 4);
+ static_assert(sizeof(MapRangeSize) == 4);
+ static_assert(sizeof(MapIoPage) == 4);
+ static_assert(sizeof(MapRegion) == 4);
+ static_assert(sizeof(InterruptPair) == 4);
+ static_assert(sizeof(ProgramType) == 4);
+ static_assert(sizeof(KernelVersion) == 4);
+ static_assert(sizeof(HandleTable) == 4);
+ static_assert(sizeof(DebugFlags) == 4);
+
+ static constexpr u32 InitializeOnceFlags =
+ CapabilityFlag<CapabilityType::CorePriority> | CapabilityFlag<CapabilityType::ProgramType> |
+ CapabilityFlag<CapabilityType::KernelVersion> |
+ CapabilityFlag<CapabilityType::HandleTable> | CapabilityFlag<CapabilityType::DebugFlags>;
+
+ static const u32 PaddingInterruptId = 0x3FF;
+ static_assert(PaddingInterruptId < InterruptIdCount);
+
+private:
+ constexpr bool SetSvcAllowed(u32 id) {
+ if (id < m_svc_access_flags.size()) [[likely]] {
+ m_svc_access_flags[id] = true;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ constexpr bool SetInterruptPermitted(u32 id) {
+ if (id < m_irq_access_flags.size()) [[likely]] {
+ m_irq_access_flags[id] = true;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ Result SetCorePriorityCapability(const u32 cap);
+ Result SetSyscallMaskCapability(const u32 cap, u32& set_svc);
+ Result MapRange_(const u32 cap, const u32 size_cap, KPageTable* page_table);
+ Result MapIoPage_(const u32 cap, KPageTable* page_table);
+ Result MapRegion_(const u32 cap, KPageTable* page_table);
+ Result SetInterruptPairCapability(const u32 cap);
+ Result SetProgramTypeCapability(const u32 cap);
+ Result SetKernelVersionCapability(const u32 cap);
+ Result SetHandleTableCapability(const u32 cap);
+ Result SetDebugFlagsCapability(const u32 cap);
+
+ template <typename F>
+ static Result ProcessMapRegionCapability(const u32 cap, F f);
+ static Result CheckMapRegion(KernelCore& kernel, const u32 cap);
+
+ Result SetCapability(const u32 cap, u32& set_flags, u32& set_svc, KPageTable* page_table);
+ Result SetCapabilities(std::span<const u32> caps, KPageTable* page_table);
+
+private:
+ Svc::SvcAccessFlagSet m_svc_access_flags{};
+ InterruptFlagSet m_irq_access_flags{};
+ u64 m_core_mask{};
+ u64 m_phys_core_mask{};
+ u64 m_priority_mask{};
+ u32 m_debug_capabilities{};
+ s32 m_handle_table_size{};
+ u32 m_intended_kernel_version{};
+ u32 m_program_type{};
+};
+
+} // namespace Kernel
diff --git a/src/core/hle/kernel/k_client_port.cpp b/src/core/hle/kernel/k_client_port.cpp
index 2ec623a58..40e09e532 100644
--- a/src/core/hle/kernel/k_client_port.cpp
+++ b/src/core/hle/kernel/k_client_port.cpp
@@ -2,7 +2,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#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"
@@ -12,26 +11,21 @@
namespace Kernel {
-KClientPort::KClientPort(KernelCore& kernel_) : KSynchronizationObject{kernel_} {}
+KClientPort::KClientPort(KernelCore& kernel) : KSynchronizationObject{kernel} {}
KClientPort::~KClientPort() = default;
-void KClientPort::Initialize(KPort* parent_port_, s32 max_sessions_, std::string&& name_) {
+void KClientPort::Initialize(KPort* parent, s32 max_sessions) {
// Set member variables.
- num_sessions = 0;
- peak_sessions = 0;
- parent = parent_port_;
- max_sessions = max_sessions_;
- name = std::move(name_);
+ m_num_sessions = 0;
+ m_peak_sessions = 0;
+ m_parent = parent;
+ m_max_sessions = max_sessions;
}
void KClientPort::OnSessionFinalized() {
- KScopedSchedulerLock sl{kernel};
+ KScopedSchedulerLock sl{m_kernel};
- // This might happen if a session was improperly used with this port.
- ASSERT_MSG(num_sessions > 0, "num_sessions is invalid");
-
- const auto prev = num_sessions--;
- if (prev == max_sessions) {
+ if (const auto prev = m_num_sessions--; prev == m_max_sessions) {
this->NotifyAvailable();
}
}
@@ -48,80 +42,81 @@ bool KClientPort::IsServerClosed() const {
void KClientPort::Destroy() {
// Note with our parent that we're closed.
- parent->OnClientClosed();
+ m_parent->OnClientClosed();
// Close our reference to our parent.
- parent->Close();
+ m_parent->Close();
}
bool KClientPort::IsSignaled() const {
- return num_sessions < max_sessions;
+ return m_num_sessions.load() < m_max_sessions;
}
Result KClientPort::CreateSession(KClientSession** out) {
+ // Declare the session we're going to allocate.
+ KSession* session{};
+
// Reserve a new session from the resource limit.
- KScopedResourceReservation session_reservation(kernel.CurrentProcess()->GetResourceLimit(),
- LimitableResource::SessionCountMax);
+ //! FIXME: we are reserving this from the wrong resource limit!
+ KScopedResourceReservation session_reservation(
+ m_kernel.ApplicationProcess()->GetResourceLimit(), LimitableResource::SessionCountMax);
R_UNLESS(session_reservation.Succeeded(), ResultLimitReached);
+ // Allocate a session normally.
+ session = KSession::Create(m_kernel);
+
+ // Check that we successfully created a session.
+ R_UNLESS(session != nullptr, ResultOutOfResource);
+
// Update the session counts.
{
+ ON_RESULT_FAILURE {
+ session->Close();
+ };
+
// Atomically increment the number of sessions.
s32 new_sessions{};
{
- const auto max = max_sessions;
- auto cur_sessions = num_sessions.load(std::memory_order_acquire);
+ const auto max = m_max_sessions;
+ auto cur_sessions = m_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));
+ } while (!m_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);
+ auto peak = m_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));
+ } while (!m_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());
+ session->Initialize(this, m_parent->GetName());
// Commit the session reservation.
session_reservation.Commit();
// Register the session.
- KSession::Register(kernel, session);
- auto session_guard = SCOPE_GUARD({
+ KSession::Register(m_kernel, session);
+ ON_RESULT_FAILURE {
session->GetClientSession().Close();
session->GetServerSession().Close();
- });
+ };
// Enqueue the session with our parent.
- R_TRY(parent->EnqueueSession(std::addressof(session->GetServerSession())));
+ R_TRY(m_parent->EnqueueSession(std::addressof(session->GetServerSession())));
// We succeeded, so set the output.
- session_guard.Cancel();
*out = std::addressof(session->GetClientSession());
- return ResultSuccess;
+ R_SUCCEED();
}
} // namespace Kernel
diff --git a/src/core/hle/kernel/k_client_port.h b/src/core/hle/kernel/k_client_port.h
index 81046fb86..23db06ddf 100644
--- a/src/core/hle/kernel/k_client_port.h
+++ b/src/core/hle/kernel/k_client_port.h
@@ -4,7 +4,6 @@
#pragma once
#include <memory>
-#include <string>
#include "common/common_types.h"
#include "core/hle/kernel/k_synchronization_object.h"
@@ -15,34 +14,33 @@ namespace Kernel {
class KClientSession;
class KernelCore;
class KPort;
-class SessionRequestManager;
class KClientPort final : public KSynchronizationObject {
KERNEL_AUTOOBJECT_TRAITS(KClientPort, KSynchronizationObject);
public:
- explicit KClientPort(KernelCore& kernel_);
+ explicit KClientPort(KernelCore& kernel);
~KClientPort() override;
- void Initialize(KPort* parent_, s32 max_sessions_, std::string&& name_);
+ void Initialize(KPort* parent, s32 max_sessions);
void OnSessionFinalized();
void OnServerClosed();
const KPort* GetParent() const {
- return parent;
+ return m_parent;
}
KPort* GetParent() {
- return parent;
+ return m_parent;
}
s32 GetNumSessions() const {
- return num_sessions;
+ return m_num_sessions;
}
s32 GetPeakSessions() const {
- return peak_sessions;
+ return m_peak_sessions;
}
s32 GetMaxSessions() const {
- return max_sessions;
+ return m_max_sessions;
}
bool IsLight() const;
@@ -55,10 +53,10 @@ public:
Result CreateSession(KClientSession** out);
private:
- std::atomic<s32> num_sessions{};
- std::atomic<s32> peak_sessions{};
- s32 max_sessions{};
- KPort* parent{};
+ std::atomic<s32> m_num_sessions{};
+ std::atomic<s32> m_peak_sessions{};
+ s32 m_max_sessions{};
+ KPort* m_parent{};
};
} // namespace Kernel
diff --git a/src/core/hle/kernel/k_client_session.cpp b/src/core/hle/kernel/k_client_session.cpp
index b4197a8d5..72b66270d 100644
--- a/src/core/hle/kernel/k_client_session.cpp
+++ b/src/core/hle/kernel/k_client_session.cpp
@@ -2,7 +2,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/scope_exit.h"
-#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"
@@ -13,28 +12,28 @@ namespace Kernel {
static constexpr u32 MessageBufferSize = 0x100;
-KClientSession::KClientSession(KernelCore& kernel_)
- : KAutoObjectWithSlabHeapAndContainer{kernel_} {}
+KClientSession::KClientSession(KernelCore& kernel) : KAutoObjectWithSlabHeapAndContainer{kernel} {}
KClientSession::~KClientSession() = default;
void KClientSession::Destroy() {
- parent->OnClientClosed();
- parent->Close();
+ m_parent->OnClientClosed();
+ m_parent->Close();
}
void KClientSession::OnServerClosed() {}
Result KClientSession::SendSyncRequest() {
// Create a session request.
- KSessionRequest* request = KSessionRequest::Create(kernel);
+ KSessionRequest* request = KSessionRequest::Create(m_kernel);
R_UNLESS(request != nullptr, ResultOutOfResource);
SCOPE_EXIT({ request->Close(); });
// Initialize the request.
- request->Initialize(nullptr, GetCurrentThread(kernel).GetTLSAddress(), MessageBufferSize);
+ request->Initialize(nullptr, GetInteger(GetCurrentThread(m_kernel).GetTlsAddress()),
+ MessageBufferSize);
// Send the request.
- return parent->GetServerSession().OnRequest(request);
+ R_RETURN(m_parent->GetServerSession().OnRequest(request));
}
} // namespace Kernel
diff --git a/src/core/hle/kernel/k_client_session.h b/src/core/hle/kernel/k_client_session.h
index b4a19c546..9b62e55e4 100644
--- a/src/core/hle/kernel/k_client_session.h
+++ b/src/core/hle/kernel/k_client_session.h
@@ -30,20 +30,19 @@ class KClientSession final
KERNEL_AUTOOBJECT_TRAITS(KClientSession, KAutoObject);
public:
- explicit KClientSession(KernelCore& kernel_);
+ explicit KClientSession(KernelCore& kernel);
~KClientSession() override;
- void Initialize(KSession* parent_session_, std::string&& name_) {
+ void Initialize(KSession* parent) {
// Set member variables.
- parent = parent_session_;
- name = std::move(name_);
+ m_parent = parent;
}
void Destroy() override;
- static void PostDestroy([[maybe_unused]] uintptr_t arg) {}
+ static void PostDestroy(uintptr_t arg) {}
KSession* GetParent() const {
- return parent;
+ return m_parent;
}
Result SendSyncRequest();
@@ -51,7 +50,7 @@ public:
void OnServerClosed();
private:
- KSession* parent{};
+ KSession* m_parent{};
};
} // namespace Kernel
diff --git a/src/core/hle/kernel/k_code_memory.cpp b/src/core/hle/kernel/k_code_memory.cpp
index d9da1e600..3583bee44 100644
--- a/src/core/hle/kernel/k_code_memory.cpp
+++ b/src/core/hle/kernel/k_code_memory.cpp
@@ -16,18 +16,19 @@
namespace Kernel {
-KCodeMemory::KCodeMemory(KernelCore& kernel_)
- : KAutoObjectWithSlabHeapAndContainer{kernel_}, m_lock(kernel_) {}
+KCodeMemory::KCodeMemory(KernelCore& kernel)
+ : KAutoObjectWithSlabHeapAndContainer{kernel}, m_lock(kernel) {}
-Result KCodeMemory::Initialize(Core::DeviceMemory& device_memory, VAddr addr, size_t size) {
+Result KCodeMemory::Initialize(Core::DeviceMemory& device_memory, KProcessAddress addr,
+ size_t size) {
// Set members.
- m_owner = kernel.CurrentProcess();
+ m_owner = GetCurrentProcessPointer(m_kernel);
// Get the owner page table.
auto& page_table = m_owner->PageTable();
// Construct the page group.
- m_page_group.emplace(kernel, page_table.GetBlockInfoManager());
+ m_page_group.emplace(m_kernel, page_table.GetBlockInfoManager());
// Lock the memory.
R_TRY(page_table.LockForCodeMemory(std::addressof(*m_page_group), addr, size))
@@ -45,7 +46,7 @@ Result KCodeMemory::Initialize(Core::DeviceMemory& device_memory, VAddr addr, si
m_is_mapped = false;
// We succeeded.
- return ResultSuccess;
+ R_SUCCEED();
}
void KCodeMemory::Finalize() {
@@ -63,7 +64,7 @@ void KCodeMemory::Finalize() {
m_owner->Close();
}
-Result KCodeMemory::Map(VAddr address, size_t size) {
+Result KCodeMemory::Map(KProcessAddress address, size_t size) {
// Validate the size.
R_UNLESS(m_page_group->GetNumPages() == Common::DivideUp(size, PageSize), ResultInvalidSize);
@@ -74,16 +75,16 @@ Result KCodeMemory::Map(VAddr address, size_t size) {
R_UNLESS(!m_is_mapped, ResultInvalidState);
// Map the memory.
- R_TRY(kernel.CurrentProcess()->PageTable().MapPages(
+ R_TRY(GetCurrentProcess(m_kernel).PageTable().MapPageGroup(
address, *m_page_group, KMemoryState::CodeOut, KMemoryPermission::UserReadWrite));
// Mark ourselves as mapped.
m_is_mapped = true;
- return ResultSuccess;
+ R_SUCCEED();
}
-Result KCodeMemory::Unmap(VAddr address, size_t size) {
+Result KCodeMemory::Unmap(KProcessAddress address, size_t size) {
// Validate the size.
R_UNLESS(m_page_group->GetNumPages() == Common::DivideUp(size, PageSize), ResultInvalidSize);
@@ -91,16 +92,16 @@ Result KCodeMemory::Unmap(VAddr address, size_t size) {
KScopedLightLock lk(m_lock);
// Unmap the memory.
- R_TRY(kernel.CurrentProcess()->PageTable().UnmapPages(address, *m_page_group,
- KMemoryState::CodeOut));
+ R_TRY(GetCurrentProcess(m_kernel).PageTable().UnmapPageGroup(address, *m_page_group,
+ KMemoryState::CodeOut));
// Mark ourselves as unmapped.
m_is_mapped = false;
- return ResultSuccess;
+ R_SUCCEED();
}
-Result KCodeMemory::MapToOwner(VAddr address, size_t size, Svc::MemoryPermission perm) {
+Result KCodeMemory::MapToOwner(KProcessAddress address, size_t size, Svc::MemoryPermission perm) {
// Validate the size.
R_UNLESS(m_page_group->GetNumPages() == Common::DivideUp(size, PageSize), ResultInvalidSize);
@@ -125,16 +126,16 @@ Result KCodeMemory::MapToOwner(VAddr address, size_t size, Svc::MemoryPermission
}
// Map the memory.
- R_TRY(
- m_owner->PageTable().MapPages(address, *m_page_group, KMemoryState::GeneratedCode, k_perm));
+ R_TRY(m_owner->PageTable().MapPageGroup(address, *m_page_group, KMemoryState::GeneratedCode,
+ k_perm));
// Mark ourselves as mapped.
m_is_owner_mapped = true;
- return ResultSuccess;
+ R_SUCCEED();
}
-Result KCodeMemory::UnmapFromOwner(VAddr address, size_t size) {
+Result KCodeMemory::UnmapFromOwner(KProcessAddress address, size_t size) {
// Validate the size.
R_UNLESS(m_page_group->GetNumPages() == Common::DivideUp(size, PageSize), ResultInvalidSize);
@@ -142,12 +143,12 @@ Result KCodeMemory::UnmapFromOwner(VAddr address, size_t size) {
KScopedLightLock lk(m_lock);
// Unmap the memory.
- R_TRY(m_owner->PageTable().UnmapPages(address, *m_page_group, KMemoryState::GeneratedCode));
+ R_TRY(m_owner->PageTable().UnmapPageGroup(address, *m_page_group, KMemoryState::GeneratedCode));
// Mark ourselves as unmapped.
m_is_owner_mapped = false;
- return ResultSuccess;
+ R_SUCCEED();
}
} // namespace Kernel
diff --git a/src/core/hle/kernel/k_code_memory.h b/src/core/hle/kernel/k_code_memory.h
index 5b260b385..26fe6b3dc 100644
--- a/src/core/hle/kernel/k_code_memory.h
+++ b/src/core/hle/kernel/k_code_memory.h
@@ -5,12 +5,12 @@
#include <optional>
-#include "common/common_types.h"
#include "core/device_memory.h"
#include "core/hle/kernel/k_auto_object.h"
#include "core/hle/kernel/k_light_lock.h"
#include "core/hle/kernel/k_page_group.h"
#include "core/hle/kernel/k_process.h"
+#include "core/hle/kernel/k_typed_address.h"
#include "core/hle/kernel/slab_helpers.h"
#include "core/hle/kernel/svc_types.h"
#include "core/hle/result.h"
@@ -29,25 +29,25 @@ class KCodeMemory final
KERNEL_AUTOOBJECT_TRAITS(KCodeMemory, KAutoObject);
public:
- explicit KCodeMemory(KernelCore& kernel_);
+ explicit KCodeMemory(KernelCore& kernel);
- Result Initialize(Core::DeviceMemory& device_memory, VAddr address, size_t size);
+ Result Initialize(Core::DeviceMemory& device_memory, KProcessAddress address, size_t size);
void Finalize() override;
- Result Map(VAddr address, size_t size);
- Result Unmap(VAddr address, size_t size);
- Result MapToOwner(VAddr address, size_t size, Svc::MemoryPermission perm);
- Result UnmapFromOwner(VAddr address, size_t size);
+ Result Map(KProcessAddress address, size_t size);
+ Result Unmap(KProcessAddress address, size_t size);
+ Result MapToOwner(KProcessAddress address, size_t size, Svc::MemoryPermission perm);
+ Result UnmapFromOwner(KProcessAddress address, size_t size);
bool IsInitialized() const override {
return m_is_initialized;
}
- static void PostDestroy([[maybe_unused]] uintptr_t arg) {}
+ static void PostDestroy(uintptr_t arg) {}
KProcess* GetOwner() const override {
return m_owner;
}
- VAddr GetSourceAddress() const {
+ KProcessAddress GetSourceAddress() const {
return m_address;
}
size_t GetSize() const {
@@ -57,7 +57,7 @@ public:
private:
std::optional<KPageGroup> m_page_group{};
KProcess* m_owner{};
- VAddr m_address{};
+ KProcessAddress m_address{};
KLightLock m_lock;
bool m_is_initialized{};
bool m_is_owner_mapped{};
diff --git a/src/core/hle/kernel/k_condition_variable.cpp b/src/core/hle/kernel/k_condition_variable.cpp
index 124149697..efbac0e6a 100644
--- a/src/core/hle/kernel/k_condition_variable.cpp
+++ b/src/core/hle/kernel/k_condition_variable.cpp
@@ -4,7 +4,6 @@
#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"
@@ -19,36 +18,41 @@ namespace Kernel {
namespace {
-bool ReadFromUser(Core::System& system, u32* out, VAddr address) {
- *out = system.Memory().Read32(address);
+bool ReadFromUser(KernelCore& kernel, u32* out, KProcessAddress address) {
+ *out = GetCurrentMemory(kernel).Read32(GetInteger(address));
return true;
}
-bool WriteToUser(Core::System& system, VAddr address, const u32* p) {
- system.Memory().Write32(address, *p);
+bool WriteToUser(KernelCore& kernel, KProcessAddress address, const u32* p) {
+ GetCurrentMemory(kernel).Write32(GetInteger(address), *p);
return true;
}
-bool UpdateLockAtomic(Core::System& system, u32* out, VAddr address, u32 if_zero,
+bool UpdateLockAtomic(Core::System& system, u32* out, KProcessAddress address, u32 if_zero,
u32 new_orr_mask) {
auto& monitor = system.Monitor();
const auto current_core = system.Kernel().CurrentPhysicalCoreIndex();
- // Load the value from the address.
- const auto expected = monitor.ExclusiveRead32(current_core, address);
+ u32 expected{};
- // Orr in the new mask.
- u32 value = expected | new_orr_mask;
+ while (true) {
+ // Load the value from the address.
+ expected = monitor.ExclusiveRead32(current_core, GetInteger(address));
- // If the value is zero, use the if_zero value, otherwise use the newly orr'd value.
- if (!expected) {
- value = if_zero;
- }
+ // Orr in the new mask.
+ u32 value = expected | new_orr_mask;
+
+ // If the value is zero, use the if_zero value, otherwise use the newly orr'd value.
+ if (!expected) {
+ value = if_zero;
+ }
+
+ // Try to store.
+ if (monitor.ExclusiveWrite32(current_core, GetInteger(address), value)) {
+ break;
+ }
- // Try to store.
- if (!monitor.ExclusiveWrite32(current_core, address, value)) {
// If we failed to store, try again.
- return UpdateLockAtomic(system, out, address, if_zero, new_orr_mask);
}
// We're done.
@@ -58,8 +62,8 @@ bool UpdateLockAtomic(Core::System& system, u32* out, VAddr address, u32 if_zero
class ThreadQueueImplForKConditionVariableWaitForAddress final : public KThreadQueue {
public:
- explicit ThreadQueueImplForKConditionVariableWaitForAddress(KernelCore& kernel_)
- : KThreadQueue(kernel_) {}
+ explicit ThreadQueueImplForKConditionVariableWaitForAddress(KernelCore& kernel)
+ : KThreadQueue(kernel) {}
void CancelWait(KThread* waiting_thread, Result wait_result, bool cancel_timer_task) override {
// Remove the thread as a waiter from its owner.
@@ -76,8 +80,8 @@ private:
public:
explicit ThreadQueueImplForKConditionVariableWaitConditionVariable(
- KernelCore& kernel_, KConditionVariable::ThreadTree* t)
- : KThreadQueue(kernel_), m_tree(t) {}
+ KernelCore& kernel, KConditionVariable::ThreadTree* t)
+ : KThreadQueue(kernel), m_tree(t) {}
void CancelWait(KThread* waiting_thread, Result wait_result, bool cancel_timer_task) override {
// Remove the thread as a waiter from its owner.
@@ -98,111 +102,113 @@ public:
} // namespace
-KConditionVariable::KConditionVariable(Core::System& system_)
- : system{system_}, kernel{system.Kernel()} {}
+KConditionVariable::KConditionVariable(Core::System& system)
+ : m_system{system}, m_kernel{system.Kernel()} {}
KConditionVariable::~KConditionVariable() = default;
-Result KConditionVariable::SignalToAddress(VAddr addr) {
- KThread* owner_thread = GetCurrentThreadPointer(kernel);
+Result KConditionVariable::SignalToAddress(KProcessAddress addr) {
+ KThread* owner_thread = GetCurrentThreadPointer(m_kernel);
// Signal the address.
{
- KScopedSchedulerLock sl(kernel);
+ KScopedSchedulerLock sl(m_kernel);
// Remove waiter thread.
- s32 num_waiters{};
- KThread* next_owner_thread =
- owner_thread->RemoveWaiterByKey(std::addressof(num_waiters), addr);
+ bool has_waiters{};
+ KThread* const next_owner_thread =
+ owner_thread->RemoveUserWaiterByKey(std::addressof(has_waiters), addr);
// Determine the next tag.
u32 next_value{};
if (next_owner_thread != nullptr) {
next_value = next_owner_thread->GetAddressKeyValue();
- if (num_waiters > 1) {
+ if (has_waiters) {
next_value |= Svc::HandleWaitMask;
}
+ }
- // Write the value to userspace.
- Result result{ResultSuccess};
- if (WriteToUser(system, addr, std::addressof(next_value))) [[likely]] {
- result = ResultSuccess;
- } else {
- result = ResultInvalidCurrentMemory;
- }
+ // Synchronize memory before proceeding.
+ std::atomic_thread_fence(std::memory_order_seq_cst);
- // Signal the next owner thread.
- next_owner_thread->EndWait(result);
- return result;
+ // Write the value to userspace.
+ Result result{ResultSuccess};
+ if (WriteToUser(m_kernel, addr, std::addressof(next_value))) [[likely]] {
+ result = ResultSuccess;
} else {
- // Just write the value to userspace.
- R_UNLESS(WriteToUser(system, addr, std::addressof(next_value)),
- ResultInvalidCurrentMemory);
+ result = ResultInvalidCurrentMemory;
+ }
- return ResultSuccess;
+ // If necessary, signal the next owner thread.
+ if (next_owner_thread != nullptr) {
+ next_owner_thread->EndWait(result);
}
+
+ R_RETURN(result);
}
}
-Result KConditionVariable::WaitForAddress(Handle handle, VAddr addr, u32 value) {
- KThread* cur_thread = GetCurrentThreadPointer(kernel);
- ThreadQueueImplForKConditionVariableWaitForAddress wait_queue(kernel);
+Result KConditionVariable::WaitForAddress(Handle handle, KProcessAddress addr, u32 value) {
+ KThread* cur_thread = GetCurrentThreadPointer(m_kernel);
+ ThreadQueueImplForKConditionVariableWaitForAddress wait_queue(m_kernel);
// Wait for the address.
KThread* owner_thread{};
{
- KScopedSchedulerLock sl(kernel);
+ KScopedSchedulerLock sl(m_kernel);
// Check if the thread should terminate.
R_UNLESS(!cur_thread->IsTerminationRequested(), ResultTerminationRequested);
// Read the tag from userspace.
u32 test_tag{};
- R_UNLESS(ReadFromUser(system, std::addressof(test_tag), addr), ResultInvalidCurrentMemory);
+ R_UNLESS(ReadFromUser(m_kernel, std::addressof(test_tag), addr),
+ ResultInvalidCurrentMemory);
// If the tag isn't the handle (with wait mask), we're done.
R_SUCCEED_IF(test_tag != (handle | Svc::HandleWaitMask));
// Get the lock owner thread.
- owner_thread = kernel.CurrentProcess()
- ->GetHandleTable()
+ owner_thread = GetCurrentProcess(m_kernel)
+ .GetHandleTable()
.GetObjectWithoutPseudoHandle<KThread>(handle)
.ReleasePointerUnsafe();
R_UNLESS(owner_thread != nullptr, ResultInvalidHandle);
// Update the lock.
- cur_thread->SetAddressKey(addr, value);
+ cur_thread->SetUserAddressKey(addr, value);
owner_thread->AddWaiter(cur_thread);
// Begin waiting.
cur_thread->BeginWait(std::addressof(wait_queue));
cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::ConditionVar);
- cur_thread->SetMutexWaitAddressForDebugging(addr);
}
// Close our reference to the owner thread, now that the wait is over.
owner_thread->Close();
// Get the wait result.
- return cur_thread->GetWaitResult();
+ R_RETURN(cur_thread->GetWaitResult());
}
void KConditionVariable::SignalImpl(KThread* thread) {
// Check pre-conditions.
- ASSERT(kernel.GlobalSchedulerContext().IsLocked());
+ ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(m_kernel));
// Update the tag.
- VAddr address = thread->GetAddressKey();
+ KProcessAddress address = thread->GetAddressKey();
u32 own_tag = thread->GetAddressKeyValue();
u32 prev_tag{};
bool can_access{};
{
- // TODO(bunnei): We should disable interrupts here via KScopedInterruptDisable.
+ // NOTE: If scheduler lock is not held here, interrupt disable is required.
+ // KScopedInterruptDisable di;
+
// TODO(bunnei): We should call CanAccessAtomic(..) here.
can_access = true;
if (can_access) [[likely]] {
- UpdateLockAtomic(system, std::addressof(prev_tag), address, own_tag,
+ UpdateLockAtomic(m_system, std::addressof(prev_tag), address, own_tag,
Svc::HandleWaitMask);
}
}
@@ -213,8 +219,8 @@ void KConditionVariable::SignalImpl(KThread* thread) {
thread->EndWait(ResultSuccess);
} else {
// Get the previous owner.
- KThread* owner_thread = kernel.CurrentProcess()
- ->GetHandleTable()
+ KThread* owner_thread = GetCurrentProcess(m_kernel)
+ .GetHandleTable()
.GetObjectWithoutPseudoHandle<KThread>(
static_cast<Handle>(prev_tag & ~Svc::HandleWaitMask))
.ReleasePointerUnsafe();
@@ -238,55 +244,58 @@ void KConditionVariable::Signal(u64 cv_key, s32 count) {
// Perform signaling.
s32 num_waiters{};
{
- KScopedSchedulerLock sl(kernel);
+ KScopedSchedulerLock sl(m_kernel);
- auto it = thread_tree.nfind_key({cv_key, -1});
- while ((it != thread_tree.end()) && (count <= 0 || num_waiters < count) &&
+ auto it = m_tree.nfind_key({cv_key, -1});
+ while ((it != m_tree.end()) && (count <= 0 || num_waiters < count) &&
(it->GetConditionVariableKey() == cv_key)) {
KThread* target_thread = std::addressof(*it);
- this->SignalImpl(target_thread);
- it = thread_tree.erase(it);
+ it = m_tree.erase(it);
target_thread->ClearConditionVariable();
+
+ this->SignalImpl(target_thread);
+
++num_waiters;
}
// If we have no waiters, clear the has waiter flag.
- if (it == thread_tree.end() || it->GetConditionVariableKey() != cv_key) {
+ if (it == m_tree.end() || it->GetConditionVariableKey() != cv_key) {
const u32 has_waiter_flag{};
- WriteToUser(system, cv_key, std::addressof(has_waiter_flag));
+ WriteToUser(m_kernel, cv_key, std::addressof(has_waiter_flag));
}
}
}
-Result KConditionVariable::Wait(VAddr addr, u64 key, u32 value, s64 timeout) {
+Result KConditionVariable::Wait(KProcessAddress addr, u64 key, u32 value, s64 timeout) {
// Prepare to wait.
- KThread* cur_thread = GetCurrentThreadPointer(kernel);
- ThreadQueueImplForKConditionVariableWaitConditionVariable wait_queue(
- kernel, std::addressof(thread_tree));
+ KThread* cur_thread = GetCurrentThreadPointer(m_kernel);
+ KHardwareTimer* timer{};
+ ThreadQueueImplForKConditionVariableWaitConditionVariable wait_queue(m_kernel,
+ std::addressof(m_tree));
{
- KScopedSchedulerLockAndSleep slp(kernel, cur_thread, timeout);
+ KScopedSchedulerLockAndSleep slp(m_kernel, std::addressof(timer), cur_thread, timeout);
// Check that the thread isn't terminating.
if (cur_thread->IsTerminationRequested()) {
slp.CancelSleep();
- return ResultTerminationRequested;
+ R_THROW(ResultTerminationRequested);
}
// Update the value and process for the next owner.
{
// Remove waiter thread.
- s32 num_waiters{};
+ bool has_waiters{};
KThread* next_owner_thread =
- cur_thread->RemoveWaiterByKey(std::addressof(num_waiters), addr);
+ cur_thread->RemoveUserWaiterByKey(std::addressof(has_waiters), addr);
// Update for the next owner thread.
u32 next_value{};
if (next_owner_thread != nullptr) {
// Get the next tag value.
next_value = next_owner_thread->GetAddressKeyValue();
- if (num_waiters > 1) {
+ if (has_waiters) {
next_value |= Svc::HandleWaitMask;
}
@@ -297,14 +306,14 @@ Result KConditionVariable::Wait(VAddr addr, u64 key, u32 value, s64 timeout) {
// Write to the cv key.
{
const u32 has_waiter_flag = 1;
- WriteToUser(system, key, std::addressof(has_waiter_flag));
- // TODO(bunnei): We should call DataMemoryBarrier(..) here.
+ WriteToUser(m_kernel, key, std::addressof(has_waiter_flag));
+ std::atomic_thread_fence(std::memory_order_seq_cst);
}
// Write the value to userspace.
- if (!WriteToUser(system, addr, std::addressof(next_value))) {
+ if (!WriteToUser(m_kernel, addr, std::addressof(next_value))) {
slp.CancelSleep();
- return ResultInvalidCurrentMemory;
+ R_THROW(ResultInvalidCurrentMemory);
}
}
@@ -312,17 +321,17 @@ Result KConditionVariable::Wait(VAddr addr, u64 key, u32 value, s64 timeout) {
R_UNLESS(timeout != 0, ResultTimedOut);
// Update condition variable tracking.
- cur_thread->SetConditionVariable(std::addressof(thread_tree), addr, key, value);
- thread_tree.insert(*cur_thread);
+ cur_thread->SetConditionVariable(std::addressof(m_tree), addr, key, value);
+ m_tree.insert(*cur_thread);
// Begin waiting.
+ wait_queue.SetHardwareTimer(timer);
cur_thread->BeginWait(std::addressof(wait_queue));
cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::ConditionVar);
- cur_thread->SetMutexWaitAddressForDebugging(addr);
}
// Get the wait result.
- return cur_thread->GetWaitResult();
+ R_RETURN(cur_thread->GetWaitResult());
}
} // namespace Kernel
diff --git a/src/core/hle/kernel/k_condition_variable.h b/src/core/hle/kernel/k_condition_variable.h
index fad4ed011..8c2f3ae51 100644
--- a/src/core/hle/kernel/k_condition_variable.h
+++ b/src/core/hle/kernel/k_condition_variable.h
@@ -4,10 +4,10 @@
#pragma once
#include "common/assert.h"
-#include "common/common_types.h"
#include "core/hle/kernel/k_scheduler.h"
#include "core/hle/kernel/k_thread.h"
+#include "core/hle/kernel/k_typed_address.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/result.h"
@@ -21,36 +21,36 @@ class KConditionVariable {
public:
using ThreadTree = typename KThread::ConditionVariableThreadTreeType;
- explicit KConditionVariable(Core::System& system_);
+ explicit KConditionVariable(Core::System& system);
~KConditionVariable();
// Arbitration
- [[nodiscard]] Result SignalToAddress(VAddr addr);
- [[nodiscard]] Result WaitForAddress(Handle handle, VAddr addr, u32 value);
+ Result SignalToAddress(KProcessAddress addr);
+ Result WaitForAddress(Handle handle, KProcessAddress addr, u32 value);
// Condition variable
void Signal(u64 cv_key, s32 count);
- [[nodiscard]] Result Wait(VAddr addr, u64 key, u32 value, s64 timeout);
+ Result Wait(KProcessAddress addr, u64 key, u32 value, s64 timeout);
private:
void SignalImpl(KThread* thread);
- ThreadTree thread_tree;
-
- Core::System& system;
- KernelCore& kernel;
+private:
+ Core::System& m_system;
+ KernelCore& m_kernel;
+ ThreadTree m_tree{};
};
-inline void BeforeUpdatePriority(const KernelCore& kernel, KConditionVariable::ThreadTree* tree,
+inline void BeforeUpdatePriority(KernelCore& kernel, KConditionVariable::ThreadTree* tree,
KThread* thread) {
- ASSERT(kernel.GlobalSchedulerContext().IsLocked());
+ ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(kernel));
tree->erase(tree->iterator_to(*thread));
}
-inline void AfterUpdatePriority(const KernelCore& kernel, KConditionVariable::ThreadTree* tree,
+inline void AfterUpdatePriority(KernelCore& kernel, KConditionVariable::ThreadTree* tree,
KThread* thread) {
- ASSERT(kernel.GlobalSchedulerContext().IsLocked());
+ ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(kernel));
tree->insert(*thread);
}
diff --git a/src/core/hle/kernel/k_debug.h b/src/core/hle/kernel/k_debug.h
index e3a0689c8..2290e3bca 100644
--- a/src/core/hle/kernel/k_debug.h
+++ b/src/core/hle/kernel/k_debug.h
@@ -12,9 +12,9 @@ class KDebug final : public KAutoObjectWithSlabHeapAndContainer<KDebug, KAutoObj
KERNEL_AUTOOBJECT_TRAITS(KDebug, KAutoObject);
public:
- explicit KDebug(KernelCore& kernel_) : KAutoObjectWithSlabHeapAndContainer{kernel_} {}
+ explicit KDebug(KernelCore& kernel) : KAutoObjectWithSlabHeapAndContainer{kernel} {}
- static void PostDestroy([[maybe_unused]] uintptr_t arg) {}
+ static void PostDestroy(uintptr_t arg) {}
};
} // namespace Kernel
diff --git a/src/core/hle/kernel/k_device_address_space.cpp b/src/core/hle/kernel/k_device_address_space.cpp
new file mode 100644
index 000000000..f48896715
--- /dev/null
+++ b/src/core/hle/kernel/k_device_address_space.cpp
@@ -0,0 +1,150 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "common/assert.h"
+#include "core/core.h"
+#include "core/hle/kernel/k_device_address_space.h"
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/svc_results.h"
+
+namespace Kernel {
+
+KDeviceAddressSpace::KDeviceAddressSpace(KernelCore& kernel)
+ : KAutoObjectWithSlabHeapAndContainer(kernel), m_lock(kernel), m_is_initialized(false) {}
+KDeviceAddressSpace::~KDeviceAddressSpace() = default;
+
+void KDeviceAddressSpace::Initialize() {
+ // This just forwards to the device page table manager.
+ // KDevicePageTable::Initialize();
+}
+
+// Member functions.
+Result KDeviceAddressSpace::Initialize(u64 address, u64 size) {
+ // Initialize the device page table.
+ // R_TRY(m_table.Initialize(address, size));
+
+ // Set member variables.
+ m_space_address = address;
+ m_space_size = size;
+ m_is_initialized = true;
+
+ R_SUCCEED();
+}
+
+void KDeviceAddressSpace::Finalize() {
+ // Finalize the table.
+ // m_table.Finalize();
+}
+
+Result KDeviceAddressSpace::Attach(Svc::DeviceName device_name) {
+ // Lock the address space.
+ KScopedLightLock lk(m_lock);
+
+ // Attach.
+ // R_RETURN(m_table.Attach(device_name, m_space_address, m_space_size));
+ R_SUCCEED();
+}
+
+Result KDeviceAddressSpace::Detach(Svc::DeviceName device_name) {
+ // Lock the address space.
+ KScopedLightLock lk(m_lock);
+
+ // Detach.
+ // R_RETURN(m_table.Detach(device_name));
+ R_SUCCEED();
+}
+
+Result KDeviceAddressSpace::Map(KPageTable* page_table, KProcessAddress process_address,
+ size_t size, u64 device_address, u32 option, bool is_aligned) {
+ // Check that the address falls within the space.
+ R_UNLESS((m_space_address <= device_address &&
+ device_address + size - 1 <= m_space_address + m_space_size - 1),
+ ResultInvalidCurrentMemory);
+
+ // Decode the option.
+ const Svc::MapDeviceAddressSpaceOption option_pack{option};
+ const auto device_perm = option_pack.permission.Value();
+ const auto flags = option_pack.flags.Value();
+ const auto reserved = option_pack.reserved.Value();
+
+ // Validate the option.
+ // TODO: It is likely that this check for flags == none is only on NX board.
+ R_UNLESS(flags == Svc::MapDeviceAddressSpaceFlag::None, ResultInvalidEnumValue);
+ R_UNLESS(reserved == 0, ResultInvalidEnumValue);
+
+ // Lock the address space.
+ KScopedLightLock lk(m_lock);
+
+ // Lock the page table to prevent concurrent device mapping operations.
+ // KScopedLightLock pt_lk = page_table->AcquireDeviceMapLock();
+
+ // Lock the pages.
+ bool is_io{};
+ R_TRY(page_table->LockForMapDeviceAddressSpace(std::addressof(is_io), process_address, size,
+ ConvertToKMemoryPermission(device_perm),
+ is_aligned, true));
+
+ // Ensure that if we fail, we don't keep unmapped pages locked.
+ ON_RESULT_FAILURE {
+ ASSERT(page_table->UnlockForDeviceAddressSpace(process_address, size) == ResultSuccess);
+ };
+
+ // Check that the io status is allowable.
+ if (is_io) {
+ R_UNLESS(static_cast<u32>(flags & Svc::MapDeviceAddressSpaceFlag::NotIoRegister) == 0,
+ ResultInvalidCombination);
+ }
+
+ // Map the pages.
+ {
+ // Perform the mapping.
+ // R_TRY(m_table.Map(page_table, process_address, size, device_address, device_perm,
+ // is_aligned, is_io));
+
+ // Ensure that we unmap the pages if we fail to update the protections.
+ // NOTE: Nintendo does not check the result of this unmap call.
+ // ON_RESULT_FAILURE { m_table.Unmap(device_address, size); };
+
+ // Update the protections in accordance with how much we mapped.
+ // R_TRY(page_table->UnlockForDeviceAddressSpacePartialMap(process_address, size));
+ }
+
+ // We succeeded.
+ R_SUCCEED();
+}
+
+Result KDeviceAddressSpace::Unmap(KPageTable* page_table, KProcessAddress process_address,
+ size_t size, u64 device_address) {
+ // Check that the address falls within the space.
+ R_UNLESS((m_space_address <= device_address &&
+ device_address + size - 1 <= m_space_address + m_space_size - 1),
+ ResultInvalidCurrentMemory);
+
+ // Lock the address space.
+ KScopedLightLock lk(m_lock);
+
+ // Lock the page table to prevent concurrent device mapping operations.
+ // KScopedLightLock pt_lk = page_table->AcquireDeviceMapLock();
+
+ // Lock the pages.
+ R_TRY(page_table->LockForUnmapDeviceAddressSpace(process_address, size, true));
+
+ // Unmap the pages.
+ {
+ // If we fail to unmap, we want to do a partial unlock.
+ // ON_RESULT_FAILURE {
+ // ASSERT(page_table->UnlockForDeviceAddressSpacePartialMap(process_address, size) ==
+ // ResultSuccess);
+ // };
+
+ // Perform the unmap.
+ // R_TRY(m_table.Unmap(page_table, process_address, size, device_address));
+ }
+
+ // Unlock the pages.
+ ASSERT(page_table->UnlockForDeviceAddressSpace(process_address, size) == ResultSuccess);
+
+ R_SUCCEED();
+}
+
+} // namespace Kernel
diff --git a/src/core/hle/kernel/k_device_address_space.h b/src/core/hle/kernel/k_device_address_space.h
new file mode 100644
index 000000000..18556e3cc
--- /dev/null
+++ b/src/core/hle/kernel/k_device_address_space.h
@@ -0,0 +1,61 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include <string>
+
+#include "core/hle/kernel/k_page_table.h"
+#include "core/hle/kernel/k_typed_address.h"
+#include "core/hle/kernel/slab_helpers.h"
+#include "core/hle/result.h"
+
+namespace Kernel {
+
+class KDeviceAddressSpace final
+ : public KAutoObjectWithSlabHeapAndContainer<KDeviceAddressSpace, KAutoObjectWithList> {
+ KERNEL_AUTOOBJECT_TRAITS(KDeviceAddressSpace, KAutoObject);
+
+public:
+ explicit KDeviceAddressSpace(KernelCore& kernel);
+ ~KDeviceAddressSpace();
+
+ Result Initialize(u64 address, u64 size);
+ void Finalize() override;
+
+ bool IsInitialized() const override {
+ return m_is_initialized;
+ }
+ static void PostDestroy(uintptr_t arg) {}
+
+ Result Attach(Svc::DeviceName device_name);
+ Result Detach(Svc::DeviceName device_name);
+
+ Result MapByForce(KPageTable* page_table, KProcessAddress process_address, size_t size,
+ u64 device_address, u32 option) {
+ R_RETURN(this->Map(page_table, process_address, size, device_address, option, false));
+ }
+
+ Result MapAligned(KPageTable* page_table, KProcessAddress process_address, size_t size,
+ u64 device_address, u32 option) {
+ R_RETURN(this->Map(page_table, process_address, size, device_address, option, true));
+ }
+
+ Result Unmap(KPageTable* page_table, KProcessAddress process_address, size_t size,
+ u64 device_address);
+
+ static void Initialize();
+
+private:
+ Result Map(KPageTable* page_table, KProcessAddress process_address, size_t size,
+ u64 device_address, u32 option, bool is_aligned);
+
+private:
+ KLightLock m_lock;
+ // KDevicePageTable m_table;
+ u64 m_space_address{};
+ u64 m_space_size{};
+ bool m_is_initialized{};
+};
+
+} // namespace Kernel
diff --git a/src/core/hle/kernel/k_dynamic_page_manager.h b/src/core/hle/kernel/k_dynamic_page_manager.h
index ac80d60a1..ad11e84b7 100644
--- a/src/core/hle/kernel/k_dynamic_page_manager.h
+++ b/src/core/hle/kernel/k_dynamic_page_manager.h
@@ -6,9 +6,9 @@
#include <vector>
#include "common/alignment.h"
-#include "common/common_types.h"
#include "core/hle/kernel/k_page_bitmap.h"
#include "core/hle/kernel/k_spin_lock.h"
+#include "core/hle/kernel/k_typed_address.h"
#include "core/hle/kernel/memory_types.h"
#include "core/hle/kernel/svc_results.h"
@@ -26,23 +26,23 @@ public:
KDynamicPageManager() = default;
template <typename T>
- T* GetPointer(VAddr addr) {
+ T* GetPointer(KVirtualAddress addr) {
return reinterpret_cast<T*>(m_backing_memory.data() + (addr - m_address));
}
template <typename T>
- const T* GetPointer(VAddr addr) const {
+ const T* GetPointer(KVirtualAddress addr) const {
return reinterpret_cast<T*>(m_backing_memory.data() + (addr - m_address));
}
- Result Initialize(VAddr memory, size_t size, size_t align) {
+ Result Initialize(KVirtualAddress memory, size_t size, size_t align) {
// We need to have positive size.
R_UNLESS(size > 0, ResultOutOfMemory);
m_backing_memory.resize(size);
// Set addresses.
m_address = memory;
- m_aligned_address = Common::AlignDown(memory, align);
+ m_aligned_address = Common::AlignDown(GetInteger(memory), align);
// Calculate extents.
const size_t managed_size = m_address + size - m_aligned_address;
@@ -79,7 +79,7 @@ public:
R_SUCCEED();
}
- VAddr GetAddress() const {
+ KVirtualAddress GetAddress() const {
return m_address;
}
size_t GetSize() const {
@@ -145,7 +145,8 @@ public:
KScopedSpinLock lk(m_lock);
// Set the bit for the free page.
- size_t offset = (reinterpret_cast<uintptr_t>(pb) - m_aligned_address) / sizeof(PageBuffer);
+ size_t offset =
+ (reinterpret_cast<uint64_t>(pb) - GetInteger(m_aligned_address)) / sizeof(PageBuffer);
m_page_bitmap.SetBit(offset);
// Decrement our used count.
@@ -158,8 +159,8 @@ private:
size_t m_used{};
size_t m_peak{};
size_t m_count{};
- VAddr m_address{};
- VAddr m_aligned_address{};
+ KVirtualAddress m_address{};
+ KVirtualAddress m_aligned_address{};
size_t m_size{};
// TODO(bunnei): Back by host memory until we emulate kernel virtual address space.
diff --git a/src/core/hle/kernel/k_dynamic_slab_heap.h b/src/core/hle/kernel/k_dynamic_slab_heap.h
index 3a0ddd050..76ed4cac1 100644
--- a/src/core/hle/kernel/k_dynamic_slab_heap.h
+++ b/src/core/hle/kernel/k_dynamic_slab_heap.h
@@ -19,7 +19,7 @@ class KDynamicSlabHeap : protected impl::KSlabHeapImpl {
public:
constexpr KDynamicSlabHeap() = default;
- constexpr VAddr GetAddress() const {
+ constexpr KVirtualAddress GetAddress() const {
return m_address;
}
constexpr size_t GetSize() const {
@@ -35,7 +35,7 @@ public:
return m_count.load();
}
- constexpr bool IsInRange(VAddr addr) const {
+ constexpr bool IsInRange(KVirtualAddress addr) const {
return this->GetAddress() <= addr && addr <= this->GetAddress() + this->GetSize() - 1;
}
@@ -115,7 +115,7 @@ private:
std::atomic<size_t> m_used{};
std::atomic<size_t> m_peak{};
std::atomic<size_t> m_count{};
- VAddr m_address{};
+ KVirtualAddress m_address{};
size_t m_size{};
};
diff --git a/src/core/hle/kernel/k_event.cpp b/src/core/hle/kernel/k_event.cpp
index d973853ab..d92b491f8 100644
--- a/src/core/hle/kernel/k_event.cpp
+++ b/src/core/hle/kernel/k_event.cpp
@@ -7,8 +7,8 @@
namespace Kernel {
-KEvent::KEvent(KernelCore& kernel_)
- : KAutoObjectWithSlabHeapAndContainer{kernel_}, m_readable_event{kernel_} {}
+KEvent::KEvent(KernelCore& kernel)
+ : KAutoObjectWithSlabHeapAndContainer{kernel}, m_readable_event{kernel} {}
KEvent::~KEvent() = default;
@@ -36,7 +36,7 @@ void KEvent::Finalize() {
}
Result KEvent::Signal() {
- KScopedSchedulerLock sl{kernel};
+ KScopedSchedulerLock sl{m_kernel};
R_SUCCEED_IF(m_readable_event_destroyed);
@@ -44,7 +44,7 @@ Result KEvent::Signal() {
}
Result KEvent::Clear() {
- KScopedSchedulerLock sl{kernel};
+ KScopedSchedulerLock sl{m_kernel};
R_SUCCEED_IF(m_readable_event_destroyed);
diff --git a/src/core/hle/kernel/k_event.h b/src/core/hle/kernel/k_event.h
index 48ce7d9a0..f522b0a84 100644
--- a/src/core/hle/kernel/k_event.h
+++ b/src/core/hle/kernel/k_event.h
@@ -16,7 +16,7 @@ class KEvent final : public KAutoObjectWithSlabHeapAndContainer<KEvent, KAutoObj
KERNEL_AUTOOBJECT_TRAITS(KEvent, KAutoObject);
public:
- explicit KEvent(KernelCore& kernel_);
+ explicit KEvent(KernelCore& kernel);
~KEvent() override;
void Initialize(KProcess* owner);
diff --git a/src/core/hle/kernel/k_event_info.h b/src/core/hle/kernel/k_event_info.h
index 25b3ff594..eacfa5dc6 100644
--- a/src/core/hle/kernel/k_event_info.h
+++ b/src/core/hle/kernel/k_event_info.h
@@ -5,14 +5,15 @@
#include <array>
-#include <boost/intrusive/list.hpp>
+#include "common/intrusive_list.h"
#include "core/hle/kernel/slab_helpers.h"
#include "core/hle/kernel/svc_types.h"
namespace Kernel {
-class KEventInfo : public KSlabAllocated<KEventInfo>, public boost::intrusive::list_base_hook<> {
+class KEventInfo : public KSlabAllocated<KEventInfo>,
+ public Common::IntrusiveListBaseNode<KEventInfo> {
public:
struct InfoCreateThread {
u32 thread_id{};
diff --git a/src/core/hle/kernel/k_handle_table.h b/src/core/hle/kernel/k_handle_table.h
index 37a24e7d9..d7660630c 100644
--- a/src/core/hle/kernel/k_handle_table.h
+++ b/src/core/hle/kernel/k_handle_table.h
@@ -90,7 +90,8 @@ public:
// Handle pseudo-handles.
if constexpr (std::derived_from<KProcess, T>) {
if (handle == Svc::PseudoHandle::CurrentProcess) {
- auto* const cur_process = m_kernel.CurrentProcess();
+ //! FIXME: this is the wrong process!
+ auto* const cur_process = m_kernel.ApplicationProcess();
ASSERT(cur_process != nullptr);
return cur_process;
}
diff --git a/src/core/hle/kernel/k_interrupt_manager.cpp b/src/core/hle/kernel/k_interrupt_manager.cpp
index 4a6b60d26..fe6a20168 100644
--- a/src/core/hle/kernel/k_interrupt_manager.cpp
+++ b/src/core/hle/kernel/k_interrupt_manager.cpp
@@ -16,7 +16,7 @@ void HandleInterrupt(KernelCore& kernel, s32 core_id) {
auto& current_thread = GetCurrentThread(kernel);
- if (auto* process = kernel.CurrentProcess(); process) {
+ if (auto* process = GetCurrentProcessPointer(kernel); process) {
// If the user disable count is set, we may need to pin the current thread.
if (current_thread.GetUserDisableCount() && !process->GetPinnedThread(core_id)) {
KScopedSchedulerLock sl{kernel};
diff --git a/src/core/hle/kernel/k_light_condition_variable.cpp b/src/core/hle/kernel/k_light_condition_variable.cpp
index cade99cfd..6d5a815aa 100644
--- a/src/core/hle/kernel/k_light_condition_variable.cpp
+++ b/src/core/hle/kernel/k_light_condition_variable.cpp
@@ -13,9 +13,9 @@ namespace {
class ThreadQueueImplForKLightConditionVariable final : public KThreadQueue {
public:
- ThreadQueueImplForKLightConditionVariable(KernelCore& kernel_, KThread::WaiterList* wl,
+ ThreadQueueImplForKLightConditionVariable(KernelCore& kernel, KThread::WaiterList* wl,
bool term)
- : KThreadQueue(kernel_), m_wait_list(wl), m_allow_terminating_thread(term) {}
+ : KThreadQueue(kernel), m_wait_list(wl), m_allow_terminating_thread(term) {}
void CancelWait(KThread* waiting_thread, Result wait_result, bool cancel_timer_task) override {
// Only process waits if we're allowed to.
@@ -39,14 +39,15 @@ private:
void KLightConditionVariable::Wait(KLightLock* lock, s64 timeout, bool allow_terminating_thread) {
// Create thread queue.
- KThread* owner = GetCurrentThreadPointer(kernel);
+ KThread* owner = GetCurrentThreadPointer(m_kernel);
+ KHardwareTimer* timer{};
- ThreadQueueImplForKLightConditionVariable wait_queue(kernel, std::addressof(wait_list),
+ ThreadQueueImplForKLightConditionVariable wait_queue(m_kernel, std::addressof(m_wait_list),
allow_terminating_thread);
// Sleep the thread.
{
- KScopedSchedulerLockAndSleep lk(kernel, owner, timeout);
+ KScopedSchedulerLockAndSleep lk(m_kernel, std::addressof(timer), owner, timeout);
if (!allow_terminating_thread && owner->IsTerminationRequested()) {
lk.CancelSleep();
@@ -56,9 +57,10 @@ void KLightConditionVariable::Wait(KLightLock* lock, s64 timeout, bool allow_ter
lock->Unlock();
// Add the thread to the queue.
- wait_list.push_back(*owner);
+ m_wait_list.push_back(*owner);
// Begin waiting.
+ wait_queue.SetHardwareTimer(timer);
owner->BeginWait(std::addressof(wait_queue));
}
@@ -67,10 +69,10 @@ void KLightConditionVariable::Wait(KLightLock* lock, s64 timeout, bool allow_ter
}
void KLightConditionVariable::Broadcast() {
- KScopedSchedulerLock lk(kernel);
+ KScopedSchedulerLock lk(m_kernel);
// Signal all threads.
- for (auto it = wait_list.begin(); it != wait_list.end(); it = wait_list.erase(it)) {
+ for (auto it = m_wait_list.begin(); it != m_wait_list.end(); it = m_wait_list.erase(it)) {
it->EndWait(ResultSuccess);
}
}
diff --git a/src/core/hle/kernel/k_light_condition_variable.h b/src/core/hle/kernel/k_light_condition_variable.h
index 3cabd6b4f..ab612426d 100644
--- a/src/core/hle/kernel/k_light_condition_variable.h
+++ b/src/core/hle/kernel/k_light_condition_variable.h
@@ -13,13 +13,13 @@ class KLightLock;
class KLightConditionVariable {
public:
- explicit KLightConditionVariable(KernelCore& kernel_) : kernel{kernel_} {}
+ explicit KLightConditionVariable(KernelCore& kernel) : m_kernel{kernel} {}
void Wait(KLightLock* lock, s64 timeout = -1, bool allow_terminating_thread = true);
void Broadcast();
private:
- KernelCore& kernel;
- KThread::WaiterList wait_list{};
+ KernelCore& m_kernel;
+ KThread::WaiterList m_wait_list{};
};
} // namespace Kernel
diff --git a/src/core/hle/kernel/k_light_lock.cpp b/src/core/hle/kernel/k_light_lock.cpp
index 43185320d..e87ee8b65 100644
--- a/src/core/hle/kernel/k_light_lock.cpp
+++ b/src/core/hle/kernel/k_light_lock.cpp
@@ -13,7 +13,7 @@ namespace {
class ThreadQueueImplForKLightLock final : public KThreadQueue {
public:
- explicit ThreadQueueImplForKLightLock(KernelCore& kernel_) : KThreadQueue(kernel_) {}
+ explicit ThreadQueueImplForKLightLock(KernelCore& kernel) : KThreadQueue(kernel) {}
void CancelWait(KThread* waiting_thread, Result wait_result, bool cancel_timer_task) override {
// Remove the thread as a waiter from its owner.
@@ -29,13 +29,13 @@ public:
} // namespace
void KLightLock::Lock() {
- const uintptr_t cur_thread = reinterpret_cast<uintptr_t>(GetCurrentThreadPointer(kernel));
+ const uintptr_t cur_thread = reinterpret_cast<uintptr_t>(GetCurrentThreadPointer(m_kernel));
while (true) {
- uintptr_t old_tag = tag.load(std::memory_order_relaxed);
+ uintptr_t old_tag = m_tag.load(std::memory_order_relaxed);
- while (!tag.compare_exchange_weak(old_tag, (old_tag == 0) ? cur_thread : (old_tag | 1),
- std::memory_order_acquire)) {
+ while (!m_tag.compare_exchange_weak(old_tag, (old_tag == 0) ? cur_thread : (old_tag | 1),
+ std::memory_order_acquire)) {
}
if (old_tag == 0 || this->LockSlowPath(old_tag | 1, cur_thread)) {
@@ -45,30 +45,30 @@ void KLightLock::Lock() {
}
void KLightLock::Unlock() {
- const uintptr_t cur_thread = reinterpret_cast<uintptr_t>(GetCurrentThreadPointer(kernel));
+ const uintptr_t cur_thread = reinterpret_cast<uintptr_t>(GetCurrentThreadPointer(m_kernel));
uintptr_t expected = cur_thread;
- if (!tag.compare_exchange_strong(expected, 0, std::memory_order_release)) {
+ if (!m_tag.compare_exchange_strong(expected, 0, std::memory_order_release)) {
this->UnlockSlowPath(cur_thread);
}
}
bool KLightLock::LockSlowPath(uintptr_t _owner, uintptr_t _cur_thread) {
KThread* cur_thread = reinterpret_cast<KThread*>(_cur_thread);
- ThreadQueueImplForKLightLock wait_queue(kernel);
+ ThreadQueueImplForKLightLock wait_queue(m_kernel);
// Pend the current thread waiting on the owner thread.
{
- KScopedSchedulerLock sl{kernel};
+ KScopedSchedulerLock sl{m_kernel};
// Ensure we actually have locking to do.
- if (tag.load(std::memory_order_relaxed) != _owner) {
+ if (m_tag.load(std::memory_order_relaxed) != _owner) {
return false;
}
// Add the current thread as a waiter on the owner.
KThread* owner_thread = reinterpret_cast<KThread*>(_owner & ~1ULL);
- cur_thread->SetAddressKey(reinterpret_cast<uintptr_t>(std::addressof(tag)));
+ cur_thread->SetKernelAddressKey(reinterpret_cast<uintptr_t>(std::addressof(m_tag)));
owner_thread->AddWaiter(cur_thread);
// Begin waiting to hold the lock.
@@ -87,18 +87,18 @@ void KLightLock::UnlockSlowPath(uintptr_t _cur_thread) {
// Unlock.
{
- KScopedSchedulerLock sl(kernel);
+ KScopedSchedulerLock sl(m_kernel);
// Get the next owner.
- s32 num_waiters;
- KThread* next_owner = owner_thread->RemoveWaiterByKey(
- std::addressof(num_waiters), reinterpret_cast<uintptr_t>(std::addressof(tag)));
+ bool has_waiters;
+ KThread* next_owner = owner_thread->RemoveKernelWaiterByKey(
+ std::addressof(has_waiters), reinterpret_cast<uintptr_t>(std::addressof(m_tag)));
// Pass the lock to the next owner.
uintptr_t next_tag = 0;
if (next_owner != nullptr) {
next_tag =
- reinterpret_cast<uintptr_t>(next_owner) | static_cast<uintptr_t>(num_waiters > 1);
+ reinterpret_cast<uintptr_t>(next_owner) | static_cast<uintptr_t>(has_waiters);
next_owner->EndWait(ResultSuccess);
@@ -114,12 +114,13 @@ void KLightLock::UnlockSlowPath(uintptr_t _cur_thread) {
}
// Write the new tag value.
- tag.store(next_tag, std::memory_order_release);
+ m_tag.store(next_tag, std::memory_order_release);
}
}
bool KLightLock::IsLockedByCurrentThread() const {
- return (tag | 1ULL) == (reinterpret_cast<uintptr_t>(GetCurrentThreadPointer(kernel)) | 1ULL);
+ return (m_tag.load() | 1ULL) ==
+ (reinterpret_cast<uintptr_t>(GetCurrentThreadPointer(m_kernel)) | 1ULL);
}
} // namespace Kernel
diff --git a/src/core/hle/kernel/k_light_lock.h b/src/core/hle/kernel/k_light_lock.h
index 7edd950c0..626f57596 100644
--- a/src/core/hle/kernel/k_light_lock.h
+++ b/src/core/hle/kernel/k_light_lock.h
@@ -13,7 +13,7 @@ class KernelCore;
class KLightLock {
public:
- explicit KLightLock(KernelCore& kernel_) : kernel{kernel_} {}
+ explicit KLightLock(KernelCore& kernel) : m_kernel{kernel} {}
void Lock();
@@ -24,14 +24,14 @@ public:
void UnlockSlowPath(uintptr_t cur_thread);
bool IsLocked() const {
- return tag != 0;
+ return m_tag.load() != 0;
}
bool IsLockedByCurrentThread() const;
private:
- std::atomic<uintptr_t> tag{};
- KernelCore& kernel;
+ std::atomic<uintptr_t> m_tag{};
+ KernelCore& m_kernel;
};
using KScopedLightLock = KScopedLock<KLightLock>;
diff --git a/src/core/hle/kernel/k_linked_list.h b/src/core/hle/kernel/k_linked_list.h
deleted file mode 100644
index 29ebd16b7..000000000
--- a/src/core/hle/kernel/k_linked_list.h
+++ /dev/null
@@ -1,238 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#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:
- explicit KLinkedListNode(KernelCore&) {}
- 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 87ca65592..41a29da24 100644
--- a/src/core/hle/kernel/k_memory_block.h
+++ b/src/core/hle/kernel/k_memory_block.h
@@ -5,8 +5,8 @@
#include "common/alignment.h"
#include "common/assert.h"
-#include "common/common_types.h"
#include "common/intrusive_red_black_tree.h"
+#include "core/hle/kernel/k_typed_address.h"
#include "core/hle/kernel/memory_types.h"
#include "core/hle/kernel/svc_types.h"
@@ -282,7 +282,7 @@ class KMemoryBlock : public Common::IntrusiveRedBlackTreeBaseNode<KMemoryBlock>
private:
u16 m_device_disable_merge_left_count{};
u16 m_device_disable_merge_right_count{};
- VAddr m_address{};
+ KProcessAddress m_address{};
size_t m_num_pages{};
KMemoryState m_memory_state{KMemoryState::None};
u16 m_ipc_lock_count{};
@@ -306,7 +306,7 @@ public:
}
public:
- constexpr VAddr GetAddress() const {
+ constexpr KProcessAddress GetAddress() const {
return m_address;
}
@@ -318,11 +318,11 @@ public:
return this->GetNumPages() * PageSize;
}
- constexpr VAddr GetEndAddress() const {
+ constexpr KProcessAddress GetEndAddress() const {
return this->GetAddress() + this->GetSize();
}
- constexpr VAddr GetLastAddress() const {
+ constexpr KProcessAddress GetLastAddress() const {
return this->GetEndAddress() - 1;
}
@@ -348,7 +348,7 @@ public:
constexpr KMemoryInfo GetMemoryInfo() const {
return {
- .m_address = this->GetAddress(),
+ .m_address = GetInteger(this->GetAddress()),
.m_size = this->GetSize(),
.m_state = m_memory_state,
.m_device_disable_merge_left_count = m_device_disable_merge_left_count,
@@ -366,12 +366,12 @@ public:
public:
explicit KMemoryBlock() = default;
- constexpr KMemoryBlock(VAddr addr, size_t np, KMemoryState ms, KMemoryPermission p,
+ constexpr KMemoryBlock(KProcessAddress addr, size_t np, KMemoryState ms, KMemoryPermission p,
KMemoryAttribute attr)
: Common::IntrusiveRedBlackTreeBaseNode<KMemoryBlock>(), m_address(addr), m_num_pages(np),
m_memory_state(ms), m_permission(p), m_attribute(attr) {}
- constexpr void Initialize(VAddr addr, size_t np, KMemoryState ms, KMemoryPermission p,
+ constexpr void Initialize(KProcessAddress addr, size_t np, KMemoryState ms, KMemoryPermission p,
KMemoryAttribute attr) {
m_device_disable_merge_left_count = 0;
m_device_disable_merge_right_count = 0;
@@ -408,7 +408,7 @@ public:
KMemoryBlockDisableMergeAttribute::None;
}
- constexpr bool Contains(VAddr addr) const {
+ constexpr bool Contains(KProcessAddress addr) const {
return this->GetAddress() <= addr && addr <= this->GetEndAddress();
}
@@ -443,10 +443,10 @@ public:
}
}
- constexpr void Split(KMemoryBlock* block, VAddr addr) {
+ constexpr void Split(KMemoryBlock* block, KProcessAddress addr) {
ASSERT(this->GetAddress() < addr);
ASSERT(this->Contains(addr));
- ASSERT(Common::IsAligned(addr, PageSize));
+ ASSERT(Common::IsAligned(GetInteger(addr), PageSize));
block->m_address = m_address;
block->m_num_pages = (addr - this->GetAddress()) / PageSize;
@@ -471,8 +471,8 @@ public:
m_disable_merge_attribute & KMemoryBlockDisableMergeAttribute::AllRight);
}
- constexpr void UpdateDeviceDisableMergeStateForShareLeft(
- [[maybe_unused]] KMemoryPermission new_perm, bool left, [[maybe_unused]] bool right) {
+ constexpr void UpdateDeviceDisableMergeStateForShareLeft(KMemoryPermission new_perm, bool left,
+ bool right) {
// New permission/right aren't used.
if (left) {
m_disable_merge_attribute = static_cast<KMemoryBlockDisableMergeAttribute>(
@@ -482,8 +482,8 @@ public:
}
}
- constexpr void UpdateDeviceDisableMergeStateForShareRight(
- [[maybe_unused]] KMemoryPermission new_perm, [[maybe_unused]] bool left, bool right) {
+ constexpr void UpdateDeviceDisableMergeStateForShareRight(KMemoryPermission new_perm, bool left,
+ bool right) {
// New permission/left aren't used.
if (right) {
m_disable_merge_attribute = static_cast<KMemoryBlockDisableMergeAttribute>(
@@ -499,8 +499,7 @@ public:
this->UpdateDeviceDisableMergeStateForShareRight(new_perm, left, right);
}
- constexpr void ShareToDevice([[maybe_unused]] KMemoryPermission new_perm, bool left,
- bool right) {
+ constexpr void ShareToDevice(KMemoryPermission new_perm, bool left, bool right) {
// New permission isn't used.
// We must either be shared or have a zero lock count.
@@ -516,8 +515,8 @@ public:
this->UpdateDeviceDisableMergeStateForShare(new_perm, left, right);
}
- constexpr void UpdateDeviceDisableMergeStateForUnshareLeft(
- [[maybe_unused]] KMemoryPermission new_perm, bool left, [[maybe_unused]] bool right) {
+ constexpr void UpdateDeviceDisableMergeStateForUnshareLeft(KMemoryPermission new_perm,
+ bool left, bool right) {
// New permission/right aren't used.
if (left) {
@@ -536,8 +535,8 @@ public:
}
}
- constexpr void UpdateDeviceDisableMergeStateForUnshareRight(
- [[maybe_unused]] KMemoryPermission new_perm, [[maybe_unused]] bool left, bool right) {
+ constexpr void UpdateDeviceDisableMergeStateForUnshareRight(KMemoryPermission new_perm,
+ bool left, bool right) {
// New permission/left aren't used.
if (right) {
@@ -556,8 +555,7 @@ public:
this->UpdateDeviceDisableMergeStateForUnshareRight(new_perm, left, right);
}
- constexpr void UnshareToDevice([[maybe_unused]] KMemoryPermission new_perm, bool left,
- bool right) {
+ constexpr void UnshareToDevice(KMemoryPermission new_perm, bool left, bool right) {
// New permission isn't used.
// We must be shared.
@@ -575,8 +573,7 @@ public:
this->UpdateDeviceDisableMergeStateForUnshare(new_perm, left, right);
}
- constexpr void UnshareToDeviceRight([[maybe_unused]] KMemoryPermission new_perm, bool left,
- bool right) {
+ constexpr void UnshareToDeviceRight(KMemoryPermission new_perm, bool left, bool right) {
// New permission isn't used.
// We must be shared.
@@ -594,7 +591,7 @@ public:
this->UpdateDeviceDisableMergeStateForUnshareRight(new_perm, left, right);
}
- constexpr void LockForIpc(KMemoryPermission new_perm, bool left, [[maybe_unused]] bool right) {
+ constexpr void LockForIpc(KMemoryPermission new_perm, bool left, bool right) {
// We must either be locked or have a zero lock count.
ASSERT((m_attribute & KMemoryAttribute::IpcLocked) == KMemoryAttribute::IpcLocked ||
m_ipc_lock_count == 0);
@@ -626,8 +623,7 @@ public:
}
}
- constexpr void UnlockForIpc([[maybe_unused]] KMemoryPermission new_perm, bool left,
- [[maybe_unused]] bool right) {
+ constexpr void UnlockForIpc(KMemoryPermission new_perm, bool left, bool right) {
// New permission isn't used.
// We must be locked.
diff --git a/src/core/hle/kernel/k_memory_block_manager.cpp b/src/core/hle/kernel/k_memory_block_manager.cpp
index cf4c1e371..ab75f550e 100644
--- a/src/core/hle/kernel/k_memory_block_manager.cpp
+++ b/src/core/hle/kernel/k_memory_block_manager.cpp
@@ -7,7 +7,8 @@ namespace Kernel {
KMemoryBlockManager::KMemoryBlockManager() = default;
-Result KMemoryBlockManager::Initialize(VAddr st, VAddr nd, KMemoryBlockSlabManager* slab_manager) {
+Result KMemoryBlockManager::Initialize(KProcessAddress st, KProcessAddress nd,
+ KMemoryBlockSlabManager* slab_manager) {
// Allocate a block to encapsulate the address space, insert it into the tree.
KMemoryBlock* start_block = slab_manager->Allocate();
R_UNLESS(start_block != nullptr, ResultOutOfResource);
@@ -15,8 +16,8 @@ Result KMemoryBlockManager::Initialize(VAddr st, VAddr nd, KMemoryBlockSlabManag
// Set our start and end.
m_start_address = st;
m_end_address = nd;
- ASSERT(Common::IsAligned(m_start_address, PageSize));
- ASSERT(Common::IsAligned(m_end_address, PageSize));
+ ASSERT(Common::IsAligned(GetInteger(m_start_address), PageSize));
+ ASSERT(Common::IsAligned(GetInteger(m_end_address), PageSize));
// Initialize and insert the block.
start_block->Initialize(m_start_address, (m_end_address - m_start_address) / PageSize,
@@ -40,12 +41,13 @@ void KMemoryBlockManager::Finalize(KMemoryBlockSlabManager* slab_manager,
ASSERT(m_memory_block_tree.empty());
}
-VAddr KMemoryBlockManager::FindFreeArea(VAddr region_start, size_t region_num_pages,
- size_t num_pages, size_t alignment, size_t offset,
- size_t guard_pages) const {
+KProcessAddress KMemoryBlockManager::FindFreeArea(KProcessAddress region_start,
+ size_t region_num_pages, size_t num_pages,
+ size_t alignment, size_t offset,
+ size_t guard_pages) const {
if (num_pages > 0) {
- const VAddr region_end = region_start + region_num_pages * PageSize;
- const VAddr region_last = region_end - 1;
+ const KProcessAddress region_end = region_start + region_num_pages * PageSize;
+ const KProcessAddress region_last = region_end - 1;
for (const_iterator it = this->FindIterator(region_start); it != m_memory_block_tree.cend();
it++) {
const KMemoryInfo info = it->GetMemoryInfo();
@@ -56,17 +58,19 @@ VAddr KMemoryBlockManager::FindFreeArea(VAddr region_start, size_t region_num_pa
continue;
}
- VAddr area = (info.GetAddress() <= region_start) ? region_start : info.GetAddress();
+ KProcessAddress area =
+ (info.GetAddress() <= GetInteger(region_start)) ? region_start : info.GetAddress();
area += guard_pages * PageSize;
- const VAddr offset_area = Common::AlignDown(area, alignment) + offset;
+ const KProcessAddress offset_area =
+ Common::AlignDown(GetInteger(area), alignment) + offset;
area = (area <= offset_area) ? offset_area : offset_area + alignment;
- const VAddr area_end = area + num_pages * PageSize + guard_pages * PageSize;
- const VAddr area_last = area_end - 1;
+ const KProcessAddress area_end = area + num_pages * PageSize + guard_pages * PageSize;
+ const KProcessAddress area_last = area_end - 1;
- if (info.GetAddress() <= area && area < area_last && area_last <= region_last &&
- area_last <= info.GetLastAddress()) {
+ if (info.GetAddress() <= GetInteger(area) && area < area_last &&
+ area_last <= region_last && area_last <= info.GetLastAddress()) {
return area;
}
}
@@ -76,7 +80,7 @@ VAddr KMemoryBlockManager::FindFreeArea(VAddr region_start, size_t region_num_pa
}
void KMemoryBlockManager::CoalesceForUpdate(KMemoryBlockManagerUpdateAllocator* allocator,
- VAddr address, size_t num_pages) {
+ KProcessAddress address, size_t num_pages) {
// Find the iterator now that we've updated.
iterator it = this->FindIterator(address);
if (address != m_start_address) {
@@ -104,18 +108,18 @@ void KMemoryBlockManager::CoalesceForUpdate(KMemoryBlockManagerUpdateAllocator*
}
}
-void KMemoryBlockManager::Update(KMemoryBlockManagerUpdateAllocator* allocator, VAddr address,
- size_t num_pages, KMemoryState state, KMemoryPermission perm,
- KMemoryAttribute attr,
+void KMemoryBlockManager::Update(KMemoryBlockManagerUpdateAllocator* allocator,
+ KProcessAddress address, size_t num_pages, KMemoryState state,
+ KMemoryPermission perm, KMemoryAttribute attr,
KMemoryBlockDisableMergeAttribute set_disable_attr,
KMemoryBlockDisableMergeAttribute clear_disable_attr) {
// Ensure for auditing that we never end up with an invalid tree.
KScopedMemoryBlockManagerAuditor auditor(this);
- ASSERT(Common::IsAligned(address, PageSize));
+ ASSERT(Common::IsAligned(GetInteger(address), PageSize));
ASSERT((attr & (KMemoryAttribute::IpcLocked | KMemoryAttribute::DeviceShared)) ==
KMemoryAttribute::None);
- VAddr cur_address = address;
+ KProcessAddress cur_address = address;
size_t remaining_pages = num_pages;
iterator it = this->FindIterator(address);
@@ -168,17 +172,17 @@ void KMemoryBlockManager::Update(KMemoryBlockManagerUpdateAllocator* allocator,
}
void KMemoryBlockManager::UpdateIfMatch(KMemoryBlockManagerUpdateAllocator* allocator,
- VAddr address, size_t num_pages, KMemoryState test_state,
- KMemoryPermission test_perm, KMemoryAttribute test_attr,
- KMemoryState state, KMemoryPermission perm,
- KMemoryAttribute attr) {
+ KProcessAddress address, size_t num_pages,
+ KMemoryState test_state, KMemoryPermission test_perm,
+ KMemoryAttribute test_attr, KMemoryState state,
+ KMemoryPermission perm, KMemoryAttribute attr) {
// Ensure for auditing that we never end up with an invalid tree.
KScopedMemoryBlockManagerAuditor auditor(this);
- ASSERT(Common::IsAligned(address, PageSize));
+ ASSERT(Common::IsAligned(GetInteger(address), PageSize));
ASSERT((attr & (KMemoryAttribute::IpcLocked | KMemoryAttribute::DeviceShared)) ==
KMemoryAttribute::None);
- VAddr cur_address = address;
+ KProcessAddress cur_address = address;
size_t remaining_pages = num_pages;
iterator it = this->FindIterator(address);
@@ -230,18 +234,18 @@ void KMemoryBlockManager::UpdateIfMatch(KMemoryBlockManagerUpdateAllocator* allo
this->CoalesceForUpdate(allocator, address, num_pages);
}
-void KMemoryBlockManager::UpdateLock(KMemoryBlockManagerUpdateAllocator* allocator, VAddr address,
- size_t num_pages, MemoryBlockLockFunction lock_func,
- KMemoryPermission perm) {
+void KMemoryBlockManager::UpdateLock(KMemoryBlockManagerUpdateAllocator* allocator,
+ KProcessAddress address, size_t num_pages,
+ MemoryBlockLockFunction lock_func, KMemoryPermission perm) {
// Ensure for auditing that we never end up with an invalid tree.
KScopedMemoryBlockManagerAuditor auditor(this);
- ASSERT(Common::IsAligned(address, PageSize));
+ ASSERT(Common::IsAligned(GetInteger(address), PageSize));
- VAddr cur_address = address;
+ KProcessAddress cur_address = address;
size_t remaining_pages = num_pages;
iterator it = this->FindIterator(address);
- const VAddr end_address = address + (num_pages * PageSize);
+ const KProcessAddress end_address = address + (num_pages * PageSize);
while (remaining_pages > 0) {
const size_t remaining_size = remaining_pages * PageSize;
diff --git a/src/core/hle/kernel/k_memory_block_manager.h b/src/core/hle/kernel/k_memory_block_manager.h
index d382722a6..96496e990 100644
--- a/src/core/hle/kernel/k_memory_block_manager.h
+++ b/src/core/hle/kernel/k_memory_block_manager.h
@@ -7,9 +7,9 @@
#include <functional>
#include "common/common_funcs.h"
-#include "common/common_types.h"
#include "core/hle/kernel/k_dynamic_resource_manager.h"
#include "core/hle/kernel/k_memory_block.h"
+#include "core/hle/kernel/k_typed_address.h"
namespace Kernel {
@@ -85,9 +85,10 @@ public:
public:
KMemoryBlockManager();
- using HostUnmapCallback = std::function<void(VAddr, u64)>;
+ using HostUnmapCallback = std::function<void(Common::ProcessAddress, u64)>;
- Result Initialize(VAddr st, VAddr nd, KMemoryBlockSlabManager* slab_manager);
+ Result Initialize(KProcessAddress st, KProcessAddress nd,
+ KMemoryBlockSlabManager* slab_manager);
void Finalize(KMemoryBlockSlabManager* slab_manager, HostUnmapCallback&& host_unmap_callback);
iterator end() {
@@ -100,27 +101,28 @@ public:
return m_memory_block_tree.cend();
}
- VAddr FindFreeArea(VAddr region_start, size_t region_num_pages, size_t num_pages,
- size_t alignment, size_t offset, size_t guard_pages) const;
+ KProcessAddress FindFreeArea(KProcessAddress region_start, size_t region_num_pages,
+ size_t num_pages, size_t alignment, size_t offset,
+ size_t guard_pages) const;
- void Update(KMemoryBlockManagerUpdateAllocator* allocator, VAddr address, size_t num_pages,
- KMemoryState state, KMemoryPermission perm, KMemoryAttribute attr,
+ void Update(KMemoryBlockManagerUpdateAllocator* allocator, KProcessAddress address,
+ size_t num_pages, KMemoryState state, KMemoryPermission perm, KMemoryAttribute attr,
KMemoryBlockDisableMergeAttribute set_disable_attr,
KMemoryBlockDisableMergeAttribute clear_disable_attr);
- void UpdateLock(KMemoryBlockManagerUpdateAllocator* allocator, VAddr address, size_t num_pages,
- MemoryBlockLockFunction lock_func, KMemoryPermission perm);
+ void UpdateLock(KMemoryBlockManagerUpdateAllocator* allocator, KProcessAddress address,
+ size_t num_pages, MemoryBlockLockFunction lock_func, KMemoryPermission perm);
- void UpdateIfMatch(KMemoryBlockManagerUpdateAllocator* allocator, VAddr address,
+ void UpdateIfMatch(KMemoryBlockManagerUpdateAllocator* allocator, KProcessAddress address,
size_t num_pages, KMemoryState test_state, KMemoryPermission test_perm,
KMemoryAttribute test_attr, KMemoryState state, KMemoryPermission perm,
KMemoryAttribute attr);
- iterator FindIterator(VAddr address) const {
+ iterator FindIterator(KProcessAddress address) const {
return m_memory_block_tree.find(KMemoryBlock(
address, 1, KMemoryState::Free, KMemoryPermission::None, KMemoryAttribute::None));
}
- const KMemoryBlock* FindBlock(VAddr address) const {
+ const KMemoryBlock* FindBlock(KProcessAddress address) const {
if (const_iterator it = this->FindIterator(address); it != m_memory_block_tree.end()) {
return std::addressof(*it);
}
@@ -132,24 +134,20 @@ public:
bool CheckState() const;
private:
- void CoalesceForUpdate(KMemoryBlockManagerUpdateAllocator* allocator, VAddr address,
+ void CoalesceForUpdate(KMemoryBlockManagerUpdateAllocator* allocator, KProcessAddress address,
size_t num_pages);
MemoryBlockTree m_memory_block_tree;
- VAddr m_start_address{};
- VAddr m_end_address{};
+ KProcessAddress m_start_address{};
+ KProcessAddress m_end_address{};
};
class KScopedMemoryBlockManagerAuditor {
public:
- explicit KScopedMemoryBlockManagerAuditor(KMemoryBlockManager* m) : m_manager(m) {
- ASSERT(m_manager->CheckState());
- }
+ explicit KScopedMemoryBlockManagerAuditor(KMemoryBlockManager* m) : m_manager(m) {}
explicit KScopedMemoryBlockManagerAuditor(KMemoryBlockManager& m)
: KScopedMemoryBlockManagerAuditor(std::addressof(m)) {}
- ~KScopedMemoryBlockManagerAuditor() {
- ASSERT(m_manager->CheckState());
- }
+ ~KScopedMemoryBlockManagerAuditor() = default;
private:
KMemoryBlockManager* m_manager;
diff --git a/src/core/hle/kernel/k_memory_layout.cpp b/src/core/hle/kernel/k_memory_layout.cpp
index 72c3ee4b7..af40092c0 100644
--- a/src/core/hle/kernel/k_memory_layout.cpp
+++ b/src/core/hle/kernel/k_memory_layout.cpp
@@ -18,11 +18,11 @@ KMemoryRegion* AllocateRegion(KMemoryRegionAllocator& memory_region_allocator, A
} // namespace
-KMemoryRegionTree::KMemoryRegionTree(KMemoryRegionAllocator& memory_region_allocator_)
- : memory_region_allocator{memory_region_allocator_} {}
+KMemoryRegionTree::KMemoryRegionTree(KMemoryRegionAllocator& memory_region_allocator)
+ : m_memory_region_allocator{memory_region_allocator} {}
void KMemoryRegionTree::InsertDirectly(u64 address, u64 last_address, u32 attr, u32 type_id) {
- this->insert(*AllocateRegion(memory_region_allocator, address, last_address, attr, type_id));
+ this->insert(*AllocateRegion(m_memory_region_allocator, address, last_address, attr, type_id));
}
bool KMemoryRegionTree::Insert(u64 address, size_t size, u32 type_id, u32 new_attr, u32 old_attr) {
@@ -69,7 +69,7 @@ bool KMemoryRegionTree::Insert(u64 address, size_t size, u32 type_id, u32 new_at
const u64 new_pair = (old_pair != std::numeric_limits<u64>::max())
? old_pair + (address - old_address)
: old_pair;
- this->insert(*AllocateRegion(memory_region_allocator, address, inserted_region_last,
+ this->insert(*AllocateRegion(m_memory_region_allocator, address, inserted_region_last,
new_pair, new_attr, type_id));
}
@@ -78,14 +78,15 @@ bool KMemoryRegionTree::Insert(u64 address, size_t size, u32 type_id, u32 new_at
const u64 after_pair = (old_pair != std::numeric_limits<u64>::max())
? old_pair + (inserted_region_end - old_address)
: old_pair;
- this->insert(*AllocateRegion(memory_region_allocator, inserted_region_end, old_last,
+ this->insert(*AllocateRegion(m_memory_region_allocator, inserted_region_end, old_last,
after_pair, old_attr, old_type));
}
return true;
}
-VAddr KMemoryRegionTree::GetRandomAlignedRegion(size_t size, size_t alignment, u32 type_id) {
+KVirtualAddress KMemoryRegionTree::GetRandomAlignedRegion(size_t size, size_t alignment,
+ u32 type_id) {
// We want to find the total extents of the type id.
const auto extents = this->GetDerivedRegionExtents(static_cast<KMemoryRegionType>(type_id));
@@ -126,14 +127,17 @@ VAddr KMemoryRegionTree::GetRandomAlignedRegion(size_t size, size_t alignment, u
}
KMemoryLayout::KMemoryLayout()
- : virtual_tree{memory_region_allocator}, physical_tree{memory_region_allocator},
- virtual_linear_tree{memory_region_allocator}, physical_linear_tree{memory_region_allocator} {}
+ : m_virtual_tree{m_memory_region_allocator}, m_physical_tree{m_memory_region_allocator},
+ m_virtual_linear_tree{m_memory_region_allocator}, m_physical_linear_tree{
+ m_memory_region_allocator} {}
-void KMemoryLayout::InitializeLinearMemoryRegionTrees(PAddr aligned_linear_phys_start,
- VAddr linear_virtual_start) {
+void KMemoryLayout::InitializeLinearMemoryRegionTrees(KPhysicalAddress aligned_linear_phys_start,
+ KVirtualAddress linear_virtual_start) {
// Set static differences.
- linear_phys_to_virt_diff = linear_virtual_start - aligned_linear_phys_start;
- linear_virt_to_phys_diff = aligned_linear_phys_start - linear_virtual_start;
+ m_linear_phys_to_virt_diff =
+ GetInteger(linear_virtual_start) - GetInteger(aligned_linear_phys_start);
+ m_linear_virt_to_phys_diff =
+ GetInteger(aligned_linear_phys_start) - GetInteger(linear_virtual_start);
// Initialize linear trees.
for (auto& region : GetPhysicalMemoryRegionTree()) {
diff --git a/src/core/hle/kernel/k_memory_layout.h b/src/core/hle/kernel/k_memory_layout.h
index fd6e1d3e6..54a71df56 100644
--- a/src/core/hle/kernel/k_memory_layout.h
+++ b/src/core/hle/kernel/k_memory_layout.h
@@ -10,6 +10,7 @@
#include "core/device_memory.h"
#include "core/hle/kernel/k_memory_region.h"
#include "core/hle/kernel/k_memory_region_type.h"
+#include "core/hle/kernel/k_typed_address.h"
#include "core/hle/kernel/memory_types.h"
namespace Kernel {
@@ -67,12 +68,13 @@ constexpr size_t KernelPageBufferAdditionalSize = 0x33C000;
constexpr std::size_t KernelResourceSize = KernelPageTableHeapSize + KernelInitialPageHeapSize +
KernelSlabHeapSize + KernelPageBufferHeapSize;
-constexpr bool IsKernelAddressKey(VAddr key) {
- return KernelVirtualAddressSpaceBase <= key && key <= KernelVirtualAddressSpaceLast;
-}
+//! NB: Use KThread::GetAddressKeyIsKernel().
+//! See explanation for deviation of GetAddressKey.
+bool IsKernelAddressKey(KProcessAddress key) = delete;
-constexpr bool IsKernelAddress(VAddr address) {
- return KernelVirtualAddressSpaceBase <= address && address < KernelVirtualAddressSpaceEnd;
+constexpr bool IsKernelAddress(KProcessAddress address) {
+ return KernelVirtualAddressSpaceBase <= GetInteger(address) &&
+ address < KernelVirtualAddressSpaceEnd;
}
class KMemoryLayout final {
@@ -80,62 +82,62 @@ public:
KMemoryLayout();
KMemoryRegionTree& GetVirtualMemoryRegionTree() {
- return virtual_tree;
+ return m_virtual_tree;
}
const KMemoryRegionTree& GetVirtualMemoryRegionTree() const {
- return virtual_tree;
+ return m_virtual_tree;
}
KMemoryRegionTree& GetPhysicalMemoryRegionTree() {
- return physical_tree;
+ return m_physical_tree;
}
const KMemoryRegionTree& GetPhysicalMemoryRegionTree() const {
- return physical_tree;
+ return m_physical_tree;
}
KMemoryRegionTree& GetVirtualLinearMemoryRegionTree() {
- return virtual_linear_tree;
+ return m_virtual_linear_tree;
}
const KMemoryRegionTree& GetVirtualLinearMemoryRegionTree() const {
- return virtual_linear_tree;
+ return m_virtual_linear_tree;
}
KMemoryRegionTree& GetPhysicalLinearMemoryRegionTree() {
- return physical_linear_tree;
+ return m_physical_linear_tree;
}
const KMemoryRegionTree& GetPhysicalLinearMemoryRegionTree() const {
- return physical_linear_tree;
+ return m_physical_linear_tree;
}
- VAddr GetLinearVirtualAddress(PAddr address) const {
- return address + linear_phys_to_virt_diff;
+ KVirtualAddress GetLinearVirtualAddress(KPhysicalAddress address) const {
+ return GetInteger(address) + m_linear_phys_to_virt_diff;
}
- PAddr GetLinearPhysicalAddress(VAddr address) const {
- return address + linear_virt_to_phys_diff;
+ KPhysicalAddress GetLinearPhysicalAddress(KVirtualAddress address) const {
+ return GetInteger(address) + m_linear_virt_to_phys_diff;
}
- const KMemoryRegion* FindVirtual(VAddr address) const {
+ const KMemoryRegion* FindVirtual(KVirtualAddress address) const {
return Find(address, GetVirtualMemoryRegionTree());
}
- const KMemoryRegion* FindPhysical(PAddr address) const {
+ const KMemoryRegion* FindPhysical(KPhysicalAddress address) const {
return Find(address, GetPhysicalMemoryRegionTree());
}
- const KMemoryRegion* FindVirtualLinear(VAddr address) const {
+ const KMemoryRegion* FindVirtualLinear(KVirtualAddress address) const {
return Find(address, GetVirtualLinearMemoryRegionTree());
}
- const KMemoryRegion* FindPhysicalLinear(PAddr address) const {
+ const KMemoryRegion* FindPhysicalLinear(KPhysicalAddress address) const {
return Find(address, GetPhysicalLinearMemoryRegionTree());
}
- VAddr GetMainStackTopAddress(s32 core_id) const {
+ KVirtualAddress GetMainStackTopAddress(s32 core_id) const {
return GetStackTopAddress(core_id, KMemoryRegionType_KernelMiscMainStack);
}
- VAddr GetIdleStackTopAddress(s32 core_id) const {
+ KVirtualAddress GetIdleStackTopAddress(s32 core_id) const {
return GetStackTopAddress(core_id, KMemoryRegionType_KernelMiscIdleStack);
}
- VAddr GetExceptionStackTopAddress(s32 core_id) const {
+ KVirtualAddress GetExceptionStackTopAddress(s32 core_id) const {
return GetStackTopAddress(core_id, KMemoryRegionType_KernelMiscExceptionStack);
}
- VAddr GetSlabRegionAddress() const {
+ KVirtualAddress GetSlabRegionAddress() const {
return Dereference(GetVirtualMemoryRegionTree().FindByType(KMemoryRegionType_KernelSlab))
.GetAddress();
}
@@ -143,10 +145,10 @@ public:
const KMemoryRegion& GetDeviceRegion(KMemoryRegionType type) const {
return Dereference(GetPhysicalMemoryRegionTree().FindFirstDerived(type));
}
- PAddr GetDevicePhysicalAddress(KMemoryRegionType type) const {
+ KPhysicalAddress GetDevicePhysicalAddress(KMemoryRegionType type) const {
return GetDeviceRegion(type).GetAddress();
}
- VAddr GetDeviceVirtualAddress(KMemoryRegionType type) const {
+ KVirtualAddress GetDeviceVirtualAddress(KMemoryRegionType type) const {
return GetDeviceRegion(type).GetPairAddress();
}
@@ -175,11 +177,11 @@ public:
KMemoryRegionType_VirtualDramKernelSecureAppletMemory));
}
- const KMemoryRegion& GetVirtualLinearRegion(VAddr address) const {
+ const KMemoryRegion& GetVirtualLinearRegion(KVirtualAddress address) const {
return Dereference(FindVirtualLinear(address));
}
- const KMemoryRegion& GetPhysicalLinearRegion(PAddr address) const {
+ const KMemoryRegion& GetPhysicalLinearRegion(KPhysicalAddress address) const {
return Dereference(FindPhysicalLinear(address));
}
@@ -193,29 +195,32 @@ public:
return GetPhysicalMemoryRegionTree().FindFirstDerived(KMemoryRegionType_DTB);
}
- bool IsHeapPhysicalAddress(const KMemoryRegion*& region, PAddr address) const {
+ bool IsHeapPhysicalAddress(const KMemoryRegion*& region, KPhysicalAddress address) const {
return IsTypedAddress(region, address, GetPhysicalLinearMemoryRegionTree(),
KMemoryRegionType_DramUserPool);
}
- bool IsHeapVirtualAddress(const KMemoryRegion*& region, VAddr address) const {
+ bool IsHeapVirtualAddress(const KMemoryRegion*& region, KVirtualAddress address) const {
return IsTypedAddress(region, address, GetVirtualLinearMemoryRegionTree(),
KMemoryRegionType_VirtualDramUserPool);
}
- bool IsHeapPhysicalAddress(const KMemoryRegion*& region, PAddr address, size_t size) const {
+ bool IsHeapPhysicalAddress(const KMemoryRegion*& region, KPhysicalAddress address,
+ size_t size) const {
return IsTypedAddress(region, address, size, GetPhysicalLinearMemoryRegionTree(),
KMemoryRegionType_DramUserPool);
}
- bool IsHeapVirtualAddress(const KMemoryRegion*& region, VAddr address, size_t size) const {
+ bool IsHeapVirtualAddress(const KMemoryRegion*& region, KVirtualAddress address,
+ size_t size) const {
return IsTypedAddress(region, address, size, GetVirtualLinearMemoryRegionTree(),
KMemoryRegionType_VirtualDramUserPool);
}
- bool IsLinearMappedPhysicalAddress(const KMemoryRegion*& region, PAddr address) const {
+ bool IsLinearMappedPhysicalAddress(const KMemoryRegion*& region,
+ KPhysicalAddress address) const {
return IsTypedAddress(region, address, GetPhysicalLinearMemoryRegionTree(),
static_cast<KMemoryRegionType>(KMemoryRegionAttr_LinearMapped));
}
- bool IsLinearMappedPhysicalAddress(const KMemoryRegion*& region, PAddr address,
+ bool IsLinearMappedPhysicalAddress(const KMemoryRegion*& region, KPhysicalAddress address,
size_t size) const {
return IsTypedAddress(region, address, size, GetPhysicalLinearMemoryRegionTree(),
static_cast<KMemoryRegionType>(KMemoryRegionAttr_LinearMapped));
@@ -234,8 +239,8 @@ public:
return std::make_pair(total_size, kernel_size);
}
- void InitializeLinearMemoryRegionTrees(PAddr aligned_linear_phys_start,
- VAddr linear_virtual_start);
+ void InitializeLinearMemoryRegionTrees(KPhysicalAddress aligned_linear_phys_start,
+ KVirtualAddress linear_virtual_start);
static size_t GetResourceRegionSizeForInit(bool use_extra_resource);
auto GetKernelRegionExtents() const {
@@ -261,8 +266,8 @@ public:
auto GetLinearRegionVirtualExtents() const {
const auto physical = GetLinearRegionPhysicalExtents();
- return KMemoryRegion(GetLinearVirtualAddress(physical.GetAddress()),
- GetLinearVirtualAddress(physical.GetLastAddress()), 0,
+ return KMemoryRegion(GetInteger(GetLinearVirtualAddress(physical.GetAddress())),
+ GetInteger(GetLinearVirtualAddress(physical.GetLastAddress())), 0,
KMemoryRegionType_None);
}
@@ -334,12 +339,12 @@ private:
static bool IsTypedAddress(const KMemoryRegion*& region, AddressType address,
const KMemoryRegionTree& tree, KMemoryRegionType type) {
// Check if the cached region already contains the address.
- if (region != nullptr && region->Contains(address)) {
+ if (region != nullptr && region->Contains(GetInteger(address))) {
return true;
}
// Find the containing region, and update the cache.
- if (const KMemoryRegion* found = tree.Find(address);
+ if (const KMemoryRegion* found = tree.Find(GetInteger(address));
found != nullptr && found->IsDerivedFrom(type)) {
region = found;
return true;
@@ -352,11 +357,12 @@ private:
static bool IsTypedAddress(const KMemoryRegion*& region, AddressType address, size_t size,
const KMemoryRegionTree& tree, KMemoryRegionType type) {
// Get the end of the checked region.
- const u64 last_address = address + size - 1;
+ const u64 last_address = GetInteger(address) + size - 1;
// Walk the tree to verify the region is correct.
- const KMemoryRegion* cur =
- (region != nullptr && region->Contains(address)) ? region : tree.Find(address);
+ const KMemoryRegion* cur = (region != nullptr && region->Contains(GetInteger(address)))
+ ? region
+ : tree.Find(GetInteger(address));
while (cur != nullptr && cur->IsDerivedFrom(type)) {
if (last_address <= cur->GetLastAddress()) {
region = cur;
@@ -370,7 +376,7 @@ private:
template <typename AddressType>
static const KMemoryRegion* Find(AddressType address, const KMemoryRegionTree& tree) {
- return tree.Find(address);
+ return tree.Find(GetInteger(address));
}
static KMemoryRegion& Dereference(KMemoryRegion* region) {
@@ -383,7 +389,7 @@ private:
return *region;
}
- VAddr GetStackTopAddress(s32 core_id, KMemoryRegionType type) const {
+ KVirtualAddress GetStackTopAddress(s32 core_id, KMemoryRegionType type) const {
const auto& region = Dereference(
GetVirtualMemoryRegionTree().FindByTypeAndAttribute(type, static_cast<u32>(core_id)));
ASSERT(region.GetEndAddress() != 0);
@@ -391,13 +397,13 @@ private:
}
private:
- u64 linear_phys_to_virt_diff{};
- u64 linear_virt_to_phys_diff{};
- KMemoryRegionAllocator memory_region_allocator;
- KMemoryRegionTree virtual_tree;
- KMemoryRegionTree physical_tree;
- KMemoryRegionTree virtual_linear_tree;
- KMemoryRegionTree physical_linear_tree;
+ u64 m_linear_phys_to_virt_diff{};
+ u64 m_linear_virt_to_phys_diff{};
+ KMemoryRegionAllocator m_memory_region_allocator;
+ KMemoryRegionTree m_virtual_tree;
+ KMemoryRegionTree m_physical_tree;
+ KMemoryRegionTree m_virtual_linear_tree;
+ KMemoryRegionTree m_physical_linear_tree;
};
namespace Init {
diff --git a/src/core/hle/kernel/k_memory_manager.cpp b/src/core/hle/kernel/k_memory_manager.cpp
index cd6ea388e..74d8169e0 100644
--- a/src/core/hle/kernel/k_memory_manager.cpp
+++ b/src/core/hle/kernel/k_memory_manager.cpp
@@ -5,7 +5,6 @@
#include "common/alignment.h"
#include "common/assert.h"
-#include "common/common_types.h"
#include "common/scope_exit.h"
#include "core/core.h"
#include "core/device_memory.h"
@@ -44,10 +43,10 @@ KMemoryManager::KMemoryManager(Core::System& system)
KLightLock{system.Kernel()},
} {}
-void KMemoryManager::Initialize(VAddr management_region, size_t management_region_size) {
+void KMemoryManager::Initialize(KVirtualAddress management_region, size_t management_region_size) {
// Clear the management region to zero.
- const VAddr management_region_end = management_region + management_region_size;
+ const KVirtualAddress management_region_end = management_region + management_region_size;
// std::memset(GetVoidPointer(management_region), 0, management_region_size);
// Reset our manager count.
@@ -56,7 +55,7 @@ void KMemoryManager::Initialize(VAddr management_region, size_t management_regio
// Traverse the virtual memory layout tree, initializing each manager as appropriate.
while (m_num_managers != MaxManagerCount) {
// Locate the region that should initialize the current manager.
- PAddr region_address = 0;
+ KPhysicalAddress region_address = 0;
size_t region_size = 0;
Pool region_pool = Pool::Count;
for (const auto& it : m_system.Kernel().MemoryLayout().GetPhysicalMemoryRegionTree()) {
@@ -70,8 +69,8 @@ void KMemoryManager::Initialize(VAddr management_region, size_t management_regio
continue;
}
- const PAddr cur_start = it.GetAddress();
- const PAddr cur_end = it.GetEndAddress();
+ const KPhysicalAddress cur_start = it.GetAddress();
+ const KPhysicalAddress cur_end = it.GetEndAddress();
// Validate the region.
ASSERT(cur_end != 0);
@@ -119,17 +118,17 @@ void KMemoryManager::Initialize(VAddr management_region, size_t management_regio
// Free each region to its corresponding heap.
size_t reserved_sizes[MaxManagerCount] = {};
- const PAddr ini_start = GetInitialProcessBinaryPhysicalAddress();
- const PAddr ini_end = ini_start + InitialProcessBinarySizeMax;
- const PAddr ini_last = ini_end - 1;
+ const KPhysicalAddress ini_start = GetInitialProcessBinaryPhysicalAddress();
+ const KPhysicalAddress ini_end = ini_start + InitialProcessBinarySizeMax;
+ const KPhysicalAddress ini_last = ini_end - 1;
for (const auto& it : m_system.Kernel().MemoryLayout().GetPhysicalMemoryRegionTree()) {
if (it.IsDerivedFrom(KMemoryRegionType_DramUserPool)) {
// Get the manager for the region.
auto& manager = m_managers[it.GetAttributes()];
- const PAddr cur_start = it.GetAddress();
- const PAddr cur_last = it.GetLastAddress();
- const PAddr cur_end = it.GetEndAddress();
+ const KPhysicalAddress cur_start = it.GetAddress();
+ const KPhysicalAddress cur_last = it.GetLastAddress();
+ const KPhysicalAddress cur_end = it.GetEndAddress();
if (cur_start <= ini_start && ini_last <= cur_last) {
// Free memory before the ini to the heap.
@@ -175,7 +174,8 @@ void KMemoryManager::FinalizeOptimizedMemory(u64 process_id, Pool pool) {
UNREACHABLE();
}
-PAddr KMemoryManager::AllocateAndOpenContinuous(size_t num_pages, size_t align_pages, u32 option) {
+KPhysicalAddress KMemoryManager::AllocateAndOpenContinuous(size_t num_pages, size_t align_pages,
+ u32 option) {
// Early return if we're allocating no pages.
if (num_pages == 0) {
return 0;
@@ -190,7 +190,7 @@ PAddr KMemoryManager::AllocateAndOpenContinuous(size_t num_pages, size_t align_p
// Loop, trying to iterate from each block.
Impl* chosen_manager = nullptr;
- PAddr allocated_block = 0;
+ KPhysicalAddress allocated_block = 0;
for (chosen_manager = this->GetFirstManager(pool, dir); chosen_manager != nullptr;
chosen_manager = this->GetNextManager(chosen_manager, dir)) {
allocated_block = chosen_manager->AllocateAligned(heap_index, num_pages, align_pages);
@@ -239,7 +239,7 @@ Result KMemoryManager::AllocatePageGroupImpl(KPageGroup* out, size_t num_pages,
cur_manager = this->GetNextManager(cur_manager, dir)) {
while (num_pages >= pages_per_alloc) {
// Allocate a block.
- PAddr allocated_block = cur_manager->AllocateBlock(index, random);
+ KPhysicalAddress allocated_block = cur_manager->AllocateBlock(index, random);
if (allocated_block == 0) {
break;
}
@@ -286,7 +286,7 @@ Result KMemoryManager::AllocateAndOpen(KPageGroup* out, size_t num_pages, u32 op
// Open the first reference to the pages.
for (const auto& block : *out) {
- PAddr cur_address = block.GetAddress();
+ KPhysicalAddress cur_address = block.GetAddress();
size_t remaining_pages = block.GetNumPages();
while (remaining_pages > 0) {
// Get the manager for the current address.
@@ -337,7 +337,7 @@ Result KMemoryManager::AllocateForProcess(KPageGroup* out, size_t num_pages, u32
// Iterate over the allocated blocks.
for (const auto& block : *out) {
// Get the block extents.
- const PAddr block_address = block.GetAddress();
+ const KPhysicalAddress block_address = block.GetAddress();
const size_t block_pages = block.GetNumPages();
// If it has no pages, we don't need to do anything.
@@ -348,7 +348,7 @@ Result KMemoryManager::AllocateForProcess(KPageGroup* out, size_t num_pages, u32
// Fill all the pages that we need to fill.
bool any_new = false;
{
- PAddr cur_address = block_address;
+ KPhysicalAddress cur_address = block_address;
size_t remaining_pages = block_pages;
while (remaining_pages > 0) {
// Get the manager for the current address.
@@ -369,7 +369,7 @@ Result KMemoryManager::AllocateForProcess(KPageGroup* out, size_t num_pages, u32
// If there are new pages, update tracking for the allocation.
if (any_new) {
// Update tracking for the allocation.
- PAddr cur_address = block_address;
+ KPhysicalAddress cur_address = block_address;
size_t remaining_pages = block_pages;
while (remaining_pages > 0) {
// Get the manager for the current address.
@@ -400,8 +400,9 @@ Result KMemoryManager::AllocateForProcess(KPageGroup* out, size_t num_pages, u32
R_SUCCEED();
}
-size_t KMemoryManager::Impl::Initialize(PAddr address, size_t size, VAddr management,
- VAddr management_end, Pool p) {
+size_t KMemoryManager::Impl::Initialize(KPhysicalAddress address, size_t size,
+ KVirtualAddress management, KVirtualAddress management_end,
+ Pool p) {
// Calculate management sizes.
const size_t ref_count_size = (size / PageSize) * sizeof(u16);
const size_t optimize_map_size = CalculateOptimizedProcessOverheadSize(size);
@@ -417,7 +418,7 @@ size_t KMemoryManager::Impl::Initialize(PAddr address, size_t size, VAddr manage
m_management_region = management;
m_page_reference_counts.resize(
Kernel::Board::Nintendo::Nx::KSystemControl::Init::GetIntendedMemorySize() / PageSize);
- ASSERT(Common::IsAligned(m_management_region, PageSize));
+ ASSERT(Common::IsAligned(GetInteger(m_management_region), PageSize));
// Initialize the manager's KPageHeap.
m_heap.Initialize(address, size, management + manager_size, page_heap_size);
@@ -425,15 +426,15 @@ size_t KMemoryManager::Impl::Initialize(PAddr address, size_t size, VAddr manage
return total_management_size;
}
-void KMemoryManager::Impl::TrackUnoptimizedAllocation(PAddr block, size_t num_pages) {
+void KMemoryManager::Impl::TrackUnoptimizedAllocation(KPhysicalAddress block, size_t num_pages) {
UNREACHABLE();
}
-void KMemoryManager::Impl::TrackOptimizedAllocation(PAddr block, size_t num_pages) {
+void KMemoryManager::Impl::TrackOptimizedAllocation(KPhysicalAddress block, size_t num_pages) {
UNREACHABLE();
}
-bool KMemoryManager::Impl::ProcessOptimizedAllocation(PAddr block, size_t num_pages,
+bool KMemoryManager::Impl::ProcessOptimizedAllocation(KPhysicalAddress block, size_t num_pages,
u8 fill_pattern) {
UNREACHABLE();
}
diff --git a/src/core/hle/kernel/k_memory_manager.h b/src/core/hle/kernel/k_memory_manager.h
index 401d4e644..7e4b41319 100644
--- a/src/core/hle/kernel/k_memory_manager.h
+++ b/src/core/hle/kernel/k_memory_manager.h
@@ -7,10 +7,10 @@
#include <tuple>
#include "common/common_funcs.h"
-#include "common/common_types.h"
#include "core/hle/kernel/k_light_lock.h"
#include "core/hle/kernel/k_memory_layout.h"
#include "core/hle/kernel/k_page_heap.h"
+#include "core/hle/kernel/k_typed_address.h"
#include "core/hle/result.h"
namespace Core {
@@ -50,21 +50,21 @@ public:
explicit KMemoryManager(Core::System& system);
- void Initialize(VAddr management_region, size_t management_region_size);
+ void Initialize(KVirtualAddress management_region, size_t management_region_size);
Result InitializeOptimizedMemory(u64 process_id, Pool pool);
void FinalizeOptimizedMemory(u64 process_id, Pool pool);
- PAddr AllocateAndOpenContinuous(size_t num_pages, size_t align_pages, u32 option);
+ KPhysicalAddress AllocateAndOpenContinuous(size_t num_pages, size_t align_pages, u32 option);
Result AllocateAndOpen(KPageGroup* out, size_t num_pages, u32 option);
Result AllocateForProcess(KPageGroup* out, size_t num_pages, u32 option, u64 process_id,
u8 fill_pattern);
- Pool GetPool(PAddr address) const {
+ Pool GetPool(KPhysicalAddress address) const {
return this->GetManager(address).GetPool();
}
- void Open(PAddr address, size_t num_pages) {
+ void Open(KPhysicalAddress address, size_t num_pages) {
// Repeatedly open references until we've done so for all pages.
while (num_pages) {
auto& manager = this->GetManager(address);
@@ -80,7 +80,7 @@ public:
}
}
- void OpenFirst(PAddr address, size_t num_pages) {
+ void OpenFirst(KPhysicalAddress address, size_t num_pages) {
// Repeatedly open references until we've done so for all pages.
while (num_pages) {
auto& manager = this->GetManager(address);
@@ -96,7 +96,7 @@ public:
}
}
- void Close(PAddr address, size_t num_pages) {
+ void Close(KPhysicalAddress address, size_t num_pages) {
// Repeatedly close references until we've done so for all pages.
while (num_pages) {
auto& manager = this->GetManager(address);
@@ -199,16 +199,16 @@ private:
public:
Impl() = default;
- size_t Initialize(PAddr address, size_t size, VAddr management, VAddr management_end,
- Pool p);
+ size_t Initialize(KPhysicalAddress address, size_t size, KVirtualAddress management,
+ KVirtualAddress management_end, Pool p);
- PAddr AllocateBlock(s32 index, bool random) {
+ KPhysicalAddress AllocateBlock(s32 index, bool random) {
return m_heap.AllocateBlock(index, random);
}
- PAddr AllocateAligned(s32 index, size_t num_pages, size_t align_pages) {
+ KPhysicalAddress AllocateAligned(s32 index, size_t num_pages, size_t align_pages) {
return m_heap.AllocateAligned(index, num_pages, align_pages);
}
- void Free(PAddr addr, size_t num_pages) {
+ void Free(KPhysicalAddress addr, size_t num_pages) {
m_heap.Free(addr, num_pages);
}
@@ -220,10 +220,10 @@ private:
UNIMPLEMENTED();
}
- void TrackUnoptimizedAllocation(PAddr block, size_t num_pages);
- void TrackOptimizedAllocation(PAddr block, size_t num_pages);
+ void TrackUnoptimizedAllocation(KPhysicalAddress block, size_t num_pages);
+ void TrackOptimizedAllocation(KPhysicalAddress block, size_t num_pages);
- bool ProcessOptimizedAllocation(PAddr block, size_t num_pages, u8 fill_pattern);
+ bool ProcessOptimizedAllocation(KPhysicalAddress block, size_t num_pages, u8 fill_pattern);
constexpr Pool GetPool() const {
return m_pool;
@@ -231,7 +231,7 @@ private:
constexpr size_t GetSize() const {
return m_heap.GetSize();
}
- constexpr PAddr GetEndAddress() const {
+ constexpr KPhysicalAddress GetEndAddress() const {
return m_heap.GetEndAddress();
}
@@ -243,10 +243,10 @@ private:
UNIMPLEMENTED();
}
- constexpr size_t GetPageOffset(PAddr address) const {
+ constexpr size_t GetPageOffset(KPhysicalAddress address) const {
return m_heap.GetPageOffset(address);
}
- constexpr size_t GetPageOffsetToEnd(PAddr address) const {
+ constexpr size_t GetPageOffsetToEnd(KPhysicalAddress address) const {
return m_heap.GetPageOffsetToEnd(address);
}
@@ -263,7 +263,7 @@ private:
return m_prev;
}
- void OpenFirst(PAddr address, size_t num_pages) {
+ void OpenFirst(KPhysicalAddress address, size_t num_pages) {
size_t index = this->GetPageOffset(address);
const size_t end = index + num_pages;
while (index < end) {
@@ -274,7 +274,7 @@ private:
}
}
- void Open(PAddr address, size_t num_pages) {
+ void Open(KPhysicalAddress address, size_t num_pages) {
size_t index = this->GetPageOffset(address);
const size_t end = index + num_pages;
while (index < end) {
@@ -285,7 +285,7 @@ private:
}
}
- void Close(PAddr address, size_t num_pages) {
+ void Close(KPhysicalAddress address, size_t num_pages) {
size_t index = this->GetPageOffset(address);
const size_t end = index + num_pages;
@@ -323,18 +323,18 @@ private:
KPageHeap m_heap;
std::vector<RefCount> m_page_reference_counts;
- VAddr m_management_region{};
+ KVirtualAddress m_management_region{};
Pool m_pool{};
Impl* m_next{};
Impl* m_prev{};
};
private:
- Impl& GetManager(PAddr address) {
+ Impl& GetManager(KPhysicalAddress address) {
return m_managers[m_memory_layout.GetPhysicalLinearRegion(address).GetAttributes()];
}
- const Impl& GetManager(PAddr address) const {
+ const Impl& GetManager(KPhysicalAddress address) const {
return m_managers[m_memory_layout.GetPhysicalLinearRegion(address).GetAttributes()];
}
diff --git a/src/core/hle/kernel/k_memory_region.h b/src/core/hle/kernel/k_memory_region.h
index 5037e657f..e3044f022 100644
--- a/src/core/hle/kernel/k_memory_region.h
+++ b/src/core/hle/kernel/k_memory_region.h
@@ -5,9 +5,9 @@
#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_memory_region_type.h"
+#include "core/hle/kernel/k_typed_address.h"
namespace Kernel {
@@ -21,15 +21,15 @@ public:
YUZU_NON_MOVEABLE(KMemoryRegion);
constexpr KMemoryRegion() = default;
- constexpr KMemoryRegion(u64 address_, u64 last_address_)
- : address{address_}, last_address{last_address_} {}
- constexpr KMemoryRegion(u64 address_, u64 last_address_, u64 pair_address_, u32 attributes_,
- u32 type_id_)
- : address(address_), last_address(last_address_), pair_address(pair_address_),
- attributes(attributes_), type_id(type_id_) {}
- constexpr KMemoryRegion(u64 address_, u64 last_address_, u32 attributes_, u32 type_id_)
- : KMemoryRegion(address_, last_address_, std::numeric_limits<u64>::max(), attributes_,
- type_id_) {}
+ constexpr KMemoryRegion(u64 address, u64 last_address)
+ : m_address{address}, m_last_address{last_address} {}
+ constexpr KMemoryRegion(u64 address, u64 last_address, u64 pair_address, u32 attributes,
+ u32 type_id)
+ : m_address(address), m_last_address(last_address), m_pair_address(pair_address),
+ m_attributes(attributes), m_type_id(type_id) {}
+ constexpr KMemoryRegion(u64 address, u64 last_address, u32 attributes, u32 type_id)
+ : KMemoryRegion(address, last_address, std::numeric_limits<u64>::max(), attributes,
+ type_id) {}
~KMemoryRegion() = default;
@@ -44,15 +44,15 @@ public:
}
constexpr u64 GetAddress() const {
- return address;
+ return m_address;
}
constexpr u64 GetPairAddress() const {
- return pair_address;
+ return m_pair_address;
}
constexpr u64 GetLastAddress() const {
- return last_address;
+ return m_last_address;
}
constexpr u64 GetEndAddress() const {
@@ -64,16 +64,16 @@ public:
}
constexpr u32 GetAttributes() const {
- return attributes;
+ return m_attributes;
}
constexpr u32 GetType() const {
- return type_id;
+ return m_type_id;
}
constexpr void SetType(u32 type) {
ASSERT(this->CanDerive(type));
- type_id = type;
+ m_type_id = type;
}
constexpr bool Contains(u64 addr) const {
@@ -94,27 +94,27 @@ public:
}
constexpr void SetPairAddress(u64 a) {
- pair_address = a;
+ m_pair_address = a;
}
constexpr void SetTypeAttribute(u32 attr) {
- type_id |= attr;
+ m_type_id |= attr;
}
private:
constexpr void Reset(u64 a, u64 la, u64 p, u32 r, u32 t) {
- address = a;
- pair_address = p;
- last_address = la;
- attributes = r;
- type_id = t;
- }
-
- u64 address{};
- u64 last_address{};
- u64 pair_address{};
- u32 attributes{};
- u32 type_id{};
+ m_address = a;
+ m_pair_address = p;
+ m_last_address = la;
+ m_attributes = r;
+ m_type_id = t;
+ }
+
+ u64 m_address{};
+ u64 m_last_address{};
+ u64 m_pair_address{};
+ u32 m_attributes{};
+ u32 m_type_id{};
};
class KMemoryRegionTree final {
@@ -243,10 +243,10 @@ public:
void InsertDirectly(u64 address, u64 last_address, u32 attr = 0, u32 type_id = 0);
bool Insert(u64 address, size_t size, u32 type_id, u32 new_attr = 0, u32 old_attr = 0);
- VAddr GetRandomAlignedRegion(size_t size, size_t alignment, u32 type_id);
+ KVirtualAddress GetRandomAlignedRegion(size_t size, size_t alignment, u32 type_id);
- VAddr GetRandomAlignedRegionWithGuard(size_t size, size_t alignment, u32 type_id,
- size_t guard_size) {
+ KVirtualAddress GetRandomAlignedRegionWithGuard(size_t size, size_t alignment, u32 type_id,
+ size_t guard_size) {
return this->GetRandomAlignedRegion(size + 2 * guard_size, alignment, type_id) + guard_size;
}
@@ -322,7 +322,7 @@ public:
private:
TreeType m_tree{};
- KMemoryRegionAllocator& memory_region_allocator;
+ KMemoryRegionAllocator& m_memory_region_allocator;
};
class KMemoryRegionAllocator final {
@@ -338,18 +338,18 @@ public:
template <typename... Args>
KMemoryRegion* Allocate(Args&&... args) {
// Ensure we stay within the bounds of our heap.
- ASSERT(this->num_regions < MaxMemoryRegions);
+ ASSERT(m_num_regions < MaxMemoryRegions);
// Create the new region.
- KMemoryRegion* region = std::addressof(this->region_heap[this->num_regions++]);
- new (region) KMemoryRegion(std::forward<Args>(args)...);
+ KMemoryRegion* region = std::addressof(m_region_heap[m_num_regions++]);
+ std::construct_at(region, std::forward<Args>(args)...);
return region;
}
private:
- std::array<KMemoryRegion, MaxMemoryRegions> region_heap{};
- size_t num_regions{};
+ std::array<KMemoryRegion, MaxMemoryRegions> m_region_heap{};
+ size_t m_num_regions{};
};
} // namespace Kernel
diff --git a/src/core/hle/kernel/k_object_name.cpp b/src/core/hle/kernel/k_object_name.cpp
new file mode 100644
index 000000000..df3a1c4c5
--- /dev/null
+++ b/src/core/hle/kernel/k_object_name.cpp
@@ -0,0 +1,102 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/kernel/k_object_name.h"
+
+namespace Kernel {
+
+KObjectNameGlobalData::KObjectNameGlobalData(KernelCore& kernel) : m_object_list_lock{kernel} {}
+KObjectNameGlobalData::~KObjectNameGlobalData() = default;
+
+void KObjectName::Initialize(KAutoObject* obj, const char* name) {
+ // Set member variables.
+ m_object = obj;
+ std::strncpy(m_name.data(), name, sizeof(m_name) - 1);
+ m_name[sizeof(m_name) - 1] = '\x00';
+
+ // Open a reference to the object we hold.
+ m_object->Open();
+}
+
+bool KObjectName::MatchesName(const char* name) const {
+ return std::strncmp(m_name.data(), name, sizeof(m_name)) == 0;
+}
+
+Result KObjectName::NewFromName(KernelCore& kernel, KAutoObject* obj, const char* name) {
+ // Create a new object name.
+ KObjectName* new_name = KObjectName::Allocate(kernel);
+ R_UNLESS(new_name != nullptr, ResultOutOfResource);
+
+ // Initialize the new name.
+ new_name->Initialize(obj, name);
+
+ // Check if there's an existing name.
+ {
+ // Get the global data.
+ KObjectNameGlobalData& gd{kernel.ObjectNameGlobalData()};
+
+ // Ensure we have exclusive access to the global list.
+ KScopedLightLock lk{gd.GetObjectListLock()};
+
+ // If the object doesn't exist, put it into the list.
+ KScopedAutoObject existing_object = FindImpl(kernel, name);
+ if (existing_object.IsNull()) {
+ gd.GetObjectList().push_back(*new_name);
+ R_SUCCEED();
+ }
+ }
+
+ // The object already exists, which is an error condition. Perform cleanup.
+ obj->Close();
+ KObjectName::Free(kernel, new_name);
+ R_THROW(ResultInvalidState);
+}
+
+Result KObjectName::Delete(KernelCore& kernel, KAutoObject* obj, const char* compare_name) {
+ // Get the global data.
+ KObjectNameGlobalData& gd{kernel.ObjectNameGlobalData()};
+
+ // Ensure we have exclusive access to the global list.
+ KScopedLightLock lk{gd.GetObjectListLock()};
+
+ // Find a matching entry in the list, and delete it.
+ for (auto& name : gd.GetObjectList()) {
+ if (name.MatchesName(compare_name) && obj == name.GetObject()) {
+ // We found a match, clean up its resources.
+ obj->Close();
+ gd.GetObjectList().erase(gd.GetObjectList().iterator_to(name));
+ KObjectName::Free(kernel, std::addressof(name));
+ R_SUCCEED();
+ }
+ }
+
+ // We didn't find the object in the list.
+ R_THROW(ResultNotFound);
+}
+
+KScopedAutoObject<KAutoObject> KObjectName::Find(KernelCore& kernel, const char* name) {
+ // Get the global data.
+ KObjectNameGlobalData& gd{kernel.ObjectNameGlobalData()};
+
+ // Ensure we have exclusive access to the global list.
+ KScopedLightLock lk{gd.GetObjectListLock()};
+
+ return FindImpl(kernel, name);
+}
+
+KScopedAutoObject<KAutoObject> KObjectName::FindImpl(KernelCore& kernel, const char* compare_name) {
+ // Get the global data.
+ KObjectNameGlobalData& gd{kernel.ObjectNameGlobalData()};
+
+ // Try to find a matching object in the global list.
+ for (const auto& name : gd.GetObjectList()) {
+ if (name.MatchesName(compare_name)) {
+ return name.GetObject();
+ }
+ }
+
+ // There's no matching entry in the list.
+ return nullptr;
+}
+
+} // namespace Kernel
diff --git a/src/core/hle/kernel/k_object_name.h b/src/core/hle/kernel/k_object_name.h
new file mode 100644
index 000000000..a8876fe37
--- /dev/null
+++ b/src/core/hle/kernel/k_object_name.h
@@ -0,0 +1,88 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include <array>
+#include <memory>
+
+#include "common/intrusive_list.h"
+
+#include "core/hle/kernel/k_light_lock.h"
+#include "core/hle/kernel/slab_helpers.h"
+#include "core/hle/kernel/svc_results.h"
+
+namespace Kernel {
+
+class KObjectNameGlobalData;
+
+class KObjectName : public KSlabAllocated<KObjectName>,
+ public Common::IntrusiveListBaseNode<KObjectName> {
+public:
+ explicit KObjectName(KernelCore&) {}
+ virtual ~KObjectName() = default;
+
+ static constexpr size_t NameLengthMax = 12;
+ using List = Common::IntrusiveListBaseTraits<KObjectName>::ListType;
+
+ static Result NewFromName(KernelCore& kernel, KAutoObject* obj, const char* name);
+ static Result Delete(KernelCore& kernel, KAutoObject* obj, const char* name);
+
+ static KScopedAutoObject<KAutoObject> Find(KernelCore& kernel, const char* name);
+
+ template <typename Derived>
+ static Result Delete(KernelCore& kernel, const char* name) {
+ // Find the object.
+ KScopedAutoObject obj = Find(kernel, name);
+ R_UNLESS(obj.IsNotNull(), ResultNotFound);
+
+ // Cast the object to the desired type.
+ Derived* derived = obj->DynamicCast<Derived*>();
+ R_UNLESS(derived != nullptr, ResultNotFound);
+
+ // Check that the object is closed.
+ R_UNLESS(derived->IsServerClosed(), ResultInvalidState);
+
+ R_RETURN(Delete(kernel, obj.GetPointerUnsafe(), name));
+ }
+
+ template <typename Derived>
+ requires(std::derived_from<Derived, KAutoObject>)
+ static KScopedAutoObject<Derived> Find(KernelCore& kernel, const char* name) {
+ return Find(kernel, name);
+ }
+
+private:
+ static KScopedAutoObject<KAutoObject> FindImpl(KernelCore& kernel, const char* name);
+
+ void Initialize(KAutoObject* obj, const char* name);
+
+ bool MatchesName(const char* name) const;
+ KAutoObject* GetObject() const {
+ return m_object;
+ }
+
+private:
+ std::array<char, NameLengthMax> m_name{};
+ KAutoObject* m_object{};
+};
+
+class KObjectNameGlobalData {
+public:
+ explicit KObjectNameGlobalData(KernelCore& kernel);
+ ~KObjectNameGlobalData();
+
+ KLightLock& GetObjectListLock() {
+ return m_object_list_lock;
+ }
+
+ KObjectName::List& GetObjectList() {
+ return m_object_list;
+ }
+
+private:
+ KLightLock m_object_list_lock;
+ KObjectName::List m_object_list;
+};
+
+} // namespace Kernel
diff --git a/src/core/hle/kernel/k_page_buffer.cpp b/src/core/hle/kernel/k_page_buffer.cpp
index 0c16dded4..e9830e6d9 100644
--- a/src/core/hle/kernel/k_page_buffer.cpp
+++ b/src/core/hle/kernel/k_page_buffer.cpp
@@ -10,8 +10,8 @@
namespace Kernel {
-KPageBuffer* KPageBuffer::FromPhysicalAddress(Core::System& system, PAddr phys_addr) {
- ASSERT(Common::IsAligned(phys_addr, PageSize));
+KPageBuffer* KPageBuffer::FromPhysicalAddress(Core::System& system, KPhysicalAddress phys_addr) {
+ ASSERT(Common::IsAligned(GetInteger(phys_addr), PageSize));
return system.DeviceMemory().GetPointer<KPageBuffer>(phys_addr);
}
diff --git a/src/core/hle/kernel/k_page_buffer.h b/src/core/hle/kernel/k_page_buffer.h
index cfedaae61..f6a7f1e39 100644
--- a/src/core/hle/kernel/k_page_buffer.h
+++ b/src/core/hle/kernel/k_page_buffer.h
@@ -26,10 +26,10 @@ public:
explicit KPageBuffer(KernelCore&) {}
KPageBuffer() = default;
- static KPageBuffer* FromPhysicalAddress(Core::System& system, PAddr phys_addr);
+ static KPageBuffer* FromPhysicalAddress(Core::System& system, KPhysicalAddress phys_addr);
private:
- [[maybe_unused]] alignas(PageSize) std::array<u8, PageSize> m_buffer{};
+ alignas(PageSize) std::array<u8, PageSize> m_buffer{};
};
static_assert(sizeof(KPageBuffer) == KPageBufferSlabHeap::BufferSize);
diff --git a/src/core/hle/kernel/k_page_group.h b/src/core/hle/kernel/k_page_group.h
index c07f17663..b32909f05 100644
--- a/src/core/hle/kernel/k_page_group.h
+++ b/src/core/hle/kernel/k_page_group.h
@@ -22,7 +22,7 @@ public:
constexpr explicit KBlockInfo() : m_next(nullptr) {}
constexpr void Initialize(KPhysicalAddress addr, size_t np) {
- ASSERT(Common::IsAligned(addr, PageSize));
+ ASSERT(Common::IsAligned(GetInteger(addr), PageSize));
ASSERT(static_cast<u32>(np) == np);
m_page_index = static_cast<u32>(addr / PageSize);
diff --git a/src/core/hle/kernel/k_page_heap.cpp b/src/core/hle/kernel/k_page_heap.cpp
index 7b02c7d8b..95762b5a2 100644
--- a/src/core/hle/kernel/k_page_heap.cpp
+++ b/src/core/hle/kernel/k_page_heap.cpp
@@ -6,14 +6,14 @@
namespace Kernel {
-void KPageHeap::Initialize(PAddr address, size_t size, VAddr management_address,
- size_t management_size, const size_t* block_shifts,
- size_t num_block_shifts) {
+void KPageHeap::Initialize(KPhysicalAddress address, size_t size,
+ KVirtualAddress management_address, size_t management_size,
+ const size_t* block_shifts, size_t num_block_shifts) {
// Check our assumptions.
- ASSERT(Common::IsAligned(address, PageSize));
+ ASSERT(Common::IsAligned(GetInteger(address), PageSize));
ASSERT(Common::IsAligned(size, PageSize));
ASSERT(0 < num_block_shifts && num_block_shifts <= NumMemoryBlockPageShifts);
- const VAddr management_end = management_address + management_size;
+ const KVirtualAddress management_end = management_address + management_size;
// Set our members.
m_heap_address = address;
@@ -31,7 +31,7 @@ void KPageHeap::Initialize(PAddr address, size_t size, VAddr management_address,
}
// Ensure we didn't overextend our bounds.
- ASSERT(VAddr(cur_bitmap_storage) <= management_end);
+ ASSERT(KVirtualAddress(cur_bitmap_storage) <= management_end);
}
size_t KPageHeap::GetNumFreePages() const {
@@ -44,11 +44,11 @@ size_t KPageHeap::GetNumFreePages() const {
return num_free;
}
-PAddr KPageHeap::AllocateByLinearSearch(s32 index) {
+KPhysicalAddress KPageHeap::AllocateByLinearSearch(s32 index) {
const size_t needed_size = m_blocks[index].GetSize();
for (s32 i = index; i < static_cast<s32>(m_num_blocks); i++) {
- if (const PAddr addr = m_blocks[i].PopBlock(false); addr != 0) {
+ if (const KPhysicalAddress addr = m_blocks[i].PopBlock(false); addr != 0) {
if (const size_t allocated_size = m_blocks[i].GetSize(); allocated_size > needed_size) {
this->Free(addr + needed_size, (allocated_size - needed_size) / PageSize);
}
@@ -59,7 +59,7 @@ PAddr KPageHeap::AllocateByLinearSearch(s32 index) {
return 0;
}
-PAddr KPageHeap::AllocateByRandom(s32 index, size_t num_pages, size_t align_pages) {
+KPhysicalAddress KPageHeap::AllocateByRandom(s32 index, size_t num_pages, size_t align_pages) {
// Get the size and required alignment.
const size_t needed_size = num_pages * PageSize;
const size_t align_size = align_pages * PageSize;
@@ -110,7 +110,7 @@ PAddr KPageHeap::AllocateByRandom(s32 index, size_t num_pages, size_t align_page
}
// Pop a block from the index we selected.
- if (PAddr addr = m_blocks[index].PopBlock(true); addr != 0) {
+ if (KPhysicalAddress addr = m_blocks[index].PopBlock(true); addr != 0) {
// Determine how much size we have left over.
if (const size_t leftover_size = m_blocks[index].GetSize() - needed_size;
leftover_size > 0) {
@@ -141,13 +141,13 @@ PAddr KPageHeap::AllocateByRandom(s32 index, size_t num_pages, size_t align_page
return 0;
}
-void KPageHeap::FreeBlock(PAddr block, s32 index) {
+void KPageHeap::FreeBlock(KPhysicalAddress block, s32 index) {
do {
block = m_blocks[index++].PushBlock(block);
} while (block != 0);
}
-void KPageHeap::Free(PAddr addr, size_t num_pages) {
+void KPageHeap::Free(KPhysicalAddress addr, size_t num_pages) {
// Freeing no pages is a no-op.
if (num_pages == 0) {
return;
@@ -155,16 +155,16 @@ void KPageHeap::Free(PAddr addr, size_t num_pages) {
// Find the largest block size that we can free, and free as many as possible.
s32 big_index = static_cast<s32>(m_num_blocks) - 1;
- const PAddr start = addr;
- const PAddr end = addr + num_pages * PageSize;
- PAddr before_start = start;
- PAddr before_end = start;
- PAddr after_start = end;
- PAddr after_end = end;
+ const KPhysicalAddress start = addr;
+ const KPhysicalAddress end = addr + num_pages * PageSize;
+ KPhysicalAddress before_start = start;
+ KPhysicalAddress before_end = start;
+ KPhysicalAddress after_start = end;
+ KPhysicalAddress after_end = end;
while (big_index >= 0) {
const size_t block_size = m_blocks[big_index].GetSize();
- const PAddr big_start = Common::AlignUp(start, block_size);
- const PAddr big_end = Common::AlignDown(end, block_size);
+ const KPhysicalAddress big_start = Common::AlignUp(GetInteger(start), block_size);
+ const KPhysicalAddress big_end = Common::AlignDown(GetInteger(end), block_size);
if (big_start < big_end) {
// Free as many big blocks as we can.
for (auto block = big_start; block < big_end; block += block_size) {
diff --git a/src/core/hle/kernel/k_page_heap.h b/src/core/hle/kernel/k_page_heap.h
index 9021edcf7..c55225bac 100644
--- a/src/core/hle/kernel/k_page_heap.h
+++ b/src/core/hle/kernel/k_page_heap.h
@@ -8,8 +8,8 @@
#include "common/alignment.h"
#include "common/common_funcs.h"
-#include "common/common_types.h"
#include "core/hle/kernel/k_page_bitmap.h"
+#include "core/hle/kernel/k_typed_address.h"
#include "core/hle/kernel/memory_types.h"
namespace Kernel {
@@ -18,24 +18,24 @@ class KPageHeap {
public:
KPageHeap() = default;
- constexpr PAddr GetAddress() const {
+ constexpr KPhysicalAddress GetAddress() const {
return m_heap_address;
}
constexpr size_t GetSize() const {
return m_heap_size;
}
- constexpr PAddr GetEndAddress() const {
+ constexpr KPhysicalAddress GetEndAddress() const {
return this->GetAddress() + this->GetSize();
}
- constexpr size_t GetPageOffset(PAddr block) const {
+ constexpr size_t GetPageOffset(KPhysicalAddress block) const {
return (block - this->GetAddress()) / PageSize;
}
- constexpr size_t GetPageOffsetToEnd(PAddr block) const {
+ constexpr size_t GetPageOffsetToEnd(KPhysicalAddress block) const {
return (this->GetEndAddress() - block) / PageSize;
}
- void Initialize(PAddr heap_address, size_t heap_size, VAddr management_address,
- size_t management_size) {
+ void Initialize(KPhysicalAddress heap_address, size_t heap_size,
+ KVirtualAddress management_address, size_t management_size) {
return this->Initialize(heap_address, heap_size, management_address, management_size,
MemoryBlockPageShifts.data(), NumMemoryBlockPageShifts);
}
@@ -53,7 +53,7 @@ public:
m_initial_used_size = m_heap_size - free_size - reserved_size;
}
- PAddr AllocateBlock(s32 index, bool random) {
+ KPhysicalAddress AllocateBlock(s32 index, bool random) {
if (random) {
const size_t block_pages = m_blocks[index].GetNumPages();
return this->AllocateByRandom(index, block_pages, block_pages);
@@ -62,12 +62,12 @@ public:
}
}
- PAddr AllocateAligned(s32 index, size_t num_pages, size_t align_pages) {
+ KPhysicalAddress AllocateAligned(s32 index, size_t num_pages, size_t align_pages) {
// TODO: linear search support?
return this->AllocateByRandom(index, num_pages, align_pages);
}
- void Free(PAddr addr, size_t num_pages);
+ void Free(KPhysicalAddress addr, size_t num_pages);
static size_t CalculateManagementOverheadSize(size_t region_size) {
return CalculateManagementOverheadSize(region_size, MemoryBlockPageShifts.data(),
@@ -125,24 +125,25 @@ private:
return this->GetNumFreeBlocks() * this->GetNumPages();
}
- u64* Initialize(PAddr addr, size_t size, size_t bs, size_t nbs, u64* bit_storage) {
+ u64* Initialize(KPhysicalAddress addr, size_t size, size_t bs, size_t nbs,
+ u64* bit_storage) {
// Set shifts.
m_block_shift = bs;
m_next_block_shift = nbs;
// Align up the address.
- PAddr end = addr + size;
+ KPhysicalAddress end = addr + size;
const size_t align = (m_next_block_shift != 0) ? (u64(1) << m_next_block_shift)
: (u64(1) << m_block_shift);
- addr = Common::AlignDown(addr, align);
- end = Common::AlignUp(end, align);
+ addr = Common::AlignDown(GetInteger(addr), align);
+ end = Common::AlignUp(GetInteger(end), align);
m_heap_address = addr;
m_end_offset = (end - addr) / (u64(1) << m_block_shift);
return m_bitmap.Initialize(bit_storage, m_end_offset);
}
- PAddr PushBlock(PAddr address) {
+ KPhysicalAddress PushBlock(KPhysicalAddress address) {
// Set the bit for the free block.
size_t offset = (address - m_heap_address) >> this->GetShift();
m_bitmap.SetBit(offset);
@@ -161,7 +162,7 @@ private:
return {};
}
- PAddr PopBlock(bool random) {
+ KPhysicalAddress PopBlock(bool random) {
// Find a free block.
s64 soffset = m_bitmap.FindFreeBlock(random);
if (soffset < 0) {
@@ -187,18 +188,19 @@ private:
private:
KPageBitmap m_bitmap;
- PAddr m_heap_address{};
+ KPhysicalAddress m_heap_address{};
uintptr_t m_end_offset{};
size_t m_block_shift{};
size_t m_next_block_shift{};
};
private:
- void Initialize(PAddr heap_address, size_t heap_size, VAddr management_address,
- size_t management_size, const size_t* block_shifts, size_t num_block_shifts);
+ void Initialize(KPhysicalAddress heap_address, size_t heap_size,
+ KVirtualAddress management_address, size_t management_size,
+ const size_t* block_shifts, size_t num_block_shifts);
size_t GetNumFreePages() const;
- void FreeBlock(PAddr block, s32 index);
+ void FreeBlock(KPhysicalAddress block, s32 index);
static constexpr size_t NumMemoryBlockPageShifts{7};
static constexpr std::array<size_t, NumMemoryBlockPageShifts> MemoryBlockPageShifts{
@@ -206,14 +208,14 @@ private:
};
private:
- PAddr AllocateByLinearSearch(s32 index);
- PAddr AllocateByRandom(s32 index, size_t num_pages, size_t align_pages);
+ KPhysicalAddress AllocateByLinearSearch(s32 index);
+ KPhysicalAddress AllocateByRandom(s32 index, size_t num_pages, size_t align_pages);
static size_t CalculateManagementOverheadSize(size_t region_size, const size_t* block_shifts,
size_t num_block_shifts);
private:
- PAddr m_heap_address{};
+ KPhysicalAddress m_heap_address{};
size_t m_heap_size{};
size_t m_initial_used_size{};
size_t m_num_blocks{};
diff --git a/src/core/hle/kernel/k_page_table.cpp b/src/core/hle/kernel/k_page_table.cpp
index 9c7ac22dc..02b5cada4 100644
--- a/src/core/hle/kernel/k_page_table.cpp
+++ b/src/core/hle/kernel/k_page_table.cpp
@@ -106,9 +106,10 @@ KPageTable::~KPageTable() = default;
Result KPageTable::InitializeForProcess(FileSys::ProgramAddressSpaceType as_type, bool enable_aslr,
bool enable_das_merge, bool from_back,
- KMemoryManager::Pool pool, VAddr code_addr,
+ KMemoryManager::Pool pool, KProcessAddress code_addr,
size_t code_size, KSystemResource* system_resource,
- KResourceLimit* resource_limit) {
+ KResourceLimit* resource_limit,
+ Core::Memory::Memory& memory) {
const auto GetSpaceStart = [this](KAddressSpaceInfo::Type type) {
return KAddressSpaceInfo::GetAddressSpaceStart(m_address_space_width, type);
@@ -117,10 +118,13 @@ Result KPageTable::InitializeForProcess(FileSys::ProgramAddressSpaceType as_type
return KAddressSpaceInfo::GetAddressSpaceSize(m_address_space_width, type);
};
+ // Set the tracking memory
+ m_memory = std::addressof(memory);
+
// Set our width and heap/alias sizes
m_address_space_width = GetAddressSpaceWidthFromType(as_type);
- const VAddr start = 0;
- const VAddr end{1ULL << m_address_space_width};
+ const KProcessAddress start = 0;
+ const KProcessAddress end{1ULL << m_address_space_width};
size_t alias_region_size{GetSpaceSize(KAddressSpaceInfo::Type::Alias)};
size_t heap_region_size{GetSpaceSize(KAddressSpaceInfo::Type::Heap)};
@@ -135,8 +139,8 @@ Result KPageTable::InitializeForProcess(FileSys::ProgramAddressSpaceType as_type
// Set code regions and determine remaining
constexpr size_t RegionAlignment{2_MiB};
- VAddr process_code_start{};
- VAddr process_code_end{};
+ KProcessAddress process_code_start{};
+ KProcessAddress process_code_end{};
size_t stack_region_size{};
size_t kernel_map_region_size{};
@@ -149,8 +153,8 @@ Result KPageTable::InitializeForProcess(FileSys::ProgramAddressSpaceType as_type
m_code_region_end = m_code_region_start + GetSpaceSize(KAddressSpaceInfo::Type::Map39Bit);
m_alias_code_region_start = m_code_region_start;
m_alias_code_region_end = m_code_region_end;
- process_code_start = Common::AlignDown(code_addr, RegionAlignment);
- process_code_end = Common::AlignUp(code_addr + code_size, RegionAlignment);
+ process_code_start = Common::AlignDown(GetInteger(code_addr), RegionAlignment);
+ process_code_end = Common::AlignUp(GetInteger(code_addr) + code_size, RegionAlignment);
} else {
stack_region_size = 0;
kernel_map_region_size = 0;
@@ -178,7 +182,7 @@ Result KPageTable::InitializeForProcess(FileSys::ProgramAddressSpaceType as_type
m_resource_limit = resource_limit;
// Determine the region we can place our undetermineds in
- VAddr alloc_start{};
+ KProcessAddress alloc_start{};
size_t alloc_size{};
if ((process_code_start - m_code_region_start) >= (end - process_code_end)) {
alloc_start = m_code_region_start;
@@ -292,7 +296,7 @@ Result KPageTable::InitializeForProcess(FileSys::ProgramAddressSpaceType as_type
: KMemoryManager::Direction::FromFront);
// Ensure that we regions inside our address space
- auto IsInAddressSpace = [&](VAddr addr) {
+ auto IsInAddressSpace = [&](KProcessAddress addr) {
return m_address_space_start <= addr && addr <= m_address_space_end;
};
ASSERT(IsInAddressSpace(m_alias_region_start));
@@ -305,14 +309,14 @@ Result KPageTable::InitializeForProcess(FileSys::ProgramAddressSpaceType as_type
ASSERT(IsInAddressSpace(m_kernel_map_region_end));
// Ensure that we selected regions that don't overlap
- const VAddr alias_start{m_alias_region_start};
- const VAddr alias_last{m_alias_region_end - 1};
- const VAddr heap_start{m_heap_region_start};
- const VAddr heap_last{m_heap_region_end - 1};
- const VAddr stack_start{m_stack_region_start};
- const VAddr stack_last{m_stack_region_end - 1};
- const VAddr kmap_start{m_kernel_map_region_start};
- const VAddr kmap_last{m_kernel_map_region_end - 1};
+ const KProcessAddress alias_start{m_alias_region_start};
+ const KProcessAddress alias_last{m_alias_region_end - 1};
+ const KProcessAddress heap_start{m_heap_region_start};
+ const KProcessAddress heap_last{m_heap_region_end - 1};
+ const KProcessAddress stack_start{m_stack_region_start};
+ const KProcessAddress stack_last{m_stack_region_end - 1};
+ const KProcessAddress kmap_start{m_kernel_map_region_start};
+ const KProcessAddress kmap_last{m_kernel_map_region_end - 1};
ASSERT(alias_last < heap_start || heap_last < alias_start);
ASSERT(alias_last < stack_start || stack_last < alias_start);
ASSERT(alias_last < kmap_start || kmap_last < alias_start);
@@ -334,9 +338,10 @@ Result KPageTable::InitializeForProcess(FileSys::ProgramAddressSpaceType as_type
void KPageTable::Finalize() {
// Finalize memory blocks.
- m_memory_block_manager.Finalize(m_memory_block_slab_manager, [&](VAddr addr, u64 size) {
- m_system.Memory().UnmapRegion(*m_page_table_impl, addr, size);
- });
+ m_memory_block_manager.Finalize(m_memory_block_slab_manager,
+ [&](KProcessAddress addr, u64 size) {
+ m_memory->UnmapRegion(*m_page_table_impl, addr, size);
+ });
// Release any insecure mapped memory.
if (m_mapped_insecure_memory) {
@@ -352,7 +357,7 @@ void KPageTable::Finalize() {
m_page_table_impl.reset();
}
-Result KPageTable::MapProcessCode(VAddr addr, size_t num_pages, KMemoryState state,
+Result KPageTable::MapProcessCode(KProcessAddress addr, size_t num_pages, KMemoryState state,
KMemoryPermission perm) {
const u64 size{num_pages * PageSize};
@@ -388,7 +393,8 @@ Result KPageTable::MapProcessCode(VAddr addr, size_t num_pages, KMemoryState sta
R_SUCCEED();
}
-Result KPageTable::MapCodeMemory(VAddr dst_address, VAddr src_address, size_t size) {
+Result KPageTable::MapCodeMemory(KProcessAddress dst_address, KProcessAddress src_address,
+ size_t size) {
// Validate the mapping request.
R_UNLESS(this->CanContain(dst_address, size, KMemoryState::AliasCode),
ResultInvalidMemoryRegion);
@@ -435,6 +441,9 @@ Result KPageTable::MapCodeMemory(VAddr dst_address, VAddr src_address, size_t si
KPageGroup pg{m_kernel, m_block_info_manager};
AddRegionToPages(src_address, num_pages, pg);
+ // We're going to perform an update, so create a helper.
+ KScopedPageTableUpdater updater(this);
+
// Reprotect the source as kernel-read/not mapped.
const auto new_perm = static_cast<KMemoryPermission>(KMemoryPermission::KernelRead |
KMemoryPermission::NotMapped);
@@ -447,7 +456,10 @@ Result KPageTable::MapCodeMemory(VAddr dst_address, VAddr src_address, size_t si
});
// Map the alias pages.
- R_TRY(MapPages(dst_address, pg, new_perm));
+ const KPageProperties dst_properties = {new_perm, false, false,
+ DisableMergeAttribute::DisableHead};
+ R_TRY(
+ this->MapPageGroupImpl(updater.GetPageList(), dst_address, pg, dst_properties, false));
// We successfully mapped the alias pages, so we don't need to unprotect the src pages on
// failure.
@@ -467,7 +479,8 @@ Result KPageTable::MapCodeMemory(VAddr dst_address, VAddr src_address, size_t si
R_SUCCEED();
}
-Result KPageTable::UnmapCodeMemory(VAddr dst_address, VAddr src_address, size_t size,
+Result KPageTable::UnmapCodeMemory(KProcessAddress dst_address, KProcessAddress src_address,
+ size_t size,
ICacheInvalidationStrategy icache_invalidation_strategy) {
// Validate the mapping request.
R_UNLESS(this->CanContain(dst_address, size, KMemoryState::AliasCode),
@@ -519,7 +532,7 @@ Result KPageTable::UnmapCodeMemory(VAddr dst_address, VAddr src_address, size_t
SCOPE_EXIT({
if (reprotected_pages && any_code_pages) {
if (icache_invalidation_strategy == ICacheInvalidationStrategy::InvalidateRange) {
- m_system.InvalidateCpuInstructionCacheRange(dst_address, size);
+ m_system.InvalidateCpuInstructionCacheRange(GetInteger(dst_address), size);
} else {
m_system.InvalidateCpuInstructionCaches();
}
@@ -569,9 +582,10 @@ Result KPageTable::UnmapCodeMemory(VAddr dst_address, VAddr src_address, size_t
R_SUCCEED();
}
-VAddr KPageTable::FindFreeArea(VAddr region_start, size_t region_num_pages, size_t num_pages,
- size_t alignment, size_t offset, size_t guard_pages) {
- VAddr address = 0;
+KProcessAddress KPageTable::FindFreeArea(KProcessAddress region_start, size_t region_num_pages,
+ size_t num_pages, size_t alignment, size_t offset,
+ size_t guard_pages) {
+ KProcessAddress address = 0;
if (num_pages <= region_num_pages) {
if (this->IsAslrEnabled()) {
@@ -587,7 +601,7 @@ VAddr KPageTable::FindFreeArea(VAddr region_start, size_t region_num_pages, size
return address;
}
-Result KPageTable::MakePageGroup(KPageGroup& pg, VAddr addr, size_t num_pages) {
+Result KPageTable::MakePageGroup(KPageGroup& pg, KProcessAddress addr, size_t num_pages) {
ASSERT(this->IsLockedByCurrentThread());
const size_t size = num_pages * PageSize;
@@ -598,11 +612,11 @@ Result KPageTable::MakePageGroup(KPageGroup& pg, VAddr addr, size_t num_pages) {
// Begin traversal.
Common::PageTable::TraversalContext context;
Common::PageTable::TraversalEntry next_entry;
- R_UNLESS(m_page_table_impl->BeginTraversal(next_entry, context, addr),
+ R_UNLESS(m_page_table_impl->BeginTraversal(next_entry, context, GetInteger(addr)),
ResultInvalidCurrentMemory);
// Prepare tracking variables.
- PAddr cur_addr = next_entry.phys_addr;
+ KPhysicalAddress cur_addr = next_entry.phys_addr;
size_t cur_size = next_entry.block_size - (cur_addr & (next_entry.block_size - 1));
size_t tot_size = cur_size;
@@ -640,7 +654,7 @@ Result KPageTable::MakePageGroup(KPageGroup& pg, VAddr addr, size_t num_pages) {
R_SUCCEED();
}
-bool KPageTable::IsValidPageGroup(const KPageGroup& pg, VAddr addr, size_t num_pages) {
+bool KPageTable::IsValidPageGroup(const KPageGroup& pg, KProcessAddress addr, size_t num_pages) {
ASSERT(this->IsLockedByCurrentThread());
const size_t size = num_pages * PageSize;
@@ -653,7 +667,7 @@ bool KPageTable::IsValidPageGroup(const KPageGroup& pg, VAddr addr, size_t num_p
// We're going to validate that the group we'd expect is the group we see.
auto cur_it = pg.begin();
- PAddr cur_block_address = cur_it->GetAddress();
+ KPhysicalAddress cur_block_address = cur_it->GetAddress();
size_t cur_block_pages = cur_it->GetNumPages();
auto UpdateCurrentIterator = [&]() {
@@ -671,12 +685,12 @@ bool KPageTable::IsValidPageGroup(const KPageGroup& pg, VAddr addr, size_t num_p
// Begin traversal.
Common::PageTable::TraversalContext context;
Common::PageTable::TraversalEntry next_entry;
- if (!m_page_table_impl->BeginTraversal(next_entry, context, addr)) {
+ if (!m_page_table_impl->BeginTraversal(next_entry, context, GetInteger(addr))) {
return false;
}
// Prepare tracking variables.
- PAddr cur_addr = next_entry.phys_addr;
+ KPhysicalAddress cur_addr = next_entry.phys_addr;
size_t cur_size = next_entry.block_size - (cur_addr & (next_entry.block_size - 1));
size_t tot_size = cur_size;
@@ -728,8 +742,8 @@ bool KPageTable::IsValidPageGroup(const KPageGroup& pg, VAddr addr, size_t num_p
return cur_block_address == cur_addr && cur_block_pages == (cur_size / PageSize);
}
-Result KPageTable::UnmapProcessMemory(VAddr dst_addr, size_t size, KPageTable& src_page_table,
- VAddr src_addr) {
+Result KPageTable::UnmapProcessMemory(KProcessAddress dst_addr, size_t size,
+ KPageTable& src_page_table, KProcessAddress src_addr) {
// Acquire the table locks.
KScopedLightLockPair lk(src_page_table.m_general_lock, m_general_lock);
@@ -768,8 +782,8 @@ Result KPageTable::UnmapProcessMemory(VAddr dst_addr, size_t size, KPageTable& s
}
Result KPageTable::SetupForIpcClient(PageLinkedList* page_list, size_t* out_blocks_needed,
- VAddr address, size_t size, KMemoryPermission test_perm,
- KMemoryState dst_state) {
+ KProcessAddress address, size_t size,
+ KMemoryPermission test_perm, KMemoryState dst_state) {
// Validate pre-conditions.
ASSERT(this->IsLockedByCurrentThread());
ASSERT(test_perm == KMemoryPermission::UserReadWrite ||
@@ -784,10 +798,10 @@ Result KPageTable::SetupForIpcClient(PageLinkedList* page_list, size_t* out_bloc
: KMemoryPermission::UserRead;
// Get aligned extents.
- const VAddr aligned_src_start = Common::AlignDown((address), PageSize);
- const VAddr aligned_src_end = Common::AlignUp((address) + size, PageSize);
- const VAddr mapping_src_start = Common::AlignUp((address), PageSize);
- const VAddr mapping_src_end = Common::AlignDown((address) + size, PageSize);
+ const KProcessAddress aligned_src_start = Common::AlignDown(GetInteger(address), PageSize);
+ const KProcessAddress aligned_src_end = Common::AlignUp(GetInteger(address) + size, PageSize);
+ const KProcessAddress mapping_src_start = Common::AlignUp(GetInteger(address), PageSize);
+ const KProcessAddress mapping_src_end = Common::AlignDown(GetInteger(address) + size, PageSize);
const auto aligned_src_last = (aligned_src_end)-1;
const auto mapping_src_last = (mapping_src_end)-1;
@@ -834,14 +848,15 @@ Result KPageTable::SetupForIpcClient(PageLinkedList* page_list, size_t* out_bloc
test_attr_mask, KMemoryAttribute::None));
if (mapping_src_start < mapping_src_end && (mapping_src_start) < info.GetEndAddress() &&
- info.GetAddress() < (mapping_src_end)) {
- const auto cur_start =
- info.GetAddress() >= (mapping_src_start) ? info.GetAddress() : (mapping_src_start);
+ info.GetAddress() < GetInteger(mapping_src_end)) {
+ const auto cur_start = info.GetAddress() >= GetInteger(mapping_src_start)
+ ? info.GetAddress()
+ : (mapping_src_start);
const auto cur_end = mapping_src_last >= info.GetLastAddress() ? info.GetEndAddress()
: (mapping_src_end);
const size_t cur_size = cur_end - cur_start;
- if (info.GetAddress() < (mapping_src_start)) {
+ if (info.GetAddress() < GetInteger(mapping_src_start)) {
++blocks_needed;
}
if (mapping_src_last < info.GetLastAddress()) {
@@ -876,30 +891,32 @@ Result KPageTable::SetupForIpcClient(PageLinkedList* page_list, size_t* out_bloc
R_SUCCEED();
}
-Result KPageTable::SetupForIpcServer(VAddr* out_addr, size_t size, VAddr src_addr,
- KMemoryPermission test_perm, KMemoryState dst_state,
- KPageTable& src_page_table, bool send) {
+Result KPageTable::SetupForIpcServer(KProcessAddress* out_addr, size_t size,
+ KProcessAddress src_addr, KMemoryPermission test_perm,
+ KMemoryState dst_state, KPageTable& src_page_table,
+ bool send) {
ASSERT(this->IsLockedByCurrentThread());
ASSERT(src_page_table.IsLockedByCurrentThread());
// Check that we can theoretically map.
- const VAddr region_start = m_alias_region_start;
+ const KProcessAddress region_start = m_alias_region_start;
const size_t region_size = m_alias_region_end - m_alias_region_start;
R_UNLESS(size < region_size, ResultOutOfAddressSpace);
// Get aligned source extents.
- const VAddr src_start = src_addr;
- const VAddr src_end = src_addr + size;
- const VAddr aligned_src_start = Common::AlignDown((src_start), PageSize);
- const VAddr aligned_src_end = Common::AlignUp((src_start) + size, PageSize);
- const VAddr mapping_src_start = Common::AlignUp((src_start), PageSize);
- const VAddr mapping_src_end = Common::AlignDown((src_start) + size, PageSize);
+ const KProcessAddress src_start = src_addr;
+ const KProcessAddress src_end = src_addr + size;
+ const KProcessAddress aligned_src_start = Common::AlignDown(GetInteger(src_start), PageSize);
+ const KProcessAddress aligned_src_end = Common::AlignUp(GetInteger(src_start) + size, PageSize);
+ const KProcessAddress mapping_src_start = Common::AlignUp(GetInteger(src_start), PageSize);
+ const KProcessAddress mapping_src_end =
+ Common::AlignDown(GetInteger(src_start) + size, PageSize);
const size_t aligned_src_size = aligned_src_end - aligned_src_start;
const size_t mapping_src_size =
(mapping_src_start < mapping_src_end) ? (mapping_src_end - mapping_src_start) : 0;
// Select a random address to map at.
- VAddr dst_addr =
+ KProcessAddress dst_addr =
this->FindFreeArea(region_start, region_size / PageSize, aligned_src_size / PageSize,
PageSize, 0, this->GetNumGuardPages());
@@ -924,9 +941,9 @@ Result KPageTable::SetupForIpcServer(VAddr* out_addr, size_t size, VAddr src_add
R_UNLESS(memory_reservation.Succeeded(), ResultLimitReached);
// Ensure that we manage page references correctly.
- PAddr start_partial_page = 0;
- PAddr end_partial_page = 0;
- VAddr cur_mapped_addr = dst_addr;
+ KPhysicalAddress start_partial_page = 0;
+ KPhysicalAddress end_partial_page = 0;
+ KProcessAddress cur_mapped_addr = dst_addr;
// If the partial pages are mapped, an extra reference will have been opened. Otherwise, they'll
// free on scope exit.
@@ -971,11 +988,12 @@ Result KPageTable::SetupForIpcServer(VAddr* out_addr, size_t size, VAddr src_add
// Begin traversal.
Common::PageTable::TraversalContext context;
Common::PageTable::TraversalEntry next_entry;
- bool traverse_valid = src_impl.BeginTraversal(next_entry, context, aligned_src_start);
+ bool traverse_valid =
+ src_impl.BeginTraversal(next_entry, context, GetInteger(aligned_src_start));
ASSERT(traverse_valid);
// Prepare tracking variables.
- PAddr cur_block_addr = next_entry.phys_addr;
+ KPhysicalAddress cur_block_addr = next_entry.phys_addr;
size_t cur_block_size =
next_entry.block_size - ((cur_block_addr) & (next_entry.block_size - 1));
size_t tot_block_size = cur_block_size;
@@ -983,7 +1001,7 @@ Result KPageTable::SetupForIpcServer(VAddr* out_addr, size_t size, VAddr src_add
// Map the start page, if we have one.
if (start_partial_page != 0) {
// Ensure the page holds correct data.
- const VAddr start_partial_virt =
+ const KVirtualAddress start_partial_virt =
GetHeapVirtualAddress(m_system.Kernel().MemoryLayout(), start_partial_page);
if (send) {
const size_t partial_offset = src_start - aligned_src_start;
@@ -996,21 +1014,22 @@ Result KPageTable::SetupForIpcServer(VAddr* out_addr, size_t size, VAddr src_add
clear_size = 0;
}
- std::memset(m_system.Memory().GetPointer<void>(start_partial_virt), fill_val,
+ std::memset(m_memory->GetPointer<void>(GetInteger(start_partial_virt)), fill_val,
partial_offset);
std::memcpy(
- m_system.Memory().GetPointer<void>(start_partial_virt + partial_offset),
- m_system.Memory().GetPointer<void>(
- GetHeapVirtualAddress(m_system.Kernel().MemoryLayout(), cur_block_addr) +
- partial_offset),
+ m_memory->GetPointer<void>(GetInteger(start_partial_virt) + partial_offset),
+ m_memory->GetPointer<void>(GetInteger(GetHeapVirtualAddress(
+ m_system.Kernel().MemoryLayout(), cur_block_addr)) +
+ partial_offset),
copy_size);
if (clear_size > 0) {
- std::memset(m_system.Memory().GetPointer<void>(start_partial_virt + partial_offset +
- copy_size),
+ std::memset(m_memory->GetPointer<void>(GetInteger(start_partial_virt) +
+ partial_offset + copy_size),
fill_val, clear_size);
}
} else {
- std::memset(m_system.Memory().GetPointer<void>(start_partial_virt), fill_val, PageSize);
+ std::memset(m_memory->GetPointer<void>(GetInteger(start_partial_virt)), fill_val,
+ PageSize);
}
// Map the page.
@@ -1055,7 +1074,8 @@ Result KPageTable::SetupForIpcServer(VAddr* out_addr, size_t size, VAddr src_add
}
// Handle the last direct-mapped page.
- if (const VAddr mapped_block_end = aligned_src_start + tot_block_size - cur_block_size;
+ if (const KProcessAddress mapped_block_end =
+ aligned_src_start + tot_block_size - cur_block_size;
mapped_block_end < mapping_src_end) {
const size_t last_block_size = mapping_src_end - mapped_block_end;
@@ -1078,18 +1098,19 @@ Result KPageTable::SetupForIpcServer(VAddr* out_addr, size_t size, VAddr src_add
// Map the end page, if we have one.
if (end_partial_page != 0) {
// Ensure the page holds correct data.
- const VAddr end_partial_virt =
+ const KVirtualAddress end_partial_virt =
GetHeapVirtualAddress(m_system.Kernel().MemoryLayout(), end_partial_page);
if (send) {
const size_t copy_size = src_end - mapping_src_end;
- std::memcpy(m_system.Memory().GetPointer<void>(end_partial_virt),
- m_system.Memory().GetPointer<void>(GetHeapVirtualAddress(
- m_system.Kernel().MemoryLayout(), cur_block_addr)),
+ std::memcpy(m_memory->GetPointer<void>(GetInteger(end_partial_virt)),
+ m_memory->GetPointer<void>(GetInteger(GetHeapVirtualAddress(
+ m_system.Kernel().MemoryLayout(), cur_block_addr))),
copy_size);
- std::memset(m_system.Memory().GetPointer<void>(end_partial_virt + copy_size), fill_val,
- PageSize - copy_size);
+ std::memset(m_memory->GetPointer<void>(GetInteger(end_partial_virt) + copy_size),
+ fill_val, PageSize - copy_size);
} else {
- std::memset(m_system.Memory().GetPointer<void>(end_partial_virt), fill_val, PageSize);
+ std::memset(m_memory->GetPointer<void>(GetInteger(end_partial_virt)), fill_val,
+ PageSize);
}
// Map the page.
@@ -1110,7 +1131,7 @@ Result KPageTable::SetupForIpcServer(VAddr* out_addr, size_t size, VAddr src_add
R_SUCCEED();
}
-Result KPageTable::SetupForIpc(VAddr* out_dst_addr, size_t size, VAddr src_addr,
+Result KPageTable::SetupForIpc(KProcessAddress* out_dst_addr, size_t size, KProcessAddress src_addr,
KPageTable& src_page_table, KMemoryPermission test_perm,
KMemoryState dst_state, bool send) {
// For convenience, alias this.
@@ -1136,8 +1157,8 @@ Result KPageTable::SetupForIpc(VAddr* out_dst_addr, size_t size, VAddr src_addr,
R_TRY(allocator_result);
// Get the mapped extents.
- const VAddr src_map_start = Common::AlignUp((src_addr), PageSize);
- const VAddr src_map_end = Common::AlignDown((src_addr) + size, PageSize);
+ const KProcessAddress src_map_start = Common::AlignUp(GetInteger(src_addr), PageSize);
+ const KProcessAddress src_map_end = Common::AlignDown(GetInteger(src_addr) + size, PageSize);
const size_t src_map_size = src_map_end - src_map_start;
// Ensure that we clean up appropriately if we fail after this.
@@ -1166,7 +1187,8 @@ Result KPageTable::SetupForIpc(VAddr* out_dst_addr, size_t size, VAddr src_addr,
R_SUCCEED();
}
-Result KPageTable::CleanupForIpcServer(VAddr address, size_t size, KMemoryState dst_state) {
+Result KPageTable::CleanupForIpcServer(KProcessAddress address, size_t size,
+ KMemoryState dst_state) {
// Validate the address.
R_UNLESS(this->Contains(address, size), ResultInvalidCurrentMemory);
@@ -1190,8 +1212,8 @@ Result KPageTable::CleanupForIpcServer(VAddr address, size_t size, KMemoryState
KScopedPageTableUpdater updater(this);
// Get aligned extents.
- const VAddr aligned_start = Common::AlignDown((address), PageSize);
- const VAddr aligned_end = Common::AlignUp((address) + size, PageSize);
+ const KProcessAddress aligned_start = Common::AlignDown(GetInteger(address), PageSize);
+ const KProcessAddress aligned_end = Common::AlignUp(GetInteger(address) + size, PageSize);
const size_t aligned_size = aligned_end - aligned_start;
const size_t aligned_num_pages = aligned_size / PageSize;
@@ -1205,22 +1227,23 @@ Result KPageTable::CleanupForIpcServer(VAddr address, size_t size, KMemoryState
KMemoryBlockDisableMergeAttribute::Normal);
// Release from the resource limit as relevant.
- const VAddr mapping_start = Common::AlignUp((address), PageSize);
- const VAddr mapping_end = Common::AlignDown((address) + size, PageSize);
+ const KProcessAddress mapping_start = Common::AlignUp(GetInteger(address), PageSize);
+ const KProcessAddress mapping_end = Common::AlignDown(GetInteger(address) + size, PageSize);
const size_t mapping_size = (mapping_start < mapping_end) ? mapping_end - mapping_start : 0;
m_resource_limit->Release(LimitableResource::PhysicalMemoryMax, aligned_size - mapping_size);
R_SUCCEED();
}
-Result KPageTable::CleanupForIpcClient(VAddr address, size_t size, KMemoryState dst_state) {
+Result KPageTable::CleanupForIpcClient(KProcessAddress address, size_t size,
+ KMemoryState dst_state) {
// Validate the address.
R_UNLESS(this->Contains(address, size), ResultInvalidCurrentMemory);
// Get aligned source extents.
- const VAddr mapping_start = Common::AlignUp((address), PageSize);
- const VAddr mapping_end = Common::AlignDown((address) + size, PageSize);
- const VAddr mapping_last = mapping_end - 1;
+ const KProcessAddress mapping_start = Common::AlignUp(GetInteger(address), PageSize);
+ const KProcessAddress mapping_end = Common::AlignDown(GetInteger(address) + size, PageSize);
+ const KProcessAddress mapping_last = mapping_end - 1;
const size_t mapping_size = (mapping_start < mapping_end) ? (mapping_end - mapping_start) : 0;
// If nothing was mapped, we're actually done immediately.
@@ -1273,7 +1296,7 @@ Result KPageTable::CleanupForIpcClient(VAddr address, size_t size, KMemoryState
KMemoryInfo cur_info = start_it->GetMemoryInfo();
// Create tracking variables.
- VAddr cur_address = cur_info.GetAddress();
+ KProcessAddress cur_address = cur_info.GetAddress();
size_t cur_size = cur_info.GetSize();
bool cur_perm_eq = cur_info.GetPermission() == cur_info.GetOriginalPermission();
bool cur_needs_set_perm = !cur_perm_eq && cur_info.GetIpcLockCount() == 1;
@@ -1346,7 +1369,7 @@ Result KPageTable::CleanupForIpcClient(VAddr address, size_t size, KMemoryState
.IsSuccess());
// Create tracking variables.
- VAddr cur_address = cur_info.GetAddress();
+ KProcessAddress cur_address = cur_info.GetAddress();
size_t cur_size = cur_info.GetSize();
bool cur_perm_eq = cur_info.GetPermission() == cur_info.GetOriginalPermission();
bool cur_needs_set_perm = !cur_perm_eq && cur_info.GetIpcLockCount() == 1;
@@ -1433,16 +1456,16 @@ Result KPageTable::CleanupForIpcClient(VAddr address, size_t size, KMemoryState
}
void KPageTable::CleanupForIpcClientOnServerSetupFailure([[maybe_unused]] PageLinkedList* page_list,
- VAddr address, size_t size,
+ KProcessAddress address, size_t size,
KMemoryPermission prot_perm) {
ASSERT(this->IsLockedByCurrentThread());
- ASSERT(Common::IsAligned(address, PageSize));
+ ASSERT(Common::IsAligned(GetInteger(address), PageSize));
ASSERT(Common::IsAligned(size, PageSize));
// Get the mapped extents.
- const VAddr src_map_start = address;
- const VAddr src_map_end = address + size;
- const VAddr src_map_last = src_map_end - 1;
+ const KProcessAddress src_map_start = address;
+ const KProcessAddress src_map_end = address + size;
+ const KProcessAddress src_map_last = src_map_end - 1;
// This function is only invoked when there's something to do.
ASSERT(src_map_end > src_map_start);
@@ -1452,8 +1475,9 @@ void KPageTable::CleanupForIpcClientOnServerSetupFailure([[maybe_unused]] PageLi
while (true) {
const KMemoryInfo info = it->GetMemoryInfo();
- const auto cur_start =
- info.GetAddress() >= src_map_start ? info.GetAddress() : src_map_start;
+ const auto cur_start = info.GetAddress() >= GetInteger(src_map_start)
+ ? info.GetAddress()
+ : GetInteger(src_map_start);
const auto cur_end =
src_map_last <= info.GetLastAddress() ? src_map_end : info.GetEndAddress();
@@ -1463,7 +1487,7 @@ void KPageTable::CleanupForIpcClientOnServerSetupFailure([[maybe_unused]] PageLi
(info.GetIpcLockCount() != 0 &&
(info.GetOriginalPermission() & KMemoryPermission::IpcLockChangeMask) != prot_perm)) {
// Check if we actually need to fix the protections on the block.
- if (cur_end == src_map_end || info.GetAddress() <= src_map_start ||
+ if (cur_end == src_map_end || info.GetAddress() <= GetInteger(src_map_start) ||
(info.GetPermission() & KMemoryPermission::IpcLockChangeMask) != prot_perm) {
ASSERT(Operate(cur_start, (cur_end - cur_start) / PageSize, info.GetPermission(),
OperationType::ChangePermissions)
@@ -1482,15 +1506,15 @@ void KPageTable::CleanupForIpcClientOnServerSetupFailure([[maybe_unused]] PageLi
}
}
-Result KPageTable::MapPhysicalMemory(VAddr address, size_t size) {
+Result KPageTable::MapPhysicalMemory(KProcessAddress address, size_t size) {
// Lock the physical memory lock.
KScopedLightLock phys_lk(m_map_physical_memory_lock);
// Calculate the last address for convenience.
- const VAddr last_address = address + size - 1;
+ const KProcessAddress last_address = address + size - 1;
// Define iteration variables.
- VAddr cur_address;
+ KProcessAddress cur_address;
size_t mapped_size;
// The entire mapping process can be retried.
@@ -1522,7 +1546,7 @@ Result KPageTable::MapPhysicalMemory(VAddr address, size_t size) {
// Track the memory if it's mapped.
if (info.GetState() != KMemoryState::Free) {
- mapped_size += VAddr(info.GetEndAddress()) - cur_address;
+ mapped_size += KProcessAddress(info.GetEndAddress()) - cur_address;
}
// Advance.
@@ -1575,7 +1599,7 @@ Result KPageTable::MapPhysicalMemory(VAddr address, size_t size) {
const bool is_free = info.GetState() == KMemoryState::Free;
if (is_free) {
- if (info.GetAddress() < address) {
+ if (info.GetAddress() < GetInteger(address)) {
++num_allocator_blocks;
}
if (last_address < info.GetLastAddress()) {
@@ -1593,7 +1617,8 @@ Result KPageTable::MapPhysicalMemory(VAddr address, size_t size) {
// Track the memory if it's mapped.
if (!is_free) {
- checked_mapped_size += VAddr(info.GetEndAddress()) - cur_address;
+ checked_mapped_size +=
+ KProcessAddress(info.GetEndAddress()) - cur_address;
}
// Advance.
@@ -1621,7 +1646,7 @@ Result KPageTable::MapPhysicalMemory(VAddr address, size_t size) {
// Prepare to iterate over the memory.
auto pg_it = pg.begin();
- PAddr pg_phys_addr = pg_it->GetAddress();
+ KPhysicalAddress pg_phys_addr = pg_it->GetAddress();
size_t pg_pages = pg_it->GetNumPages();
// Reset the current tracking address, and make sure we clean up on failure.
@@ -1629,7 +1654,7 @@ Result KPageTable::MapPhysicalMemory(VAddr address, size_t size) {
cur_address = address;
ON_RESULT_FAILURE {
if (cur_address > address) {
- const VAddr last_unmap_address = cur_address - 1;
+ const KProcessAddress last_unmap_address = cur_address - 1;
// Iterate, unmapping the pages.
cur_address = address;
@@ -1646,7 +1671,7 @@ Result KPageTable::MapPhysicalMemory(VAddr address, size_t size) {
if (info.GetState() == KMemoryState::Free) {
// Determine the range to unmap.
const size_t cur_pages =
- std::min(VAddr(info.GetEndAddress()) - cur_address,
+ std::min(KProcessAddress(info.GetEndAddress()) - cur_address,
last_unmap_address + 1 - cur_address) /
PageSize;
@@ -1689,9 +1714,10 @@ Result KPageTable::MapPhysicalMemory(VAddr address, size_t size) {
// If it's unmapped, we need to map it.
if (info.GetState() == KMemoryState::Free) {
// Determine the range to map.
- size_t map_pages = std::min(VAddr(info.GetEndAddress()) - cur_address,
- last_address + 1 - cur_address) /
- PageSize;
+ size_t map_pages =
+ std::min(KProcessAddress(info.GetEndAddress()) - cur_address,
+ last_address + 1 - cur_address) /
+ PageSize;
// While we have pages to map, map them.
while (map_pages > 0) {
@@ -1748,7 +1774,7 @@ Result KPageTable::MapPhysicalMemory(VAddr address, size_t size) {
}
}
-Result KPageTable::UnmapPhysicalMemory(VAddr address, size_t size) {
+Result KPageTable::UnmapPhysicalMemory(KProcessAddress address, size_t size) {
// Lock the physical memory lock.
KScopedLightLock phys_lk(m_map_physical_memory_lock);
@@ -1756,13 +1782,13 @@ Result KPageTable::UnmapPhysicalMemory(VAddr address, size_t size) {
KScopedLightLock lk(m_general_lock);
// Calculate the last address for convenience.
- const VAddr last_address = address + size - 1;
+ const KProcessAddress last_address = address + size - 1;
// Define iteration variables.
- VAddr map_start_address = 0;
- VAddr map_last_address = 0;
+ KProcessAddress map_start_address = 0;
+ KProcessAddress map_last_address = 0;
- VAddr cur_address;
+ KProcessAddress cur_address;
size_t mapped_size;
size_t num_allocator_blocks = 0;
@@ -1795,7 +1821,7 @@ Result KPageTable::UnmapPhysicalMemory(VAddr address, size_t size) {
map_last_address =
(last_address >= info.GetLastAddress()) ? info.GetLastAddress() : last_address;
- if (info.GetAddress() < address) {
+ if (info.GetAddress() < GetInteger(address)) {
++num_allocator_blocks;
}
if (last_address < info.GetLastAddress()) {
@@ -1848,7 +1874,7 @@ Result KPageTable::UnmapPhysicalMemory(VAddr address, size_t size) {
// If the memory state is normal, we need to unmap it.
if (info.GetState() == KMemoryState::Normal) {
// Determine the range to unmap.
- const size_t cur_pages = std::min(VAddr(info.GetEndAddress()) - cur_address,
+ const size_t cur_pages = std::min(KProcessAddress(info.GetEndAddress()) - cur_address,
last_address + 1 - cur_address) /
PageSize;
@@ -1881,7 +1907,8 @@ Result KPageTable::UnmapPhysicalMemory(VAddr address, size_t size) {
R_SUCCEED();
}
-Result KPageTable::MapMemory(VAddr dst_address, VAddr src_address, size_t size) {
+Result KPageTable::MapMemory(KProcessAddress dst_address, KProcessAddress src_address,
+ size_t size) {
// Lock the table.
KScopedLightLock lk(m_general_lock);
@@ -1902,53 +1929,73 @@ Result KPageTable::MapMemory(VAddr dst_address, VAddr src_address, size_t size)
KMemoryAttribute::None));
// Create an update allocator for the source.
- Result src_allocator_result{ResultSuccess};
+ Result src_allocator_result;
KMemoryBlockManagerUpdateAllocator src_allocator(std::addressof(src_allocator_result),
m_memory_block_slab_manager,
num_src_allocator_blocks);
R_TRY(src_allocator_result);
// Create an update allocator for the destination.
- Result dst_allocator_result{ResultSuccess};
+ Result dst_allocator_result;
KMemoryBlockManagerUpdateAllocator dst_allocator(std::addressof(dst_allocator_result),
m_memory_block_slab_manager,
num_dst_allocator_blocks);
R_TRY(dst_allocator_result);
// Map the memory.
- KPageGroup page_linked_list{m_kernel, m_block_info_manager};
- const size_t num_pages{size / PageSize};
- const KMemoryPermission new_src_perm = static_cast<KMemoryPermission>(
- KMemoryPermission::KernelRead | KMemoryPermission::NotMapped);
- const KMemoryAttribute new_src_attr = KMemoryAttribute::Locked;
-
- AddRegionToPages(src_address, num_pages, page_linked_list);
{
+ // Determine the number of pages being operated on.
+ const size_t num_pages = size / PageSize;
+
+ // Create page groups for the memory being unmapped.
+ KPageGroup pg{m_kernel, m_block_info_manager};
+
+ // Create the page group representing the source.
+ R_TRY(this->MakePageGroup(pg, src_address, num_pages));
+
+ // We're going to perform an update, so create a helper.
+ KScopedPageTableUpdater updater(this);
+
// Reprotect the source as kernel-read/not mapped.
- auto block_guard = detail::ScopeExit([&] {
- Operate(src_address, num_pages, KMemoryPermission::UserReadWrite,
- OperationType::ChangePermissions);
- });
- R_TRY(Operate(src_address, num_pages, new_src_perm, OperationType::ChangePermissions));
- R_TRY(MapPages(dst_address, page_linked_list, KMemoryPermission::UserReadWrite));
+ const KMemoryPermission new_src_perm = static_cast<KMemoryPermission>(
+ KMemoryPermission::KernelRead | KMemoryPermission::NotMapped);
+ const KMemoryAttribute new_src_attr = KMemoryAttribute::Locked;
+ const KPageProperties src_properties = {new_src_perm, false, false,
+ DisableMergeAttribute::DisableHeadBodyTail};
+ R_TRY(this->Operate(src_address, num_pages, src_properties.perm,
+ OperationType::ChangePermissions));
- block_guard.Cancel();
- }
+ // Ensure that we unprotect the source pages on failure.
+ ON_RESULT_FAILURE {
+ const KPageProperties unprotect_properties = {
+ KMemoryPermission::UserReadWrite, false, false,
+ DisableMergeAttribute::EnableHeadBodyTail};
+ ASSERT(this->Operate(src_address, num_pages, unprotect_properties.perm,
+ OperationType::ChangePermissions) == ResultSuccess);
+ };
- // Apply the memory block updates.
- m_memory_block_manager.Update(std::addressof(src_allocator), src_address, num_pages, src_state,
- new_src_perm, new_src_attr,
- KMemoryBlockDisableMergeAttribute::Locked,
- KMemoryBlockDisableMergeAttribute::None);
- m_memory_block_manager.Update(std::addressof(dst_allocator), dst_address, num_pages,
- KMemoryState::Stack, KMemoryPermission::UserReadWrite,
- KMemoryAttribute::None, KMemoryBlockDisableMergeAttribute::Normal,
- KMemoryBlockDisableMergeAttribute::None);
+ // Map the alias pages.
+ const KPageProperties dst_map_properties = {KMemoryPermission::UserReadWrite, false, false,
+ DisableMergeAttribute::DisableHead};
+ R_TRY(this->MapPageGroupImpl(updater.GetPageList(), dst_address, pg, dst_map_properties,
+ false));
+
+ // Apply the memory block updates.
+ m_memory_block_manager.Update(std::addressof(src_allocator), src_address, num_pages,
+ src_state, new_src_perm, new_src_attr,
+ KMemoryBlockDisableMergeAttribute::Locked,
+ KMemoryBlockDisableMergeAttribute::None);
+ m_memory_block_manager.Update(
+ std::addressof(dst_allocator), dst_address, num_pages, KMemoryState::Stack,
+ KMemoryPermission::UserReadWrite, KMemoryAttribute::None,
+ KMemoryBlockDisableMergeAttribute::Normal, KMemoryBlockDisableMergeAttribute::None);
+ }
R_SUCCEED();
}
-Result KPageTable::UnmapMemory(VAddr dst_address, VAddr src_address, size_t size) {
+Result KPageTable::UnmapMemory(KProcessAddress dst_address, KProcessAddress src_address,
+ size_t size) {
// Lock the table.
KScopedLightLock lk(m_general_lock);
@@ -1970,108 +2017,209 @@ Result KPageTable::UnmapMemory(VAddr dst_address, VAddr src_address, size_t size
KMemoryPermission::None, KMemoryAttribute::All, KMemoryAttribute::None));
// Create an update allocator for the source.
- Result src_allocator_result{ResultSuccess};
+ Result src_allocator_result;
KMemoryBlockManagerUpdateAllocator src_allocator(std::addressof(src_allocator_result),
m_memory_block_slab_manager,
num_src_allocator_blocks);
R_TRY(src_allocator_result);
// Create an update allocator for the destination.
- Result dst_allocator_result{ResultSuccess};
+ Result dst_allocator_result;
KMemoryBlockManagerUpdateAllocator dst_allocator(std::addressof(dst_allocator_result),
m_memory_block_slab_manager,
num_dst_allocator_blocks);
R_TRY(dst_allocator_result);
- KPageGroup src_pages{m_kernel, m_block_info_manager};
- KPageGroup dst_pages{m_kernel, m_block_info_manager};
- const size_t num_pages{size / PageSize};
+ // Unmap the memory.
+ {
+ // Determine the number of pages being operated on.
+ const size_t num_pages = size / PageSize;
- AddRegionToPages(src_address, num_pages, src_pages);
- AddRegionToPages(dst_address, num_pages, dst_pages);
+ // Create page groups for the memory being unmapped.
+ KPageGroup pg{m_kernel, m_block_info_manager};
- R_UNLESS(dst_pages.IsEquivalentTo(src_pages), ResultInvalidMemoryRegion);
+ // Create the page group representing the destination.
+ R_TRY(this->MakePageGroup(pg, dst_address, num_pages));
- {
- auto block_guard = detail::ScopeExit([&] { MapPages(dst_address, dst_pages, dst_perm); });
+ // Ensure the page group is the valid for the source.
+ R_UNLESS(this->IsValidPageGroup(pg, src_address, num_pages), ResultInvalidMemoryRegion);
- R_TRY(Operate(dst_address, num_pages, KMemoryPermission::None, OperationType::Unmap));
- R_TRY(Operate(src_address, num_pages, KMemoryPermission::UserReadWrite,
- OperationType::ChangePermissions));
+ // We're going to perform an update, so create a helper.
+ KScopedPageTableUpdater updater(this);
- block_guard.Cancel();
- }
+ // Unmap the aliased copy of the pages.
+ const KPageProperties dst_unmap_properties = {KMemoryPermission::None, false, false,
+ DisableMergeAttribute::None};
+ R_TRY(
+ this->Operate(dst_address, num_pages, dst_unmap_properties.perm, OperationType::Unmap));
+
+ // Ensure that we re-map the aliased pages on failure.
+ ON_RESULT_FAILURE {
+ this->RemapPageGroup(updater.GetPageList(), dst_address, size, pg);
+ };
- // Apply the memory block updates.
- m_memory_block_manager.Update(std::addressof(src_allocator), src_address, num_pages, src_state,
- KMemoryPermission::UserReadWrite, KMemoryAttribute::None,
- KMemoryBlockDisableMergeAttribute::None,
- KMemoryBlockDisableMergeAttribute::Locked);
- m_memory_block_manager.Update(std::addressof(dst_allocator), dst_address, num_pages,
- KMemoryState::None, KMemoryPermission::None,
- KMemoryAttribute::None, KMemoryBlockDisableMergeAttribute::None,
- KMemoryBlockDisableMergeAttribute::Normal);
+ // Try to set the permissions for the source pages back to what they should be.
+ const KPageProperties src_properties = {KMemoryPermission::UserReadWrite, false, false,
+ DisableMergeAttribute::EnableAndMergeHeadBodyTail};
+ R_TRY(this->Operate(src_address, num_pages, src_properties.perm,
+ OperationType::ChangePermissions));
+
+ // Apply the memory block updates.
+ m_memory_block_manager.Update(
+ std::addressof(src_allocator), src_address, num_pages, src_state,
+ KMemoryPermission::UserReadWrite, KMemoryAttribute::None,
+ KMemoryBlockDisableMergeAttribute::None, KMemoryBlockDisableMergeAttribute::Locked);
+ m_memory_block_manager.Update(
+ std::addressof(dst_allocator), dst_address, num_pages, KMemoryState::None,
+ KMemoryPermission::None, KMemoryAttribute::None,
+ KMemoryBlockDisableMergeAttribute::None, KMemoryBlockDisableMergeAttribute::Normal);
+ }
R_SUCCEED();
}
-Result KPageTable::MapPages(VAddr addr, const KPageGroup& page_linked_list,
- KMemoryPermission perm) {
+Result KPageTable::AllocateAndMapPagesImpl(PageLinkedList* page_list, KProcessAddress address,
+ size_t num_pages, KMemoryPermission perm) {
ASSERT(this->IsLockedByCurrentThread());
- VAddr cur_addr{addr};
+ // Create a page group to hold the pages we allocate.
+ KPageGroup pg{m_kernel, m_block_info_manager};
- for (const auto& node : page_linked_list) {
- if (const auto result{
- Operate(cur_addr, node.GetNumPages(), perm, OperationType::Map, node.GetAddress())};
- result.IsError()) {
- const size_t num_pages{(addr - cur_addr) / PageSize};
+ // Allocate the pages.
+ R_TRY(
+ m_kernel.MemoryManager().AllocateAndOpen(std::addressof(pg), num_pages, m_allocate_option));
- ASSERT(Operate(addr, num_pages, KMemoryPermission::None, OperationType::Unmap)
- .IsSuccess());
+ // Ensure that the page group is closed when we're done working with it.
+ SCOPE_EXIT({ pg.Close(); });
- R_RETURN(result);
+ // Clear all pages.
+ for (const auto& it : pg) {
+ std::memset(m_system.DeviceMemory().GetPointer<void>(it.GetAddress()), m_heap_fill_value,
+ it.GetSize());
+ }
+
+ // Map the pages.
+ R_RETURN(this->Operate(address, num_pages, pg, OperationType::MapGroup));
+}
+
+Result KPageTable::MapPageGroupImpl(PageLinkedList* page_list, KProcessAddress address,
+ const KPageGroup& pg, const KPageProperties properties,
+ bool reuse_ll) {
+ ASSERT(this->IsLockedByCurrentThread());
+
+ // Note the current address, so that we can iterate.
+ const KProcessAddress start_address = address;
+ KProcessAddress cur_address = address;
+
+ // Ensure that we clean up on failure.
+ ON_RESULT_FAILURE {
+ ASSERT(!reuse_ll);
+ if (cur_address != start_address) {
+ const KPageProperties unmap_properties = {KMemoryPermission::None, false, false,
+ DisableMergeAttribute::None};
+ ASSERT(this->Operate(start_address, (cur_address - start_address) / PageSize,
+ unmap_properties.perm, OperationType::Unmap) == ResultSuccess);
}
+ };
- cur_addr += node.GetNumPages() * PageSize;
+ // Iterate, mapping all pages in the group.
+ for (const auto& block : pg) {
+ // Map and advance.
+ const KPageProperties cur_properties =
+ (cur_address == start_address)
+ ? properties
+ : KPageProperties{properties.perm, properties.io, properties.uncached,
+ DisableMergeAttribute::None};
+ this->Operate(cur_address, block.GetNumPages(), cur_properties.perm, OperationType::Map,
+ block.GetAddress());
+ cur_address += block.GetSize();
}
+ // We succeeded!
R_SUCCEED();
}
-Result KPageTable::MapPages(VAddr address, KPageGroup& page_linked_list, KMemoryState state,
- KMemoryPermission perm) {
- // Check that the map is in range.
- const size_t num_pages{page_linked_list.GetNumPages()};
- const size_t size{num_pages * PageSize};
- R_UNLESS(this->CanContain(address, size, state), ResultInvalidCurrentMemory);
+void KPageTable::RemapPageGroup(PageLinkedList* page_list, KProcessAddress address, size_t size,
+ const KPageGroup& pg) {
+ ASSERT(this->IsLockedByCurrentThread());
- // Lock the table.
- KScopedLightLock lk(m_general_lock);
+ // Note the current address, so that we can iterate.
+ const KProcessAddress start_address = address;
+ const KProcessAddress last_address = start_address + size - 1;
+ const KProcessAddress end_address = last_address + 1;
- // Check the memory state.
- R_TRY(this->CheckMemoryState(address, size, KMemoryState::All, KMemoryState::Free,
- KMemoryPermission::None, KMemoryPermission::None,
- KMemoryAttribute::None, KMemoryAttribute::None));
+ // Iterate over the memory.
+ auto pg_it = pg.begin();
+ ASSERT(pg_it != pg.end());
- // Create an update allocator.
- Result allocator_result{ResultSuccess};
- KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result),
- m_memory_block_slab_manager);
+ KPhysicalAddress pg_phys_addr = pg_it->GetAddress();
+ size_t pg_pages = pg_it->GetNumPages();
- // Map the pages.
- R_TRY(MapPages(address, page_linked_list, perm));
+ auto it = m_memory_block_manager.FindIterator(start_address);
+ while (true) {
+ // Check that the iterator is valid.
+ ASSERT(it != m_memory_block_manager.end());
- // Update the blocks.
- m_memory_block_manager.Update(std::addressof(allocator), address, num_pages, state, perm,
- KMemoryAttribute::None, KMemoryBlockDisableMergeAttribute::Normal,
- KMemoryBlockDisableMergeAttribute::None);
+ // Get the memory info.
+ const KMemoryInfo info = it->GetMemoryInfo();
- R_SUCCEED();
+ // Determine the range to map.
+ KProcessAddress map_address = std::max<KProcessAddress>(info.GetAddress(), start_address);
+ const KProcessAddress map_end_address =
+ std::min<KProcessAddress>(info.GetEndAddress(), end_address);
+ ASSERT(map_end_address != map_address);
+
+ // Determine if we should disable head merge.
+ const bool disable_head_merge =
+ info.GetAddress() >= GetInteger(start_address) &&
+ True(info.GetDisableMergeAttribute() & KMemoryBlockDisableMergeAttribute::Normal);
+ const KPageProperties map_properties = {
+ info.GetPermission(), false, false,
+ disable_head_merge ? DisableMergeAttribute::DisableHead : DisableMergeAttribute::None};
+
+ // While we have pages to map, map them.
+ size_t map_pages = (map_end_address - map_address) / PageSize;
+ while (map_pages > 0) {
+ // Check if we're at the end of the physical block.
+ if (pg_pages == 0) {
+ // Ensure there are more pages to map.
+ ASSERT(pg_it != pg.end());
+
+ // Advance our physical block.
+ ++pg_it;
+ pg_phys_addr = pg_it->GetAddress();
+ pg_pages = pg_it->GetNumPages();
+ }
+
+ // Map whatever we can.
+ const size_t cur_pages = std::min(pg_pages, map_pages);
+ ASSERT(this->Operate(map_address, map_pages, map_properties.perm, OperationType::Map,
+ pg_phys_addr) == ResultSuccess);
+
+ // Advance.
+ map_address += cur_pages * PageSize;
+ map_pages -= cur_pages;
+
+ pg_phys_addr += cur_pages * PageSize;
+ pg_pages -= cur_pages;
+ }
+
+ // Check if we're done.
+ if (last_address <= info.GetLastAddress()) {
+ break;
+ }
+
+ // Advance.
+ ++it;
+ }
+
+ // Check that we re-mapped precisely the page group.
+ ASSERT((++pg_it) == pg.end());
}
-Result KPageTable::MapPages(VAddr* out_addr, size_t num_pages, size_t alignment, PAddr phys_addr,
- bool is_pa_valid, VAddr region_start, size_t region_num_pages,
+Result KPageTable::MapPages(KProcessAddress* out_addr, size_t num_pages, size_t alignment,
+ KPhysicalAddress phys_addr, bool is_pa_valid,
+ KProcessAddress region_start, size_t region_num_pages,
KMemoryState state, KMemoryPermission perm) {
ASSERT(Common::IsAligned(alignment, PageSize) && alignment >= PageSize);
@@ -2084,26 +2232,30 @@ Result KPageTable::MapPages(VAddr* out_addr, size_t num_pages, size_t alignment,
KScopedLightLock lk(m_general_lock);
// Find a random address to map at.
- VAddr addr = this->FindFreeArea(region_start, region_num_pages, num_pages, alignment, 0,
- this->GetNumGuardPages());
+ KProcessAddress addr = this->FindFreeArea(region_start, region_num_pages, num_pages, alignment,
+ 0, this->GetNumGuardPages());
R_UNLESS(addr != 0, ResultOutOfMemory);
- ASSERT(Common::IsAligned(addr, alignment));
+ ASSERT(Common::IsAligned(GetInteger(addr), alignment));
ASSERT(this->CanContain(addr, num_pages * PageSize, state));
ASSERT(this->CheckMemoryState(addr, num_pages * PageSize, KMemoryState::All, KMemoryState::Free,
KMemoryPermission::None, KMemoryPermission::None,
- KMemoryAttribute::None, KMemoryAttribute::None)
- .IsSuccess());
+ KMemoryAttribute::None, KMemoryAttribute::None) == ResultSuccess);
// Create an update allocator.
- Result allocator_result{ResultSuccess};
+ Result allocator_result;
KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result),
m_memory_block_slab_manager);
+ R_TRY(allocator_result);
+
+ // We're going to perform an update, so create a helper.
+ KScopedPageTableUpdater updater(this);
// Perform mapping operation.
if (is_pa_valid) {
- R_TRY(this->Operate(addr, num_pages, perm, OperationType::Map, phys_addr));
+ const KPageProperties properties = {perm, false, false, DisableMergeAttribute::DisableHead};
+ R_TRY(this->Operate(addr, num_pages, properties.perm, OperationType::Map, phys_addr));
} else {
- UNIMPLEMENTED();
+ R_TRY(this->AllocateAndMapPagesImpl(updater.GetPageList(), addr, num_pages, perm));
}
// Update the blocks.
@@ -2116,28 +2268,45 @@ Result KPageTable::MapPages(VAddr* out_addr, size_t num_pages, size_t alignment,
R_SUCCEED();
}
-Result KPageTable::UnmapPages(VAddr addr, const KPageGroup& page_linked_list) {
- ASSERT(this->IsLockedByCurrentThread());
+Result KPageTable::MapPages(KProcessAddress address, size_t num_pages, KMemoryState state,
+ KMemoryPermission perm) {
+ // Check that the map is in range.
+ const size_t size = num_pages * PageSize;
+ R_UNLESS(this->CanContain(address, size, state), ResultInvalidCurrentMemory);
- VAddr cur_addr{addr};
+ // Lock the table.
+ KScopedLightLock lk(m_general_lock);
- for (const auto& node : page_linked_list) {
- if (const auto result{Operate(cur_addr, node.GetNumPages(), KMemoryPermission::None,
- OperationType::Unmap)};
- result.IsError()) {
- R_RETURN(result);
- }
+ // Check the memory state.
+ size_t num_allocator_blocks;
+ R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks), address, size,
+ KMemoryState::All, KMemoryState::Free, KMemoryPermission::None,
+ KMemoryPermission::None, KMemoryAttribute::None,
+ KMemoryAttribute::None));
- cur_addr += node.GetNumPages() * PageSize;
- }
+ // Create an update allocator.
+ Result allocator_result;
+ KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result),
+ m_memory_block_slab_manager, num_allocator_blocks);
+ R_TRY(allocator_result);
+
+ // We're going to perform an update, so create a helper.
+ KScopedPageTableUpdater updater(this);
+
+ // Map the pages.
+ R_TRY(this->AllocateAndMapPagesImpl(updater.GetPageList(), address, num_pages, perm));
+
+ // Update the blocks.
+ m_memory_block_manager.Update(std::addressof(allocator), address, num_pages, state, perm,
+ KMemoryAttribute::None, KMemoryBlockDisableMergeAttribute::Normal,
+ KMemoryBlockDisableMergeAttribute::None);
R_SUCCEED();
}
-Result KPageTable::UnmapPages(VAddr address, KPageGroup& page_linked_list, KMemoryState state) {
+Result KPageTable::UnmapPages(KProcessAddress address, size_t num_pages, KMemoryState state) {
// Check that the unmap is in range.
- const size_t num_pages{page_linked_list.GetNumPages()};
- const size_t size{num_pages * PageSize};
+ const size_t size = num_pages * PageSize;
R_UNLESS(this->Contains(address, size), ResultInvalidCurrentMemory);
// Lock the table.
@@ -2151,13 +2320,18 @@ Result KPageTable::UnmapPages(VAddr address, KPageGroup& page_linked_list, KMemo
KMemoryAttribute::None));
// Create an update allocator.
- Result allocator_result{ResultSuccess};
+ Result allocator_result;
KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result),
m_memory_block_slab_manager, num_allocator_blocks);
R_TRY(allocator_result);
+ // We're going to perform an update, so create a helper.
+ KScopedPageTableUpdater updater(this);
+
// Perform the unmap.
- R_TRY(UnmapPages(address, page_linked_list));
+ const KPageProperties unmap_properties = {KMemoryPermission::None, false, false,
+ DisableMergeAttribute::None};
+ R_TRY(this->Operate(address, num_pages, unmap_properties.perm, OperationType::Unmap));
// Update the blocks.
m_memory_block_manager.Update(std::addressof(allocator), address, num_pages, KMemoryState::Free,
@@ -2168,29 +2342,130 @@ Result KPageTable::UnmapPages(VAddr address, KPageGroup& page_linked_list, KMemo
R_SUCCEED();
}
-Result KPageTable::UnmapPages(VAddr address, size_t num_pages, KMemoryState state) {
- // Check that the unmap is in range.
+Result KPageTable::MapPageGroup(KProcessAddress* out_addr, const KPageGroup& pg,
+ KProcessAddress region_start, size_t region_num_pages,
+ KMemoryState state, KMemoryPermission perm) {
+ ASSERT(!this->IsLockedByCurrentThread());
+
+ // Ensure this is a valid map request.
+ const size_t num_pages = pg.GetNumPages();
+ R_UNLESS(this->CanContain(region_start, region_num_pages * PageSize, state),
+ ResultInvalidCurrentMemory);
+ R_UNLESS(num_pages < region_num_pages, ResultOutOfMemory);
+
+ // Lock the table.
+ KScopedLightLock lk(m_general_lock);
+
+ // Find a random address to map at.
+ KProcessAddress addr = this->FindFreeArea(region_start, region_num_pages, num_pages, PageSize,
+ 0, this->GetNumGuardPages());
+ R_UNLESS(addr != 0, ResultOutOfMemory);
+ ASSERT(this->CanContain(addr, num_pages * PageSize, state));
+ ASSERT(this->CheckMemoryState(addr, num_pages * PageSize, KMemoryState::All, KMemoryState::Free,
+ KMemoryPermission::None, KMemoryPermission::None,
+ KMemoryAttribute::None, KMemoryAttribute::None) == ResultSuccess);
+
+ // Create an update allocator.
+ Result allocator_result;
+ KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result),
+ m_memory_block_slab_manager);
+ R_TRY(allocator_result);
+
+ // We're going to perform an update, so create a helper.
+ KScopedPageTableUpdater updater(this);
+
+ // Perform mapping operation.
+ const KPageProperties properties = {perm, state == KMemoryState::Io, false,
+ DisableMergeAttribute::DisableHead};
+ R_TRY(this->MapPageGroupImpl(updater.GetPageList(), addr, pg, properties, false));
+
+ // Update the blocks.
+ m_memory_block_manager.Update(std::addressof(allocator), addr, num_pages, state, perm,
+ KMemoryAttribute::None, KMemoryBlockDisableMergeAttribute::Normal,
+ KMemoryBlockDisableMergeAttribute::None);
+
+ // We successfully mapped the pages.
+ *out_addr = addr;
+ R_SUCCEED();
+}
+
+Result KPageTable::MapPageGroup(KProcessAddress addr, const KPageGroup& pg, KMemoryState state,
+ KMemoryPermission perm) {
+ ASSERT(!this->IsLockedByCurrentThread());
+
+ // Ensure this is a valid map request.
+ const size_t num_pages = pg.GetNumPages();
const size_t size = num_pages * PageSize;
- R_UNLESS(this->Contains(address, size), ResultInvalidCurrentMemory);
+ R_UNLESS(this->CanContain(addr, size, state), ResultInvalidCurrentMemory);
// Lock the table.
KScopedLightLock lk(m_general_lock);
- // Check the memory state.
- size_t num_allocator_blocks{};
+ // Check if state allows us to map.
+ size_t num_allocator_blocks;
+ R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks), addr, size,
+ KMemoryState::All, KMemoryState::Free, KMemoryPermission::None,
+ KMemoryPermission::None, KMemoryAttribute::None,
+ KMemoryAttribute::None));
+
+ // Create an update allocator.
+ Result allocator_result;
+ KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result),
+ m_memory_block_slab_manager, num_allocator_blocks);
+ R_TRY(allocator_result);
+
+ // We're going to perform an update, so create a helper.
+ KScopedPageTableUpdater updater(this);
+
+ // Perform mapping operation.
+ const KPageProperties properties = {perm, state == KMemoryState::Io, false,
+ DisableMergeAttribute::DisableHead};
+ R_TRY(this->MapPageGroupImpl(updater.GetPageList(), addr, pg, properties, false));
+
+ // Update the blocks.
+ m_memory_block_manager.Update(std::addressof(allocator), addr, num_pages, state, perm,
+ KMemoryAttribute::None, KMemoryBlockDisableMergeAttribute::Normal,
+ KMemoryBlockDisableMergeAttribute::None);
+
+ // We successfully mapped the pages.
+ R_SUCCEED();
+}
+
+Result KPageTable::UnmapPageGroup(KProcessAddress address, const KPageGroup& pg,
+ KMemoryState state) {
+ ASSERT(!this->IsLockedByCurrentThread());
+
+ // Ensure this is a valid unmap request.
+ const size_t num_pages = pg.GetNumPages();
+ const size_t size = num_pages * PageSize;
+ R_UNLESS(this->CanContain(address, size, state), ResultInvalidCurrentMemory);
+
+ // Lock the table.
+ KScopedLightLock lk(m_general_lock);
+
+ // Check if state allows us to unmap.
+ size_t num_allocator_blocks;
R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks), address, size,
KMemoryState::All, state, KMemoryPermission::None,
KMemoryPermission::None, KMemoryAttribute::All,
KMemoryAttribute::None));
+ // Check that the page group is valid.
+ R_UNLESS(this->IsValidPageGroup(pg, address, num_pages), ResultInvalidCurrentMemory);
+
// Create an update allocator.
- Result allocator_result{ResultSuccess};
+ Result allocator_result;
KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result),
m_memory_block_slab_manager, num_allocator_blocks);
R_TRY(allocator_result);
- // Perform the unmap.
- R_TRY(Operate(address, num_pages, KMemoryPermission::None, OperationType::Unmap));
+ // We're going to perform an update, so create a helper.
+ KScopedPageTableUpdater updater(this);
+
+ // Perform unmapping operation.
+ const KPageProperties properties = {KMemoryPermission::None, false, false,
+ DisableMergeAttribute::None};
+ R_TRY(this->Operate(address, num_pages, properties.perm, OperationType::Unmap));
// Update the blocks.
m_memory_block_manager.Update(std::addressof(allocator), address, num_pages, KMemoryState::Free,
@@ -2201,7 +2476,7 @@ Result KPageTable::UnmapPages(VAddr address, size_t num_pages, KMemoryState stat
R_SUCCEED();
}
-Result KPageTable::MakeAndOpenPageGroup(KPageGroup* out, VAddr address, size_t num_pages,
+Result KPageTable::MakeAndOpenPageGroup(KPageGroup* out, KProcessAddress address, size_t num_pages,
KMemoryState state_mask, KMemoryState state,
KMemoryPermission perm_mask, KMemoryPermission perm,
KMemoryAttribute attr_mask, KMemoryAttribute attr) {
@@ -2226,7 +2501,7 @@ Result KPageTable::MakeAndOpenPageGroup(KPageGroup* out, VAddr address, size_t n
R_SUCCEED();
}
-Result KPageTable::SetProcessMemoryPermission(VAddr addr, size_t size,
+Result KPageTable::SetProcessMemoryPermission(KProcessAddress addr, size_t size,
Svc::MemoryPermission svc_perm) {
const size_t num_pages = size / PageSize;
@@ -2287,23 +2562,23 @@ Result KPageTable::SetProcessMemoryPermission(VAddr addr, size_t size,
// Ensure cache coherency, if we're setting pages as executable.
if (is_x) {
- m_system.InvalidateCpuInstructionCacheRange(addr, size);
+ m_system.InvalidateCpuInstructionCacheRange(GetInteger(addr), size);
}
R_SUCCEED();
}
-KMemoryInfo KPageTable::QueryInfoImpl(VAddr addr) {
+KMemoryInfo KPageTable::QueryInfoImpl(KProcessAddress addr) {
KScopedLightLock lk(m_general_lock);
return m_memory_block_manager.FindBlock(addr)->GetMemoryInfo();
}
-KMemoryInfo KPageTable::QueryInfo(VAddr addr) {
+KMemoryInfo KPageTable::QueryInfo(KProcessAddress addr) {
if (!Contains(addr, 1)) {
return {
- .m_address = m_address_space_end,
- .m_size = 0 - m_address_space_end,
+ .m_address = GetInteger(m_address_space_end),
+ .m_size = 0 - GetInteger(m_address_space_end),
.m_state = static_cast<KMemoryState>(Svc::MemoryState::Inaccessible),
.m_device_disable_merge_left_count = 0,
.m_device_disable_merge_right_count = 0,
@@ -2320,7 +2595,8 @@ KMemoryInfo KPageTable::QueryInfo(VAddr addr) {
return QueryInfoImpl(addr);
}
-Result KPageTable::SetMemoryPermission(VAddr addr, size_t size, Svc::MemoryPermission svc_perm) {
+Result KPageTable::SetMemoryPermission(KProcessAddress addr, size_t size,
+ Svc::MemoryPermission svc_perm) {
const size_t num_pages = size / PageSize;
// Lock the table.
@@ -2357,7 +2633,7 @@ Result KPageTable::SetMemoryPermission(VAddr addr, size_t size, Svc::MemoryPermi
R_SUCCEED();
}
-Result KPageTable::SetMemoryAttribute(VAddr addr, size_t size, u32 mask, u32 attr) {
+Result KPageTable::SetMemoryAttribute(KProcessAddress addr, size_t size, u32 mask, u32 attr) {
const size_t num_pages = size / PageSize;
ASSERT((static_cast<KMemoryAttribute>(mask) | KMemoryAttribute::SetMask) ==
KMemoryAttribute::SetMask);
@@ -2412,12 +2688,12 @@ Result KPageTable::SetMaxHeapSize(size_t size) {
R_SUCCEED();
}
-Result KPageTable::SetHeapSize(VAddr* out, size_t size) {
+Result KPageTable::SetHeapSize(u64* out, size_t size) {
// Lock the physical memory mutex.
KScopedLightLock map_phys_mem_lk(m_map_physical_memory_lock);
// Try to perform a reduction in heap, instead of an extension.
- VAddr cur_address{};
+ KProcessAddress cur_address{};
size_t allocation_size{};
{
// Lock the table.
@@ -2468,11 +2744,11 @@ Result KPageTable::SetHeapSize(VAddr* out, size_t size) {
m_current_heap_end = m_heap_region_start + size;
// Set the output.
- *out = m_heap_region_start;
+ *out = GetInteger(m_heap_region_start);
R_SUCCEED();
} else if (size == GetHeapSize()) {
// The size requested is exactly the current size.
- *out = m_heap_region_start;
+ *out = GetInteger(m_heap_region_start);
R_SUCCEED();
} else {
// We have to allocate memory. Determine how much to allocate and where while the table
@@ -2526,7 +2802,7 @@ Result KPageTable::SetHeapSize(VAddr* out, size_t size) {
// Clear all the newly allocated pages.
for (size_t cur_page = 0; cur_page < num_pages; ++cur_page) {
- std::memset(m_system.Memory().GetPointer(m_current_heap_end + (cur_page * PageSize)), 0,
+ std::memset(m_memory->GetPointer(m_current_heap_end + (cur_page * PageSize)), 0,
PageSize);
}
@@ -2545,62 +2821,14 @@ Result KPageTable::SetHeapSize(VAddr* out, size_t size) {
m_current_heap_end = m_heap_region_start + size;
// Set the output.
- *out = m_heap_region_start;
+ *out = GetInteger(m_heap_region_start);
R_SUCCEED();
}
}
-ResultVal<VAddr> KPageTable::AllocateAndMapMemory(size_t needed_num_pages, size_t align,
- bool is_map_only, VAddr region_start,
- size_t region_num_pages, KMemoryState state,
- KMemoryPermission perm, PAddr map_addr) {
- KScopedLightLock lk(m_general_lock);
-
- R_UNLESS(CanContain(region_start, region_num_pages * PageSize, state),
- ResultInvalidCurrentMemory);
- R_UNLESS(region_num_pages > needed_num_pages, ResultOutOfMemory);
- const VAddr addr{
- AllocateVirtualMemory(region_start, region_num_pages, needed_num_pages, align)};
- R_UNLESS(addr, ResultOutOfMemory);
-
- // Create an update allocator.
- Result allocator_result{ResultSuccess};
- KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result),
- m_memory_block_slab_manager);
-
- if (is_map_only) {
- R_TRY(Operate(addr, needed_num_pages, perm, OperationType::Map, map_addr));
- } else {
- // Create a page group tohold the pages we allocate.
- KPageGroup pg{m_kernel, m_block_info_manager};
-
- R_TRY(m_system.Kernel().MemoryManager().AllocateAndOpen(
- &pg, needed_num_pages,
- KMemoryManager::EncodeOption(m_memory_pool, m_allocation_option)));
-
- // Ensure that the page group is closed when we're done working with it.
- SCOPE_EXIT({ pg.Close(); });
-
- // Clear all pages.
- for (const auto& it : pg) {
- std::memset(m_system.DeviceMemory().GetPointer<void>(it.GetAddress()),
- m_heap_fill_value, it.GetSize());
- }
-
- R_TRY(Operate(addr, needed_num_pages, pg, OperationType::MapGroup));
- }
-
- // Update the blocks.
- m_memory_block_manager.Update(std::addressof(allocator), addr, needed_num_pages, state, perm,
- KMemoryAttribute::None, KMemoryBlockDisableMergeAttribute::Normal,
- KMemoryBlockDisableMergeAttribute::None);
-
- return addr;
-}
-
-Result KPageTable::LockForMapDeviceAddressSpace(bool* out_is_io, VAddr address, size_t size,
- KMemoryPermission perm, bool is_aligned,
- bool check_heap) {
+Result KPageTable::LockForMapDeviceAddressSpace(bool* out_is_io, KProcessAddress address,
+ size_t size, KMemoryPermission perm,
+ bool is_aligned, bool check_heap) {
// Lightly validate the range before doing anything else.
const size_t num_pages = size / PageSize;
R_UNLESS(this->Contains(address, size), ResultInvalidCurrentMemory);
@@ -2636,7 +2864,8 @@ Result KPageTable::LockForMapDeviceAddressSpace(bool* out_is_io, VAddr address,
R_SUCCEED();
}
-Result KPageTable::LockForUnmapDeviceAddressSpace(VAddr address, size_t size, bool check_heap) {
+Result KPageTable::LockForUnmapDeviceAddressSpace(KProcessAddress address, size_t size,
+ bool check_heap) {
// Lightly validate the range before doing anything else.
const size_t num_pages = size / PageSize;
R_UNLESS(this->Contains(address, size), ResultInvalidCurrentMemory);
@@ -2670,7 +2899,7 @@ Result KPageTable::LockForUnmapDeviceAddressSpace(VAddr address, size_t size, bo
R_SUCCEED();
}
-Result KPageTable::UnlockForDeviceAddressSpace(VAddr address, size_t size) {
+Result KPageTable::UnlockForDeviceAddressSpace(KProcessAddress address, size_t size) {
// Lightly validate the range before doing anything else.
const size_t num_pages = size / PageSize;
R_UNLESS(this->Contains(address, size), ResultInvalidCurrentMemory);
@@ -2698,7 +2927,8 @@ Result KPageTable::UnlockForDeviceAddressSpace(VAddr address, size_t size) {
R_SUCCEED();
}
-Result KPageTable::LockForIpcUserBuffer(PAddr* out, VAddr address, size_t size) {
+Result KPageTable::LockForIpcUserBuffer(KPhysicalAddress* out, KProcessAddress address,
+ size_t size) {
R_RETURN(this->LockMemoryAndOpen(
nullptr, out, address, size, KMemoryState::FlagCanIpcUserBuffer,
KMemoryState::FlagCanIpcUserBuffer, KMemoryPermission::All,
@@ -2707,7 +2937,7 @@ Result KPageTable::LockForIpcUserBuffer(PAddr* out, VAddr address, size_t size)
KMemoryAttribute::Locked));
}
-Result KPageTable::UnlockForIpcUserBuffer(VAddr address, size_t size) {
+Result KPageTable::UnlockForIpcUserBuffer(KProcessAddress address, size_t size) {
R_RETURN(this->UnlockMemory(address, size, KMemoryState::FlagCanIpcUserBuffer,
KMemoryState::FlagCanIpcUserBuffer, KMemoryPermission::None,
KMemoryPermission::None, KMemoryAttribute::All,
@@ -2715,7 +2945,7 @@ Result KPageTable::UnlockForIpcUserBuffer(VAddr address, size_t size) {
KMemoryAttribute::Locked, nullptr));
}
-Result KPageTable::LockForCodeMemory(KPageGroup* out, VAddr addr, size_t size) {
+Result KPageTable::LockForCodeMemory(KPageGroup* out, KProcessAddress addr, size_t size) {
R_RETURN(this->LockMemoryAndOpen(
out, nullptr, addr, size, KMemoryState::FlagCanCodeMemory, KMemoryState::FlagCanCodeMemory,
KMemoryPermission::All, KMemoryPermission::UserReadWrite, KMemoryAttribute::All,
@@ -2723,17 +2953,17 @@ Result KPageTable::LockForCodeMemory(KPageGroup* out, VAddr addr, size_t size) {
KMemoryAttribute::Locked));
}
-Result KPageTable::UnlockForCodeMemory(VAddr addr, size_t size, const KPageGroup& pg) {
+Result KPageTable::UnlockForCodeMemory(KProcessAddress addr, size_t size, const KPageGroup& pg) {
R_RETURN(this->UnlockMemory(
addr, size, KMemoryState::FlagCanCodeMemory, KMemoryState::FlagCanCodeMemory,
KMemoryPermission::None, KMemoryPermission::None, KMemoryAttribute::All,
KMemoryAttribute::Locked, KMemoryPermission::UserReadWrite, KMemoryAttribute::Locked, &pg));
}
-bool KPageTable::IsRegionContiguous(VAddr addr, u64 size) const {
- auto start_ptr = m_system.DeviceMemory().GetPointer<u8>(addr);
+bool KPageTable::IsRegionContiguous(KProcessAddress addr, u64 size) const {
+ auto start_ptr = m_system.DeviceMemory().GetPointer<u8>(GetInteger(addr));
for (u64 offset{}; offset < size; offset += PageSize) {
- if (start_ptr != m_system.DeviceMemory().GetPointer<u8>(addr + offset)) {
+ if (start_ptr != m_system.DeviceMemory().GetPointer<u8>(GetInteger(addr) + offset)) {
return false;
}
start_ptr += PageSize;
@@ -2741,18 +2971,19 @@ bool KPageTable::IsRegionContiguous(VAddr addr, u64 size) const {
return true;
}
-void KPageTable::AddRegionToPages(VAddr start, size_t num_pages, KPageGroup& page_linked_list) {
- VAddr addr{start};
+void KPageTable::AddRegionToPages(KProcessAddress start, size_t num_pages,
+ KPageGroup& page_linked_list) {
+ KProcessAddress addr{start};
while (addr < start + (num_pages * PageSize)) {
- const PAddr paddr{GetPhysicalAddr(addr)};
+ const KPhysicalAddress paddr{GetPhysicalAddr(addr)};
ASSERT(paddr != 0);
page_linked_list.AddBlock(paddr, 1);
addr += PageSize;
}
}
-VAddr KPageTable::AllocateVirtualMemory(VAddr start, size_t region_num_pages, u64 needed_num_pages,
- size_t align) {
+KProcessAddress KPageTable::AllocateVirtualMemory(KProcessAddress start, size_t region_num_pages,
+ u64 needed_num_pages, size_t align) {
if (m_enable_aslr) {
UNIMPLEMENTED();
}
@@ -2760,11 +2991,11 @@ VAddr KPageTable::AllocateVirtualMemory(VAddr start, size_t region_num_pages, u6
IsKernel() ? 1 : 4);
}
-Result KPageTable::Operate(VAddr addr, size_t num_pages, const KPageGroup& page_group,
+Result KPageTable::Operate(KProcessAddress addr, size_t num_pages, const KPageGroup& page_group,
OperationType operation) {
ASSERT(this->IsLockedByCurrentThread());
- ASSERT(Common::IsAligned(addr, PageSize));
+ ASSERT(Common::IsAligned(GetInteger(addr), PageSize));
ASSERT(num_pages > 0);
ASSERT(num_pages == page_group.GetNumPages());
@@ -2777,7 +3008,7 @@ Result KPageTable::Operate(VAddr addr, size_t num_pages, const KPageGroup& page_
const size_t size{node.GetNumPages() * PageSize};
// Map the pages.
- m_system.Memory().MapMemoryRegion(*m_page_table_impl, addr, size, node.GetAddress());
+ m_memory->MapMemoryRegion(*m_page_table_impl, addr, size, node.GetAddress());
addr += size;
}
@@ -2795,12 +3026,12 @@ Result KPageTable::Operate(VAddr addr, size_t num_pages, const KPageGroup& page_
R_SUCCEED();
}
-Result KPageTable::Operate(VAddr addr, size_t num_pages, KMemoryPermission perm,
- OperationType operation, PAddr map_addr) {
+Result KPageTable::Operate(KProcessAddress addr, size_t num_pages, KMemoryPermission perm,
+ OperationType operation, KPhysicalAddress map_addr) {
ASSERT(this->IsLockedByCurrentThread());
ASSERT(num_pages > 0);
- ASSERT(Common::IsAligned(addr, PageSize));
+ ASSERT(Common::IsAligned(GetInteger(addr), PageSize));
ASSERT(ContainsPages(addr, num_pages));
switch (operation) {
@@ -2810,14 +3041,14 @@ Result KPageTable::Operate(VAddr addr, size_t num_pages, KMemoryPermission perm,
SCOPE_EXIT({ pages_to_close.CloseAndReset(); });
this->AddRegionToPages(addr, num_pages, pages_to_close);
- m_system.Memory().UnmapRegion(*m_page_table_impl, addr, num_pages * PageSize);
+ m_memory->UnmapRegion(*m_page_table_impl, addr, num_pages * PageSize);
break;
}
case OperationType::MapFirst:
case OperationType::Map: {
ASSERT(map_addr);
- ASSERT(Common::IsAligned(map_addr, PageSize));
- m_system.Memory().MapMemoryRegion(*m_page_table_impl, addr, num_pages * PageSize, map_addr);
+ ASSERT(Common::IsAligned(GetInteger(map_addr), PageSize));
+ m_memory->MapMemoryRegion(*m_page_table_impl, addr, num_pages * PageSize, map_addr);
// Open references to pages, if we should.
if (IsHeapPhysicalAddress(m_kernel.MemoryLayout(), map_addr)) {
@@ -2854,7 +3085,7 @@ void KPageTable::FinalizeUpdate(PageLinkedList* page_list) {
}
}
-VAddr KPageTable::GetRegionAddress(KMemoryState state) const {
+KProcessAddress KPageTable::GetRegionAddress(KMemoryState state) const {
switch (state) {
case KMemoryState::Free:
case KMemoryState::Kernel:
@@ -2926,11 +3157,11 @@ size_t KPageTable::GetRegionSize(KMemoryState state) const {
}
}
-bool KPageTable::CanContain(VAddr addr, size_t size, KMemoryState state) const {
- const VAddr end = addr + size;
- const VAddr last = end - 1;
+bool KPageTable::CanContain(KProcessAddress addr, size_t size, KMemoryState state) const {
+ const KProcessAddress end = addr + size;
+ const KProcessAddress last = end - 1;
- const VAddr region_start = this->GetRegionAddress(state);
+ const KProcessAddress region_start = this->GetRegionAddress(state);
const size_t region_size = this->GetRegionSize(state);
const bool is_in_region =
@@ -2985,21 +3216,21 @@ Result KPageTable::CheckMemoryState(const KMemoryInfo& info, KMemoryState state_
R_SUCCEED();
}
-Result KPageTable::CheckMemoryStateContiguous(size_t* out_blocks_needed, VAddr addr, size_t size,
- KMemoryState state_mask, KMemoryState state,
- KMemoryPermission perm_mask, KMemoryPermission perm,
- KMemoryAttribute attr_mask,
+Result KPageTable::CheckMemoryStateContiguous(size_t* out_blocks_needed, KProcessAddress addr,
+ size_t size, KMemoryState state_mask,
+ KMemoryState state, KMemoryPermission perm_mask,
+ KMemoryPermission perm, KMemoryAttribute attr_mask,
KMemoryAttribute attr) const {
ASSERT(this->IsLockedByCurrentThread());
// Get information about the first block.
- const VAddr last_addr = addr + size - 1;
+ const KProcessAddress last_addr = addr + size - 1;
KMemoryBlockManager::const_iterator it = m_memory_block_manager.FindIterator(addr);
KMemoryInfo info = it->GetMemoryInfo();
// If the start address isn't aligned, we need a block.
const size_t blocks_for_start_align =
- (Common::AlignDown(addr, PageSize) != info.GetAddress()) ? 1 : 0;
+ (Common::AlignDown(GetInteger(addr), PageSize) != info.GetAddress()) ? 1 : 0;
while (true) {
// Validate against the provided masks.
@@ -3018,7 +3249,7 @@ Result KPageTable::CheckMemoryStateContiguous(size_t* out_blocks_needed, VAddr a
// If the end address isn't aligned, we need a block.
const size_t blocks_for_end_align =
- (Common::AlignUp(addr + size, PageSize) != info.GetEndAddress()) ? 1 : 0;
+ (Common::AlignUp(GetInteger(addr) + size, PageSize) != info.GetEndAddress()) ? 1 : 0;
if (out_blocks_needed != nullptr) {
*out_blocks_needed = blocks_for_start_align + blocks_for_end_align;
@@ -3029,20 +3260,20 @@ Result KPageTable::CheckMemoryStateContiguous(size_t* out_blocks_needed, VAddr a
Result KPageTable::CheckMemoryState(KMemoryState* out_state, KMemoryPermission* out_perm,
KMemoryAttribute* out_attr, size_t* out_blocks_needed,
- VAddr addr, size_t size, KMemoryState state_mask,
+ KProcessAddress addr, size_t size, KMemoryState state_mask,
KMemoryState state, KMemoryPermission perm_mask,
KMemoryPermission perm, KMemoryAttribute attr_mask,
KMemoryAttribute attr, KMemoryAttribute ignore_attr) const {
ASSERT(this->IsLockedByCurrentThread());
// Get information about the first block.
- const VAddr last_addr = addr + size - 1;
+ const KProcessAddress last_addr = addr + size - 1;
KMemoryBlockManager::const_iterator it = m_memory_block_manager.FindIterator(addr);
KMemoryInfo info = it->GetMemoryInfo();
// If the start address isn't aligned, we need a block.
const size_t blocks_for_start_align =
- (Common::AlignDown(addr, PageSize) != info.GetAddress()) ? 1 : 0;
+ (Common::AlignDown(GetInteger(addr), PageSize) != info.GetAddress()) ? 1 : 0;
// Validate all blocks in the range have correct state.
const KMemoryState first_state = info.m_state;
@@ -3071,7 +3302,7 @@ Result KPageTable::CheckMemoryState(KMemoryState* out_state, KMemoryPermission*
// If the end address isn't aligned, we need a block.
const size_t blocks_for_end_align =
- (Common::AlignUp(addr + size, PageSize) != info.GetEndAddress()) ? 1 : 0;
+ (Common::AlignUp(GetInteger(addr) + size, PageSize) != info.GetEndAddress()) ? 1 : 0;
// Write output state.
if (out_state != nullptr) {
@@ -3089,11 +3320,12 @@ Result KPageTable::CheckMemoryState(KMemoryState* out_state, KMemoryPermission*
R_SUCCEED();
}
-Result KPageTable::LockMemoryAndOpen(KPageGroup* out_pg, PAddr* out_paddr, VAddr addr, size_t size,
- KMemoryState state_mask, KMemoryState state,
- KMemoryPermission perm_mask, KMemoryPermission perm,
- KMemoryAttribute attr_mask, KMemoryAttribute attr,
- KMemoryPermission new_perm, KMemoryAttribute lock_attr) {
+Result KPageTable::LockMemoryAndOpen(KPageGroup* out_pg, KPhysicalAddress* out_KPhysicalAddress,
+ KProcessAddress addr, size_t size, KMemoryState state_mask,
+ KMemoryState state, KMemoryPermission perm_mask,
+ KMemoryPermission perm, KMemoryAttribute attr_mask,
+ KMemoryAttribute attr, KMemoryPermission new_perm,
+ KMemoryAttribute lock_attr) {
// Validate basic preconditions.
ASSERT((lock_attr & attr) == KMemoryAttribute::None);
ASSERT((lock_attr & (KMemoryAttribute::IpcLocked | KMemoryAttribute::DeviceShared)) ==
@@ -3123,8 +3355,8 @@ Result KPageTable::LockMemoryAndOpen(KPageGroup* out_pg, PAddr* out_paddr, VAddr
attr_mask, attr));
// Get the physical address, if we're supposed to.
- if (out_paddr != nullptr) {
- ASSERT(this->GetPhysicalAddressLocked(out_paddr, addr));
+ if (out_KPhysicalAddress != nullptr) {
+ ASSERT(this->GetPhysicalAddressLocked(out_KPhysicalAddress, addr));
}
// Make the page group, if we're supposed to.
@@ -3155,7 +3387,7 @@ Result KPageTable::LockMemoryAndOpen(KPageGroup* out_pg, PAddr* out_paddr, VAddr
R_SUCCEED();
}
-Result KPageTable::UnlockMemory(VAddr addr, size_t size, KMemoryState state_mask,
+Result KPageTable::UnlockMemory(KProcessAddress addr, size_t size, KMemoryState state_mask,
KMemoryState state, KMemoryPermission perm_mask,
KMemoryPermission perm, KMemoryAttribute attr_mask,
KMemoryAttribute attr, KMemoryPermission new_perm,
diff --git a/src/core/hle/kernel/k_page_table.h b/src/core/hle/kernel/k_page_table.h
index 0a454b05b..022d15f35 100644
--- a/src/core/hle/kernel/k_page_table.h
+++ b/src/core/hle/kernel/k_page_table.h
@@ -6,7 +6,6 @@
#include <memory>
#include "common/common_funcs.h"
-#include "common/common_types.h"
#include "common/page_table.h"
#include "core/file_sys/program_metadata.h"
#include "core/hle/kernel/k_dynamic_resource_manager.h"
@@ -15,6 +14,7 @@
#include "core/hle/kernel/k_memory_block_manager.h"
#include "core/hle/kernel/k_memory_layout.h"
#include "core/hle/kernel/k_memory_manager.h"
+#include "core/hle/kernel/k_typed_address.h"
#include "core/hle/result.h"
#include "core/memory.h"
@@ -24,12 +24,36 @@ class System;
namespace Kernel {
+enum class DisableMergeAttribute : u8 {
+ None = (0U << 0),
+ DisableHead = (1U << 0),
+ DisableHeadAndBody = (1U << 1),
+ EnableHeadAndBody = (1U << 2),
+ DisableTail = (1U << 3),
+ EnableTail = (1U << 4),
+ EnableAndMergeHeadBodyTail = (1U << 5),
+ EnableHeadBodyTail = EnableHeadAndBody | EnableTail,
+ DisableHeadBodyTail = DisableHeadAndBody | DisableTail,
+};
+
+struct KPageProperties {
+ KMemoryPermission perm;
+ bool io;
+ bool uncached;
+ DisableMergeAttribute disable_merge_attributes;
+};
+static_assert(std::is_trivial_v<KPageProperties>);
+static_assert(sizeof(KPageProperties) == sizeof(u32));
+
class KBlockInfoManager;
class KMemoryBlockManager;
class KResourceLimit;
class KSystemResource;
class KPageTable final {
+protected:
+ struct PageLinkedList;
+
public:
enum class ICacheInvalidationStrategy : u32 { InvalidateRange, InvalidateAll };
@@ -41,60 +65,48 @@ public:
Result InitializeForProcess(FileSys::ProgramAddressSpaceType as_type, bool enable_aslr,
bool enable_das_merge, bool from_back, KMemoryManager::Pool pool,
- VAddr code_addr, size_t code_size, KSystemResource* system_resource,
- KResourceLimit* resource_limit);
+ KProcessAddress code_addr, size_t code_size,
+ KSystemResource* system_resource, KResourceLimit* resource_limit,
+ Core::Memory::Memory& memory);
void Finalize();
- Result MapProcessCode(VAddr addr, size_t pages_count, KMemoryState state,
+ Result MapProcessCode(KProcessAddress addr, size_t pages_count, KMemoryState state,
KMemoryPermission perm);
- Result MapCodeMemory(VAddr dst_address, VAddr src_address, size_t size);
- Result UnmapCodeMemory(VAddr dst_address, VAddr src_address, size_t size,
+ Result MapCodeMemory(KProcessAddress dst_address, KProcessAddress src_address, size_t size);
+ Result UnmapCodeMemory(KProcessAddress dst_address, KProcessAddress src_address, size_t size,
ICacheInvalidationStrategy icache_invalidation_strategy);
- Result UnmapProcessMemory(VAddr dst_addr, size_t size, KPageTable& src_page_table,
- VAddr src_addr);
- Result MapPhysicalMemory(VAddr addr, size_t size);
- Result UnmapPhysicalMemory(VAddr addr, size_t size);
- Result MapMemory(VAddr dst_addr, VAddr src_addr, size_t size);
- Result UnmapMemory(VAddr dst_addr, VAddr src_addr, size_t size);
- Result MapPages(VAddr addr, KPageGroup& page_linked_list, KMemoryState state,
- KMemoryPermission perm);
- Result MapPages(VAddr* out_addr, size_t num_pages, size_t alignment, PAddr phys_addr,
- KMemoryState state, KMemoryPermission perm) {
- R_RETURN(this->MapPages(out_addr, num_pages, alignment, phys_addr, true,
- this->GetRegionAddress(state),
- this->GetRegionSize(state) / PageSize, state, perm));
- }
- Result UnmapPages(VAddr addr, KPageGroup& page_linked_list, KMemoryState state);
- Result UnmapPages(VAddr address, size_t num_pages, KMemoryState state);
- Result SetProcessMemoryPermission(VAddr addr, size_t size, Svc::MemoryPermission svc_perm);
- KMemoryInfo QueryInfo(VAddr addr);
- Result SetMemoryPermission(VAddr addr, size_t size, Svc::MemoryPermission perm);
- Result SetMemoryAttribute(VAddr addr, size_t size, u32 mask, u32 attr);
+ Result UnmapProcessMemory(KProcessAddress dst_addr, size_t size, KPageTable& src_page_table,
+ KProcessAddress src_addr);
+ Result MapPhysicalMemory(KProcessAddress addr, size_t size);
+ Result UnmapPhysicalMemory(KProcessAddress addr, size_t size);
+ Result MapMemory(KProcessAddress dst_addr, KProcessAddress src_addr, size_t size);
+ Result UnmapMemory(KProcessAddress dst_addr, KProcessAddress src_addr, size_t size);
+ Result SetProcessMemoryPermission(KProcessAddress addr, size_t size,
+ Svc::MemoryPermission svc_perm);
+ KMemoryInfo QueryInfo(KProcessAddress addr);
+ Result SetMemoryPermission(KProcessAddress addr, size_t size, Svc::MemoryPermission perm);
+ Result SetMemoryAttribute(KProcessAddress addr, size_t size, u32 mask, u32 attr);
Result SetMaxHeapSize(size_t size);
- Result SetHeapSize(VAddr* out, size_t size);
- ResultVal<VAddr> AllocateAndMapMemory(size_t needed_num_pages, size_t align, bool is_map_only,
- VAddr region_start, size_t region_num_pages,
- KMemoryState state, KMemoryPermission perm,
- PAddr map_addr = 0);
-
- Result LockForMapDeviceAddressSpace(bool* out_is_io, VAddr address, size_t size,
+ Result SetHeapSize(u64* out, size_t size);
+ Result LockForMapDeviceAddressSpace(bool* out_is_io, KProcessAddress address, size_t size,
KMemoryPermission perm, bool is_aligned, bool check_heap);
- Result LockForUnmapDeviceAddressSpace(VAddr address, size_t size, bool check_heap);
+ Result LockForUnmapDeviceAddressSpace(KProcessAddress address, size_t size, bool check_heap);
- Result UnlockForDeviceAddressSpace(VAddr addr, size_t size);
+ Result UnlockForDeviceAddressSpace(KProcessAddress addr, size_t size);
- Result LockForIpcUserBuffer(PAddr* out, VAddr address, size_t size);
- Result UnlockForIpcUserBuffer(VAddr address, size_t size);
+ Result LockForIpcUserBuffer(KPhysicalAddress* out, KProcessAddress address, size_t size);
+ Result UnlockForIpcUserBuffer(KProcessAddress address, size_t size);
- Result SetupForIpc(VAddr* out_dst_addr, size_t size, VAddr src_addr, KPageTable& src_page_table,
- KMemoryPermission test_perm, KMemoryState dst_state, bool send);
- Result CleanupForIpcServer(VAddr address, size_t size, KMemoryState dst_state);
- Result CleanupForIpcClient(VAddr address, size_t size, KMemoryState dst_state);
+ Result SetupForIpc(KProcessAddress* out_dst_addr, size_t size, KProcessAddress src_addr,
+ KPageTable& src_page_table, KMemoryPermission test_perm,
+ KMemoryState dst_state, bool send);
+ Result CleanupForIpcServer(KProcessAddress address, size_t size, KMemoryState dst_state);
+ Result CleanupForIpcClient(KProcessAddress address, size_t size, KMemoryState dst_state);
- Result LockForCodeMemory(KPageGroup* out, VAddr addr, size_t size);
- Result UnlockForCodeMemory(VAddr addr, size_t size, const KPageGroup& pg);
- Result MakeAndOpenPageGroup(KPageGroup* out, VAddr address, size_t num_pages,
+ Result LockForCodeMemory(KPageGroup* out, KProcessAddress addr, size_t size);
+ Result UnlockForCodeMemory(KProcessAddress addr, size_t size, const KPageGroup& pg);
+ Result MakeAndOpenPageGroup(KPageGroup* out, KProcessAddress address, size_t num_pages,
KMemoryState state_mask, KMemoryState state,
KMemoryPermission perm_mask, KMemoryPermission perm,
KMemoryAttribute attr_mask, KMemoryAttribute attr);
@@ -111,7 +123,41 @@ public:
return m_block_info_manager;
}
- bool CanContain(VAddr addr, size_t size, KMemoryState state) const;
+ bool CanContain(KProcessAddress addr, size_t size, KMemoryState state) const;
+
+ Result MapPages(KProcessAddress* out_addr, size_t num_pages, size_t alignment,
+ KPhysicalAddress phys_addr, KProcessAddress region_start,
+ size_t region_num_pages, KMemoryState state, KMemoryPermission perm) {
+ R_RETURN(this->MapPages(out_addr, num_pages, alignment, phys_addr, true, region_start,
+ region_num_pages, state, perm));
+ }
+
+ Result MapPages(KProcessAddress* out_addr, size_t num_pages, size_t alignment,
+ KPhysicalAddress phys_addr, KMemoryState state, KMemoryPermission perm) {
+ R_RETURN(this->MapPages(out_addr, num_pages, alignment, phys_addr, true,
+ this->GetRegionAddress(state),
+ this->GetRegionSize(state) / PageSize, state, perm));
+ }
+
+ Result MapPages(KProcessAddress* out_addr, size_t num_pages, KMemoryState state,
+ KMemoryPermission perm) {
+ R_RETURN(this->MapPages(out_addr, num_pages, PageSize, 0, false,
+ this->GetRegionAddress(state),
+ this->GetRegionSize(state) / PageSize, state, perm));
+ }
+
+ Result MapPages(KProcessAddress address, size_t num_pages, KMemoryState state,
+ KMemoryPermission perm);
+ Result UnmapPages(KProcessAddress address, size_t num_pages, KMemoryState state);
+
+ Result MapPageGroup(KProcessAddress* out_addr, const KPageGroup& pg,
+ KProcessAddress region_start, size_t region_num_pages, KMemoryState state,
+ KMemoryPermission perm);
+ Result MapPageGroup(KProcessAddress address, const KPageGroup& pg, KMemoryState state,
+ KMemoryPermission perm);
+ Result UnmapPageGroup(KProcessAddress address, const KPageGroup& pg, KMemoryState state);
+ void RemapPageGroup(PageLinkedList* page_list, KProcessAddress address, size_t size,
+ const KPageGroup& pg);
protected:
struct PageLinkedList {
@@ -130,8 +176,8 @@ protected:
m_root = n;
}
- void Push(Core::Memory::Memory& memory, VAddr addr) {
- this->Push(memory.GetPointer<Node>(addr));
+ void Push(Core::Memory::Memory& memory, KVirtualAddress addr) {
+ this->Push(memory.GetPointer<Node>(GetInteger(addr)));
}
Node* Peek() const {
@@ -166,32 +212,31 @@ private:
static constexpr KMemoryAttribute DefaultMemoryIgnoreAttr =
KMemoryAttribute::IpcLocked | KMemoryAttribute::DeviceShared;
- Result MapPages(VAddr addr, const KPageGroup& page_linked_list, KMemoryPermission perm);
- Result MapPages(VAddr* out_addr, size_t num_pages, size_t alignment, PAddr phys_addr,
- bool is_pa_valid, VAddr region_start, size_t region_num_pages,
- KMemoryState state, KMemoryPermission perm);
- Result UnmapPages(VAddr addr, const KPageGroup& page_linked_list);
- bool IsRegionContiguous(VAddr addr, u64 size) const;
- void AddRegionToPages(VAddr start, size_t num_pages, KPageGroup& page_linked_list);
- KMemoryInfo QueryInfoImpl(VAddr addr);
- VAddr AllocateVirtualMemory(VAddr start, size_t region_num_pages, u64 needed_num_pages,
- size_t align);
- Result Operate(VAddr addr, size_t num_pages, const KPageGroup& page_group,
+ Result MapPages(KProcessAddress* out_addr, size_t num_pages, size_t alignment,
+ KPhysicalAddress phys_addr, bool is_pa_valid, KProcessAddress region_start,
+ size_t region_num_pages, KMemoryState state, KMemoryPermission perm);
+ bool IsRegionContiguous(KProcessAddress addr, u64 size) const;
+ void AddRegionToPages(KProcessAddress start, size_t num_pages, KPageGroup& page_linked_list);
+ KMemoryInfo QueryInfoImpl(KProcessAddress addr);
+ KProcessAddress AllocateVirtualMemory(KProcessAddress start, size_t region_num_pages,
+ u64 needed_num_pages, size_t align);
+ Result Operate(KProcessAddress addr, size_t num_pages, const KPageGroup& page_group,
OperationType operation);
- Result Operate(VAddr addr, size_t num_pages, KMemoryPermission perm, OperationType operation,
- PAddr map_addr = 0);
+ Result Operate(KProcessAddress addr, size_t num_pages, KMemoryPermission perm,
+ OperationType operation, KPhysicalAddress map_addr = 0);
void FinalizeUpdate(PageLinkedList* page_list);
- VAddr GetRegionAddress(KMemoryState state) const;
+ KProcessAddress GetRegionAddress(KMemoryState state) const;
size_t GetRegionSize(KMemoryState state) const;
- VAddr FindFreeArea(VAddr region_start, size_t region_num_pages, size_t num_pages,
- size_t alignment, size_t offset, size_t guard_pages);
+ KProcessAddress FindFreeArea(KProcessAddress region_start, size_t region_num_pages,
+ size_t num_pages, size_t alignment, size_t offset,
+ size_t guard_pages);
- Result CheckMemoryStateContiguous(size_t* out_blocks_needed, VAddr addr, size_t size,
+ Result CheckMemoryStateContiguous(size_t* out_blocks_needed, KProcessAddress addr, size_t size,
KMemoryState state_mask, KMemoryState state,
KMemoryPermission perm_mask, KMemoryPermission perm,
KMemoryAttribute attr_mask, KMemoryAttribute attr) const;
- Result CheckMemoryStateContiguous(VAddr addr, size_t size, KMemoryState state_mask,
+ Result CheckMemoryStateContiguous(KProcessAddress addr, size_t size, KMemoryState state_mask,
KMemoryState state, KMemoryPermission perm_mask,
KMemoryPermission perm, KMemoryAttribute attr_mask,
KMemoryAttribute attr) const {
@@ -203,12 +248,12 @@ private:
KMemoryPermission perm_mask, KMemoryPermission perm,
KMemoryAttribute attr_mask, KMemoryAttribute attr) const;
Result CheckMemoryState(KMemoryState* out_state, KMemoryPermission* out_perm,
- KMemoryAttribute* out_attr, size_t* out_blocks_needed, VAddr addr,
- size_t size, KMemoryState state_mask, KMemoryState state,
- KMemoryPermission perm_mask, KMemoryPermission perm,
+ KMemoryAttribute* out_attr, size_t* out_blocks_needed,
+ KProcessAddress addr, size_t size, KMemoryState state_mask,
+ KMemoryState state, KMemoryPermission perm_mask, KMemoryPermission perm,
KMemoryAttribute attr_mask, KMemoryAttribute attr,
KMemoryAttribute ignore_attr = DefaultMemoryIgnoreAttr) const;
- Result CheckMemoryState(size_t* out_blocks_needed, VAddr addr, size_t size,
+ Result CheckMemoryState(size_t* out_blocks_needed, KProcessAddress addr, size_t size,
KMemoryState state_mask, KMemoryState state,
KMemoryPermission perm_mask, KMemoryPermission perm,
KMemoryAttribute attr_mask, KMemoryAttribute attr,
@@ -217,39 +262,40 @@ private:
state_mask, state, perm_mask, perm, attr_mask, attr,
ignore_attr));
}
- Result CheckMemoryState(VAddr addr, size_t size, KMemoryState state_mask, KMemoryState state,
- KMemoryPermission perm_mask, KMemoryPermission perm,
+ Result CheckMemoryState(KProcessAddress addr, size_t size, KMemoryState state_mask,
+ KMemoryState state, KMemoryPermission perm_mask, KMemoryPermission perm,
KMemoryAttribute attr_mask, KMemoryAttribute attr,
KMemoryAttribute ignore_attr = DefaultMemoryIgnoreAttr) const {
R_RETURN(this->CheckMemoryState(nullptr, addr, size, state_mask, state, perm_mask, perm,
attr_mask, attr, ignore_attr));
}
- Result LockMemoryAndOpen(KPageGroup* out_pg, PAddr* out_paddr, VAddr addr, size_t size,
- KMemoryState state_mask, KMemoryState state,
- KMemoryPermission perm_mask, KMemoryPermission perm,
- KMemoryAttribute attr_mask, KMemoryAttribute attr,
- KMemoryPermission new_perm, KMemoryAttribute lock_attr);
- Result UnlockMemory(VAddr addr, size_t size, KMemoryState state_mask, KMemoryState state,
- KMemoryPermission perm_mask, KMemoryPermission perm,
+ Result LockMemoryAndOpen(KPageGroup* out_pg, KPhysicalAddress* out_KPhysicalAddress,
+ KProcessAddress addr, size_t size, KMemoryState state_mask,
+ KMemoryState state, KMemoryPermission perm_mask,
+ KMemoryPermission perm, KMemoryAttribute attr_mask,
+ KMemoryAttribute attr, KMemoryPermission new_perm,
+ KMemoryAttribute lock_attr);
+ Result UnlockMemory(KProcessAddress addr, size_t size, KMemoryState state_mask,
+ KMemoryState state, KMemoryPermission perm_mask, KMemoryPermission perm,
KMemoryAttribute attr_mask, KMemoryAttribute attr,
KMemoryPermission new_perm, KMemoryAttribute lock_attr,
const KPageGroup* pg);
- Result MakePageGroup(KPageGroup& pg, VAddr addr, size_t num_pages);
- bool IsValidPageGroup(const KPageGroup& pg, VAddr addr, size_t num_pages);
+ Result MakePageGroup(KPageGroup& pg, KProcessAddress addr, size_t num_pages);
+ bool IsValidPageGroup(const KPageGroup& pg, KProcessAddress addr, size_t num_pages);
bool IsLockedByCurrentThread() const {
return m_general_lock.IsLockedByCurrentThread();
}
- bool IsHeapPhysicalAddress(const KMemoryLayout& layout, PAddr phys_addr) {
+ bool IsHeapPhysicalAddress(const KMemoryLayout& layout, KPhysicalAddress phys_addr) {
ASSERT(this->IsLockedByCurrentThread());
return layout.IsHeapPhysicalAddress(m_cached_physical_heap_region, phys_addr);
}
- bool GetPhysicalAddressLocked(PAddr* out, VAddr virt_addr) const {
+ bool GetPhysicalAddressLocked(KPhysicalAddress* out, KProcessAddress virt_addr) const {
ASSERT(this->IsLockedByCurrentThread());
*out = GetPhysicalAddr(virt_addr);
@@ -257,73 +303,79 @@ private:
return *out != 0;
}
- Result SetupForIpcClient(PageLinkedList* page_list, size_t* out_blocks_needed, VAddr address,
- size_t size, KMemoryPermission test_perm, KMemoryState dst_state);
- Result SetupForIpcServer(VAddr* out_addr, size_t size, VAddr src_addr,
+ Result SetupForIpcClient(PageLinkedList* page_list, size_t* out_blocks_needed,
+ KProcessAddress address, size_t size, KMemoryPermission test_perm,
+ KMemoryState dst_state);
+ Result SetupForIpcServer(KProcessAddress* out_addr, size_t size, KProcessAddress src_addr,
KMemoryPermission test_perm, KMemoryState dst_state,
KPageTable& src_page_table, bool send);
- void CleanupForIpcClientOnServerSetupFailure(PageLinkedList* page_list, VAddr address,
+ void CleanupForIpcClientOnServerSetupFailure(PageLinkedList* page_list, KProcessAddress address,
size_t size, KMemoryPermission prot_perm);
+ Result AllocateAndMapPagesImpl(PageLinkedList* page_list, KProcessAddress address,
+ size_t num_pages, KMemoryPermission perm);
+ Result MapPageGroupImpl(PageLinkedList* page_list, KProcessAddress address,
+ const KPageGroup& pg, const KPageProperties properties, bool reuse_ll);
+
mutable KLightLock m_general_lock;
mutable KLightLock m_map_physical_memory_lock;
public:
- constexpr VAddr GetAddressSpaceStart() const {
+ constexpr KProcessAddress GetAddressSpaceStart() const {
return m_address_space_start;
}
- constexpr VAddr GetAddressSpaceEnd() const {
+ constexpr KProcessAddress GetAddressSpaceEnd() const {
return m_address_space_end;
}
constexpr size_t GetAddressSpaceSize() const {
return m_address_space_end - m_address_space_start;
}
- constexpr VAddr GetHeapRegionStart() const {
+ constexpr KProcessAddress GetHeapRegionStart() const {
return m_heap_region_start;
}
- constexpr VAddr GetHeapRegionEnd() const {
+ constexpr KProcessAddress GetHeapRegionEnd() const {
return m_heap_region_end;
}
constexpr size_t GetHeapRegionSize() const {
return m_heap_region_end - m_heap_region_start;
}
- constexpr VAddr GetAliasRegionStart() const {
+ constexpr KProcessAddress GetAliasRegionStart() const {
return m_alias_region_start;
}
- constexpr VAddr GetAliasRegionEnd() const {
+ constexpr KProcessAddress GetAliasRegionEnd() const {
return m_alias_region_end;
}
constexpr size_t GetAliasRegionSize() const {
return m_alias_region_end - m_alias_region_start;
}
- constexpr VAddr GetStackRegionStart() const {
+ constexpr KProcessAddress GetStackRegionStart() const {
return m_stack_region_start;
}
- constexpr VAddr GetStackRegionEnd() const {
+ constexpr KProcessAddress GetStackRegionEnd() const {
return m_stack_region_end;
}
constexpr size_t GetStackRegionSize() const {
return m_stack_region_end - m_stack_region_start;
}
- constexpr VAddr GetKernelMapRegionStart() const {
+ constexpr KProcessAddress GetKernelMapRegionStart() const {
return m_kernel_map_region_start;
}
- constexpr VAddr GetKernelMapRegionEnd() const {
+ constexpr KProcessAddress GetKernelMapRegionEnd() const {
return m_kernel_map_region_end;
}
- constexpr VAddr GetCodeRegionStart() const {
+ constexpr KProcessAddress GetCodeRegionStart() const {
return m_code_region_start;
}
- constexpr VAddr GetCodeRegionEnd() const {
+ constexpr KProcessAddress GetCodeRegionEnd() const {
return m_code_region_end;
}
- constexpr VAddr GetAliasCodeRegionStart() const {
+ constexpr KProcessAddress GetAliasCodeRegionStart() const {
return m_alias_code_region_start;
}
- constexpr VAddr GetAliasCodeRegionEnd() const {
+ constexpr KProcessAddress GetAliasCodeRegionEnd() const {
return m_alias_code_region_end;
}
- constexpr VAddr GetAliasCodeRegionSize() const {
+ constexpr size_t GetAliasCodeRegionSize() const {
return m_alias_code_region_end - m_alias_code_region_start;
}
size_t GetNormalMemorySize() {
@@ -336,25 +388,25 @@ public:
constexpr size_t GetHeapSize() const {
return m_current_heap_end - m_heap_region_start;
}
- constexpr bool IsInsideAddressSpace(VAddr address, size_t size) const {
+ constexpr bool IsInsideAddressSpace(KProcessAddress address, size_t size) const {
return m_address_space_start <= address && address + size - 1 <= m_address_space_end - 1;
}
- constexpr bool IsOutsideAliasRegion(VAddr address, size_t size) const {
+ constexpr bool IsOutsideAliasRegion(KProcessAddress address, size_t size) const {
return m_alias_region_start > address || address + size - 1 > m_alias_region_end - 1;
}
- constexpr bool IsOutsideStackRegion(VAddr address, size_t size) const {
+ constexpr bool IsOutsideStackRegion(KProcessAddress address, size_t size) const {
return m_stack_region_start > address || address + size - 1 > m_stack_region_end - 1;
}
- constexpr bool IsInvalidRegion(VAddr address, size_t size) const {
+ constexpr bool IsInvalidRegion(KProcessAddress address, size_t size) const {
return address + size - 1 > GetAliasCodeRegionStart() + GetAliasCodeRegionSize() - 1;
}
- constexpr bool IsInsideHeapRegion(VAddr address, size_t size) const {
+ constexpr bool IsInsideHeapRegion(KProcessAddress address, size_t size) const {
return address + size > m_heap_region_start && m_heap_region_end > address;
}
- constexpr bool IsInsideAliasRegion(VAddr address, size_t size) const {
+ constexpr bool IsInsideAliasRegion(KProcessAddress address, size_t size) const {
return address + size > m_alias_region_start && m_alias_region_end > address;
}
- constexpr bool IsOutsideASLRRegion(VAddr address, size_t size) const {
+ constexpr bool IsOutsideASLRRegion(KProcessAddress address, size_t size) const {
if (IsInvalidRegion(address, size)) {
return true;
}
@@ -366,47 +418,53 @@ public:
}
return {};
}
- constexpr bool IsInsideASLRRegion(VAddr address, size_t size) const {
+ constexpr bool IsInsideASLRRegion(KProcessAddress address, size_t size) const {
return !IsOutsideASLRRegion(address, size);
}
constexpr size_t GetNumGuardPages() const {
return IsKernel() ? 1 : 4;
}
- PAddr GetPhysicalAddr(VAddr addr) const {
+ KPhysicalAddress GetPhysicalAddr(KProcessAddress addr) const {
const auto backing_addr = m_page_table_impl->backing_addr[addr >> PageBits];
ASSERT(backing_addr);
- return backing_addr + addr;
+ return backing_addr + GetInteger(addr);
}
- constexpr bool Contains(VAddr addr) const {
+ constexpr bool Contains(KProcessAddress addr) const {
return m_address_space_start <= addr && addr <= m_address_space_end - 1;
}
- constexpr bool Contains(VAddr addr, size_t size) const {
+ constexpr bool Contains(KProcessAddress addr, size_t size) const {
return m_address_space_start <= addr && addr < addr + size &&
addr + size - 1 <= m_address_space_end - 1;
}
public:
- static VAddr GetLinearMappedVirtualAddress(const KMemoryLayout& layout, PAddr addr) {
+ static KVirtualAddress GetLinearMappedVirtualAddress(const KMemoryLayout& layout,
+ KPhysicalAddress addr) {
return layout.GetLinearVirtualAddress(addr);
}
- static PAddr GetLinearMappedPhysicalAddress(const KMemoryLayout& layout, VAddr addr) {
+ static KPhysicalAddress GetLinearMappedPhysicalAddress(const KMemoryLayout& layout,
+ KVirtualAddress addr) {
return layout.GetLinearPhysicalAddress(addr);
}
- static VAddr GetHeapVirtualAddress(const KMemoryLayout& layout, PAddr addr) {
+ static KVirtualAddress GetHeapVirtualAddress(const KMemoryLayout& layout,
+ KPhysicalAddress addr) {
return GetLinearMappedVirtualAddress(layout, addr);
}
- static PAddr GetHeapPhysicalAddress(const KMemoryLayout& layout, VAddr addr) {
+ static KPhysicalAddress GetHeapPhysicalAddress(const KMemoryLayout& layout,
+ KVirtualAddress addr) {
return GetLinearMappedPhysicalAddress(layout, addr);
}
- static VAddr GetPageTableVirtualAddress(const KMemoryLayout& layout, PAddr addr) {
+ static KVirtualAddress GetPageTableVirtualAddress(const KMemoryLayout& layout,
+ KPhysicalAddress addr) {
return GetLinearMappedVirtualAddress(layout, addr);
}
- static PAddr GetPageTablePhysicalAddress(const KMemoryLayout& layout, VAddr addr) {
+ static KPhysicalAddress GetPageTablePhysicalAddress(const KMemoryLayout& layout,
+ KVirtualAddress addr) {
return GetLinearMappedPhysicalAddress(layout, addr);
}
@@ -418,7 +476,7 @@ private:
return m_enable_aslr;
}
- constexpr bool ContainsPages(VAddr addr, size_t num_pages) const {
+ constexpr bool ContainsPages(KProcessAddress addr, size_t num_pages) const {
return (m_address_space_start <= addr) &&
(num_pages <= (m_address_space_end - m_address_space_start) / PageSize) &&
(addr + num_pages * PageSize - 1 <= m_address_space_end - 1);
@@ -438,26 +496,26 @@ private:
}
PageLinkedList* GetPageList() {
- return &m_ll;
+ return std::addressof(m_ll);
}
};
private:
- VAddr m_address_space_start{};
- VAddr m_address_space_end{};
- VAddr m_heap_region_start{};
- VAddr m_heap_region_end{};
- VAddr m_current_heap_end{};
- VAddr m_alias_region_start{};
- VAddr m_alias_region_end{};
- VAddr m_stack_region_start{};
- VAddr m_stack_region_end{};
- VAddr m_kernel_map_region_start{};
- VAddr m_kernel_map_region_end{};
- VAddr m_code_region_start{};
- VAddr m_code_region_end{};
- VAddr m_alias_code_region_start{};
- VAddr m_alias_code_region_end{};
+ KProcessAddress m_address_space_start{};
+ KProcessAddress m_address_space_end{};
+ KProcessAddress m_heap_region_start{};
+ KProcessAddress m_heap_region_end{};
+ KProcessAddress m_current_heap_end{};
+ KProcessAddress m_alias_region_start{};
+ KProcessAddress m_alias_region_end{};
+ KProcessAddress m_stack_region_start{};
+ KProcessAddress m_stack_region_end{};
+ KProcessAddress m_kernel_map_region_start{};
+ KProcessAddress m_kernel_map_region_end{};
+ KProcessAddress m_code_region_start{};
+ KProcessAddress m_code_region_end{};
+ KProcessAddress m_alias_code_region_start{};
+ KProcessAddress m_alias_code_region_end{};
size_t m_max_heap_size{};
size_t m_mapped_physical_memory_size{};
@@ -489,6 +547,7 @@ private:
Core::System& m_system;
KernelCore& m_kernel;
+ Core::Memory::Memory* m_memory{};
};
} // namespace Kernel
diff --git a/src/core/hle/kernel/k_page_table_manager.h b/src/core/hle/kernel/k_page_table_manager.h
index 91a45cde3..4b0e034d0 100644
--- a/src/core/hle/kernel/k_page_table_manager.h
+++ b/src/core/hle/kernel/k_page_table_manager.h
@@ -5,9 +5,9 @@
#include <atomic>
-#include "common/common_types.h"
#include "core/hle/kernel/k_dynamic_resource_manager.h"
#include "core/hle/kernel/k_page_table_slab_heap.h"
+#include "core/hle/kernel/k_typed_address.h"
namespace Kernel {
@@ -26,23 +26,23 @@ public:
BaseHeap::Initialize(page_allocator, pt_heap);
}
- VAddr Allocate() {
- return VAddr(BaseHeap::Allocate());
+ KVirtualAddress Allocate() {
+ return KVirtualAddress(BaseHeap::Allocate());
}
- RefCount GetRefCount(VAddr addr) const {
+ RefCount GetRefCount(KVirtualAddress addr) const {
return m_pt_heap->GetRefCount(addr);
}
- void Open(VAddr addr, int count) {
+ void Open(KVirtualAddress addr, int count) {
return m_pt_heap->Open(addr, count);
}
- bool Close(VAddr addr, int count) {
+ bool Close(KVirtualAddress addr, int count) {
return m_pt_heap->Close(addr, count);
}
- bool IsInPageTableHeap(VAddr addr) const {
+ bool IsInPageTableHeap(KVirtualAddress addr) const {
return m_pt_heap->IsInRange(addr);
}
diff --git a/src/core/hle/kernel/k_page_table_slab_heap.h b/src/core/hle/kernel/k_page_table_slab_heap.h
index a9543cbd0..7da0ea669 100644
--- a/src/core/hle/kernel/k_page_table_slab_heap.h
+++ b/src/core/hle/kernel/k_page_table_slab_heap.h
@@ -6,8 +6,8 @@
#include <array>
#include <vector>
-#include "common/common_types.h"
#include "core/hle/kernel/k_dynamic_slab_heap.h"
+#include "core/hle/kernel/k_typed_address.h"
#include "core/hle/kernel/slab_helpers.h"
namespace Kernel {
@@ -20,7 +20,8 @@ public:
PageTablePage() = default;
private:
- std::array<u8, PageSize> m_buffer{};
+ // Initializer intentionally skipped
+ std::array<u8, PageSize> m_buffer;
};
static_assert(sizeof(PageTablePage) == PageSize);
@@ -44,12 +45,12 @@ public:
this->Initialize(rc);
}
- RefCount GetRefCount(VAddr addr) {
+ RefCount GetRefCount(KVirtualAddress addr) {
ASSERT(this->IsInRange(addr));
return *this->GetRefCountPointer(addr);
}
- void Open(VAddr addr, int count) {
+ void Open(KVirtualAddress addr, int count) {
ASSERT(this->IsInRange(addr));
*this->GetRefCountPointer(addr) += static_cast<RefCount>(count);
@@ -57,7 +58,7 @@ public:
ASSERT(this->GetRefCount(addr) > 0);
}
- bool Close(VAddr addr, int count) {
+ bool Close(KVirtualAddress addr, int count) {
ASSERT(this->IsInRange(addr));
ASSERT(this->GetRefCount(addr) >= count);
@@ -65,7 +66,7 @@ public:
return this->GetRefCount(addr) == 0;
}
- bool IsInPageTableHeap(VAddr addr) const {
+ bool IsInPageTableHeap(KVirtualAddress addr) const {
return this->IsInRange(addr);
}
@@ -80,7 +81,7 @@ private:
}
}
- RefCount* GetRefCountPointer(VAddr addr) {
+ RefCount* GetRefCountPointer(KVirtualAddress addr) {
return m_ref_counts.data() + ((addr - this->GetAddress()) / PageSize);
}
diff --git a/src/core/hle/kernel/k_port.cpp b/src/core/hle/kernel/k_port.cpp
index 77d00ae2c..1621ca1d3 100644
--- a/src/core/hle/kernel/k_port.cpp
+++ b/src/core/hle/kernel/k_port.cpp
@@ -1,63 +1,61 @@
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
-#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(KernelCore& kernel)
+ : KAutoObjectWithSlabHeapAndContainer{kernel}, m_server{kernel}, m_client{kernel} {}
KPort::~KPort() = default;
-void KPort::Initialize(s32 max_sessions_, bool is_light_, const std::string& name_) {
+void KPort::Initialize(s32 max_sessions, bool is_light, uintptr_t name) {
// Open a new reference count to the initialized port.
- Open();
+ this->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");
+ KAutoObject::Create(std::addressof(m_server));
+ KAutoObject::Create(std::addressof(m_client));
+ m_server.Initialize(this);
+ m_client.Initialize(this, max_sessions);
// Set our member variables.
- is_light = is_light_;
- name = name_;
- state = State::Normal;
+ m_is_light = is_light;
+ m_name = name;
+ m_state = State::Normal;
}
void KPort::OnClientClosed() {
- KScopedSchedulerLock sl{kernel};
+ KScopedSchedulerLock sl{m_kernel};
- if (state == State::Normal) {
- state = State::ClientClosed;
+ if (m_state == State::Normal) {
+ m_state = State::ClientClosed;
}
}
void KPort::OnServerClosed() {
- KScopedSchedulerLock sl{kernel};
+ KScopedSchedulerLock sl{m_kernel};
- if (state == State::Normal) {
- state = State::ServerClosed;
+ if (m_state == State::Normal) {
+ m_state = State::ServerClosed;
}
}
bool KPort::IsServerClosed() const {
- KScopedSchedulerLock sl{kernel};
- return state == State::ServerClosed;
+ KScopedSchedulerLock sl{m_kernel};
+ return m_state == State::ServerClosed;
}
Result KPort::EnqueueSession(KServerSession* session) {
- KScopedSchedulerLock sl{kernel};
+ KScopedSchedulerLock sl{m_kernel};
- R_UNLESS(state == State::Normal, ResultPortClosed);
+ R_UNLESS(m_state == State::Normal, ResultPortClosed);
- server.EnqueueSession(session);
-
- return ResultSuccess;
+ m_server.EnqueueSession(session);
+ R_SUCCEED();
}
} // namespace Kernel
diff --git a/src/core/hle/kernel/k_port.h b/src/core/hle/kernel/k_port.h
index 0cfc16dab..991be27ab 100644
--- a/src/core/hle/kernel/k_port.h
+++ b/src/core/hle/kernel/k_port.h
@@ -19,17 +19,20 @@ class KPort final : public KAutoObjectWithSlabHeapAndContainer<KPort, KAutoObjec
KERNEL_AUTOOBJECT_TRAITS(KPort, KAutoObject);
public:
- explicit KPort(KernelCore& kernel_);
+ explicit KPort(KernelCore& kernel);
~KPort() override;
- static void PostDestroy([[maybe_unused]] uintptr_t arg) {}
+ static void PostDestroy(uintptr_t arg) {}
- void Initialize(s32 max_sessions_, bool is_light_, const std::string& name_);
+ void Initialize(s32 max_sessions, bool is_light, uintptr_t name);
void OnClientClosed();
void OnServerClosed();
+ uintptr_t GetName() const {
+ return m_name;
+ }
bool IsLight() const {
- return is_light;
+ return m_is_light;
}
bool IsServerClosed() const;
@@ -37,16 +40,16 @@ public:
Result EnqueueSession(KServerSession* session);
KClientPort& GetClientPort() {
- return client;
+ return m_client;
}
KServerPort& GetServerPort() {
- return server;
+ return m_server;
}
const KClientPort& GetClientPort() const {
- return client;
+ return m_client;
}
const KServerPort& GetServerPort() const {
- return server;
+ return m_server;
}
private:
@@ -57,10 +60,11 @@ private:
ServerClosed = 3,
};
- KServerPort server;
- KClientPort client;
- State state{State::Invalid};
- bool is_light{};
+ KServerPort m_server;
+ KClientPort m_client;
+ uintptr_t m_name;
+ State m_state{State::Invalid};
+ bool m_is_light{};
};
} // namespace Kernel
diff --git a/src/core/hle/kernel/k_priority_queue.h b/src/core/hle/kernel/k_priority_queue.h
index cb2512b0b..26677ec65 100644
--- a/src/core/hle/kernel/k_priority_queue.h
+++ b/src/core/hle/kernel/k_priority_queue.h
@@ -17,35 +17,41 @@ namespace Kernel {
class KThread;
template <typename T>
-concept KPriorityQueueAffinityMask = !std::is_reference_v<T> && requires(T & t) {
- { t.GetAffinityMask() } -> Common::ConvertibleTo<u64>;
- {t.SetAffinityMask(0)};
+concept KPriorityQueueAffinityMask = !
+std::is_reference_v<T>&& requires(T& t) {
+ { t.GetAffinityMask() } -> Common::ConvertibleTo<u64>;
+ { t.SetAffinityMask(0) };
- { t.GetAffinity(0) } -> std::same_as<bool>;
- {t.SetAffinity(0, false)};
- {t.SetAll()};
-};
+ { t.GetAffinity(0) } -> std::same_as<bool>;
+ { t.SetAffinity(0, false) };
+ { t.SetAll() };
+ };
template <typename T>
-concept KPriorityQueueMember = !std::is_reference_v<T> && requires(T & t) {
- {typename T::QueueEntry()};
- {(typename T::QueueEntry()).Initialize()};
- {(typename T::QueueEntry()).SetPrev(std::addressof(t))};
- {(typename T::QueueEntry()).SetNext(std::addressof(t))};
- { (typename T::QueueEntry()).GetNext() } -> std::same_as<T*>;
- { (typename T::QueueEntry()).GetPrev() } -> std::same_as<T*>;
- { t.GetPriorityQueueEntry(0) } -> std::same_as<typename T::QueueEntry&>;
-
- {t.GetAffinityMask()};
- { std::remove_cvref_t<decltype(t.GetAffinityMask())>() } -> KPriorityQueueAffinityMask;
-
- { t.GetActiveCore() } -> Common::ConvertibleTo<s32>;
- { t.GetPriority() } -> Common::ConvertibleTo<s32>;
- { t.IsDummyThread() } -> Common::ConvertibleTo<bool>;
-};
+concept KPriorityQueueMember = !
+std::is_reference_v<T>&& requires(T& t) {
+ { typename T::QueueEntry() };
+ { (typename T::QueueEntry()).Initialize() };
+ { (typename T::QueueEntry()).SetPrev(std::addressof(t)) };
+ { (typename T::QueueEntry()).SetNext(std::addressof(t)) };
+ { (typename T::QueueEntry()).GetNext() } -> std::same_as<T*>;
+ { (typename T::QueueEntry()).GetPrev() } -> std::same_as<T*>;
+ {
+ t.GetPriorityQueueEntry(0)
+ } -> std::same_as<typename T::QueueEntry&>;
+
+ { t.GetAffinityMask() };
+ {
+ std::remove_cvref_t<decltype(t.GetAffinityMask())>()
+ } -> KPriorityQueueAffinityMask;
+
+ { t.GetActiveCore() } -> Common::ConvertibleTo<s32>;
+ { t.GetPriority() } -> Common::ConvertibleTo<s32>;
+ { t.IsDummyThread() } -> Common::ConvertibleTo<bool>;
+ };
template <typename Member, size_t NumCores_, int LowestPriority, int HighestPriority>
-requires KPriorityQueueMember<Member>
+ requires KPriorityQueueMember<Member>
class KPriorityQueue {
public:
using AffinityMaskType = std::remove_cv_t<
@@ -71,11 +77,11 @@ private:
public:
class KPerCoreQueue {
private:
- std::array<Entry, NumCores> root{};
+ std::array<Entry, NumCores> m_root{};
public:
constexpr KPerCoreQueue() {
- for (auto& per_core_root : root) {
+ for (auto& per_core_root : m_root) {
per_core_root.Initialize();
}
}
@@ -85,15 +91,15 @@ public:
Entry& member_entry = member->GetPriorityQueueEntry(core);
// Get the entry associated with the end of the queue.
- Member* tail = this->root[core].GetPrev();
+ Member* tail = m_root[core].GetPrev();
Entry& tail_entry =
- (tail != nullptr) ? tail->GetPriorityQueueEntry(core) : this->root[core];
+ (tail != nullptr) ? tail->GetPriorityQueueEntry(core) : m_root[core];
// Link the entries.
member_entry.SetPrev(tail);
member_entry.SetNext(nullptr);
tail_entry.SetNext(member);
- this->root[core].SetPrev(member);
+ m_root[core].SetPrev(member);
return tail == nullptr;
}
@@ -103,15 +109,15 @@ public:
Entry& member_entry = member->GetPriorityQueueEntry(core);
// Get the entry associated with the front of the queue.
- Member* head = this->root[core].GetNext();
+ Member* head = m_root[core].GetNext();
Entry& head_entry =
- (head != nullptr) ? head->GetPriorityQueueEntry(core) : this->root[core];
+ (head != nullptr) ? head->GetPriorityQueueEntry(core) : m_root[core];
// Link the entries.
member_entry.SetPrev(nullptr);
member_entry.SetNext(head);
head_entry.SetPrev(member);
- this->root[core].SetNext(member);
+ m_root[core].SetNext(member);
return (head == nullptr);
}
@@ -124,9 +130,9 @@ public:
Member* prev = member_entry.GetPrev();
Member* next = member_entry.GetNext();
Entry& prev_entry =
- (prev != nullptr) ? prev->GetPriorityQueueEntry(core) : this->root[core];
+ (prev != nullptr) ? prev->GetPriorityQueueEntry(core) : m_root[core];
Entry& next_entry =
- (next != nullptr) ? next->GetPriorityQueueEntry(core) : this->root[core];
+ (next != nullptr) ? next->GetPriorityQueueEntry(core) : m_root[core];
// Unlink.
prev_entry.SetNext(next);
@@ -136,7 +142,7 @@ public:
}
constexpr Member* GetFront(s32 core) const {
- return this->root[core].GetNext();
+ return m_root[core].GetNext();
}
};
@@ -152,8 +158,8 @@ public:
return;
}
- if (this->queues[priority].PushBack(core, member)) {
- this->available_priorities[core].SetBit(priority);
+ if (m_queues[priority].PushBack(core, member)) {
+ m_available_priorities[core].SetBit(priority);
}
}
@@ -165,8 +171,8 @@ public:
return;
}
- if (this->queues[priority].PushFront(core, member)) {
- this->available_priorities[core].SetBit(priority);
+ if (m_queues[priority].PushFront(core, member)) {
+ m_available_priorities[core].SetBit(priority);
}
}
@@ -178,18 +184,17 @@ public:
return;
}
- if (this->queues[priority].Remove(core, member)) {
- this->available_priorities[core].ClearBit(priority);
+ if (m_queues[priority].Remove(core, member)) {
+ m_available_priorities[core].ClearBit(priority);
}
}
constexpr Member* GetFront(s32 core) const {
ASSERT(IsValidCore(core));
- const s32 priority =
- static_cast<s32>(this->available_priorities[core].CountLeadingZero());
+ const s32 priority = static_cast<s32>(m_available_priorities[core].CountLeadingZero());
if (priority <= LowestPriority) {
- return this->queues[priority].GetFront(core);
+ return m_queues[priority].GetFront(core);
} else {
return nullptr;
}
@@ -200,7 +205,7 @@ public:
ASSERT(IsValidPriority(priority));
if (priority <= LowestPriority) {
- return this->queues[priority].GetFront(core);
+ return m_queues[priority].GetFront(core);
} else {
return nullptr;
}
@@ -212,9 +217,9 @@ public:
Member* next = member->GetPriorityQueueEntry(core).GetNext();
if (next == nullptr) {
const s32 priority = static_cast<s32>(
- this->available_priorities[core].GetNextSet(member->GetPriority()));
+ m_available_priorities[core].GetNextSet(member->GetPriority()));
if (priority <= LowestPriority) {
- next = this->queues[priority].GetFront(core);
+ next = m_queues[priority].GetFront(core);
}
}
return next;
@@ -225,8 +230,8 @@ public:
ASSERT(IsValidPriority(priority));
if (priority <= LowestPriority) {
- this->queues[priority].Remove(core, member);
- this->queues[priority].PushFront(core, member);
+ m_queues[priority].Remove(core, member);
+ m_queues[priority].PushFront(core, member);
}
}
@@ -235,29 +240,29 @@ public:
ASSERT(IsValidPriority(priority));
if (priority <= LowestPriority) {
- this->queues[priority].Remove(core, member);
- this->queues[priority].PushBack(core, member);
- return this->queues[priority].GetFront(core);
+ m_queues[priority].Remove(core, member);
+ m_queues[priority].PushBack(core, member);
+ return m_queues[priority].GetFront(core);
} else {
return nullptr;
}
}
private:
- std::array<KPerCoreQueue, NumPriority> queues{};
- std::array<Common::BitSet64<NumPriority>, NumCores> available_priorities{};
+ std::array<KPerCoreQueue, NumPriority> m_queues{};
+ std::array<Common::BitSet64<NumPriority>, NumCores> m_available_priorities{};
};
private:
- KPriorityQueueImpl scheduled_queue;
- KPriorityQueueImpl suggested_queue;
+ KPriorityQueueImpl m_scheduled_queue;
+ KPriorityQueueImpl m_suggested_queue;
private:
- constexpr void ClearAffinityBit(u64& affinity, s32 core) {
+ static constexpr void ClearAffinityBit(u64& affinity, s32 core) {
affinity &= ~(UINT64_C(1) << core);
}
- constexpr s32 GetNextCore(u64& affinity) {
+ static constexpr s32 GetNextCore(u64& affinity) {
const s32 core = std::countr_zero(affinity);
ClearAffinityBit(affinity, core);
return core;
@@ -269,13 +274,13 @@ private:
// Push onto the scheduled queue for its core, if we can.
u64 affinity = member->GetAffinityMask().GetAffinityMask();
if (const s32 core = member->GetActiveCore(); core >= 0) {
- this->scheduled_queue.PushBack(priority, core, member);
+ m_scheduled_queue.PushBack(priority, core, member);
ClearAffinityBit(affinity, core);
}
// And suggest the thread for all other cores.
while (affinity) {
- this->suggested_queue.PushBack(priority, GetNextCore(affinity), member);
+ m_suggested_queue.PushBack(priority, GetNextCore(affinity), member);
}
}
@@ -285,14 +290,14 @@ private:
// Push onto the scheduled queue for its core, if we can.
u64 affinity = member->GetAffinityMask().GetAffinityMask();
if (const s32 core = member->GetActiveCore(); core >= 0) {
- this->scheduled_queue.PushFront(priority, core, member);
+ m_scheduled_queue.PushFront(priority, core, member);
ClearAffinityBit(affinity, core);
}
// And suggest the thread for all other cores.
// Note: Nintendo pushes onto the back of the suggested queue, not the front.
while (affinity) {
- this->suggested_queue.PushBack(priority, GetNextCore(affinity), member);
+ m_suggested_queue.PushBack(priority, GetNextCore(affinity), member);
}
}
@@ -302,13 +307,13 @@ private:
// Remove from the scheduled queue for its core.
u64 affinity = member->GetAffinityMask().GetAffinityMask();
if (const s32 core = member->GetActiveCore(); core >= 0) {
- this->scheduled_queue.Remove(priority, core, member);
+ m_scheduled_queue.Remove(priority, core, member);
ClearAffinityBit(affinity, core);
}
// Remove from the suggested queue for all other cores.
while (affinity) {
- this->suggested_queue.Remove(priority, GetNextCore(affinity), member);
+ m_suggested_queue.Remove(priority, GetNextCore(affinity), member);
}
}
@@ -317,27 +322,27 @@ public:
// Getters.
constexpr Member* GetScheduledFront(s32 core) const {
- return this->scheduled_queue.GetFront(core);
+ return m_scheduled_queue.GetFront(core);
}
constexpr Member* GetScheduledFront(s32 core, s32 priority) const {
- return this->scheduled_queue.GetFront(priority, core);
+ return m_scheduled_queue.GetFront(priority, core);
}
constexpr Member* GetSuggestedFront(s32 core) const {
- return this->suggested_queue.GetFront(core);
+ return m_suggested_queue.GetFront(core);
}
constexpr Member* GetSuggestedFront(s32 core, s32 priority) const {
- return this->suggested_queue.GetFront(priority, core);
+ return m_suggested_queue.GetFront(priority, core);
}
constexpr Member* GetScheduledNext(s32 core, const Member* member) const {
- return this->scheduled_queue.GetNext(core, member);
+ return m_scheduled_queue.GetNext(core, member);
}
constexpr Member* GetSuggestedNext(s32 core, const Member* member) const {
- return this->suggested_queue.GetNext(core, member);
+ return m_suggested_queue.GetNext(core, member);
}
constexpr Member* GetSamePriorityNext(s32 core, const Member* member) const {
@@ -369,7 +374,7 @@ public:
return;
}
- this->scheduled_queue.MoveToFront(member->GetPriority(), member->GetActiveCore(), member);
+ m_scheduled_queue.MoveToFront(member->GetPriority(), member->GetActiveCore(), member);
}
constexpr KThread* MoveToScheduledBack(Member* member) {
@@ -378,8 +383,7 @@ public:
return {};
}
- return this->scheduled_queue.MoveToBack(member->GetPriority(), member->GetActiveCore(),
- member);
+ return m_scheduled_queue.MoveToBack(member->GetPriority(), member->GetActiveCore(), member);
}
// First class fancy operations.
@@ -419,9 +423,9 @@ public:
for (s32 core = 0; core < static_cast<s32>(NumCores); core++) {
if (prev_affinity.GetAffinity(core)) {
if (core == prev_core) {
- this->scheduled_queue.Remove(priority, core, member);
+ m_scheduled_queue.Remove(priority, core, member);
} else {
- this->suggested_queue.Remove(priority, core, member);
+ m_suggested_queue.Remove(priority, core, member);
}
}
}
@@ -430,9 +434,9 @@ public:
for (s32 core = 0; core < static_cast<s32>(NumCores); core++) {
if (new_affinity.GetAffinity(core)) {
if (core == new_core) {
- this->scheduled_queue.PushBack(priority, core, member);
+ m_scheduled_queue.PushBack(priority, core, member);
} else {
- this->suggested_queue.PushBack(priority, core, member);
+ m_suggested_queue.PushBack(priority, core, member);
}
}
}
@@ -452,22 +456,22 @@ public:
if (prev_core != new_core) {
// Remove from the scheduled queue for the previous core.
if (prev_core >= 0) {
- this->scheduled_queue.Remove(priority, prev_core, member);
+ m_scheduled_queue.Remove(priority, prev_core, member);
}
// Remove from the suggested queue and add to the scheduled queue for the new core.
if (new_core >= 0) {
- this->suggested_queue.Remove(priority, new_core, member);
+ m_suggested_queue.Remove(priority, new_core, member);
if (to_front) {
- this->scheduled_queue.PushFront(priority, new_core, member);
+ m_scheduled_queue.PushFront(priority, new_core, member);
} else {
- this->scheduled_queue.PushBack(priority, new_core, member);
+ m_scheduled_queue.PushBack(priority, new_core, member);
}
}
// Add to the suggested queue for the previous core.
if (prev_core >= 0) {
- this->suggested_queue.PushBack(priority, prev_core, member);
+ m_suggested_queue.PushBack(priority, prev_core, member);
}
}
}
diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp
index a1abf5d68..efe86ad27 100644
--- a/src/core/hle/kernel/k_process.cpp
+++ b/src/core/hle/kernel/k_process.cpp
@@ -36,22 +36,23 @@ 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, KProcess& owner_process, u32 priority, VAddr stack_top) {
- const VAddr entry_point = owner_process.PageTable().GetCodeRegionStart();
+void SetupMainThread(Core::System& system, KProcess& owner_process, u32 priority,
+ KProcessAddress stack_top) {
+ const KProcessAddress entry_point = owner_process.PageTable().GetCodeRegionStart();
ASSERT(owner_process.GetResourceLimit()->Reserve(LimitableResource::ThreadCountMax, 1));
KThread* thread = KThread::Create(system.Kernel());
SCOPE_EXIT({ thread->Close(); });
ASSERT(KThread::InitializeUserThread(system, thread, entry_point, 0, stack_top, priority,
- owner_process.GetIdealCoreId(), &owner_process)
+ owner_process.GetIdealCoreId(),
+ std::addressof(owner_process))
.IsSuccess());
// Register 1 must be a handle to the main thread
Handle thread_handle{};
- owner_process.GetHandleTable().Add(&thread_handle, thread);
+ owner_process.GetHandleTable().Add(std::addressof(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;
@@ -71,32 +72,32 @@ Result KProcess::Initialize(KProcess* process, Core::System& system, std::string
auto& kernel = system.Kernel();
process->name = std::move(process_name);
- process->resource_limit = res_limit;
- process->system_resource_address = 0;
- process->state = State::Created;
- process->program_id = 0;
- process->process_id = type == ProcessType::KernelInternal ? kernel.CreateNewKernelProcessID()
- : kernel.CreateNewUserProcessID();
- process->capabilities.InitializeForMetadatalessProcess();
- process->is_initialized = true;
+ process->m_resource_limit = res_limit;
+ process->m_system_resource_address = 0;
+ process->m_state = State::Created;
+ process->m_program_id = 0;
+ process->m_process_id = type == ProcessType::KernelInternal ? kernel.CreateNewKernelProcessID()
+ : kernel.CreateNewUserProcessID();
+ process->m_capabilities.InitializeForMetadatalessProcess();
+ process->m_is_initialized = true;
std::mt19937 rng(Settings::values.rng_seed.GetValue().value_or(std::time(nullptr)));
std::uniform_int_distribution<u64> distribution;
- std::generate(process->random_entropy.begin(), process->random_entropy.end(),
+ std::generate(process->m_random_entropy.begin(), process->m_random_entropy.end(),
[&] { return distribution(rng); });
kernel.AppendNewProcess(process);
// Clear remaining fields.
- process->num_running_threads = 0;
- process->is_signaled = false;
- process->exception_thread = nullptr;
- process->is_suspended = false;
- process->schedule_count = 0;
- process->is_handle_table_initialized = false;
+ process->m_num_running_threads = 0;
+ process->m_is_signaled = false;
+ process->m_exception_thread = nullptr;
+ process->m_is_suspended = false;
+ process->m_schedule_count = 0;
+ process->m_is_handle_table_initialized = false;
// Open a reference to the resource limit.
- process->resource_limit->Open();
+ process->m_resource_limit->Open();
R_SUCCEED();
}
@@ -106,66 +107,65 @@ void KProcess::DoWorkerTaskImpl() {
}
KResourceLimit* KProcess::GetResourceLimit() const {
- return resource_limit;
+ return m_resource_limit;
}
void KProcess::IncrementRunningThreadCount() {
- ASSERT(num_running_threads.load() >= 0);
- ++num_running_threads;
+ ASSERT(m_num_running_threads.load() >= 0);
+ ++m_num_running_threads;
}
void KProcess::DecrementRunningThreadCount() {
- ASSERT(num_running_threads.load() > 0);
+ ASSERT(m_num_running_threads.load() > 0);
- if (const auto prev = num_running_threads--; prev == 1) {
+ if (const auto prev = m_num_running_threads--; prev == 1) {
// TODO(bunnei): Process termination to be implemented when multiprocess is supported.
- UNIMPLEMENTED_MSG("KProcess termination is not implemennted!");
}
}
u64 KProcess::GetTotalPhysicalMemoryAvailable() {
- const u64 capacity{resource_limit->GetFreeValue(LimitableResource::PhysicalMemoryMax) +
- page_table.GetNormalMemorySize() + GetSystemResourceSize() + image_size +
- main_thread_stack_size};
- if (const auto pool_size = kernel.MemoryManager().GetSize(KMemoryManager::Pool::Application);
+ const u64 capacity{m_resource_limit->GetFreeValue(LimitableResource::PhysicalMemoryMax) +
+ m_page_table.GetNormalMemorySize() + GetSystemResourceSize() + m_image_size +
+ m_main_thread_stack_size};
+ if (const auto pool_size = m_kernel.MemoryManager().GetSize(KMemoryManager::Pool::Application);
capacity != pool_size) {
LOG_WARNING(Kernel, "capacity {} != application pool size {}", capacity, pool_size);
}
- if (capacity < memory_usage_capacity) {
+ if (capacity < m_memory_usage_capacity) {
return capacity;
}
- return memory_usage_capacity;
+ return m_memory_usage_capacity;
}
u64 KProcess::GetTotalPhysicalMemoryAvailableWithoutSystemResource() {
- return GetTotalPhysicalMemoryAvailable() - GetSystemResourceSize();
+ return this->GetTotalPhysicalMemoryAvailable() - this->GetSystemResourceSize();
}
u64 KProcess::GetTotalPhysicalMemoryUsed() {
- return image_size + main_thread_stack_size + page_table.GetNormalMemorySize() +
- GetSystemResourceSize();
+ return m_image_size + m_main_thread_stack_size + m_page_table.GetNormalMemorySize() +
+ this->GetSystemResourceSize();
}
u64 KProcess::GetTotalPhysicalMemoryUsedWithoutSystemResource() {
- return GetTotalPhysicalMemoryUsed() - GetSystemResourceUsage();
+ return this->GetTotalPhysicalMemoryUsed() - this->GetSystemResourceUsage();
}
bool KProcess::ReleaseUserException(KThread* thread) {
- KScopedSchedulerLock sl{kernel};
+ KScopedSchedulerLock sl{m_kernel};
- if (exception_thread == thread) {
- exception_thread = nullptr;
+ if (m_exception_thread == thread) {
+ m_exception_thread = nullptr;
// Remove waiter thread.
- s32 num_waiters{};
- if (KThread* next = thread->RemoveWaiterByKey(
- std::addressof(num_waiters),
- reinterpret_cast<uintptr_t>(std::addressof(exception_thread)));
+ bool has_waiters{};
+ if (KThread* next = thread->RemoveKernelWaiterByKey(
+ std::addressof(has_waiters),
+ reinterpret_cast<uintptr_t>(std::addressof(m_exception_thread)));
next != nullptr) {
next->EndWait(ResultSuccess);
}
- KScheduler::SetSchedulerUpdateNeeded(kernel);
+ KScheduler::SetSchedulerUpdateNeeded(m_kernel);
return true;
} else {
@@ -174,72 +174,72 @@ bool KProcess::ReleaseUserException(KThread* thread) {
}
void KProcess::PinCurrentThread(s32 core_id) {
- ASSERT(kernel.GlobalSchedulerContext().IsLocked());
+ ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(m_kernel));
// Get the current thread.
KThread* cur_thread =
- kernel.Scheduler(static_cast<std::size_t>(core_id)).GetSchedulerCurrentThread();
+ m_kernel.Scheduler(static_cast<std::size_t>(core_id)).GetSchedulerCurrentThread();
// If the thread isn't terminated, pin it.
if (!cur_thread->IsTerminationRequested()) {
// Pin it.
- PinThread(core_id, cur_thread);
+ this->PinThread(core_id, cur_thread);
cur_thread->Pin(core_id);
// An update is needed.
- KScheduler::SetSchedulerUpdateNeeded(kernel);
+ KScheduler::SetSchedulerUpdateNeeded(m_kernel);
}
}
void KProcess::UnpinCurrentThread(s32 core_id) {
- ASSERT(kernel.GlobalSchedulerContext().IsLocked());
+ ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(m_kernel));
// Get the current thread.
KThread* cur_thread =
- kernel.Scheduler(static_cast<std::size_t>(core_id)).GetSchedulerCurrentThread();
+ m_kernel.Scheduler(static_cast<std::size_t>(core_id)).GetSchedulerCurrentThread();
// Unpin it.
cur_thread->Unpin();
- UnpinThread(core_id, cur_thread);
+ this->UnpinThread(core_id, cur_thread);
// An update is needed.
- KScheduler::SetSchedulerUpdateNeeded(kernel);
+ KScheduler::SetSchedulerUpdateNeeded(m_kernel);
}
void KProcess::UnpinThread(KThread* thread) {
- ASSERT(kernel.GlobalSchedulerContext().IsLocked());
+ ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(m_kernel));
// Get the thread's core id.
const auto core_id = thread->GetActiveCore();
// Unpin it.
- UnpinThread(core_id, thread);
+ this->UnpinThread(core_id, thread);
thread->Unpin();
// An update is needed.
- KScheduler::SetSchedulerUpdateNeeded(kernel);
+ KScheduler::SetSchedulerUpdateNeeded(m_kernel);
}
-Result KProcess::AddSharedMemory(KSharedMemory* shmem, [[maybe_unused]] VAddr address,
+Result KProcess::AddSharedMemory(KSharedMemory* shmem, [[maybe_unused]] KProcessAddress address,
[[maybe_unused]] size_t size) {
// Lock ourselves, to prevent concurrent access.
- KScopedLightLock lk(state_lock);
+ KScopedLightLock lk(m_state_lock);
// Try to find an existing info for the memory.
KSharedMemoryInfo* shemen_info = nullptr;
const auto iter = std::find_if(
- shared_memory_list.begin(), shared_memory_list.end(),
+ m_shared_memory_list.begin(), m_shared_memory_list.end(),
[shmem](const KSharedMemoryInfo* info) { return info->GetSharedMemory() == shmem; });
- if (iter != shared_memory_list.end()) {
+ if (iter != m_shared_memory_list.end()) {
shemen_info = *iter;
}
if (shemen_info == nullptr) {
- shemen_info = KSharedMemoryInfo::Allocate(kernel);
+ shemen_info = KSharedMemoryInfo::Allocate(m_kernel);
R_UNLESS(shemen_info != nullptr, ResultOutOfMemory);
shemen_info->Initialize(shmem);
- shared_memory_list.push_back(shemen_info);
+ m_shared_memory_list.push_back(shemen_info);
}
// Open a reference to the shared memory and its info.
@@ -249,24 +249,24 @@ Result KProcess::AddSharedMemory(KSharedMemory* shmem, [[maybe_unused]] VAddr ad
R_SUCCEED();
}
-void KProcess::RemoveSharedMemory(KSharedMemory* shmem, [[maybe_unused]] VAddr address,
+void KProcess::RemoveSharedMemory(KSharedMemory* shmem, [[maybe_unused]] KProcessAddress address,
[[maybe_unused]] size_t size) {
// Lock ourselves, to prevent concurrent access.
- KScopedLightLock lk(state_lock);
+ KScopedLightLock lk(m_state_lock);
KSharedMemoryInfo* shemen_info = nullptr;
const auto iter = std::find_if(
- shared_memory_list.begin(), shared_memory_list.end(),
+ m_shared_memory_list.begin(), m_shared_memory_list.end(),
[shmem](const KSharedMemoryInfo* info) { return info->GetSharedMemory() == shmem; });
- if (iter != shared_memory_list.end()) {
+ if (iter != m_shared_memory_list.end()) {
shemen_info = *iter;
}
ASSERT(shemen_info != nullptr);
if (shemen_info->Close()) {
- shared_memory_list.erase(iter);
- KSharedMemoryInfo::Free(kernel, shemen_info);
+ m_shared_memory_list.erase(iter);
+ KSharedMemoryInfo::Free(m_kernel, shemen_info);
}
// Close a reference to the shared memory.
@@ -274,22 +274,22 @@ void KProcess::RemoveSharedMemory(KSharedMemory* shmem, [[maybe_unused]] VAddr a
}
void KProcess::RegisterThread(KThread* thread) {
- KScopedLightLock lk{list_lock};
+ KScopedLightLock lk{m_list_lock};
- thread_list.push_back(thread);
+ m_thread_list.push_back(thread);
}
void KProcess::UnregisterThread(KThread* thread) {
- KScopedLightLock lk{list_lock};
+ KScopedLightLock lk{m_list_lock};
- thread_list.remove(thread);
+ m_thread_list.remove(thread);
}
u64 KProcess::GetFreeThreadCount() const {
- if (resource_limit != nullptr) {
+ if (m_resource_limit != nullptr) {
const auto current_value =
- resource_limit->GetCurrentValue(LimitableResource::ThreadCountMax);
- const auto limit_value = resource_limit->GetLimitValue(LimitableResource::ThreadCountMax);
+ m_resource_limit->GetCurrentValue(LimitableResource::ThreadCountMax);
+ const auto limit_value = m_resource_limit->GetLimitValue(LimitableResource::ThreadCountMax);
return limit_value - current_value;
} else {
return 0;
@@ -298,87 +298,85 @@ u64 KProcess::GetFreeThreadCount() const {
Result KProcess::Reset() {
// Lock the process and the scheduler.
- KScopedLightLock lk(state_lock);
- KScopedSchedulerLock sl{kernel};
+ KScopedLightLock lk(m_state_lock);
+ KScopedSchedulerLock sl{m_kernel};
// Validate that we're in a state that we can reset.
- R_UNLESS(state != State::Terminated, ResultInvalidState);
- R_UNLESS(is_signaled, ResultInvalidState);
+ R_UNLESS(m_state != State::Terminated, ResultInvalidState);
+ R_UNLESS(m_is_signaled, ResultInvalidState);
// Clear signaled.
- is_signaled = false;
+ m_is_signaled = false;
R_SUCCEED();
}
Result KProcess::SetActivity(ProcessActivity activity) {
// Lock ourselves and the scheduler.
- KScopedLightLock lk{state_lock};
- KScopedLightLock list_lk{list_lock};
- KScopedSchedulerLock sl{kernel};
+ KScopedLightLock lk{m_state_lock};
+ KScopedLightLock list_lk{m_list_lock};
+ KScopedSchedulerLock sl{m_kernel};
// Validate our state.
- R_UNLESS(state != State::Terminating, ResultInvalidState);
- R_UNLESS(state != State::Terminated, ResultInvalidState);
+ R_UNLESS(m_state != State::Terminating, ResultInvalidState);
+ R_UNLESS(m_state != State::Terminated, ResultInvalidState);
// Either pause or resume.
if (activity == ProcessActivity::Paused) {
// Verify that we're not suspended.
- R_UNLESS(!is_suspended, ResultInvalidState);
+ R_UNLESS(!m_is_suspended, ResultInvalidState);
// Suspend all threads.
- for (auto* thread : GetThreadList()) {
+ for (auto* thread : this->GetThreadList()) {
thread->RequestSuspend(SuspendType::Process);
}
// Set ourselves as suspended.
- SetSuspended(true);
+ this->SetSuspended(true);
} else {
ASSERT(activity == ProcessActivity::Runnable);
// Verify that we're suspended.
- R_UNLESS(is_suspended, ResultInvalidState);
+ R_UNLESS(m_is_suspended, ResultInvalidState);
// Resume all threads.
- for (auto* thread : GetThreadList()) {
+ for (auto* thread : this->GetThreadList()) {
thread->Resume(SuspendType::Process);
}
// Set ourselves as resumed.
- SetSuspended(false);
+ this->SetSuspended(false);
}
R_SUCCEED();
}
Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std::size_t code_size) {
- program_id = metadata.GetTitleID();
- ideal_core = metadata.GetMainThreadCore();
- is_64bit_process = metadata.Is64BitProgram();
- system_resource_size = metadata.GetSystemResourceSize();
- image_size = code_size;
-
- // We currently do not support process-specific system resource
- UNIMPLEMENTED_IF(system_resource_size != 0);
+ m_program_id = metadata.GetTitleID();
+ m_ideal_core = metadata.GetMainThreadCore();
+ m_is_64bit_process = metadata.Is64BitProgram();
+ m_system_resource_size = metadata.GetSystemResourceSize();
+ m_image_size = code_size;
KScopedResourceReservation memory_reservation(
- resource_limit, LimitableResource::PhysicalMemoryMax, code_size + system_resource_size);
+ m_resource_limit, LimitableResource::PhysicalMemoryMax, code_size + m_system_resource_size);
if (!memory_reservation.Succeeded()) {
LOG_ERROR(Kernel, "Could not reserve process memory requirements of size {:X} bytes",
- code_size + system_resource_size);
+ code_size + m_system_resource_size);
R_RETURN(ResultLimitReached);
}
- // Initialize proces address space
- if (const Result result{page_table.InitializeForProcess(
+ // Initialize process address space
+ if (const Result result{m_page_table.InitializeForProcess(
metadata.GetAddressSpaceType(), false, false, false, KMemoryManager::Pool::Application,
- 0x8000000, code_size, &kernel.GetSystemSystemResource(), resource_limit)};
+ 0x8000000, code_size, std::addressof(m_kernel.GetAppSystemResource()), m_resource_limit,
+ m_kernel.System().ApplicationMemory())};
result.IsError()) {
R_RETURN(result);
}
// Map process code region
- if (const Result result{page_table.MapProcessCode(page_table.GetCodeRegionStart(),
- code_size / PageSize, KMemoryState::Code,
- KMemoryPermission::None)};
+ if (const Result result{m_page_table.MapProcessCode(m_page_table.GetCodeRegionStart(),
+ code_size / PageSize, KMemoryState::Code,
+ KMemoryPermission::None)};
result.IsError()) {
R_RETURN(result);
}
@@ -386,7 +384,7 @@ Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std:
// Initialize process capabilities
const auto& caps{metadata.GetKernelCapabilities()};
if (const Result result{
- capabilities.InitializeForUserProcess(caps.data(), caps.size(), page_table)};
+ m_capabilities.InitializeForUserProcess(caps.data(), caps.size(), m_page_table)};
result.IsError()) {
R_RETURN(result);
}
@@ -396,12 +394,14 @@ Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std:
case FileSys::ProgramAddressSpaceType::Is32Bit:
case FileSys::ProgramAddressSpaceType::Is36Bit:
case FileSys::ProgramAddressSpaceType::Is39Bit:
- memory_usage_capacity = page_table.GetHeapRegionEnd() - page_table.GetHeapRegionStart();
+ m_memory_usage_capacity =
+ m_page_table.GetHeapRegionEnd() - m_page_table.GetHeapRegionStart();
break;
case FileSys::ProgramAddressSpaceType::Is32BitNoMap:
- memory_usage_capacity = page_table.GetHeapRegionEnd() - page_table.GetHeapRegionStart() +
- page_table.GetAliasRegionEnd() - page_table.GetAliasRegionStart();
+ m_memory_usage_capacity =
+ (m_page_table.GetHeapRegionEnd() - m_page_table.GetHeapRegionStart()) +
+ (m_page_table.GetAliasRegionEnd() - m_page_table.GetAliasRegionStart());
break;
default:
@@ -410,34 +410,34 @@ Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std:
}
// Create TLS region
- R_TRY(this->CreateThreadLocalRegion(std::addressof(plr_address)));
+ R_TRY(this->CreateThreadLocalRegion(std::addressof(m_plr_address)));
memory_reservation.Commit();
- R_RETURN(handle_table.Initialize(capabilities.GetHandleTableSize()));
+ R_RETURN(m_handle_table.Initialize(m_capabilities.GetHandleTableSize()));
}
void KProcess::Run(s32 main_thread_priority, u64 stack_size) {
- AllocateMainThreadStack(stack_size);
- resource_limit->Reserve(LimitableResource::ThreadCountMax, 1);
- resource_limit->Reserve(LimitableResource::PhysicalMemoryMax, main_thread_stack_size);
+ ASSERT(this->AllocateMainThreadStack(stack_size) == ResultSuccess);
+ m_resource_limit->Reserve(LimitableResource::ThreadCountMax, 1);
- const std::size_t heap_capacity{memory_usage_capacity - (main_thread_stack_size + image_size)};
- ASSERT(!page_table.SetMaxHeapSize(heap_capacity).IsError());
+ const std::size_t heap_capacity{m_memory_usage_capacity -
+ (m_main_thread_stack_size + m_image_size)};
+ ASSERT(!m_page_table.SetMaxHeapSize(heap_capacity).IsError());
- ChangeState(State::Running);
+ this->ChangeState(State::Running);
- SetupMainThread(kernel.System(), *this, main_thread_priority, main_thread_stack_top);
+ SetupMainThread(m_kernel.System(), *this, main_thread_priority, m_main_thread_stack_top);
}
void KProcess::PrepareForTermination() {
- ChangeState(State::Terminating);
+ this->ChangeState(State::Terminating);
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 == GetCurrentThreadPointer(kernel))
+ if (thread == GetCurrentThreadPointer(m_kernel))
continue;
// TODO(Subv): When are the other running/ready threads terminated?
@@ -448,24 +448,24 @@ void KProcess::PrepareForTermination() {
}
};
- stop_threads(kernel.System().GlobalSchedulerContext().GetThreadList());
+ stop_threads(m_kernel.System().GlobalSchedulerContext().GetThreadList());
- this->DeleteThreadLocalRegion(plr_address);
- plr_address = 0;
+ this->DeleteThreadLocalRegion(m_plr_address);
+ m_plr_address = 0;
- if (resource_limit) {
- resource_limit->Release(LimitableResource::PhysicalMemoryMax,
- main_thread_stack_size + image_size);
+ if (m_resource_limit) {
+ m_resource_limit->Release(LimitableResource::PhysicalMemoryMax,
+ m_main_thread_stack_size + m_image_size);
}
- ChangeState(State::Terminated);
+ this->ChangeState(State::Terminated);
}
void KProcess::Finalize() {
// Free all shared memory infos.
{
- auto it = shared_memory_list.begin();
- while (it != shared_memory_list.end()) {
+ auto it = m_shared_memory_list.begin();
+ while (it != m_shared_memory_list.end()) {
KSharedMemoryInfo* info = *it;
KSharedMemory* shmem = info->GetSharedMemory();
@@ -475,40 +475,40 @@ void KProcess::Finalize() {
shmem->Close();
- it = shared_memory_list.erase(it);
- KSharedMemoryInfo::Free(kernel, info);
+ it = m_shared_memory_list.erase(it);
+ KSharedMemoryInfo::Free(m_kernel, info);
}
}
// Release memory to the resource limit.
- if (resource_limit != nullptr) {
- resource_limit->Close();
- resource_limit = nullptr;
+ if (m_resource_limit != nullptr) {
+ m_resource_limit->Close();
+ m_resource_limit = nullptr;
}
// Finalize the page table.
- page_table.Finalize();
+ m_page_table.Finalize();
// Perform inherited finalization.
- KAutoObjectWithSlabHeapAndContainer<KProcess, KWorkerTask>::Finalize();
+ KSynchronizationObject::Finalize();
}
-Result KProcess::CreateThreadLocalRegion(VAddr* out) {
+Result KProcess::CreateThreadLocalRegion(KProcessAddress* out) {
KThreadLocalPage* tlp = nullptr;
- VAddr tlr = 0;
+ KProcessAddress tlr = 0;
// See if we can get a region from a partially used TLP.
{
- KScopedSchedulerLock sl{kernel};
+ KScopedSchedulerLock sl{m_kernel};
- if (auto it = partially_used_tlp_tree.begin(); it != partially_used_tlp_tree.end()) {
+ if (auto it = m_partially_used_tlp_tree.begin(); it != m_partially_used_tlp_tree.end()) {
tlr = it->Reserve();
ASSERT(tlr != 0);
if (it->IsAllUsed()) {
tlp = std::addressof(*it);
- partially_used_tlp_tree.erase(it);
- fully_used_tlp_tree.insert(*tlp);
+ m_partially_used_tlp_tree.erase(it);
+ m_fully_used_tlp_tree.insert(*tlp);
}
*out = tlr;
@@ -517,12 +517,12 @@ Result KProcess::CreateThreadLocalRegion(VAddr* out) {
}
// Allocate a new page.
- tlp = KThreadLocalPage::Allocate(kernel);
+ tlp = KThreadLocalPage::Allocate(m_kernel);
R_UNLESS(tlp != nullptr, ResultOutOfMemory);
- auto tlp_guard = SCOPE_GUARD({ KThreadLocalPage::Free(kernel, tlp); });
+ auto tlp_guard = SCOPE_GUARD({ KThreadLocalPage::Free(m_kernel, tlp); });
// Initialize the new page.
- R_TRY(tlp->Initialize(kernel, this));
+ R_TRY(tlp->Initialize(m_kernel, this));
// Reserve a TLR.
tlr = tlp->Reserve();
@@ -530,11 +530,11 @@ Result KProcess::CreateThreadLocalRegion(VAddr* out) {
// Insert into our tree.
{
- KScopedSchedulerLock sl{kernel};
+ KScopedSchedulerLock sl{m_kernel};
if (tlp->IsAllUsed()) {
- fully_used_tlp_tree.insert(*tlp);
+ m_fully_used_tlp_tree.insert(*tlp);
} else {
- partially_used_tlp_tree.insert(*tlp);
+ m_partially_used_tlp_tree.insert(*tlp);
}
}
@@ -544,30 +544,30 @@ Result KProcess::CreateThreadLocalRegion(VAddr* out) {
R_SUCCEED();
}
-Result KProcess::DeleteThreadLocalRegion(VAddr addr) {
+Result KProcess::DeleteThreadLocalRegion(KProcessAddress addr) {
KThreadLocalPage* page_to_free = nullptr;
// Release the region.
{
- KScopedSchedulerLock sl{kernel};
+ KScopedSchedulerLock sl{m_kernel};
// Try to find the page in the partially used list.
- auto it = partially_used_tlp_tree.find_key(Common::AlignDown(addr, PageSize));
- if (it == partially_used_tlp_tree.end()) {
+ auto it = m_partially_used_tlp_tree.find_key(Common::AlignDown(GetInteger(addr), PageSize));
+ if (it == m_partially_used_tlp_tree.end()) {
// If we don't find it, it has to be in the fully used list.
- it = fully_used_tlp_tree.find_key(Common::AlignDown(addr, PageSize));
- R_UNLESS(it != fully_used_tlp_tree.end(), ResultInvalidAddress);
+ it = m_fully_used_tlp_tree.find_key(Common::AlignDown(GetInteger(addr), PageSize));
+ R_UNLESS(it != m_fully_used_tlp_tree.end(), ResultInvalidAddress);
// Release the region.
it->Release(addr);
// Move the page out of the fully used list.
KThreadLocalPage* tlp = std::addressof(*it);
- fully_used_tlp_tree.erase(it);
+ m_fully_used_tlp_tree.erase(it);
if (tlp->IsAllFree()) {
page_to_free = tlp;
} else {
- partially_used_tlp_tree.insert(*tlp);
+ m_partially_used_tlp_tree.insert(*tlp);
}
} else {
// Release the region.
@@ -576,7 +576,7 @@ Result KProcess::DeleteThreadLocalRegion(VAddr addr) {
// Handle the all-free case.
KThreadLocalPage* tlp = std::addressof(*it);
if (tlp->IsAllFree()) {
- partially_used_tlp_tree.erase(it);
+ m_partially_used_tlp_tree.erase(it);
page_to_free = tlp;
}
}
@@ -586,19 +586,18 @@ Result KProcess::DeleteThreadLocalRegion(VAddr addr) {
if (page_to_free != nullptr) {
page_to_free->Finalize();
- KThreadLocalPage::Free(kernel, page_to_free);
+ KThreadLocalPage::Free(m_kernel, page_to_free);
}
R_SUCCEED();
}
-bool KProcess::InsertWatchpoint(Core::System& system, VAddr addr, u64 size,
- DebugWatchpointType type) {
- const auto watch{std::find_if(watchpoints.begin(), watchpoints.end(), [&](const auto& wp) {
+bool KProcess::InsertWatchpoint(KProcessAddress addr, u64 size, DebugWatchpointType type) {
+ const auto watch{std::find_if(m_watchpoints.begin(), m_watchpoints.end(), [&](const auto& wp) {
return wp.type == DebugWatchpointType::None;
})};
- if (watch == watchpoints.end()) {
+ if (watch == m_watchpoints.end()) {
return false;
}
@@ -606,21 +605,21 @@ bool KProcess::InsertWatchpoint(Core::System& system, VAddr addr, u64 size,
watch->end_address = addr + size;
watch->type = type;
- for (VAddr page = Common::AlignDown(addr, PageSize); page < addr + size; page += PageSize) {
- debug_page_refcounts[page]++;
- system.Memory().MarkRegionDebug(page, PageSize, true);
+ for (KProcessAddress page = Common::AlignDown(GetInteger(addr), PageSize); page < addr + size;
+ page += PageSize) {
+ m_debug_page_refcounts[page]++;
+ this->GetMemory().MarkRegionDebug(page, PageSize, true);
}
return true;
}
-bool KProcess::RemoveWatchpoint(Core::System& system, VAddr addr, u64 size,
- DebugWatchpointType type) {
- const auto watch{std::find_if(watchpoints.begin(), watchpoints.end(), [&](const auto& wp) {
+bool KProcess::RemoveWatchpoint(KProcessAddress addr, u64 size, DebugWatchpointType type) {
+ const auto watch{std::find_if(m_watchpoints.begin(), m_watchpoints.end(), [&](const auto& wp) {
return wp.start_address == addr && wp.end_address == addr + size && wp.type == type;
})};
- if (watch == watchpoints.end()) {
+ if (watch == m_watchpoints.end()) {
return false;
}
@@ -628,24 +627,24 @@ bool KProcess::RemoveWatchpoint(Core::System& system, VAddr addr, u64 size,
watch->end_address = 0;
watch->type = DebugWatchpointType::None;
- for (VAddr page = Common::AlignDown(addr, PageSize); page < addr + size; page += PageSize) {
- debug_page_refcounts[page]--;
- if (!debug_page_refcounts[page]) {
- system.Memory().MarkRegionDebug(page, PageSize, false);
+ for (KProcessAddress page = Common::AlignDown(GetInteger(addr), PageSize); page < addr + size;
+ page += PageSize) {
+ m_debug_page_refcounts[page]--;
+ if (!m_debug_page_refcounts[page]) {
+ this->GetMemory().MarkRegionDebug(page, PageSize, false);
}
}
return true;
}
-void KProcess::LoadModule(CodeSet code_set, VAddr base_addr) {
+void KProcess::LoadModule(CodeSet code_set, KProcessAddress base_addr) {
const auto ReprotectSegment = [&](const CodeSet::Segment& segment,
Svc::MemoryPermission permission) {
- page_table.SetProcessMemoryPermission(segment.addr + base_addr, segment.size, permission);
+ m_page_table.SetProcessMemoryPermission(segment.addr + base_addr, segment.size, permission);
};
- kernel.System().Memory().WriteBlock(*this, base_addr, code_set.memory.data(),
- code_set.memory.size());
+ this->GetMemory().WriteBlock(base_addr, code_set.memory.data(), code_set.memory.size());
ReprotectSegment(code_set.CodeSegment(), Svc::MemoryPermission::ReadExecute);
ReprotectSegment(code_set.RODataSegment(), Svc::MemoryPermission::Read);
@@ -653,44 +652,60 @@ void KProcess::LoadModule(CodeSet code_set, VAddr base_addr) {
}
bool KProcess::IsSignaled() const {
- ASSERT(kernel.GlobalSchedulerContext().IsLocked());
- return is_signaled;
+ ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(m_kernel));
+ return m_is_signaled;
}
-KProcess::KProcess(KernelCore& kernel_)
- : KAutoObjectWithSlabHeapAndContainer{kernel_}, page_table{kernel_.System()},
- handle_table{kernel_}, address_arbiter{kernel_.System()}, condition_var{kernel_.System()},
- state_lock{kernel_}, list_lock{kernel_} {}
+KProcess::KProcess(KernelCore& kernel)
+ : KAutoObjectWithSlabHeapAndContainer{kernel}, m_page_table{m_kernel.System()},
+ m_handle_table{m_kernel}, m_address_arbiter{m_kernel.System()},
+ m_condition_var{m_kernel.System()}, m_state_lock{m_kernel}, m_list_lock{m_kernel} {}
KProcess::~KProcess() = default;
void KProcess::ChangeState(State new_state) {
- if (state == new_state) {
+ if (m_state == new_state) {
return;
}
- state = new_state;
- is_signaled = true;
- NotifyAvailable();
+ m_state = new_state;
+ m_is_signaled = true;
+ this->NotifyAvailable();
}
Result KProcess::AllocateMainThreadStack(std::size_t stack_size) {
- ASSERT(stack_size);
-
- // The kernel always ensures that the given stack size is page aligned.
- main_thread_stack_size = Common::AlignUp(stack_size, PageSize);
-
- const VAddr start{page_table.GetStackRegionStart()};
- const std::size_t size{page_table.GetStackRegionEnd() - start};
-
- CASCADE_RESULT(main_thread_stack_top,
- page_table.AllocateAndMapMemory(
- main_thread_stack_size / PageSize, PageSize, false, start, size / PageSize,
- KMemoryState::Stack, KMemoryPermission::UserReadWrite));
+ // Ensure that we haven't already allocated stack.
+ ASSERT(m_main_thread_stack_size == 0);
+
+ // Ensure that we're allocating a valid stack.
+ stack_size = Common::AlignUp(stack_size, PageSize);
+ // R_UNLESS(stack_size + image_size <= m_max_process_memory, ResultOutOfMemory);
+ R_UNLESS(stack_size + m_image_size >= m_image_size, ResultOutOfMemory);
+
+ // Place a tentative reservation of memory for our new stack.
+ KScopedResourceReservation mem_reservation(this, Svc::LimitableResource::PhysicalMemoryMax,
+ stack_size);
+ R_UNLESS(mem_reservation.Succeeded(), ResultLimitReached);
+
+ // Allocate and map our stack.
+ if (stack_size) {
+ KProcessAddress stack_bottom;
+ R_TRY(m_page_table.MapPages(std::addressof(stack_bottom), stack_size / PageSize,
+ KMemoryState::Stack, KMemoryPermission::UserReadWrite));
+
+ m_main_thread_stack_top = stack_bottom + stack_size;
+ m_main_thread_stack_size = stack_size;
+ }
- main_thread_stack_top += main_thread_stack_size;
+ // We succeeded! Commit our memory reservation.
+ mem_reservation.Commit();
R_SUCCEED();
}
+Core::Memory::Memory& KProcess::GetMemory() const {
+ // TODO: per-process memory
+ return m_kernel.System().ApplicationMemory();
+}
+
} // namespace Kernel
diff --git a/src/core/hle/kernel/k_process.h b/src/core/hle/kernel/k_process.h
index 09bf2f1d0..925981d06 100644
--- a/src/core/hle/kernel/k_process.h
+++ b/src/core/hle/kernel/k_process.h
@@ -8,7 +8,6 @@
#include <list>
#include <map>
#include <string>
-#include "common/common_types.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"
@@ -16,14 +15,19 @@
#include "core/hle/kernel/k_page_table.h"
#include "core/hle/kernel/k_synchronization_object.h"
#include "core/hle/kernel/k_thread_local_page.h"
+#include "core/hle/kernel/k_typed_address.h"
#include "core/hle/kernel/k_worker_task.h"
#include "core/hle/kernel/process_capability.h"
#include "core/hle/kernel/slab_helpers.h"
#include "core/hle/result.h"
namespace Core {
+namespace Memory {
+class Memory;
+};
+
class System;
-}
+} // namespace Core
namespace FileSys {
class ProgramMetadata;
@@ -59,8 +63,8 @@ enum class DebugWatchpointType : u8 {
DECLARE_ENUM_FLAG_OPERATORS(DebugWatchpointType);
struct DebugWatchpoint {
- VAddr start_address;
- VAddr end_address;
+ KProcessAddress start_address;
+ KProcessAddress end_address;
DebugWatchpointType type;
};
@@ -68,7 +72,7 @@ class KProcess final : public KAutoObjectWithSlabHeapAndContainer<KProcess, KWor
KERNEL_AUTOOBJECT_TRAITS(KProcess, KSynchronizationObject);
public:
- explicit KProcess(KernelCore& kernel_);
+ explicit KProcess(KernelCore& kernel);
~KProcess() override;
enum class State {
@@ -107,66 +111,80 @@ public:
/// Gets a reference to the process' page table.
KPageTable& PageTable() {
- return page_table;
+ return m_page_table;
}
/// Gets const a reference to the process' page table.
const KPageTable& PageTable() const {
- return page_table;
+ return m_page_table;
+ }
+
+ /// Gets a reference to the process' page table.
+ KPageTable& GetPageTable() {
+ return m_page_table;
+ }
+
+ /// Gets const a reference to the process' page table.
+ const KPageTable& GetPageTable() const {
+ return m_page_table;
}
/// Gets a reference to the process' handle table.
KHandleTable& GetHandleTable() {
- return handle_table;
+ return m_handle_table;
}
/// Gets a const reference to the process' handle table.
const KHandleTable& GetHandleTable() const {
- return handle_table;
+ return m_handle_table;
}
- Result SignalToAddress(VAddr address) {
- return condition_var.SignalToAddress(address);
+ /// Gets a reference to process's memory.
+ Core::Memory::Memory& GetMemory() const;
+
+ Result SignalToAddress(KProcessAddress address) {
+ return m_condition_var.SignalToAddress(address);
}
- Result WaitForAddress(Handle handle, VAddr address, u32 tag) {
- return condition_var.WaitForAddress(handle, address, tag);
+ Result WaitForAddress(Handle handle, KProcessAddress address, u32 tag) {
+ return m_condition_var.WaitForAddress(handle, address, tag);
}
void SignalConditionVariable(u64 cv_key, int32_t count) {
- return condition_var.Signal(cv_key, count);
+ return m_condition_var.Signal(cv_key, count);
}
- Result WaitConditionVariable(VAddr address, u64 cv_key, u32 tag, s64 ns) {
- R_RETURN(condition_var.Wait(address, cv_key, tag, ns));
+ Result WaitConditionVariable(KProcessAddress address, u64 cv_key, u32 tag, s64 ns) {
+ R_RETURN(m_condition_var.Wait(address, cv_key, tag, ns));
}
- Result SignalAddressArbiter(VAddr address, Svc::SignalType signal_type, s32 value, s32 count) {
- R_RETURN(address_arbiter.SignalToAddress(address, signal_type, value, count));
+ Result SignalAddressArbiter(uint64_t address, Svc::SignalType signal_type, s32 value,
+ s32 count) {
+ R_RETURN(m_address_arbiter.SignalToAddress(address, signal_type, value, count));
}
- Result WaitAddressArbiter(VAddr address, Svc::ArbitrationType arb_type, s32 value,
+ Result WaitAddressArbiter(uint64_t address, Svc::ArbitrationType arb_type, s32 value,
s64 timeout) {
- R_RETURN(address_arbiter.WaitForAddress(address, arb_type, value, timeout));
+ R_RETURN(m_address_arbiter.WaitForAddress(address, arb_type, value, timeout));
}
- VAddr GetProcessLocalRegionAddress() const {
- return plr_address;
+ KProcessAddress GetProcessLocalRegionAddress() const {
+ return m_plr_address;
}
/// Gets the current status of the process
State GetState() const {
- return state;
+ return m_state;
}
/// Gets the unique ID that identifies this particular process.
- u64 GetProcessID() const {
- return process_id;
+ u64 GetProcessId() const {
+ return m_process_id;
}
/// Gets the program ID corresponding to this process.
- u64 GetProgramID() const {
- return program_id;
+ u64 GetProgramId() const {
+ return m_program_id;
}
/// Gets the resource limit descriptor for this process
@@ -174,7 +192,7 @@ public:
/// Gets the ideal CPU core ID for this process
u8 GetIdealCoreId() const {
- return ideal_core;
+ return m_ideal_core;
}
/// Checks if the specified thread priority is valid.
@@ -184,17 +202,17 @@ public:
/// Gets the bitmask of allowed cores that this process' threads can run on.
u64 GetCoreMask() const {
- return capabilities.GetCoreMask();
+ return m_capabilities.GetCoreMask();
}
/// Gets the bitmask of allowed thread priorities.
u64 GetPriorityMask() const {
- return capabilities.GetPriorityMask();
+ return m_capabilities.GetPriorityMask();
}
/// Gets the amount of secure memory to allocate for memory management.
u32 GetSystemResourceSize() const {
- return system_resource_size;
+ return m_system_resource_size;
}
/// Gets the amount of secure memory currently in use for memory management.
@@ -214,67 +232,67 @@ public:
/// Whether this process is an AArch64 or AArch32 process.
bool Is64BitProcess() const {
- return is_64bit_process;
+ return m_is_64bit_process;
}
- [[nodiscard]] bool IsSuspended() const {
- return is_suspended;
+ bool IsSuspended() const {
+ return m_is_suspended;
}
void SetSuspended(bool suspended) {
- is_suspended = suspended;
+ m_is_suspended = suspended;
}
/// Gets the total running time of the process instance in ticks.
u64 GetCPUTimeTicks() const {
- return total_process_running_time_ticks;
+ return m_total_process_running_time_ticks;
}
/// Updates the total running time, adding the given ticks to it.
void UpdateCPUTimeTicks(u64 ticks) {
- total_process_running_time_ticks += ticks;
+ m_total_process_running_time_ticks += ticks;
}
- /// Gets the process schedule count, used for thread yelding
+ /// Gets the process schedule count, used for thread yielding
s64 GetScheduledCount() const {
- return schedule_count;
+ return m_schedule_count;
}
/// Increments the process schedule count, used for thread yielding.
void IncrementScheduledCount() {
- ++schedule_count;
+ ++m_schedule_count;
}
void IncrementRunningThreadCount();
void DecrementRunningThreadCount();
void SetRunningThread(s32 core, KThread* thread, u64 idle_count) {
- running_threads[core] = thread;
- running_thread_idle_counts[core] = idle_count;
+ m_running_threads[core] = thread;
+ m_running_thread_idle_counts[core] = idle_count;
}
void ClearRunningThread(KThread* thread) {
- for (size_t i = 0; i < running_threads.size(); ++i) {
- if (running_threads[i] == thread) {
- running_threads[i] = nullptr;
+ for (size_t i = 0; i < m_running_threads.size(); ++i) {
+ if (m_running_threads[i] == thread) {
+ m_running_threads[i] = nullptr;
}
}
}
[[nodiscard]] KThread* GetRunningThread(s32 core) const {
- return running_threads[core];
+ return m_running_threads[core];
}
bool ReleaseUserException(KThread* thread);
[[nodiscard]] KThread* GetPinnedThread(s32 core_id) const {
ASSERT(0 <= core_id && core_id < static_cast<s32>(Core::Hardware::NUM_CPU_CORES));
- return pinned_threads[core_id];
+ return m_pinned_threads[core_id];
}
/// Gets 8 bytes of random data for svcGetInfo RandomEntropy
u64 GetRandomEntropy(std::size_t index) const {
- return random_entropy.at(index);
+ return m_random_entropy.at(index);
}
/// Retrieves the total physical memory available to this process in bytes.
@@ -293,7 +311,7 @@ public:
/// Gets the list of all threads created with this process as their owner.
std::list<KThread*>& GetThreadList() {
- return thread_list;
+ return m_thread_list;
}
/// Registers a thread as being created under this process,
@@ -310,10 +328,10 @@ public:
/// Clears the signaled state of the process if and only if it's signaled.
///
/// @pre The process must not be already terminated. If this is called on a
- /// terminated process, then ERR_INVALID_STATE will be returned.
+ /// terminated process, then ResultInvalidState will be returned.
///
/// @pre The process must be in a signaled state. If this is called on a
- /// process instance that is not signaled, ERR_INVALID_STATE will be
+ /// process instance that is not signaled, ResultInvalidState will be
/// returned.
Result Reset();
@@ -342,18 +360,18 @@ public:
*/
void PrepareForTermination();
- void LoadModule(CodeSet code_set, VAddr base_addr);
+ void LoadModule(CodeSet code_set, KProcessAddress base_addr);
bool IsInitialized() const override {
- return is_initialized;
+ return m_is_initialized;
}
- static void PostDestroy([[maybe_unused]] uintptr_t arg) {}
+ static void PostDestroy(uintptr_t arg) {}
void Finalize() override;
u64 GetId() const override {
- return GetProcessID();
+ return GetProcessId();
}
bool IsSignaled() const override;
@@ -367,55 +385,59 @@ public:
void UnpinThread(KThread* thread);
KLightLock& GetStateLock() {
- return state_lock;
+ return m_state_lock;
}
- Result AddSharedMemory(KSharedMemory* shmem, VAddr address, size_t size);
- void RemoveSharedMemory(KSharedMemory* shmem, VAddr address, size_t size);
+ Result AddSharedMemory(KSharedMemory* shmem, KProcessAddress address, size_t size);
+ void RemoveSharedMemory(KSharedMemory* shmem, KProcessAddress address, size_t size);
///////////////////////////////////////////////////////////////////////////////////////////////
// Thread-local storage management
// Marks the next available region as used and returns the address of the slot.
- [[nodiscard]] Result CreateThreadLocalRegion(VAddr* out);
+ [[nodiscard]] Result CreateThreadLocalRegion(KProcessAddress* out);
// Frees a used TLS slot identified by the given address
- Result DeleteThreadLocalRegion(VAddr addr);
+ Result DeleteThreadLocalRegion(KProcessAddress addr);
///////////////////////////////////////////////////////////////////////////////////////////////
// Debug watchpoint management
// Attempts to insert a watchpoint into a free slot. Returns false if none are available.
- bool InsertWatchpoint(Core::System& system, VAddr addr, u64 size, DebugWatchpointType type);
+ bool InsertWatchpoint(KProcessAddress addr, u64 size, DebugWatchpointType type);
// Attempts to remove the watchpoint specified by the given parameters.
- bool RemoveWatchpoint(Core::System& system, VAddr addr, u64 size, DebugWatchpointType type);
+ bool RemoveWatchpoint(KProcessAddress addr, u64 size, DebugWatchpointType type);
const std::array<DebugWatchpoint, Core::Hardware::NUM_WATCHPOINTS>& GetWatchpoints() const {
- return watchpoints;
+ return m_watchpoints;
+ }
+
+ const std::string& GetName() {
+ return name;
}
private:
void PinThread(s32 core_id, KThread* thread) {
ASSERT(0 <= core_id && core_id < static_cast<s32>(Core::Hardware::NUM_CPU_CORES));
ASSERT(thread != nullptr);
- ASSERT(pinned_threads[core_id] == nullptr);
- pinned_threads[core_id] = thread;
+ ASSERT(m_pinned_threads[core_id] == nullptr);
+ m_pinned_threads[core_id] = thread;
}
void UnpinThread(s32 core_id, KThread* thread) {
ASSERT(0 <= core_id && core_id < static_cast<s32>(Core::Hardware::NUM_CPU_CORES));
ASSERT(thread != nullptr);
- ASSERT(pinned_threads[core_id] == thread);
- pinned_threads[core_id] = nullptr;
+ ASSERT(m_pinned_threads[core_id] == thread);
+ m_pinned_threads[core_id] = nullptr;
}
void FinalizeHandleTable() {
// Finalize the table.
- handle_table.Finalize();
+ m_handle_table.Finalize();
// Note that the table is finalized.
- is_handle_table_initialized = false;
+ m_is_handle_table_initialized = false;
}
void ChangeState(State new_state);
@@ -424,105 +446,107 @@ private:
Result AllocateMainThreadStack(std::size_t stack_size);
/// Memory manager for this process
- KPageTable page_table;
+ KPageTable m_page_table;
/// Current status of the process
- State state{};
+ State m_state{};
/// The ID of this process
- u64 process_id = 0;
+ u64 m_process_id = 0;
/// Title ID corresponding to the process
- u64 program_id = 0;
+ u64 m_program_id = 0;
/// Specifies additional memory to be reserved for the process's memory management by the
/// system. When this is non-zero, secure memory is allocated and used for page table allocation
/// instead of using the normal global page tables/memory block management.
- u32 system_resource_size = 0;
+ u32 m_system_resource_size = 0;
/// Resource limit descriptor for this process
- KResourceLimit* resource_limit{};
+ KResourceLimit* m_resource_limit{};
- VAddr system_resource_address{};
+ KVirtualAddress m_system_resource_address{};
/// The ideal CPU core for this process, threads are scheduled on this core by default.
- u8 ideal_core = 0;
+ u8 m_ideal_core = 0;
/// Contains the parsed process capability descriptors.
- ProcessCapabilities capabilities;
+ ProcessCapabilities m_capabilities;
/// Whether or not this process is AArch64, or AArch32.
/// By default, we currently assume this is true, unless otherwise
/// specified by metadata provided to the process during loading.
- bool is_64bit_process = true;
+ bool m_is_64bit_process = true;
/// Total running time for the process in ticks.
- std::atomic<u64> total_process_running_time_ticks = 0;
+ std::atomic<u64> m_total_process_running_time_ticks = 0;
/// Per-process handle table for storing created object handles in.
- KHandleTable handle_table;
+ KHandleTable m_handle_table;
/// Per-process address arbiter.
- KAddressArbiter address_arbiter;
+ KAddressArbiter m_address_arbiter;
/// The per-process mutex lock instance used for handling various
/// forms of services, such as lock arbitration, and condition
/// variable related facilities.
- KConditionVariable condition_var;
+ KConditionVariable m_condition_var;
/// Address indicating the location of the process' dedicated TLS region.
- VAddr plr_address = 0;
+ KProcessAddress m_plr_address = 0;
/// Random values for svcGetInfo RandomEntropy
- std::array<u64, RANDOM_ENTROPY_SIZE> random_entropy{};
+ std::array<u64, RANDOM_ENTROPY_SIZE> m_random_entropy{};
/// List of threads that are running with this process as their owner.
- std::list<KThread*> thread_list;
+ std::list<KThread*> m_thread_list;
/// List of shared memory that are running with this process as their owner.
- std::list<KSharedMemoryInfo*> shared_memory_list;
+ std::list<KSharedMemoryInfo*> m_shared_memory_list;
/// Address of the top of the main thread's stack
- VAddr main_thread_stack_top{};
+ KProcessAddress m_main_thread_stack_top{};
/// Size of the main thread's stack
- std::size_t main_thread_stack_size{};
+ std::size_t m_main_thread_stack_size{};
/// Memory usage capacity for the process
- std::size_t memory_usage_capacity{};
+ std::size_t m_memory_usage_capacity{};
/// Process total image size
- std::size_t image_size{};
+ std::size_t m_image_size{};
/// Schedule count of this process
- s64 schedule_count{};
+ s64 m_schedule_count{};
+
+ size_t m_memory_release_hint{};
- size_t memory_release_hint{};
+ std::string name{};
- bool is_signaled{};
- bool is_suspended{};
- bool is_immortal{};
- bool is_handle_table_initialized{};
- bool is_initialized{};
+ bool m_is_signaled{};
+ bool m_is_suspended{};
+ bool m_is_immortal{};
+ bool m_is_handle_table_initialized{};
+ bool m_is_initialized{};
- std::atomic<u16> num_running_threads{};
+ std::atomic<u16> m_num_running_threads{};
- std::array<KThread*, Core::Hardware::NUM_CPU_CORES> running_threads{};
- std::array<u64, Core::Hardware::NUM_CPU_CORES> running_thread_idle_counts{};
- std::array<KThread*, Core::Hardware::NUM_CPU_CORES> pinned_threads{};
- std::array<DebugWatchpoint, Core::Hardware::NUM_WATCHPOINTS> watchpoints{};
- std::map<VAddr, u64> debug_page_refcounts;
+ std::array<KThread*, Core::Hardware::NUM_CPU_CORES> m_running_threads{};
+ std::array<u64, Core::Hardware::NUM_CPU_CORES> m_running_thread_idle_counts{};
+ std::array<KThread*, Core::Hardware::NUM_CPU_CORES> m_pinned_threads{};
+ std::array<DebugWatchpoint, Core::Hardware::NUM_WATCHPOINTS> m_watchpoints{};
+ std::map<KProcessAddress, u64> m_debug_page_refcounts;
- KThread* exception_thread{};
+ KThread* m_exception_thread{};
- KLightLock state_lock;
- KLightLock list_lock;
+ KLightLock m_state_lock;
+ KLightLock m_list_lock;
using TLPTree =
Common::IntrusiveRedBlackTreeBaseTraits<KThreadLocalPage>::TreeType<KThreadLocalPage>;
using TLPIterator = TLPTree::iterator;
- TLPTree fully_used_tlp_tree;
- TLPTree partially_used_tlp_tree;
+ TLPTree m_fully_used_tlp_tree;
+ TLPTree m_partially_used_tlp_tree;
};
} // namespace Kernel
diff --git a/src/core/hle/kernel/k_readable_event.cpp b/src/core/hle/kernel/k_readable_event.cpp
index 5c942d47c..c30662666 100644
--- a/src/core/hle/kernel/k_readable_event.cpp
+++ b/src/core/hle/kernel/k_readable_event.cpp
@@ -11,7 +11,7 @@
namespace Kernel {
-KReadableEvent::KReadableEvent(KernelCore& kernel_) : KSynchronizationObject{kernel_} {}
+KReadableEvent::KReadableEvent(KernelCore& kernel) : KSynchronizationObject{kernel} {}
KReadableEvent::~KReadableEvent() = default;
@@ -25,7 +25,7 @@ void KReadableEvent::Initialize(KEvent* parent) {
}
bool KReadableEvent::IsSignaled() const {
- ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(kernel));
+ ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(m_kernel));
return m_is_signaled;
}
@@ -33,7 +33,7 @@ bool KReadableEvent::IsSignaled() const {
void KReadableEvent::Destroy() {
if (m_parent) {
{
- KScopedSchedulerLock sl{kernel};
+ KScopedSchedulerLock sl{m_kernel};
m_parent->OnReadableEventDestroyed();
}
m_parent->Close();
@@ -41,31 +41,29 @@ void KReadableEvent::Destroy() {
}
Result KReadableEvent::Signal() {
- KScopedSchedulerLock lk{kernel};
+ KScopedSchedulerLock lk{m_kernel};
if (!m_is_signaled) {
m_is_signaled = true;
this->NotifyAvailable();
}
- return ResultSuccess;
+ R_SUCCEED();
}
Result KReadableEvent::Clear() {
this->Reset();
- return ResultSuccess;
+ R_SUCCEED();
}
Result KReadableEvent::Reset() {
- KScopedSchedulerLock lk{kernel};
+ KScopedSchedulerLock lk{m_kernel};
- if (!m_is_signaled) {
- return ResultInvalidState;
- }
+ R_UNLESS(m_is_signaled, ResultInvalidState);
m_is_signaled = false;
- return ResultSuccess;
+ R_SUCCEED();
}
} // namespace Kernel
diff --git a/src/core/hle/kernel/k_readable_event.h b/src/core/hle/kernel/k_readable_event.h
index 743f96bf5..d2ec36323 100644
--- a/src/core/hle/kernel/k_readable_event.h
+++ b/src/core/hle/kernel/k_readable_event.h
@@ -17,7 +17,7 @@ class KReadableEvent : public KSynchronizationObject {
KERNEL_AUTOOBJECT_TRAITS(KReadableEvent, KSynchronizationObject);
public:
- explicit KReadableEvent(KernelCore& kernel_);
+ explicit KReadableEvent(KernelCore& kernel);
~KReadableEvent() override;
void Initialize(KEvent* parent);
diff --git a/src/core/hle/kernel/k_resource_limit.cpp b/src/core/hle/kernel/k_resource_limit.cpp
index b9d22b414..fcee26a29 100644
--- a/src/core/hle/kernel/k_resource_limit.cpp
+++ b/src/core/hle/kernel/k_resource_limit.cpp
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/assert.h"
+#include "common/overflow.h"
#include "core/core.h"
#include "core/core_timing.h"
#include "core/hle/kernel/k_resource_limit.h"
@@ -10,12 +11,12 @@
namespace Kernel {
constexpr s64 DefaultTimeout = 10000000000; // 10 seconds
-KResourceLimit::KResourceLimit(KernelCore& kernel_)
- : KAutoObjectWithSlabHeapAndContainer{kernel_}, lock{kernel_}, cond_var{kernel_} {}
+KResourceLimit::KResourceLimit(KernelCore& kernel)
+ : KAutoObjectWithSlabHeapAndContainer{kernel}, m_lock{m_kernel}, m_cond_var{m_kernel} {}
KResourceLimit::~KResourceLimit() = default;
-void KResourceLimit::Initialize(const Core::Timing::CoreTiming* core_timing_) {
- core_timing = core_timing_;
+void KResourceLimit::Initialize(const Core::Timing::CoreTiming* core_timing) {
+ m_core_timing = core_timing;
}
void KResourceLimit::Finalize() {}
@@ -24,11 +25,11 @@ s64 KResourceLimit::GetLimitValue(LimitableResource which) const {
const auto index = static_cast<std::size_t>(which);
s64 value{};
{
- KScopedLightLock lk{lock};
- value = limit_values[index];
+ KScopedLightLock lk{m_lock};
+ value = m_limit_values[index];
ASSERT(value >= 0);
- ASSERT(current_values[index] <= limit_values[index]);
- ASSERT(current_hints[index] <= current_values[index]);
+ ASSERT(m_current_values[index] <= m_limit_values[index]);
+ ASSERT(m_current_hints[index] <= m_current_values[index]);
}
return value;
}
@@ -37,11 +38,11 @@ s64 KResourceLimit::GetCurrentValue(LimitableResource which) const {
const auto index = static_cast<std::size_t>(which);
s64 value{};
{
- KScopedLightLock lk{lock};
- value = current_values[index];
+ KScopedLightLock lk{m_lock};
+ value = m_current_values[index];
ASSERT(value >= 0);
- ASSERT(current_values[index] <= limit_values[index]);
- ASSERT(current_hints[index] <= current_values[index]);
+ ASSERT(m_current_values[index] <= m_limit_values[index]);
+ ASSERT(m_current_hints[index] <= m_current_values[index]);
}
return value;
}
@@ -50,11 +51,11 @@ s64 KResourceLimit::GetPeakValue(LimitableResource which) const {
const auto index = static_cast<std::size_t>(which);
s64 value{};
{
- KScopedLightLock lk{lock};
- value = peak_values[index];
+ KScopedLightLock lk{m_lock};
+ value = m_peak_values[index];
ASSERT(value >= 0);
- ASSERT(current_values[index] <= limit_values[index]);
- ASSERT(current_hints[index] <= current_values[index]);
+ ASSERT(m_current_values[index] <= m_limit_values[index]);
+ ASSERT(m_current_hints[index] <= m_current_values[index]);
}
return value;
}
@@ -63,11 +64,11 @@ s64 KResourceLimit::GetFreeValue(LimitableResource which) const {
const auto index = static_cast<std::size_t>(which);
s64 value{};
{
- KScopedLightLock lk(lock);
- ASSERT(current_values[index] >= 0);
- ASSERT(current_values[index] <= limit_values[index]);
- ASSERT(current_hints[index] <= current_values[index]);
- value = limit_values[index] - current_values[index];
+ KScopedLightLock lk(m_lock);
+ ASSERT(m_current_values[index] >= 0);
+ ASSERT(m_current_values[index] <= m_limit_values[index]);
+ ASSERT(m_current_hints[index] <= m_current_values[index]);
+ value = m_limit_values[index] - m_current_values[index];
}
return value;
@@ -75,51 +76,51 @@ s64 KResourceLimit::GetFreeValue(LimitableResource which) const {
Result KResourceLimit::SetLimitValue(LimitableResource which, s64 value) {
const auto index = static_cast<std::size_t>(which);
- KScopedLightLock lk(lock);
- R_UNLESS(current_values[index] <= value, ResultInvalidState);
+ KScopedLightLock lk(m_lock);
+ R_UNLESS(m_current_values[index] <= value, ResultInvalidState);
- limit_values[index] = value;
- peak_values[index] = current_values[index];
+ m_limit_values[index] = value;
+ m_peak_values[index] = m_current_values[index];
- return ResultSuccess;
+ R_SUCCEED();
}
bool KResourceLimit::Reserve(LimitableResource which, s64 value) {
- return Reserve(which, value, core_timing->GetGlobalTimeNs().count() + DefaultTimeout);
+ return Reserve(which, value, m_core_timing->GetGlobalTimeNs().count() + DefaultTimeout);
}
bool KResourceLimit::Reserve(LimitableResource which, s64 value, s64 timeout) {
ASSERT(value >= 0);
const auto index = static_cast<std::size_t>(which);
- KScopedLightLock lk(lock);
+ KScopedLightLock lk(m_lock);
- ASSERT(current_hints[index] <= current_values[index]);
- if (current_hints[index] >= limit_values[index]) {
+ ASSERT(m_current_hints[index] <= m_current_values[index]);
+ if (m_current_hints[index] >= m_limit_values[index]) {
return false;
}
// Loop until we reserve or run out of time.
while (true) {
- ASSERT(current_values[index] <= limit_values[index]);
- ASSERT(current_hints[index] <= current_values[index]);
+ ASSERT(m_current_values[index] <= m_limit_values[index]);
+ ASSERT(m_current_hints[index] <= m_current_values[index]);
// If we would overflow, don't allow to succeed.
- if (current_values[index] + value <= current_values[index]) {
+ if (Common::WrappingAdd(m_current_values[index], value) <= m_current_values[index]) {
break;
}
- if (current_values[index] + value <= limit_values[index]) {
- current_values[index] += value;
- current_hints[index] += value;
- peak_values[index] = std::max(peak_values[index], current_values[index]);
+ if (m_current_values[index] + value <= m_limit_values[index]) {
+ m_current_values[index] += value;
+ m_current_hints[index] += value;
+ m_peak_values[index] = std::max(m_peak_values[index], m_current_values[index]);
return true;
}
- if (current_hints[index] + value <= limit_values[index] &&
- (timeout < 0 || core_timing->GetGlobalTimeNs().count() < timeout)) {
- waiter_count++;
- cond_var.Wait(&lock, timeout, false);
- waiter_count--;
+ if (m_current_hints[index] + value <= m_limit_values[index] &&
+ (timeout < 0 || m_core_timing->GetGlobalTimeNs().count() < timeout)) {
+ m_waiter_count++;
+ m_cond_var.Wait(std::addressof(m_lock), timeout, false);
+ m_waiter_count--;
} else {
break;
}
@@ -137,23 +138,23 @@ void KResourceLimit::Release(LimitableResource which, s64 value, s64 hint) {
ASSERT(hint >= 0);
const auto index = static_cast<std::size_t>(which);
- KScopedLightLock lk(lock);
- ASSERT(current_values[index] <= limit_values[index]);
- ASSERT(current_hints[index] <= current_values[index]);
- ASSERT(value <= current_values[index]);
- ASSERT(hint <= current_hints[index]);
+ KScopedLightLock lk(m_lock);
+ ASSERT(m_current_values[index] <= m_limit_values[index]);
+ ASSERT(m_current_hints[index] <= m_current_values[index]);
+ ASSERT(value <= m_current_values[index]);
+ ASSERT(hint <= m_current_hints[index]);
- current_values[index] -= value;
- current_hints[index] -= hint;
+ m_current_values[index] -= value;
+ m_current_hints[index] -= hint;
- if (waiter_count != 0) {
- cond_var.Broadcast();
+ if (m_waiter_count != 0) {
+ m_cond_var.Broadcast();
}
}
KResourceLimit* CreateResourceLimitForProcess(Core::System& system, s64 physical_memory_size) {
auto* resource_limit = KResourceLimit::Create(system.Kernel());
- resource_limit->Initialize(&system.CoreTiming());
+ resource_limit->Initialize(std::addressof(system.CoreTiming()));
// Initialize default resource limit values.
// TODO(bunnei): These values are the system defaults, the limits for service processes are
diff --git a/src/core/hle/kernel/k_resource_limit.h b/src/core/hle/kernel/k_resource_limit.h
index 2573d1b7c..15e69af56 100644
--- a/src/core/hle/kernel/k_resource_limit.h
+++ b/src/core/hle/kernel/k_resource_limit.h
@@ -28,10 +28,10 @@ class KResourceLimit final
KERNEL_AUTOOBJECT_TRAITS(KResourceLimit, KAutoObject);
public:
- explicit KResourceLimit(KernelCore& kernel_);
+ explicit KResourceLimit(KernelCore& kernel);
~KResourceLimit() override;
- void Initialize(const Core::Timing::CoreTiming* core_timing_);
+ void Initialize(const Core::Timing::CoreTiming* core_timing);
void Finalize() override;
s64 GetLimitValue(LimitableResource which) const;
@@ -46,18 +46,18 @@ public:
void Release(LimitableResource which, s64 value);
void Release(LimitableResource which, s64 value, s64 hint);
- static void PostDestroy([[maybe_unused]] uintptr_t arg) {}
+ static void PostDestroy(uintptr_t arg) {}
private:
using ResourceArray = std::array<s64, static_cast<std::size_t>(LimitableResource::Count)>;
- ResourceArray limit_values{};
- ResourceArray current_values{};
- ResourceArray current_hints{};
- ResourceArray peak_values{};
- mutable KLightLock lock;
- s32 waiter_count{};
- KLightConditionVariable cond_var;
- const Core::Timing::CoreTiming* core_timing{};
+ ResourceArray m_limit_values{};
+ ResourceArray m_current_values{};
+ ResourceArray m_current_hints{};
+ ResourceArray m_peak_values{};
+ mutable KLightLock m_lock;
+ s32 m_waiter_count{};
+ KLightConditionVariable m_cond_var;
+ const Core::Timing::CoreTiming* m_core_timing{};
};
KResourceLimit* CreateResourceLimitForProcess(Core::System& system, s64 physical_memory_size);
diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp
index d6676904b..75ce5a23c 100644
--- a/src/core/hle/kernel/k_scheduler.cpp
+++ b/src/core/hle/kernel/k_scheduler.cpp
@@ -27,7 +27,7 @@ static void IncrementScheduledCount(Kernel::KThread* thread) {
}
}
-KScheduler::KScheduler(KernelCore& kernel_) : kernel{kernel_} {
+KScheduler::KScheduler(KernelCore& kernel) : m_kernel{kernel} {
m_switch_fiber = std::make_shared<Common::Fiber>([this] {
while (true) {
ScheduleImplFiber();
@@ -47,7 +47,7 @@ void KScheduler::SetInterruptTaskRunnable() {
void KScheduler::RequestScheduleOnInterrupt() {
m_state.needs_scheduling = true;
- if (CanSchedule(kernel)) {
+ if (CanSchedule(m_kernel)) {
ScheduleOnInterrupt();
}
}
@@ -97,50 +97,50 @@ u64 KScheduler::UpdateHighestPriorityThreads(KernelCore& kernel) {
}
void KScheduler::Schedule() {
- ASSERT(GetCurrentThread(kernel).GetDisableDispatchCount() == 1);
- ASSERT(m_core_id == GetCurrentCoreId(kernel));
+ ASSERT(GetCurrentThread(m_kernel).GetDisableDispatchCount() == 1);
+ ASSERT(m_core_id == GetCurrentCoreId(m_kernel));
ScheduleImpl();
}
void KScheduler::ScheduleOnInterrupt() {
- GetCurrentThread(kernel).DisableDispatch();
+ GetCurrentThread(m_kernel).DisableDispatch();
Schedule();
- GetCurrentThread(kernel).EnableDispatch();
+ GetCurrentThread(m_kernel).EnableDispatch();
}
void KScheduler::PreemptSingleCore() {
- GetCurrentThread(kernel).DisableDispatch();
+ GetCurrentThread(m_kernel).DisableDispatch();
- auto* thread = GetCurrentThreadPointer(kernel);
- auto& previous_scheduler = kernel.Scheduler(thread->GetCurrentCore());
+ auto* thread = GetCurrentThreadPointer(m_kernel);
+ auto& previous_scheduler = m_kernel.Scheduler(thread->GetCurrentCore());
previous_scheduler.Unload(thread);
Common::Fiber::YieldTo(thread->GetHostContext(), *m_switch_fiber);
- GetCurrentThread(kernel).EnableDispatch();
+ GetCurrentThread(m_kernel).EnableDispatch();
}
void KScheduler::RescheduleCurrentCore() {
- ASSERT(!kernel.IsPhantomModeForSingleCore());
- ASSERT(GetCurrentThread(kernel).GetDisableDispatchCount() == 1);
+ ASSERT(!m_kernel.IsPhantomModeForSingleCore());
+ ASSERT(GetCurrentThread(m_kernel).GetDisableDispatchCount() == 1);
- GetCurrentThread(kernel).EnableDispatch();
+ GetCurrentThread(m_kernel).EnableDispatch();
if (m_state.needs_scheduling.load()) {
// Disable interrupts, and then check again if rescheduling is needed.
// KScopedInterruptDisable intr_disable;
- kernel.CurrentScheduler()->RescheduleCurrentCoreImpl();
+ m_kernel.CurrentScheduler()->RescheduleCurrentCoreImpl();
}
}
void KScheduler::RescheduleCurrentCoreImpl() {
// Check that scheduling is needed.
if (m_state.needs_scheduling.load()) [[likely]] {
- GetCurrentThread(kernel).DisableDispatch();
+ GetCurrentThread(m_kernel).DisableDispatch();
Schedule();
- GetCurrentThread(kernel).EnableDispatch();
+ GetCurrentThread(m_kernel).EnableDispatch();
}
}
@@ -149,18 +149,18 @@ void KScheduler::Initialize(KThread* main_thread, KThread* idle_thread, s32 core
m_core_id = core_id;
m_idle_thread = idle_thread;
// m_state.idle_thread_stack = m_idle_thread->GetStackTop();
- // m_state.interrupt_task_manager = &kernel.GetInterruptTaskManager();
+ // m_state.interrupt_task_manager = std::addressof(kernel.GetInterruptTaskManager());
// Insert the main thread into the priority queue.
// {
- // KScopedSchedulerLock lk{kernel};
- // GetPriorityQueue(kernel).PushBack(GetCurrentThreadPointer(kernel));
- // SetSchedulerUpdateNeeded(kernel);
+ // KScopedSchedulerLock lk{m_kernel};
+ // GetPriorityQueue(m_kernel).PushBack(GetCurrentThreadPointer(m_kernel));
+ // SetSchedulerUpdateNeeded(m_kernel);
// }
// Bind interrupt handler.
// kernel.GetInterruptManager().BindHandler(
- // GetSchedulerInterruptHandler(kernel), KInterruptName::Scheduler, m_core_id,
+ // GetSchedulerInterruptHandler(m_kernel), KInterruptName::Scheduler, m_core_id,
// KInterruptController::PriorityLevel::Scheduler, false, false);
// Set the current thread.
@@ -168,7 +168,7 @@ void KScheduler::Initialize(KThread* main_thread, KThread* idle_thread, s32 core
}
void KScheduler::Activate() {
- ASSERT(GetCurrentThread(kernel).GetDisableDispatchCount() == 1);
+ ASSERT(GetCurrentThread(m_kernel).GetDisableDispatchCount() == 1);
// m_state.should_count_idle = KTargetSystem::IsDebugMode();
m_is_active = true;
@@ -176,7 +176,7 @@ void KScheduler::Activate() {
}
void KScheduler::OnThreadStart() {
- GetCurrentThread(kernel).EnableDispatch();
+ GetCurrentThread(m_kernel).EnableDispatch();
}
u64 KScheduler::UpdateHighestPriorityThread(KThread* highest_thread) {
@@ -184,7 +184,8 @@ u64 KScheduler::UpdateHighestPriorityThread(KThread* highest_thread) {
prev_highest_thread != highest_thread) [[likely]] {
if (prev_highest_thread != nullptr) [[likely]] {
IncrementScheduledCount(prev_highest_thread);
- prev_highest_thread->SetLastScheduledTick(kernel.System().CoreTiming().GetCPUTicks());
+ prev_highest_thread->SetLastScheduledTick(
+ m_kernel.System().CoreTiming().GetClockTicks());
}
if (m_state.should_count_idle) {
if (highest_thread != nullptr) [[likely]] {
@@ -328,8 +329,8 @@ u64 KScheduler::UpdateHighestPriorityThreadsImpl(KernelCore& kernel) {
}
void KScheduler::SwitchThread(KThread* next_thread) {
- KProcess* const cur_process = kernel.CurrentProcess();
- KThread* const cur_thread = GetCurrentThreadPointer(kernel);
+ KProcess* const cur_process = GetCurrentProcessPointer(m_kernel);
+ KThread* const cur_thread = GetCurrentThreadPointer(m_kernel);
// We never want to schedule a null thread, so use the idle thread if we don't have a next.
if (next_thread == nullptr) {
@@ -351,7 +352,7 @@ void KScheduler::SwitchThread(KThread* next_thread) {
// Update the CPU time tracking variables.
const s64 prev_tick = m_last_context_switch_time;
- const s64 cur_tick = kernel.System().CoreTiming().GetCPUTicks();
+ const s64 cur_tick = m_kernel.System().CoreTiming().GetClockTicks();
const s64 tick_diff = cur_tick - prev_tick;
cur_thread->AddCpuTime(m_core_id, tick_diff);
if (cur_process != nullptr) {
@@ -375,7 +376,7 @@ void KScheduler::SwitchThread(KThread* next_thread) {
// }
// Set the new thread.
- SetCurrentThread(kernel, next_thread);
+ SetCurrentThread(m_kernel, next_thread);
m_current_thread = next_thread;
// Set the new Thread Local region.
@@ -388,7 +389,7 @@ void KScheduler::ScheduleImpl() {
std::atomic_thread_fence(std::memory_order_seq_cst);
// Load the appropriate thread pointers for scheduling.
- KThread* const cur_thread{GetCurrentThreadPointer(kernel)};
+ KThread* const cur_thread{GetCurrentThreadPointer(m_kernel)};
KThread* highest_priority_thread{m_state.highest_priority_thread};
// Check whether there are runnable interrupt tasks.
@@ -411,7 +412,7 @@ void KScheduler::ScheduleImpl() {
m_switch_cur_thread = cur_thread;
m_switch_highest_priority_thread = highest_priority_thread;
m_switch_from_schedule = true;
- Common::Fiber::YieldTo(cur_thread->host_context, *m_switch_fiber);
+ Common::Fiber::YieldTo(cur_thread->m_host_context, *m_switch_fiber);
// Returning from ScheduleImpl occurs after this thread has been scheduled again.
}
@@ -450,7 +451,7 @@ void KScheduler::ScheduleImplFiber() {
// We want to try to lock the highest priority thread's context.
// Try to take it.
- while (!highest_priority_thread->context_guard.try_lock()) {
+ while (!highest_priority_thread->m_context_guard.try_lock()) {
// The highest priority thread's context is already locked.
// Check if we need scheduling. If we don't, we can retry directly.
if (m_state.needs_scheduling.load(std::memory_order_seq_cst)) {
@@ -468,7 +469,7 @@ void KScheduler::ScheduleImplFiber() {
if (m_state.needs_scheduling.load(std::memory_order_seq_cst)) {
// Our switch failed.
// We should unlock the thread context, and then retry.
- highest_priority_thread->context_guard.unlock();
+ highest_priority_thread->m_context_guard.unlock();
goto retry;
} else {
break;
@@ -489,30 +490,30 @@ void KScheduler::ScheduleImplFiber() {
Reload(highest_priority_thread);
// Reload the host thread.
- Common::Fiber::YieldTo(m_switch_fiber, *highest_priority_thread->host_context);
+ Common::Fiber::YieldTo(m_switch_fiber, *highest_priority_thread->m_host_context);
}
void KScheduler::Unload(KThread* thread) {
- auto& cpu_core = kernel.System().ArmInterface(m_core_id);
+ auto& cpu_core = m_kernel.System().ArmInterface(m_core_id);
cpu_core.SaveContext(thread->GetContext32());
cpu_core.SaveContext(thread->GetContext64());
// Save the TPIDR_EL0 system register in case it was modified.
- thread->SetTPIDR_EL0(cpu_core.GetTPIDR_EL0());
+ thread->SetTpidrEl0(cpu_core.GetTPIDR_EL0());
cpu_core.ClearExclusiveState();
// Check if the thread is terminated by checking the DPC flags.
if ((thread->GetStackParameters().dpc_flags & static_cast<u32>(DpcFlag::Terminated)) == 0) {
// The thread isn't terminated, so we want to unlock it.
- thread->context_guard.unlock();
+ thread->m_context_guard.unlock();
}
}
void KScheduler::Reload(KThread* thread) {
- auto& cpu_core = kernel.System().ArmInterface(m_core_id);
+ auto& cpu_core = m_kernel.System().ArmInterface(m_core_id);
cpu_core.LoadContext(thread->GetContext32());
cpu_core.LoadContext(thread->GetContext64());
- cpu_core.SetTlsAddress(thread->GetTLSAddress());
- cpu_core.SetTPIDR_EL0(thread->GetTPIDR_EL0());
+ cpu_core.SetTlsAddress(GetInteger(thread->GetTlsAddress()));
+ cpu_core.SetTPIDR_EL0(thread->GetTpidrEl0());
cpu_core.LoadWatchpointArray(thread->GetOwnerProcess()->GetWatchpoints());
cpu_core.ClearExclusiveState();
}
@@ -689,11 +690,11 @@ void KScheduler::RotateScheduledQueue(KernelCore& kernel, s32 core_id, s32 prior
void KScheduler::YieldWithoutCoreMigration(KernelCore& kernel) {
// Validate preconditions.
ASSERT(CanSchedule(kernel));
- ASSERT(kernel.CurrentProcess() != nullptr);
+ ASSERT(GetCurrentProcessPointer(kernel) != nullptr);
// Get the current thread and process.
KThread& cur_thread = GetCurrentThread(kernel);
- KProcess& cur_process = *kernel.CurrentProcess();
+ KProcess& cur_process = GetCurrentProcess(kernel);
// If the thread's yield count matches, there's nothing for us to do.
if (cur_thread.GetYieldScheduleCount() == cur_process.GetScheduledCount()) {
@@ -728,11 +729,11 @@ void KScheduler::YieldWithoutCoreMigration(KernelCore& kernel) {
void KScheduler::YieldWithCoreMigration(KernelCore& kernel) {
// Validate preconditions.
ASSERT(CanSchedule(kernel));
- ASSERT(kernel.CurrentProcess() != nullptr);
+ ASSERT(GetCurrentProcessPointer(kernel) != nullptr);
// Get the current thread and process.
KThread& cur_thread = GetCurrentThread(kernel);
- KProcess& cur_process = *kernel.CurrentProcess();
+ KProcess& cur_process = GetCurrentProcess(kernel);
// If the thread's yield count matches, there's nothing for us to do.
if (cur_thread.GetYieldScheduleCount() == cur_process.GetScheduledCount()) {
@@ -816,11 +817,11 @@ void KScheduler::YieldWithCoreMigration(KernelCore& kernel) {
void KScheduler::YieldToAnyThread(KernelCore& kernel) {
// Validate preconditions.
ASSERT(CanSchedule(kernel));
- ASSERT(kernel.CurrentProcess() != nullptr);
+ ASSERT(GetCurrentProcessPointer(kernel) != nullptr);
// Get the current thread and process.
KThread& cur_thread = GetCurrentThread(kernel);
- KProcess& cur_process = *kernel.CurrentProcess();
+ KProcess& cur_process = GetCurrentProcess(kernel);
// If the thread's yield count matches, there's nothing for us to do.
if (cur_thread.GetYieldScheduleCount() == cur_process.GetScheduledCount()) {
@@ -891,7 +892,7 @@ void KScheduler::YieldToAnyThread(KernelCore& kernel) {
void KScheduler::RescheduleOtherCores(u64 cores_needing_scheduling) {
if (const u64 core_mask = cores_needing_scheduling & ~(1ULL << m_core_id); core_mask != 0) {
- RescheduleCores(kernel, core_mask);
+ RescheduleCores(m_kernel, core_mask);
}
}
diff --git a/src/core/hle/kernel/k_scheduler.h b/src/core/hle/kernel/k_scheduler.h
index 534321d8d..d85a0c040 100644
--- a/src/core/hle/kernel/k_scheduler.h
+++ b/src/core/hle/kernel/k_scheduler.h
@@ -80,17 +80,17 @@ public:
return GetCurrentThread(kernel).GetDisableDispatchCount() == 0;
}
static bool IsSchedulerLockedByCurrentThread(KernelCore& kernel) {
- return kernel.GlobalSchedulerContext().scheduler_lock.IsLockedByCurrentThread();
+ return kernel.GlobalSchedulerContext().m_scheduler_lock.IsLockedByCurrentThread();
}
static bool IsSchedulerUpdateNeeded(KernelCore& kernel) {
- return kernel.GlobalSchedulerContext().scheduler_update_needed;
+ return kernel.GlobalSchedulerContext().m_scheduler_update_needed;
}
static void SetSchedulerUpdateNeeded(KernelCore& kernel) {
- kernel.GlobalSchedulerContext().scheduler_update_needed = true;
+ kernel.GlobalSchedulerContext().m_scheduler_update_needed = true;
}
static void ClearSchedulerUpdateNeeded(KernelCore& kernel) {
- kernel.GlobalSchedulerContext().scheduler_update_needed = false;
+ kernel.GlobalSchedulerContext().m_scheduler_update_needed = false;
}
static void DisableScheduling(KernelCore& kernel);
@@ -115,7 +115,7 @@ public:
private:
// Static private API.
static KSchedulerPriorityQueue& GetPriorityQueue(KernelCore& kernel) {
- return kernel.GlobalSchedulerContext().priority_queue;
+ return kernel.GlobalSchedulerContext().m_priority_queue;
}
static u64 UpdateHighestPriorityThreadsImpl(KernelCore& kernel);
@@ -149,7 +149,7 @@ private:
KInterruptTaskManager* interrupt_task_manager{nullptr};
};
- KernelCore& kernel;
+ KernelCore& m_kernel;
SchedulingState m_state;
bool m_is_active{false};
s32 m_core_id{0};
@@ -166,7 +166,7 @@ private:
class KScopedSchedulerLock : public KScopedLock<KScheduler::LockType> {
public:
explicit KScopedSchedulerLock(KernelCore& kernel)
- : KScopedLock(kernel.GlobalSchedulerContext().scheduler_lock) {}
+ : KScopedLock(kernel.GlobalSchedulerContext().m_scheduler_lock) {}
~KScopedSchedulerLock() = default;
};
diff --git a/src/core/hle/kernel/k_scheduler_lock.h b/src/core/hle/kernel/k_scheduler_lock.h
index 129d60472..caa1404f1 100644
--- a/src/core/hle/kernel/k_scheduler_lock.h
+++ b/src/core/hle/kernel/k_scheduler_lock.h
@@ -14,73 +14,67 @@
namespace Kernel {
class KernelCore;
+class GlobalSchedulerContext;
template <typename SchedulerType>
class KAbstractSchedulerLock {
public:
- explicit KAbstractSchedulerLock(KernelCore& kernel_) : kernel{kernel_} {}
+ explicit KAbstractSchedulerLock(KernelCore& kernel) : m_kernel{kernel} {}
bool IsLockedByCurrentThread() const {
- return owner_thread == GetCurrentThreadPointer(kernel);
+ return m_owner_thread == GetCurrentThreadPointer(m_kernel);
}
void Lock() {
- // If we are shutting down the kernel, none of this is relevant anymore.
- if (kernel.IsShuttingDown()) {
- return;
- }
-
- if (IsLockedByCurrentThread()) {
- // If we already own the lock, we can just increment the count.
- ASSERT(lock_count > 0);
- lock_count++;
+ if (this->IsLockedByCurrentThread()) {
+ // If we already own the lock, the lock count should be > 0.
+ // For debug, ensure this is true.
+ ASSERT(m_lock_count > 0);
} else {
// Otherwise, we want to disable scheduling and acquire the spinlock.
- SchedulerType::DisableScheduling(kernel);
- spin_lock.Lock();
+ SchedulerType::DisableScheduling(m_kernel);
+ m_spin_lock.Lock();
- // For debug, ensure that our state is valid.
- ASSERT(lock_count == 0);
- ASSERT(owner_thread == nullptr);
+ ASSERT(m_lock_count == 0);
+ ASSERT(m_owner_thread == nullptr);
- // Increment count, take ownership.
- lock_count = 1;
- owner_thread = GetCurrentThreadPointer(kernel);
+ // Take ownership of the lock.
+ m_owner_thread = GetCurrentThreadPointer(m_kernel);
}
+
+ // Increment the lock count.
+ m_lock_count++;
}
void Unlock() {
- // If we are shutting down the kernel, none of this is relevant anymore.
- if (kernel.IsShuttingDown()) {
- return;
- }
-
- ASSERT(IsLockedByCurrentThread());
- ASSERT(lock_count > 0);
+ ASSERT(this->IsLockedByCurrentThread());
+ ASSERT(m_lock_count > 0);
// Release an instance of the lock.
- if ((--lock_count) == 0) {
+ if ((--m_lock_count) == 0) {
// Perform a memory barrier here.
std::atomic_thread_fence(std::memory_order_seq_cst);
// We're no longer going to hold the lock. Take note of what cores need scheduling.
const u64 cores_needing_scheduling =
- SchedulerType::UpdateHighestPriorityThreads(kernel);
+ SchedulerType::UpdateHighestPriorityThreads(m_kernel);
// Note that we no longer hold the lock, and unlock the spinlock.
- owner_thread = nullptr;
- spin_lock.Unlock();
+ m_owner_thread = nullptr;
+ m_spin_lock.Unlock();
// Enable scheduling, and perform a rescheduling operation.
- SchedulerType::EnableScheduling(kernel, cores_needing_scheduling);
+ SchedulerType::EnableScheduling(m_kernel, cores_needing_scheduling);
}
}
private:
- KernelCore& kernel;
- KAlignedSpinLock spin_lock{};
- s32 lock_count{};
- std::atomic<KThread*> owner_thread{};
+ friend class GlobalSchedulerContext;
+
+ KernelCore& m_kernel;
+ KAlignedSpinLock m_spin_lock{};
+ s32 m_lock_count{};
+ std::atomic<KThread*> m_owner_thread{};
};
} // namespace Kernel
diff --git a/src/core/hle/kernel/k_scoped_lock.h b/src/core/hle/kernel/k_scoped_lock.h
index 857e21156..629a7d20d 100644
--- a/src/core/hle/kernel/k_scoped_lock.h
+++ b/src/core/hle/kernel/k_scoped_lock.h
@@ -4,27 +4,29 @@
#pragma once
#include <concepts>
+#include <memory>
#include <type_traits>
namespace Kernel {
template <typename T>
-concept KLockable = !std::is_reference_v<T> && requires(T & t) {
- { t.Lock() } -> std::same_as<void>;
- { t.Unlock() } -> std::same_as<void>;
-};
+concept KLockable = !
+std::is_reference_v<T>&& requires(T& t) {
+ { t.Lock() } -> std::same_as<void>;
+ { t.Unlock() } -> std::same_as<void>;
+ };
template <typename T>
-requires KLockable<T>
-class [[nodiscard]] KScopedLock {
+ requires KLockable<T>
+class KScopedLock {
public:
- explicit KScopedLock(T* l) : lock_ptr(l) {
- this->lock_ptr->Lock();
+ explicit KScopedLock(T* l) : m_lock(*l) {}
+ explicit KScopedLock(T& l) : m_lock(l) {
+ m_lock.Lock();
}
- explicit KScopedLock(T& l) : KScopedLock(std::addressof(l)) {}
~KScopedLock() {
- this->lock_ptr->Unlock();
+ m_lock.Unlock();
}
KScopedLock(const KScopedLock&) = delete;
@@ -34,7 +36,7 @@ public:
KScopedLock& operator=(KScopedLock&&) = delete;
private:
- T* lock_ptr;
+ T& m_lock;
};
} // namespace Kernel
diff --git a/src/core/hle/kernel/k_scoped_resource_reservation.h b/src/core/hle/kernel/k_scoped_resource_reservation.h
index 436bcf9fe..2cc464612 100644
--- a/src/core/hle/kernel/k_scoped_resource_reservation.h
+++ b/src/core/hle/kernel/k_scoped_resource_reservation.h
@@ -12,20 +12,20 @@ namespace Kernel {
class KScopedResourceReservation {
public:
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);
+ : m_limit(l), m_value(v), m_resource(r) {
+ if (m_limit && m_value) {
+ m_succeeded = m_limit->Reserve(m_resource, m_value, timeout);
} else {
- success = true;
+ m_succeeded = true;
}
}
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);
+ : m_limit(l), m_value(v), m_resource(r) {
+ if (m_limit && m_value) {
+ m_succeeded = m_limit->Reserve(m_resource, m_value);
} else {
- success = true;
+ m_succeeded = true;
}
}
@@ -36,26 +36,26 @@ public:
: KScopedResourceReservation(p->GetResourceLimit(), r, v) {}
~KScopedResourceReservation() noexcept {
- if (resource_limit && value && success) {
- // resource was not committed, release the reservation.
- resource_limit->Release(resource, value);
+ if (m_limit && m_value && m_succeeded) {
+ // Resource was not committed, release the reservation.
+ m_limit->Release(m_resource, m_value);
}
}
/// Commit the resource reservation, destruction of this object does not release the resource
void Commit() {
- resource_limit = nullptr;
+ m_limit = nullptr;
}
- [[nodiscard]] bool Succeeded() const {
- return success;
+ bool Succeeded() const {
+ return m_succeeded;
}
private:
- KResourceLimit* resource_limit{};
- s64 value;
- LimitableResource resource;
- bool success;
+ KResourceLimit* m_limit{};
+ s64 m_value{};
+ LimitableResource m_resource{};
+ bool m_succeeded{};
};
} // namespace Kernel
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 76db65a4d..c485022f5 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
@@ -11,32 +11,39 @@
namespace Kernel {
-class [[nodiscard]] KScopedSchedulerLockAndSleep {
+class KScopedSchedulerLockAndSleep {
public:
- explicit KScopedSchedulerLockAndSleep(KernelCore& kernel_, KThread* t, s64 timeout)
- : kernel(kernel_), thread(t), timeout_tick(timeout) {
+ explicit KScopedSchedulerLockAndSleep(KernelCore& kernel, KHardwareTimer** out_timer,
+ KThread* thread, s64 timeout_tick)
+ : m_kernel(kernel), m_timeout_tick(timeout_tick), m_thread(thread), m_timer() {
// Lock the scheduler.
- kernel.GlobalSchedulerContext().scheduler_lock.Lock();
+ kernel.GlobalSchedulerContext().m_scheduler_lock.Lock();
+
+ // Set our timer only if the time is positive.
+ m_timer = (timeout_tick > 0) ? std::addressof(kernel.HardwareTimer()) : nullptr;
+
+ *out_timer = m_timer;
}
~KScopedSchedulerLockAndSleep() {
// Register the sleep.
- if (timeout_tick > 0) {
- kernel.HardwareTimer().RegisterTask(thread, timeout_tick);
+ if (m_timeout_tick > 0) {
+ m_timer->RegisterTask(m_thread, m_timeout_tick);
}
// Unlock the scheduler.
- kernel.GlobalSchedulerContext().scheduler_lock.Unlock();
+ m_kernel.GlobalSchedulerContext().m_scheduler_lock.Unlock();
}
void CancelSleep() {
- timeout_tick = 0;
+ m_timeout_tick = 0;
}
private:
- KernelCore& kernel;
- KThread* thread{};
- s64 timeout_tick{};
+ KernelCore& m_kernel;
+ s64 m_timeout_tick{};
+ KThread* m_thread{};
+ KHardwareTimer* m_timer{};
};
} // namespace Kernel
diff --git a/src/core/hle/kernel/k_server_port.cpp b/src/core/hle/kernel/k_server_port.cpp
index 16968ba97..a29d34bc1 100644
--- a/src/core/hle/kernel/k_server_port.cpp
+++ b/src/core/hle/kernel/k_server_port.cpp
@@ -12,13 +12,12 @@
namespace Kernel {
-KServerPort::KServerPort(KernelCore& kernel_) : KSynchronizationObject{kernel_} {}
+KServerPort::KServerPort(KernelCore& kernel) : KSynchronizationObject{kernel} {}
KServerPort::~KServerPort() = default;
-void KServerPort::Initialize(KPort* parent_port_, std::string&& name_) {
+void KServerPort::Initialize(KPort* parent) {
// Set member variables.
- parent = parent_port_;
- name = std::move(name_);
+ m_parent = parent;
}
bool KServerPort::IsLight() const {
@@ -36,10 +35,10 @@ void KServerPort::CleanupSessions() {
// 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();
+ KScopedSchedulerLock sl{m_kernel};
+ if (!m_session_list.empty()) {
+ session = std::addressof(m_session_list.front());
+ m_session_list.pop_front();
}
}
@@ -54,13 +53,13 @@ void KServerPort::CleanupSessions() {
void KServerPort::Destroy() {
// Note with our parent that we're closed.
- parent->OnServerClosed();
+ m_parent->OnServerClosed();
// Perform necessary cleanup of our session lists.
this->CleanupSessions();
// Close our reference to our parent.
- parent->Close();
+ m_parent->Close();
}
bool KServerPort::IsSignaled() const {
@@ -68,18 +67,18 @@ bool KServerPort::IsSignaled() const {
UNIMPLEMENTED();
return false;
} else {
- return !session_list.empty();
+ return !m_session_list.empty();
}
}
void KServerPort::EnqueueSession(KServerSession* session) {
ASSERT(!this->IsLight());
- KScopedSchedulerLock sl{kernel};
+ KScopedSchedulerLock sl{m_kernel};
// Add the session to our queue.
- session_list.push_back(*session);
- if (session_list.size() == 1) {
+ m_session_list.push_back(*session);
+ if (m_session_list.size() == 1) {
this->NotifyAvailable();
}
}
@@ -87,15 +86,15 @@ void KServerPort::EnqueueSession(KServerSession* session) {
KServerSession* KServerPort::AcceptSession() {
ASSERT(!this->IsLight());
- KScopedSchedulerLock sl{kernel};
+ KScopedSchedulerLock sl{m_kernel};
// Return the first session in the list.
- if (session_list.empty()) {
+ if (m_session_list.empty()) {
return nullptr;
}
- KServerSession* session = std::addressof(session_list.front());
- session_list.pop_front();
+ KServerSession* session = std::addressof(m_session_list.front());
+ m_session_list.pop_front();
return session;
}
diff --git a/src/core/hle/kernel/k_server_port.h b/src/core/hle/kernel/k_server_port.h
index 5fc7ee683..625280290 100644
--- a/src/core/hle/kernel/k_server_port.h
+++ b/src/core/hle/kernel/k_server_port.h
@@ -7,7 +7,7 @@
#include <string>
#include <utility>
-#include <boost/intrusive/list.hpp>
+#include "common/intrusive_list.h"
#include "core/hle/kernel/k_server_session.h"
#include "core/hle/kernel/k_synchronization_object.h"
@@ -22,17 +22,17 @@ class KServerPort final : public KSynchronizationObject {
KERNEL_AUTOOBJECT_TRAITS(KServerPort, KSynchronizationObject);
public:
- explicit KServerPort(KernelCore& kernel_);
+ explicit KServerPort(KernelCore& kernel);
~KServerPort() override;
- void Initialize(KPort* parent_port_, std::string&& name_);
+ void Initialize(KPort* parent);
- void EnqueueSession(KServerSession* pending_session);
+ void EnqueueSession(KServerSession* session);
KServerSession* AcceptSession();
const KPort* GetParent() const {
- return parent;
+ return m_parent;
}
bool IsLight() const;
@@ -42,12 +42,12 @@ public:
bool IsSignaled() const override;
private:
- using SessionList = boost::intrusive::list<KServerSession>;
+ using SessionList = Common::IntrusiveListBaseTraits<KServerSession>::ListType;
void CleanupSessions();
- SessionList session_list;
- KPort* parent{};
+ SessionList m_session_list{};
+ KPort* m_parent{};
};
} // namespace Kernel
diff --git a/src/core/hle/kernel/k_server_session.cpp b/src/core/hle/kernel/k_server_session.cpp
index aa1941f01..c66aff501 100644
--- a/src/core/hle/kernel/k_server_session.cpp
+++ b/src/core/hle/kernel/k_server_session.cpp
@@ -10,8 +10,6 @@
#include "common/scope_exit.h"
#include "core/core.h"
#include "core/core_timing.h"
-#include "core/hle/ipc_helpers.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"
@@ -22,29 +20,25 @@
#include "core/hle/kernel/k_thread.h"
#include "core/hle/kernel/k_thread_queue.h"
#include "core/hle/kernel/kernel.h"
+#include "core/hle/service/hle_ipc.h"
+#include "core/hle/service/ipc_helpers.h"
#include "core/memory.h"
namespace Kernel {
using ThreadQueueImplForKServerSessionRequest = KThreadQueue;
-KServerSession::KServerSession(KernelCore& kernel_)
- : KSynchronizationObject{kernel_}, m_lock{kernel_} {}
+KServerSession::KServerSession(KernelCore& kernel)
+ : KSynchronizationObject{kernel}, m_lock{m_kernel} {}
KServerSession::~KServerSession() = default;
-void KServerSession::Initialize(KSession* parent_session_, std::string&& name_) {
- // Set member variables.
- parent = parent_session_;
- name = std::move(name_);
-}
-
void KServerSession::Destroy() {
- parent->OnServerClosed();
+ m_parent->OnServerClosed();
this->CleanupRequests();
- parent->Close();
+ m_parent->Close();
}
void KServerSession::OnClientClosed() {
@@ -62,7 +56,7 @@ void KServerSession::OnClientClosed() {
// Get the next request.
{
- KScopedSchedulerLock sl{kernel};
+ KScopedSchedulerLock sl{m_kernel};
if (m_current_request != nullptr && m_current_request != prev_request) {
// Set the request, open a reference as we process it.
@@ -121,7 +115,7 @@ void KServerSession::OnClientClosed() {
// // Get the process and page table.
// KProcess *client_process = thread->GetOwnerProcess();
- // auto &client_pt = client_process->GetPageTable();
+ // auto& client_pt = client_process->GetPageTable();
// // Reply to the request.
// ReplyAsyncError(client_process, request->GetAddress(), request->GetSize(),
@@ -141,10 +135,10 @@ void KServerSession::OnClientClosed() {
}
bool KServerSession::IsSignaled() const {
- ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(kernel));
+ ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(m_kernel));
// If the client is closed, we're always signaled.
- if (parent->IsClientClosed()) {
+ if (m_parent->IsClientClosed()) {
return true;
}
@@ -154,17 +148,17 @@ bool KServerSession::IsSignaled() const {
Result KServerSession::OnRequest(KSessionRequest* request) {
// Create the wait queue.
- ThreadQueueImplForKServerSessionRequest wait_queue{kernel};
+ ThreadQueueImplForKServerSessionRequest wait_queue{m_kernel};
{
// Lock the scheduler.
- KScopedSchedulerLock sl{kernel};
+ KScopedSchedulerLock sl{m_kernel};
// Ensure that we can handle new requests.
- R_UNLESS(!parent->IsServerClosed(), ResultSessionClosed);
+ R_UNLESS(!m_parent->IsServerClosed(), ResultSessionClosed);
// Check that we're not terminating.
- R_UNLESS(!GetCurrentThread(kernel).IsTerminationRequested(), ResultTerminationRequested);
+ R_UNLESS(!GetCurrentThread(m_kernel).IsTerminationRequested(), ResultTerminationRequested);
// Get whether we're empty.
const bool was_empty = m_request_list.empty();
@@ -182,11 +176,11 @@ Result KServerSession::OnRequest(KSessionRequest* request) {
R_SUCCEED_IF(request->GetEvent() != nullptr);
// This is a synchronous request, so we should wait for our request to complete.
- GetCurrentThread(kernel).SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::IPC);
- GetCurrentThread(kernel).BeginWait(&wait_queue);
+ GetCurrentThread(m_kernel).SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::IPC);
+ GetCurrentThread(m_kernel).BeginWait(std::addressof(wait_queue));
}
- return GetCurrentThread(kernel).GetWaitResult();
+ return GetCurrentThread(m_kernel).GetWaitResult();
}
Result KServerSession::SendReply(bool is_hle) {
@@ -196,7 +190,7 @@ Result KServerSession::SendReply(bool is_hle) {
// Get the request.
KSessionRequest* request;
{
- KScopedSchedulerLock sl{kernel};
+ KScopedSchedulerLock sl{m_kernel};
// Get the current request.
request = m_current_request;
@@ -219,7 +213,7 @@ Result KServerSession::SendReply(bool is_hle) {
KEvent* event = request->GetEvent();
// Check whether we're closed.
- const bool closed = (client_thread == nullptr || parent->IsClientClosed());
+ const bool closed = (client_thread == nullptr || m_parent->IsClientClosed());
Result result = ResultSuccess;
if (!closed) {
@@ -228,11 +222,11 @@ Result KServerSession::SendReply(bool is_hle) {
// HLE servers write directly to a pointer to the thread command buffer. Therefore
// the reply has already been written in this case.
} else {
- Core::Memory::Memory& memory{kernel.System().Memory()};
- KThread* server_thread{GetCurrentThreadPointer(kernel)};
+ Core::Memory::Memory& memory{client_thread->GetOwnerProcess()->GetMemory()};
+ KThread* server_thread{GetCurrentThreadPointer(m_kernel)};
UNIMPLEMENTED_IF(server_thread->GetOwnerProcess() != client_thread->GetOwnerProcess());
- auto* src_msg_buffer = memory.GetPointer(server_thread->GetTLSAddress());
+ auto* src_msg_buffer = memory.GetPointer(server_thread->GetTlsAddress());
auto* dst_msg_buffer = memory.GetPointer(client_message);
std::memcpy(dst_msg_buffer, src_msg_buffer, client_buffer_size);
}
@@ -254,7 +248,7 @@ Result KServerSession::SendReply(bool is_hle) {
if (event != nullptr) {
// // Get the client process/page table.
// KProcess *client_process = client_thread->GetOwnerProcess();
- // KPageTable *client_page_table = &client_process->PageTable();
+ // KPageTable *client_page_table = std::addressof(client_process->PageTable());
// // If we need to, reply with an async error.
// if (R_FAILED(client_result)) {
@@ -270,7 +264,7 @@ Result KServerSession::SendReply(bool is_hle) {
event->Signal();
} else {
// End the client thread's wait.
- KScopedSchedulerLock sl{kernel};
+ KScopedSchedulerLock sl{m_kernel};
if (!client_thread->IsTerminationRequested()) {
client_thread->EndWait(client_result);
@@ -278,11 +272,11 @@ Result KServerSession::SendReply(bool is_hle) {
}
}
- return result;
+ R_RETURN(result);
}
-Result KServerSession::ReceiveRequest(std::shared_ptr<HLERequestContext>* out_context,
- std::weak_ptr<SessionRequestManager> manager) {
+Result KServerSession::ReceiveRequest(std::shared_ptr<Service::HLERequestContext>* out_context,
+ std::weak_ptr<Service::SessionRequestManager> manager) {
// Lock the session.
KScopedLightLock lk{m_lock};
@@ -291,10 +285,10 @@ Result KServerSession::ReceiveRequest(std::shared_ptr<HLERequestContext>* out_co
KThread* client_thread;
{
- KScopedSchedulerLock sl{kernel};
+ KScopedSchedulerLock sl{m_kernel};
// Ensure that we can service the request.
- R_UNLESS(!parent->IsClientClosed(), ResultSessionClosed);
+ R_UNLESS(!m_parent->IsClientClosed(), ResultSessionClosed);
// Ensure we aren't already servicing a request.
R_UNLESS(m_current_request == nullptr, ResultNotFound);
@@ -303,7 +297,7 @@ Result KServerSession::ReceiveRequest(std::shared_ptr<HLERequestContext>* out_co
R_UNLESS(!m_request_list.empty(), ResultNotFound);
// Pop the first request from the list.
- request = &m_request_list.front();
+ request = std::addressof(m_request_list.front());
m_request_list.pop_front();
// Get the thread for the request.
@@ -325,26 +319,27 @@ Result KServerSession::ReceiveRequest(std::shared_ptr<HLERequestContext>* out_co
// bool recv_list_broken = false;
// Receive the message.
- Core::Memory::Memory& memory{kernel.System().Memory()};
+ Core::Memory::Memory& memory{client_thread->GetOwnerProcess()->GetMemory()};
if (out_context != nullptr) {
// HLE request.
u32* cmd_buf{reinterpret_cast<u32*>(memory.GetPointer(client_message))};
- *out_context = std::make_shared<HLERequestContext>(kernel, memory, this, client_thread);
+ *out_context =
+ std::make_shared<Service::HLERequestContext>(m_kernel, memory, this, client_thread);
(*out_context)->SetSessionRequestManager(manager);
(*out_context)
->PopulateFromIncomingCommandBuffer(client_thread->GetOwnerProcess()->GetHandleTable(),
cmd_buf);
} else {
- KThread* server_thread{GetCurrentThreadPointer(kernel)};
+ KThread* server_thread{GetCurrentThreadPointer(m_kernel)};
UNIMPLEMENTED_IF(server_thread->GetOwnerProcess() != client_thread->GetOwnerProcess());
auto* src_msg_buffer = memory.GetPointer(client_message);
- auto* dst_msg_buffer = memory.GetPointer(server_thread->GetTLSAddress());
+ auto* dst_msg_buffer = memory.GetPointer(server_thread->GetTlsAddress());
std::memcpy(dst_msg_buffer, src_msg_buffer, client_buffer_size);
}
// We succeeded.
- return ResultSuccess;
+ R_SUCCEED();
}
void KServerSession::CleanupRequests() {
@@ -355,7 +350,7 @@ void KServerSession::CleanupRequests() {
// Get the next request.
KSessionRequest* request = nullptr;
{
- KScopedSchedulerLock sl{kernel};
+ KScopedSchedulerLock sl{m_kernel};
if (m_current_request) {
// Choose the current request if we have one.
@@ -363,7 +358,7 @@ void KServerSession::CleanupRequests() {
m_current_request = nullptr;
} else if (!m_request_list.empty()) {
// Pop the request from the front of the list.
- request = &m_request_list.front();
+ request = std::addressof(m_request_list.front());
m_request_list.pop_front();
}
}
@@ -386,7 +381,8 @@ void KServerSession::CleanupRequests() {
// KProcess *client_process = (client_thread != nullptr) ?
// client_thread->GetOwnerProcess() : nullptr;
// KProcessPageTable *client_page_table = (client_process != nullptr) ?
- // &client_process->GetPageTable() : nullptr;
+ // std::addressof(client_process->GetPageTable())
+ // : nullptr;
// Cleanup the mappings.
// Result result = CleanupMap(request, server_process, client_page_table);
@@ -406,7 +402,7 @@ void KServerSession::CleanupRequests() {
event->Signal();
} else {
// End the client thread's wait.
- KScopedSchedulerLock sl{kernel};
+ KScopedSchedulerLock sl{m_kernel};
if (!client_thread->IsTerminationRequested()) {
client_thread->EndWait(ResultSessionClosed);
diff --git a/src/core/hle/kernel/k_server_session.h b/src/core/hle/kernel/k_server_session.h
index 6e189af8b..403891919 100644
--- a/src/core/hle/kernel/k_server_session.h
+++ b/src/core/hle/kernel/k_server_session.h
@@ -8,42 +8,42 @@
#include <string>
#include <utility>
-#include <boost/intrusive/list.hpp>
+#include "common/intrusive_list.h"
-#include "core/hle/kernel/hle_ipc.h"
#include "core/hle/kernel/k_light_lock.h"
#include "core/hle/kernel/k_session_request.h"
#include "core/hle/kernel/k_synchronization_object.h"
#include "core/hle/result.h"
+namespace Service {
+class HLERequestContext;
+class SessionRequestManager;
+} // namespace Service
+
namespace Kernel {
-class HLERequestContext;
class KernelCore;
class KSession;
-class SessionRequestManager;
class KThread;
class KServerSession final : public KSynchronizationObject,
- public boost::intrusive::list_base_hook<> {
+ public Common::IntrusiveListBaseNode<KServerSession> {
KERNEL_AUTOOBJECT_TRAITS(KServerSession, KSynchronizationObject);
friend class ServiceThread;
public:
- explicit KServerSession(KernelCore& kernel_);
+ explicit KServerSession(KernelCore& kernel);
~KServerSession() override;
void Destroy() override;
- void Initialize(KSession* parent_session_, std::string&& name_);
-
- KSession* GetParent() {
- return parent;
+ void Initialize(KSession* p) {
+ m_parent = p;
}
const KSession* GetParent() const {
- return parent;
+ return m_parent;
}
bool IsSignaled() const override;
@@ -52,8 +52,8 @@ public:
/// TODO: flesh these out to match the real kernel
Result OnRequest(KSessionRequest* request);
Result SendReply(bool is_hle = false);
- Result ReceiveRequest(std::shared_ptr<HLERequestContext>* out_context = nullptr,
- std::weak_ptr<SessionRequestManager> manager = {});
+ Result ReceiveRequest(std::shared_ptr<Service::HLERequestContext>* out_context = nullptr,
+ std::weak_ptr<Service::SessionRequestManager> manager = {});
Result SendReplyHLE() {
return SendReply(true);
@@ -64,10 +64,11 @@ private:
void CleanupRequests();
/// KSession that owns this KServerSession
- KSession* parent{};
+ KSession* m_parent{};
/// List of threads which are pending a reply.
- boost::intrusive::list<KSessionRequest> m_request_list;
+ using RequestList = Common::IntrusiveListBaseTraits<KSessionRequest>::ListType;
+ RequestList m_request_list{};
KSessionRequest* m_current_request{};
KLightLock m_lock;
diff --git a/src/core/hle/kernel/k_session.cpp b/src/core/hle/kernel/k_session.cpp
index b6f6fe9d9..44d7a8f02 100644
--- a/src/core/hle/kernel/k_session.cpp
+++ b/src/core/hle/kernel/k_session.cpp
@@ -9,68 +9,63 @@
namespace Kernel {
-KSession::KSession(KernelCore& kernel_)
- : KAutoObjectWithSlabHeapAndContainer{kernel_}, server{kernel_}, client{kernel_} {}
+KSession::KSession(KernelCore& kernel)
+ : KAutoObjectWithSlabHeapAndContainer{kernel}, m_server{kernel}, m_client{kernel} {}
KSession::~KSession() = default;
-void KSession::Initialize(KClientPort* port_, const std::string& name_) {
+void KSession::Initialize(KClientPort* client_port, uintptr_t 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();
+ this->Open();
// Create our sub sessions.
- KAutoObject::Create(std::addressof(server));
- KAutoObject::Create(std::addressof(client));
+ KAutoObject::Create(std::addressof(m_server));
+ KAutoObject::Create(std::addressof(m_client));
// Initialize our sub sessions.
- server.Initialize(this, name_ + ":Server");
- client.Initialize(this, name_ + ":Client");
+ m_server.Initialize(this);
+ m_client.Initialize(this);
// Set state and name.
- SetState(State::Normal);
- name = name_;
+ this->SetState(State::Normal);
+ m_name = name;
// Set our owner process.
- process = kernel.CurrentProcess();
- process->Open();
+ //! FIXME: this is the wrong process!
+ m_process = m_kernel.ApplicationProcess();
+ m_process->Open();
// Set our port.
- port = port_;
- if (port != nullptr) {
- port->Open();
+ m_port = client_port;
+ if (m_port != nullptr) {
+ m_port->Open();
}
// Mark initialized.
- initialized = true;
+ m_initialized = true;
}
void KSession::Finalize() {
- if (port == nullptr) {
- return;
+ if (m_port != nullptr) {
+ m_port->OnSessionFinalized();
+ m_port->Close();
}
-
- port->OnSessionFinalized();
- port->Close();
}
void KSession::OnServerClosed() {
- if (GetState() != State::Normal) {
- return;
+ if (this->GetState() == State::Normal) {
+ this->SetState(State::ServerClosed);
+ m_client.OnServerClosed();
}
-
- SetState(State::ServerClosed);
- client.OnServerClosed();
}
void KSession::OnClientClosed() {
- if (GetState() != State::Normal) {
- return;
+ if (this->GetState() == State::Normal) {
+ SetState(State::ClientClosed);
+ m_server.OnClientClosed();
}
-
- SetState(State::ClientClosed);
- server.OnClientClosed();
}
void KSession::PostDestroy(uintptr_t arg) {
diff --git a/src/core/hle/kernel/k_session.h b/src/core/hle/kernel/k_session.h
index 93e5e6f71..f69bab088 100644
--- a/src/core/hle/kernel/k_session.h
+++ b/src/core/hle/kernel/k_session.h
@@ -18,19 +18,18 @@ class KSession final : public KAutoObjectWithSlabHeapAndContainer<KSession, KAut
KERNEL_AUTOOBJECT_TRAITS(KSession, KAutoObject);
public:
- explicit KSession(KernelCore& kernel_);
+ explicit KSession(KernelCore& kernel);
~KSession() override;
- void Initialize(KClientPort* port_, const std::string& name_);
-
+ void Initialize(KClientPort* port, uintptr_t name);
void Finalize() override;
bool IsInitialized() const override {
- return initialized;
+ return m_initialized;
}
uintptr_t GetPostDestroyArgument() const override {
- return reinterpret_cast<uintptr_t>(process);
+ return reinterpret_cast<uintptr_t>(m_process);
}
static void PostDestroy(uintptr_t arg);
@@ -48,27 +47,23 @@ public:
}
KClientSession& GetClientSession() {
- return client;
+ return m_client;
}
KServerSession& GetServerSession() {
- return server;
+ return m_server;
}
const KClientSession& GetClientSession() const {
- return client;
+ return m_client;
}
const KServerSession& GetServerSession() const {
- return server;
+ return m_server;
}
const KClientPort* GetParent() const {
- return port;
- }
-
- KClientPort* GetParent() {
- return port;
+ return m_port;
}
private:
@@ -80,20 +75,20 @@ private:
};
void SetState(State state) {
- atomic_state = static_cast<u8>(state);
+ m_atomic_state = static_cast<u8>(state);
}
State GetState() const {
- return static_cast<State>(atomic_state.load(std::memory_order_relaxed));
+ return static_cast<State>(m_atomic_state.load());
}
- 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{};
+ KServerSession m_server;
+ KClientSession m_client;
+ KClientPort* m_port{};
+ uintptr_t m_name{};
+ KProcess* m_process{};
+ std::atomic<u8> m_atomic_state{static_cast<u8>(State::Invalid)};
+ bool m_initialized{};
};
} // namespace Kernel
diff --git a/src/core/hle/kernel/k_session_request.cpp b/src/core/hle/kernel/k_session_request.cpp
index 520da6aa7..9a69b4ffc 100644
--- a/src/core/hle/kernel/k_session_request.cpp
+++ b/src/core/hle/kernel/k_session_request.cpp
@@ -6,54 +6,55 @@
namespace Kernel {
-Result KSessionRequest::SessionMappings::PushMap(VAddr client, VAddr server, size_t size,
- KMemoryState state, size_t index) {
+Result KSessionRequest::SessionMappings::PushMap(KProcessAddress client, KProcessAddress server,
+ size_t size, KMemoryState state, size_t index) {
// At most 15 buffers of each type (4-bit descriptor counts).
ASSERT(index < ((1ul << 4) - 1) * 3);
// Get the mapping.
Mapping* mapping;
if (index < NumStaticMappings) {
- mapping = &m_static_mappings[index];
+ mapping = std::addressof(m_static_mappings[index]);
} else {
// Allocate a page for the extra mappings.
if (m_mappings == nullptr) {
- KPageBuffer* page_buffer = KPageBuffer::Allocate(kernel);
+ KPageBuffer* page_buffer = KPageBuffer::Allocate(m_kernel);
R_UNLESS(page_buffer != nullptr, ResultOutOfMemory);
m_mappings = reinterpret_cast<Mapping*>(page_buffer);
}
- mapping = &m_mappings[index - NumStaticMappings];
+ mapping = std::addressof(m_mappings[index - NumStaticMappings]);
}
// Set the mapping.
mapping->Set(client, server, size, state);
- return ResultSuccess;
+ R_SUCCEED();
}
-Result KSessionRequest::SessionMappings::PushSend(VAddr client, VAddr server, size_t size,
- KMemoryState state) {
+Result KSessionRequest::SessionMappings::PushSend(KProcessAddress client, KProcessAddress server,
+ size_t size, KMemoryState state) {
ASSERT(m_num_recv == 0);
ASSERT(m_num_exch == 0);
- return this->PushMap(client, server, size, state, m_num_send++);
+ R_RETURN(this->PushMap(client, server, size, state, m_num_send++));
}
-Result KSessionRequest::SessionMappings::PushReceive(VAddr client, VAddr server, size_t size,
- KMemoryState state) {
+Result KSessionRequest::SessionMappings::PushReceive(KProcessAddress client, KProcessAddress server,
+ size_t size, KMemoryState state) {
ASSERT(m_num_exch == 0);
- return this->PushMap(client, server, size, state, m_num_send + m_num_recv++);
+ R_RETURN(this->PushMap(client, server, size, state, m_num_send + m_num_recv++));
}
-Result KSessionRequest::SessionMappings::PushExchange(VAddr client, VAddr server, size_t size,
+Result KSessionRequest::SessionMappings::PushExchange(KProcessAddress client,
+ KProcessAddress server, size_t size,
KMemoryState state) {
- return this->PushMap(client, server, size, state, m_num_send + m_num_recv + m_num_exch++);
+ R_RETURN(this->PushMap(client, server, size, state, m_num_send + m_num_recv + m_num_exch++));
}
void KSessionRequest::SessionMappings::Finalize() {
if (m_mappings) {
- KPageBuffer::Free(kernel, reinterpret_cast<KPageBuffer*>(m_mappings));
+ KPageBuffer::Free(m_kernel, reinterpret_cast<KPageBuffer*>(m_mappings));
m_mappings = nullptr;
}
}
diff --git a/src/core/hle/kernel/k_session_request.h b/src/core/hle/kernel/k_session_request.h
index e5558bc2c..283669e0a 100644
--- a/src/core/hle/kernel/k_session_request.h
+++ b/src/core/hle/kernel/k_session_request.h
@@ -5,6 +5,8 @@
#include <array>
+#include "common/intrusive_list.h"
+
#include "core/hle/kernel/k_auto_object.h"
#include "core/hle/kernel/k_event.h"
#include "core/hle/kernel/k_memory_block.h"
@@ -16,7 +18,7 @@ namespace Kernel {
class KSessionRequest final : public KSlabAllocated<KSessionRequest>,
public KAutoObject,
- public boost::intrusive::list_base_hook<> {
+ public Common::IntrusiveListBaseNode<KSessionRequest> {
KERNEL_AUTOOBJECT_TRAITS(KSessionRequest, KAutoObject);
public:
@@ -26,17 +28,17 @@ public:
class Mapping {
public:
- constexpr void Set(VAddr c, VAddr s, size_t sz, KMemoryState st) {
+ constexpr void Set(KProcessAddress c, KProcessAddress s, size_t sz, KMemoryState st) {
m_client_address = c;
m_server_address = s;
m_size = sz;
m_state = st;
}
- constexpr VAddr GetClientAddress() const {
+ constexpr KProcessAddress GetClientAddress() const {
return m_client_address;
}
- constexpr VAddr GetServerAddress() const {
+ constexpr KProcessAddress GetServerAddress() const {
return m_server_address;
}
constexpr size_t GetSize() const {
@@ -47,14 +49,14 @@ public:
}
private:
- VAddr m_client_address;
- VAddr m_server_address;
- size_t m_size;
- KMemoryState m_state;
+ KProcessAddress m_client_address{};
+ KProcessAddress m_server_address{};
+ size_t m_size{};
+ KMemoryState m_state{};
};
public:
- explicit SessionMappings(KernelCore& kernel_) : kernel(kernel_) {}
+ explicit SessionMappings(KernelCore& kernel) : m_kernel(kernel) {}
void Initialize() {}
void Finalize();
@@ -69,14 +71,17 @@ public:
return m_num_exch;
}
- Result PushSend(VAddr client, VAddr server, size_t size, KMemoryState state);
- Result PushReceive(VAddr client, VAddr server, size_t size, KMemoryState state);
- Result PushExchange(VAddr client, VAddr server, size_t size, KMemoryState state);
+ Result PushSend(KProcessAddress client, KProcessAddress server, size_t size,
+ KMemoryState state);
+ Result PushReceive(KProcessAddress client, KProcessAddress server, size_t size,
+ KMemoryState state);
+ Result PushExchange(KProcessAddress client, KProcessAddress server, size_t size,
+ KMemoryState state);
- VAddr GetSendClientAddress(size_t i) const {
+ KProcessAddress GetSendClientAddress(size_t i) const {
return GetSendMapping(i).GetClientAddress();
}
- VAddr GetSendServerAddress(size_t i) const {
+ KProcessAddress GetSendServerAddress(size_t i) const {
return GetSendMapping(i).GetServerAddress();
}
size_t GetSendSize(size_t i) const {
@@ -86,10 +91,10 @@ public:
return GetSendMapping(i).GetMemoryState();
}
- VAddr GetReceiveClientAddress(size_t i) const {
+ KProcessAddress GetReceiveClientAddress(size_t i) const {
return GetReceiveMapping(i).GetClientAddress();
}
- VAddr GetReceiveServerAddress(size_t i) const {
+ KProcessAddress GetReceiveServerAddress(size_t i) const {
return GetReceiveMapping(i).GetServerAddress();
}
size_t GetReceiveSize(size_t i) const {
@@ -99,10 +104,10 @@ public:
return GetReceiveMapping(i).GetMemoryState();
}
- VAddr GetExchangeClientAddress(size_t i) const {
+ KProcessAddress GetExchangeClientAddress(size_t i) const {
return GetExchangeMapping(i).GetClientAddress();
}
- VAddr GetExchangeServerAddress(size_t i) const {
+ KProcessAddress GetExchangeServerAddress(size_t i) const {
return GetExchangeMapping(i).GetServerAddress();
}
size_t GetExchangeSize(size_t i) const {
@@ -113,7 +118,8 @@ public:
}
private:
- Result PushMap(VAddr client, VAddr server, size_t size, KMemoryState state, size_t index);
+ Result PushMap(KProcessAddress client, KProcessAddress server, size_t size,
+ KMemoryState state, size_t index);
const Mapping& GetSendMapping(size_t i) const {
ASSERT(i < m_num_send);
@@ -149,8 +155,8 @@ public:
}
private:
- KernelCore& kernel;
- std::array<Mapping, NumStaticMappings> m_static_mappings;
+ KernelCore& m_kernel;
+ std::array<Mapping, NumStaticMappings> m_static_mappings{};
Mapping* m_mappings{};
u8 m_num_send{};
u8 m_num_recv{};
@@ -158,7 +164,7 @@ public:
};
public:
- explicit KSessionRequest(KernelCore& kernel_) : KAutoObject(kernel_), m_mappings(kernel_) {}
+ explicit KSessionRequest(KernelCore& kernel) : KAutoObject(kernel), m_mappings(kernel) {}
static KSessionRequest* Create(KernelCore& kernel) {
KSessionRequest* req = KSessionRequest::Allocate(kernel);
@@ -170,13 +176,13 @@ public:
void Destroy() override {
this->Finalize();
- KSessionRequest::Free(kernel, this);
+ KSessionRequest::Free(m_kernel, this);
}
void Initialize(KEvent* event, uintptr_t address, size_t size) {
m_mappings.Initialize();
- m_thread = GetCurrentThreadPointer(kernel);
+ m_thread = GetCurrentThreadPointer(m_kernel);
m_event = event;
m_address = address;
m_size = size;
@@ -227,22 +233,25 @@ public:
return m_mappings.GetExchangeCount();
}
- Result PushSend(VAddr client, VAddr server, size_t size, KMemoryState state) {
+ Result PushSend(KProcessAddress client, KProcessAddress server, size_t size,
+ KMemoryState state) {
return m_mappings.PushSend(client, server, size, state);
}
- Result PushReceive(VAddr client, VAddr server, size_t size, KMemoryState state) {
+ Result PushReceive(KProcessAddress client, KProcessAddress server, size_t size,
+ KMemoryState state) {
return m_mappings.PushReceive(client, server, size, state);
}
- Result PushExchange(VAddr client, VAddr server, size_t size, KMemoryState state) {
+ Result PushExchange(KProcessAddress client, KProcessAddress server, size_t size,
+ KMemoryState state) {
return m_mappings.PushExchange(client, server, size, state);
}
- VAddr GetSendClientAddress(size_t i) const {
+ KProcessAddress GetSendClientAddress(size_t i) const {
return m_mappings.GetSendClientAddress(i);
}
- VAddr GetSendServerAddress(size_t i) const {
+ KProcessAddress GetSendServerAddress(size_t i) const {
return m_mappings.GetSendServerAddress(i);
}
size_t GetSendSize(size_t i) const {
@@ -252,10 +261,10 @@ public:
return m_mappings.GetSendMemoryState(i);
}
- VAddr GetReceiveClientAddress(size_t i) const {
+ KProcessAddress GetReceiveClientAddress(size_t i) const {
return m_mappings.GetReceiveClientAddress(i);
}
- VAddr GetReceiveServerAddress(size_t i) const {
+ KProcessAddress GetReceiveServerAddress(size_t i) const {
return m_mappings.GetReceiveServerAddress(i);
}
size_t GetReceiveSize(size_t i) const {
@@ -265,10 +274,10 @@ public:
return m_mappings.GetReceiveMemoryState(i);
}
- VAddr GetExchangeClientAddress(size_t i) const {
+ KProcessAddress GetExchangeClientAddress(size_t i) const {
return m_mappings.GetExchangeClientAddress(i);
}
- VAddr GetExchangeServerAddress(size_t i) const {
+ KProcessAddress GetExchangeServerAddress(size_t i) const {
return m_mappings.GetExchangeServerAddress(i);
}
size_t GetExchangeSize(size_t i) const {
diff --git a/src/core/hle/kernel/k_shared_memory.cpp b/src/core/hle/kernel/k_shared_memory.cpp
index 3cf2b5d91..efb5699de 100644
--- a/src/core/hle/kernel/k_shared_memory.cpp
+++ b/src/core/hle/kernel/k_shared_memory.cpp
@@ -12,29 +12,27 @@
namespace Kernel {
-KSharedMemory::KSharedMemory(KernelCore& kernel_) : KAutoObjectWithSlabHeapAndContainer{kernel_} {}
+KSharedMemory::KSharedMemory(KernelCore& kernel) : KAutoObjectWithSlabHeapAndContainer{kernel} {}
KSharedMemory::~KSharedMemory() = default;
-Result KSharedMemory::Initialize(Core::DeviceMemory& device_memory_, KProcess* owner_process_,
- Svc::MemoryPermission owner_permission_,
- Svc::MemoryPermission user_permission_, std::size_t size_,
- std::string name_) {
+Result KSharedMemory::Initialize(Core::DeviceMemory& device_memory, KProcess* owner_process,
+ Svc::MemoryPermission owner_permission,
+ Svc::MemoryPermission user_permission, std::size_t size) {
// Set members.
- owner_process = owner_process_;
- device_memory = &device_memory_;
- owner_permission = owner_permission_;
- user_permission = user_permission_;
- size = Common::AlignUp(size_, PageSize);
- name = std::move(name_);
+ m_owner_process = owner_process;
+ m_device_memory = std::addressof(device_memory);
+ m_owner_permission = owner_permission;
+ m_user_permission = user_permission;
+ m_size = Common::AlignUp(size, PageSize);
const size_t num_pages = Common::DivideUp(size, PageSize);
// Get the resource limit.
- KResourceLimit* reslimit = kernel.GetSystemResourceLimit();
+ KResourceLimit* reslimit = m_kernel.GetSystemResourceLimit();
// Reserve memory for ourselves.
KScopedResourceReservation memory_reservation(reslimit, LimitableResource::PhysicalMemoryMax,
- size_);
+ size);
R_UNLESS(memory_reservation.Succeeded(), ResultLimitReached);
// Allocate the memory.
@@ -42,67 +40,67 @@ Result KSharedMemory::Initialize(Core::DeviceMemory& device_memory_, KProcess* o
//! HACK: Open continuous mapping from sysmodule pool.
auto option = KMemoryManager::EncodeOption(KMemoryManager::Pool::Secure,
KMemoryManager::Direction::FromBack);
- physical_address = kernel.MemoryManager().AllocateAndOpenContinuous(num_pages, 1, option);
- R_UNLESS(physical_address != 0, ResultOutOfMemory);
+ m_physical_address = m_kernel.MemoryManager().AllocateAndOpenContinuous(num_pages, 1, option);
+ R_UNLESS(m_physical_address != 0, ResultOutOfMemory);
//! Insert the result into our page group.
- page_group.emplace(kernel, &kernel.GetSystemSystemResource().GetBlockInfoManager());
- page_group->AddBlock(physical_address, num_pages);
+ m_page_group.emplace(m_kernel,
+ std::addressof(m_kernel.GetSystemSystemResource().GetBlockInfoManager()));
+ m_page_group->AddBlock(m_physical_address, num_pages);
// Commit our reservation.
memory_reservation.Commit();
// Set our resource limit.
- resource_limit = reslimit;
- resource_limit->Open();
+ m_resource_limit = reslimit;
+ m_resource_limit->Open();
// Mark initialized.
- is_initialized = true;
+ m_is_initialized = true;
// Clear all pages in the memory.
- for (const auto& block : *page_group) {
- std::memset(device_memory_.GetPointer<void>(block.GetAddress()), 0, block.GetSize());
+ for (const auto& block : *m_page_group) {
+ std::memset(m_device_memory->GetPointer<void>(block.GetAddress()), 0, block.GetSize());
}
- return ResultSuccess;
+ R_SUCCEED();
}
void KSharedMemory::Finalize() {
// Close and finalize the page group.
- page_group->Close();
- page_group->Finalize();
+ m_page_group->Close();
+ m_page_group->Finalize();
// Release the memory reservation.
- resource_limit->Release(LimitableResource::PhysicalMemoryMax, size);
- resource_limit->Close();
-
- // Perform inherited finalization.
- KAutoObjectWithSlabHeapAndContainer<KSharedMemory, KAutoObjectWithList>::Finalize();
+ m_resource_limit->Release(LimitableResource::PhysicalMemoryMax, m_size);
+ m_resource_limit->Close();
}
-Result KSharedMemory::Map(KProcess& target_process, VAddr address, std::size_t map_size,
+Result KSharedMemory::Map(KProcess& target_process, KProcessAddress address, std::size_t map_size,
Svc::MemoryPermission map_perm) {
// Validate the size.
- R_UNLESS(size == map_size, ResultInvalidSize);
+ R_UNLESS(m_size == map_size, ResultInvalidSize);
// Validate the permission.
const Svc::MemoryPermission test_perm =
- &target_process == owner_process ? owner_permission : user_permission;
+ std::addressof(target_process) == m_owner_process ? m_owner_permission : m_user_permission;
if (test_perm == Svc::MemoryPermission::DontCare) {
ASSERT(map_perm == Svc::MemoryPermission::Read || map_perm == Svc::MemoryPermission::Write);
} else {
R_UNLESS(map_perm == test_perm, ResultInvalidNewMemoryPermission);
}
- return target_process.PageTable().MapPages(address, *page_group, KMemoryState::Shared,
- ConvertToKMemoryPermission(map_perm));
+ R_RETURN(target_process.PageTable().MapPageGroup(address, *m_page_group, KMemoryState::Shared,
+ ConvertToKMemoryPermission(map_perm)));
}
-Result KSharedMemory::Unmap(KProcess& target_process, VAddr address, std::size_t unmap_size) {
+Result KSharedMemory::Unmap(KProcess& target_process, KProcessAddress address,
+ std::size_t unmap_size) {
// Validate the size.
- R_UNLESS(size == unmap_size, ResultInvalidSize);
+ R_UNLESS(m_size == unmap_size, ResultInvalidSize);
- return target_process.PageTable().UnmapPages(address, *page_group, KMemoryState::Shared);
+ R_RETURN(
+ target_process.PageTable().UnmapPageGroup(address, *m_page_group, 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 8b29f0b4a..54b23d7ac 100644
--- a/src/core/hle/kernel/k_shared_memory.h
+++ b/src/core/hle/kernel/k_shared_memory.h
@@ -6,11 +6,11 @@
#include <optional>
#include <string>
-#include "common/common_types.h"
#include "core/device_memory.h"
#include "core/hle/kernel/k_memory_block.h"
#include "core/hle/kernel/k_page_group.h"
#include "core/hle/kernel/k_process.h"
+#include "core/hle/kernel/k_typed_address.h"
#include "core/hle/kernel/slab_helpers.h"
#include "core/hle/result.h"
@@ -23,12 +23,12 @@ class KSharedMemory final
KERNEL_AUTOOBJECT_TRAITS(KSharedMemory, KAutoObject);
public:
- explicit KSharedMemory(KernelCore& kernel_);
+ explicit KSharedMemory(KernelCore& kernel);
~KSharedMemory() override;
Result Initialize(Core::DeviceMemory& device_memory_, KProcess* owner_process_,
Svc::MemoryPermission owner_permission_,
- Svc::MemoryPermission user_permission_, std::size_t size_, std::string name_);
+ Svc::MemoryPermission user_permission_, std::size_t size_);
/**
* Maps a shared memory block to an address in the target process' address space
@@ -37,7 +37,7 @@ public:
* @param map_size Size of the shared memory block to map
* @param permissions Memory block map permissions (specified by SVC field)
*/
- Result Map(KProcess& target_process, VAddr address, std::size_t map_size,
+ Result Map(KProcess& target_process, KProcessAddress address, std::size_t map_size,
Svc::MemoryPermission permissions);
/**
@@ -46,7 +46,7 @@ public:
* @param address Address in system memory to unmap shared memory block
* @param unmap_size Size of the shared memory block to unmap
*/
- Result Unmap(KProcess& target_process, VAddr address, std::size_t unmap_size);
+ Result Unmap(KProcess& target_process, KProcessAddress address, std::size_t unmap_size);
/**
* Gets a pointer to the shared memory block
@@ -54,7 +54,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<u8>(physical_address + offset);
+ return m_device_memory->GetPointer<u8>(m_physical_address + offset);
}
/**
@@ -63,26 +63,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<u8>(physical_address + offset);
+ return m_device_memory->GetPointer<u8>(m_physical_address + offset);
}
void Finalize() override;
bool IsInitialized() const override {
- return is_initialized;
+ return m_is_initialized;
}
- static void PostDestroy([[maybe_unused]] uintptr_t arg) {}
+ static void PostDestroy(uintptr_t arg) {}
private:
- Core::DeviceMemory* device_memory{};
- KProcess* owner_process{};
- std::optional<KPageGroup> page_group{};
- Svc::MemoryPermission owner_permission{};
- Svc::MemoryPermission user_permission{};
- PAddr physical_address{};
- std::size_t size{};
- KResourceLimit* resource_limit{};
- bool is_initialized{};
+ Core::DeviceMemory* m_device_memory{};
+ KProcess* m_owner_process{};
+ std::optional<KPageGroup> m_page_group{};
+ Svc::MemoryPermission m_owner_permission{};
+ Svc::MemoryPermission m_user_permission{};
+ KPhysicalAddress m_physical_address{};
+ std::size_t m_size{};
+ KResourceLimit* m_resource_limit{};
+ bool m_is_initialized{};
};
} // namespace Kernel
diff --git a/src/core/hle/kernel/k_shared_memory_info.h b/src/core/hle/kernel/k_shared_memory_info.h
index 2bb6b6d08..2d8ff20d6 100644
--- a/src/core/hle/kernel/k_shared_memory_info.h
+++ b/src/core/hle/kernel/k_shared_memory_info.h
@@ -3,7 +3,7 @@
#pragma once
-#include <boost/intrusive/list.hpp>
+#include "common/intrusive_list.h"
#include "core/hle/kernel/slab_helpers.h"
@@ -12,31 +12,34 @@ namespace Kernel {
class KSharedMemory;
class KSharedMemoryInfo final : public KSlabAllocated<KSharedMemoryInfo>,
- public boost::intrusive::list_base_hook<> {
+ public Common::IntrusiveListBaseNode<KSharedMemoryInfo> {
public:
explicit KSharedMemoryInfo(KernelCore&) {}
KSharedMemoryInfo() = default;
- constexpr void Initialize(KSharedMemory* shmem) {
- shared_memory = shmem;
+ constexpr void Initialize(KSharedMemory* m) {
+ m_shared_memory = m;
+ m_reference_count = 0;
}
constexpr KSharedMemory* GetSharedMemory() const {
- return shared_memory;
+ return m_shared_memory;
}
constexpr void Open() {
- ++reference_count;
+ ++m_reference_count;
+ ASSERT(m_reference_count > 0);
}
constexpr bool Close() {
- return (--reference_count) == 0;
+ ASSERT(m_reference_count > 0);
+ return (--m_reference_count) == 0;
}
private:
- KSharedMemory* shared_memory{};
- size_t reference_count{};
+ KSharedMemory* m_shared_memory{};
+ size_t m_reference_count{};
};
} // namespace Kernel
diff --git a/src/core/hle/kernel/k_slab_heap.h b/src/core/hle/kernel/k_slab_heap.h
index 68469b041..334afebb7 100644
--- a/src/core/hle/kernel/k_slab_heap.h
+++ b/src/core/hle/kernel/k_slab_heap.h
@@ -89,7 +89,8 @@ private:
if (alloc_peak <= cur_peak) {
break;
}
- } while (!Common::AtomicCompareAndSwap(&m_peak, alloc_peak, cur_peak, cur_peak));
+ } while (
+ !Common::AtomicCompareAndSwap(std::addressof(m_peak), alloc_peak, cur_peak, cur_peak));
}
public:
diff --git a/src/core/hle/kernel/k_spin_lock.cpp b/src/core/hle/kernel/k_spin_lock.cpp
index 6e16a1849..852532037 100644
--- a/src/core/hle/kernel/k_spin_lock.cpp
+++ b/src/core/hle/kernel/k_spin_lock.cpp
@@ -6,15 +6,15 @@
namespace Kernel {
void KSpinLock::Lock() {
- lck.lock();
+ m_lock.lock();
}
void KSpinLock::Unlock() {
- lck.unlock();
+ m_lock.unlock();
}
bool KSpinLock::TryLock() {
- return lck.try_lock();
+ return m_lock.try_lock();
}
} // namespace Kernel
diff --git a/src/core/hle/kernel/k_spin_lock.h b/src/core/hle/kernel/k_spin_lock.h
index 397a93d21..094a1e6be 100644
--- a/src/core/hle/kernel/k_spin_lock.h
+++ b/src/core/hle/kernel/k_spin_lock.h
@@ -5,26 +5,24 @@
#include <mutex>
+#include "common/common_funcs.h"
#include "core/hle/kernel/k_scoped_lock.h"
namespace Kernel {
class KSpinLock {
public:
- KSpinLock() = default;
+ explicit KSpinLock() = default;
- KSpinLock(const KSpinLock&) = delete;
- KSpinLock& operator=(const KSpinLock&) = delete;
-
- KSpinLock(KSpinLock&&) = delete;
- KSpinLock& operator=(KSpinLock&&) = delete;
+ YUZU_NON_COPYABLE(KSpinLock);
+ YUZU_NON_MOVEABLE(KSpinLock);
void Lock();
void Unlock();
- [[nodiscard]] bool TryLock();
+ bool TryLock();
private:
- std::mutex lck;
+ std::mutex m_lock;
};
// TODO(bunnei): Alias for now, in case we want to implement these accurately in the future.
diff --git a/src/core/hle/kernel/k_synchronization_object.cpp b/src/core/hle/kernel/k_synchronization_object.cpp
index 802dca046..3e5b735b1 100644
--- a/src/core/hle/kernel/k_synchronization_object.cpp
+++ b/src/core/hle/kernel/k_synchronization_object.cpp
@@ -3,6 +3,7 @@
#include "common/assert.h"
#include "common/common_types.h"
+#include "common/scratch_buffer.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"
@@ -17,9 +18,9 @@ namespace {
class ThreadQueueImplForKSynchronizationObjectWait final : public KThreadQueueWithoutEndWait {
public:
- ThreadQueueImplForKSynchronizationObjectWait(KernelCore& kernel_, KSynchronizationObject** o,
+ ThreadQueueImplForKSynchronizationObjectWait(KernelCore& kernel, KSynchronizationObject** o,
KSynchronizationObject::ThreadListNode* n, s32 c)
- : KThreadQueueWithoutEndWait(kernel_), m_objects(o), m_nodes(n), m_count(c) {}
+ : KThreadQueueWithoutEndWait(kernel), m_objects(o), m_nodes(n), m_count(c) {}
void NotifyAvailable(KThread* waiting_thread, KSynchronizationObject* signaled_object,
Result wait_result) override {
@@ -71,25 +72,26 @@ void KSynchronizationObject::Finalize() {
KAutoObject::Finalize();
}
-Result KSynchronizationObject::Wait(KernelCore& kernel_ctx, s32* out_index,
+Result KSynchronizationObject::Wait(KernelCore& kernel, 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);
+ std::array<ThreadListNode, Svc::ArgumentHandleCountMax> thread_nodes;
// Prepare for wait.
- KThread* thread = GetCurrentThreadPointer(kernel_ctx);
- ThreadQueueImplForKSynchronizationObjectWait wait_queue(kernel_ctx, objects,
- thread_nodes.data(), num_objects);
+ KThread* thread = GetCurrentThreadPointer(kernel);
+ KHardwareTimer* timer{};
+ ThreadQueueImplForKSynchronizationObjectWait wait_queue(kernel, objects, thread_nodes.data(),
+ num_objects);
{
// Setup the scheduling lock and sleep.
- KScopedSchedulerLockAndSleep slp(kernel_ctx, thread, timeout);
+ KScopedSchedulerLockAndSleep slp(kernel, std::addressof(timer), thread, timeout);
// Check if the thread should terminate.
if (thread->IsTerminationRequested()) {
slp.CancelSleep();
- return ResultTerminationRequested;
+ R_THROW(ResultTerminationRequested);
}
// Check if any of the objects are already signaled.
@@ -99,21 +101,21 @@ Result KSynchronizationObject::Wait(KernelCore& kernel_ctx, s32* out_index,
if (objects[i]->IsSignaled()) {
*out_index = i;
slp.CancelSleep();
- return ResultSuccess;
+ R_THROW(ResultSuccess);
}
}
// Check if the timeout is zero.
if (timeout == 0) {
slp.CancelSleep();
- return ResultTimedOut;
+ R_THROW(ResultTimedOut);
}
// Check if waiting was canceled.
if (thread->IsWaitCancelled()) {
slp.CancelSleep();
thread->ClearWaitCancelled();
- return ResultCancelled;
+ R_THROW(ResultCancelled);
}
// Add the waiters.
@@ -131,6 +133,7 @@ Result KSynchronizationObject::Wait(KernelCore& kernel_ctx, s32* out_index,
thread->SetSyncedIndex(-1);
// Wait for an object to be signaled.
+ wait_queue.SetHardwareTimer(timer);
thread->BeginWait(std::addressof(wait_queue));
thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Synchronization);
}
@@ -139,16 +142,15 @@ Result KSynchronizationObject::Wait(KernelCore& kernel_ctx, s32* out_index,
*out_index = thread->GetSyncedIndex();
// Get the wait result.
- return thread->GetWaitResult();
+ R_RETURN(thread->GetWaitResult());
}
-KSynchronizationObject::KSynchronizationObject(KernelCore& kernel_)
- : KAutoObjectWithList{kernel_} {}
+KSynchronizationObject::KSynchronizationObject(KernelCore& kernel) : KAutoObjectWithList{kernel} {}
KSynchronizationObject::~KSynchronizationObject() = default;
void KSynchronizationObject::NotifyAvailable(Result result) {
- KScopedSchedulerLock sl(kernel);
+ KScopedSchedulerLock sl(m_kernel);
// If we're not signaled, we've nothing to notify.
if (!this->IsSignaled()) {
@@ -156,7 +158,7 @@ void KSynchronizationObject::NotifyAvailable(Result result) {
}
// Iterate over each thread.
- for (auto* cur_node = thread_list_head; cur_node != nullptr; cur_node = cur_node->next) {
+ for (auto* cur_node = m_thread_list_head; cur_node != nullptr; cur_node = cur_node->next) {
cur_node->thread->NotifyAvailable(this, result);
}
}
@@ -166,8 +168,8 @@ std::vector<KThread*> KSynchronizationObject::GetWaitingThreadsForDebugging() co
// If debugging, dump the list of waiters.
{
- KScopedSchedulerLock lock(kernel);
- for (auto* cur_node = thread_list_head; cur_node != nullptr; cur_node = cur_node->next) {
+ KScopedSchedulerLock lock(m_kernel);
+ for (auto* cur_node = m_thread_list_head; cur_node != nullptr; cur_node = cur_node->next) {
threads.emplace_back(cur_node->thread);
}
}
diff --git a/src/core/hle/kernel/k_synchronization_object.h b/src/core/hle/kernel/k_synchronization_object.h
index 8d8122ab7..d55a2673d 100644
--- a/src/core/hle/kernel/k_synchronization_object.h
+++ b/src/core/hle/kernel/k_synchronization_object.h
@@ -24,31 +24,30 @@ public:
KThread* thread{};
};
- [[nodiscard]] static Result Wait(KernelCore& kernel, s32* out_index,
- KSynchronizationObject** objects, const s32 num_objects,
- s64 timeout);
+ static Result Wait(KernelCore& kernel, s32* out_index, KSynchronizationObject** objects,
+ const s32 num_objects, s64 timeout);
void Finalize() override;
- [[nodiscard]] virtual bool IsSignaled() const = 0;
+ virtual bool IsSignaled() const = 0;
- [[nodiscard]] std::vector<KThread*> GetWaitingThreadsForDebugging() const;
+ std::vector<KThread*> GetWaitingThreadsForDebugging() const;
void LinkNode(ThreadListNode* node_) {
// Link the node to the list.
- if (thread_list_tail == nullptr) {
- thread_list_head = node_;
+ if (m_thread_list_tail == nullptr) {
+ m_thread_list_head = node_;
} else {
- thread_list_tail->next = node_;
+ m_thread_list_tail->next = node_;
}
- thread_list_tail = node_;
+ m_thread_list_tail = node_;
}
void UnlinkNode(ThreadListNode* node_) {
// Unlink the node from the list.
ThreadListNode* prev_ptr =
- reinterpret_cast<ThreadListNode*>(std::addressof(thread_list_head));
+ reinterpret_cast<ThreadListNode*>(std::addressof(m_thread_list_head));
ThreadListNode* prev_val = nullptr;
ThreadListNode *prev, *tail_prev;
@@ -59,8 +58,8 @@ public:
prev_val = prev_ptr;
} while (prev_ptr != node_);
- if (thread_list_tail == node_) {
- thread_list_tail = tail_prev;
+ if (m_thread_list_tail == node_) {
+ m_thread_list_tail = tail_prev;
}
prev->next = node_->next;
@@ -78,8 +77,8 @@ protected:
}
private:
- ThreadListNode* thread_list_head{};
- ThreadListNode* thread_list_tail{};
+ ThreadListNode* m_thread_list_head{};
+ ThreadListNode* m_thread_list_tail{};
};
} // namespace Kernel
diff --git a/src/core/hle/kernel/k_system_resource.cpp b/src/core/hle/kernel/k_system_resource.cpp
index 4cc377a6c..e6c8d589a 100644
--- a/src/core/hle/kernel/k_system_resource.cpp
+++ b/src/core/hle/kernel/k_system_resource.cpp
@@ -5,9 +5,8 @@
namespace Kernel {
-Result KSecureSystemResource::Initialize([[maybe_unused]] size_t size,
- [[maybe_unused]] KResourceLimit* resource_limit,
- [[maybe_unused]] KMemoryManager::Pool pool) {
+Result KSecureSystemResource::Initialize(size_t size, KResourceLimit* resource_limit,
+ KMemoryManager::Pool pool) {
// Unimplemented
UNREACHABLE();
}
@@ -17,8 +16,8 @@ void KSecureSystemResource::Finalize() {
UNREACHABLE();
}
-size_t KSecureSystemResource::CalculateRequiredSecureMemorySize(
- [[maybe_unused]] size_t size, [[maybe_unused]] KMemoryManager::Pool pool) {
+size_t KSecureSystemResource::CalculateRequiredSecureMemorySize(size_t size,
+ KMemoryManager::Pool pool) {
// Unimplemented
UNREACHABLE();
}
diff --git a/src/core/hle/kernel/k_system_resource.h b/src/core/hle/kernel/k_system_resource.h
index 9a991f725..6ea482185 100644
--- a/src/core/hle/kernel/k_system_resource.h
+++ b/src/core/hle/kernel/k_system_resource.h
@@ -21,7 +21,7 @@ class KSystemResource : public KAutoObject {
KERNEL_AUTOOBJECT_TRAITS(KSystemResource, KAutoObject);
public:
- explicit KSystemResource(KernelCore& kernel_) : KAutoObject(kernel_) {}
+ explicit KSystemResource(KernelCore& kernel) : KAutoObject(kernel) {}
protected:
void SetSecureResource() {
@@ -87,8 +87,8 @@ private:
class KSecureSystemResource final
: public KAutoObjectWithSlabHeap<KSecureSystemResource, KSystemResource> {
public:
- explicit KSecureSystemResource(KernelCore& kernel_)
- : KAutoObjectWithSlabHeap<KSecureSystemResource, KSystemResource>(kernel_) {
+ explicit KSecureSystemResource(KernelCore& kernel)
+ : KAutoObjectWithSlabHeap<KSecureSystemResource, KSystemResource>(kernel) {
// Mark ourselves as being a secure resource.
this->SetSecureResource();
}
@@ -99,7 +99,7 @@ public:
bool IsInitialized() const {
return m_is_initialized;
}
- static void PostDestroy([[maybe_unused]] uintptr_t arg) {}
+ static void PostDestroy(uintptr_t arg) {}
size_t CalculateRequiredSecureMemorySize() const {
return CalculateRequiredSecureMemorySize(m_resource_size, m_resource_pool);
@@ -130,7 +130,7 @@ private:
KBlockInfoSlabHeap m_block_info_heap;
KPageTableSlabHeap m_page_table_heap;
KResourceLimit* m_resource_limit{};
- VAddr m_resource_address{};
+ KVirtualAddress m_resource_address{};
size_t m_resource_size{};
};
diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp
index 21207fe99..adb6ec581 100644
--- a/src/core/hle/kernel/k_thread.cpp
+++ b/src/core/hle/kernel/k_thread.cpp
@@ -4,6 +4,8 @@
#include <algorithm>
#include <atomic>
#include <cinttypes>
+#include <condition_variable>
+#include <mutex>
#include <optional>
#include <vector>
@@ -29,36 +31,34 @@
#include "core/hle/kernel/k_thread_queue.h"
#include "core/hle/kernel/k_worker_task_manager.h"
#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/svc.h"
#include "core/hle/kernel/svc_results.h"
#include "core/hle/kernel/svc_types.h"
#include "core/hle/result.h"
#include "core/memory.h"
-#ifdef ARCHITECTURE_x86_64
-#include "core/arm/dynarmic/arm_dynarmic_32.h"
-#endif
-
namespace {
constexpr inline s32 TerminatingThreadPriority = Kernel::Svc::SystemThreadPriorityHighest - 1;
-static void ResetThreadContext32(Core::ARM_Interface::ThreadContext32& context, u32 stack_top,
+static void ResetThreadContext32(Kernel::KThread::ThreadContext32& context, u32 stack_top,
u32 entry_point, u32 arg) {
context = {};
context.cpu_registers[0] = arg;
context.cpu_registers[15] = entry_point;
context.cpu_registers[13] = stack_top;
+ context.fpscr = 0;
}
-static void ResetThreadContext64(Core::ARM_Interface::ThreadContext64& context, VAddr stack_top,
- VAddr entry_point, u64 arg) {
+static void ResetThreadContext64(Kernel::KThread::ThreadContext64& context, u64 stack_top,
+ u64 entry_point, u64 arg) {
context = {};
context.cpu_registers[0] = arg;
context.cpu_registers[18] = Kernel::KSystemControl::GenerateRandomU64() | 1;
context.pc = entry_point;
context.sp = stack_top;
- // TODO(merry): Perform a hardware test to determine the below value.
context.fpcr = 0;
+ context.fpsr = 0;
}
} // namespace
@@ -75,14 +75,14 @@ struct ThreadLocalRegion {
class ThreadQueueImplForKThreadSleep final : public KThreadQueueWithoutEndWait {
public:
- explicit ThreadQueueImplForKThreadSleep(KernelCore& kernel_)
- : KThreadQueueWithoutEndWait(kernel_) {}
+ explicit ThreadQueueImplForKThreadSleep(KernelCore& kernel)
+ : KThreadQueueWithoutEndWait(kernel) {}
};
class ThreadQueueImplForKThreadSetProperty final : public KThreadQueue {
public:
- explicit ThreadQueueImplForKThreadSetProperty(KernelCore& kernel_, KThread::WaiterList* wl)
- : KThreadQueue(kernel_), m_wait_list(wl) {}
+ explicit ThreadQueueImplForKThreadSetProperty(KernelCore& kernel, KThread::WaiterList* wl)
+ : KThreadQueue(kernel), m_wait_list(wl) {}
void CancelWait(KThread* waiting_thread, Result wait_result, bool cancel_timer_task) override {
// Remove the thread from the wait list.
@@ -93,17 +93,17 @@ public:
}
private:
- KThread::WaiterList* m_wait_list;
+ KThread::WaiterList* m_wait_list{};
};
} // namespace
-KThread::KThread(KernelCore& kernel_)
- : KAutoObjectWithSlabHeapAndContainer{kernel_}, activity_pause_lock{kernel_} {}
+KThread::KThread(KernelCore& kernel)
+ : KAutoObjectWithSlabHeapAndContainer{kernel}, m_activity_pause_lock{kernel} {}
KThread::~KThread() = default;
-Result KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_stack_top, s32 prio,
- s32 virt_core, KProcess* owner, ThreadType type) {
+Result KThread::Initialize(KThreadFunction func, uintptr_t arg, KProcessAddress user_stack_top,
+ s32 prio, s32 virt_core, KProcess* owner, ThreadType type) {
// Assert parameters are valid.
ASSERT((type == ThreadType::Main) || (type == ThreadType::Dummy) ||
(Svc::HighestThreadPriority <= prio && prio <= Svc::LowestThreadPriority));
@@ -115,7 +115,7 @@ Result KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_stack
ASSERT(0 <= phys_core && phys_core < static_cast<s32>(Core::Hardware::NUM_CPU_CORES));
// First, clear the TLS address.
- tls_address = {};
+ m_tls_address = {};
// Next, assert things based on the type.
switch (type) {
@@ -139,110 +139,110 @@ Result KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_stack
ASSERT_MSG(false, "KThread::Initialize: Unknown ThreadType {}", static_cast<u32>(type));
break;
}
- thread_type = type;
+ m_thread_type = type;
// Set the ideal core ID and affinity mask.
- virtual_ideal_core_id = virt_core;
- physical_ideal_core_id = phys_core;
- virtual_affinity_mask = 1ULL << virt_core;
- physical_affinity_mask.SetAffinity(phys_core, true);
+ m_virtual_ideal_core_id = virt_core;
+ m_physical_ideal_core_id = phys_core;
+ m_virtual_affinity_mask = 1ULL << virt_core;
+ m_physical_affinity_mask.SetAffinity(phys_core, true);
// Set the thread state.
- thread_state = (type == ThreadType::Main || type == ThreadType::Dummy)
- ? ThreadState::Runnable
- : ThreadState::Initialized;
+ m_thread_state = (type == ThreadType::Main || type == ThreadType::Dummy)
+ ? ThreadState::Runnable
+ : ThreadState::Initialized;
// Set TLS address.
- tls_address = 0;
+ m_tls_address = 0;
// Set parent and condvar tree.
- parent = nullptr;
- condvar_tree = nullptr;
+ m_parent = nullptr;
+ m_condvar_tree = nullptr;
// Set sync booleans.
- signaled = false;
- termination_requested = false;
- wait_cancelled = false;
- cancellable = false;
+ m_signaled = false;
+ m_termination_requested = false;
+ m_wait_cancelled = false;
+ m_cancellable = false;
// Set core ID and wait result.
- core_id = phys_core;
- wait_result = ResultNoSynchronizationObject;
+ m_core_id = phys_core;
+ m_wait_result = ResultNoSynchronizationObject;
// Set priorities.
- priority = prio;
- base_priority = prio;
+ m_priority = prio;
+ m_base_priority = prio;
// Initialize sleeping queue.
- wait_queue = nullptr;
+ m_wait_queue = nullptr;
// Set suspend flags.
- suspend_request_flags = 0;
- suspend_allowed_flags = static_cast<u32>(ThreadState::SuspendFlagMask);
+ m_suspend_request_flags = 0;
+ m_suspend_allowed_flags = static_cast<u32>(ThreadState::SuspendFlagMask);
// We're neither debug attached, nor are we nesting our priority inheritance.
- debug_attached = false;
- priority_inheritance_count = 0;
+ m_debug_attached = false;
+ m_priority_inheritance_count = 0;
// We haven't been scheduled, and we have done no light IPC.
- schedule_count = -1;
- last_scheduled_tick = 0;
- light_ipc_data = nullptr;
+ m_schedule_count = -1;
+ m_last_scheduled_tick = 0;
+ m_light_ipc_data = nullptr;
// We're not waiting for a lock, and we haven't disabled migration.
- lock_owner = nullptr;
- num_core_migration_disables = 0;
+ m_waiting_lock_info = nullptr;
+ m_num_core_migration_disables = 0;
// We have no waiters, but we do have an entrypoint.
- num_kernel_waiters = 0;
+ m_num_kernel_waiters = 0;
// Set our current core id.
- current_core_id = phys_core;
+ m_current_core_id = phys_core;
// We haven't released our resource limit hint, and we've spent no time on the cpu.
- resource_limit_release_hint = false;
- cpu_time = 0;
+ m_resource_limit_release_hint = false;
+ m_cpu_time = 0;
// Set debug context.
- stack_top = user_stack_top;
- argument = arg;
+ m_stack_top = user_stack_top;
+ m_argument = arg;
// Clear our stack parameters.
- std::memset(static_cast<void*>(std::addressof(GetStackParameters())), 0,
+ std::memset(static_cast<void*>(std::addressof(this->GetStackParameters())), 0,
sizeof(StackParameters));
// Set parent, if relevant.
if (owner != nullptr) {
// Setup the TLS, if needed.
if (type == ThreadType::User) {
- R_TRY(owner->CreateThreadLocalRegion(std::addressof(tls_address)));
+ R_TRY(owner->CreateThreadLocalRegion(std::addressof(m_tls_address)));
}
- parent = owner;
- parent->Open();
+ m_parent = owner;
+ m_parent->Open();
}
// Initialize thread context.
- ResetThreadContext64(thread_context_64, user_stack_top, func, arg);
- ResetThreadContext32(thread_context_32, static_cast<u32>(user_stack_top),
- static_cast<u32>(func), static_cast<u32>(arg));
+ ResetThreadContext64(m_thread_context_64, GetInteger(user_stack_top), GetInteger(func), arg);
+ ResetThreadContext32(m_thread_context_32, static_cast<u32>(GetInteger(user_stack_top)),
+ static_cast<u32>(GetInteger(func)), static_cast<u32>(arg));
// Setup the stack parameters.
- StackParameters& sp = GetStackParameters();
+ StackParameters& sp = this->GetStackParameters();
sp.cur_thread = this;
sp.disable_count = 1;
- SetInExceptionHandler();
+ this->SetInExceptionHandler();
// Set thread ID.
- thread_id = kernel.CreateNewThreadID();
+ m_thread_id = m_kernel.CreateNewThreadID();
// We initialized!
- initialized = true;
+ m_initialized = true;
// Register ourselves with our parent process.
- if (parent != nullptr) {
- parent->RegisterThread(this);
- if (parent->IsSuspended()) {
+ if (m_parent != nullptr) {
+ m_parent->RegisterThread(this);
+ if (m_parent->IsSuspended()) {
RequestSuspend(SuspendType::Process);
}
}
@@ -251,14 +251,14 @@ Result KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_stack
}
Result KThread::InitializeThread(KThread* thread, KThreadFunction func, uintptr_t arg,
- VAddr user_stack_top, s32 prio, s32 core, KProcess* owner,
- ThreadType type, std::function<void()>&& init_func) {
+ KProcessAddress user_stack_top, s32 prio, s32 core,
+ KProcess* owner, ThreadType type,
+ std::function<void()>&& init_func) {
// Initialize the thread.
R_TRY(thread->Initialize(func, arg, user_stack_top, prio, core, owner, type));
// Initialize emulation parameters.
- thread->host_context = std::make_shared<Common::Fiber>(std::move(init_func));
- thread->is_single_core = !Settings::values.use_multi_core.GetValue();
+ thread->m_host_context = std::make_shared<Common::Fiber>(std::move(init_func));
R_SUCCEED();
}
@@ -268,7 +268,7 @@ Result KThread::InitializeDummyThread(KThread* thread, KProcess* owner) {
R_TRY(thread->Initialize({}, {}, {}, DummyThreadPriority, 3, owner, ThreadType::Dummy));
// Initialize emulation parameters.
- thread->stack_parameters.disable_count = 0;
+ thread->m_stack_parameters.disable_count = 0;
R_SUCCEED();
}
@@ -291,13 +291,32 @@ Result KThread::InitializeHighPriorityThread(Core::System& system, KThread* thre
}
Result KThread::InitializeUserThread(Core::System& system, KThread* thread, KThreadFunction func,
- uintptr_t arg, VAddr user_stack_top, s32 prio, s32 virt_core,
- KProcess* owner) {
+ uintptr_t arg, KProcessAddress user_stack_top, s32 prio,
+ s32 virt_core, KProcess* owner) {
system.Kernel().GlobalSchedulerContext().AddThread(thread);
R_RETURN(InitializeThread(thread, func, arg, user_stack_top, prio, virt_core, owner,
ThreadType::User, system.GetCpuManager().GetGuestThreadFunc()));
}
+Result KThread::InitializeServiceThread(Core::System& system, KThread* thread,
+ std::function<void()>&& func, s32 prio, s32 virt_core,
+ KProcess* owner) {
+ system.Kernel().GlobalSchedulerContext().AddThread(thread);
+ std::function<void()> func2{[&system, func{std::move(func)}] {
+ // Similar to UserModeThreadStarter.
+ system.Kernel().CurrentScheduler()->OnThreadStart();
+
+ // Run the guest function.
+ func();
+
+ // Exit.
+ Svc::ExitThread(system);
+ }};
+
+ R_RETURN(InitializeThread(thread, {}, {}, {}, prio, virt_core, owner, ThreadType::HighPriority,
+ std::move(func2)));
+}
+
void KThread::PostDestroy(uintptr_t arg) {
KProcess* owner = reinterpret_cast<KProcess*>(arg & ~1ULL);
const bool resource_limit_release_hint = (arg & 1);
@@ -310,96 +329,110 @@ void KThread::PostDestroy(uintptr_t arg) {
void KThread::Finalize() {
// If the thread has an owner process, unregister it.
- if (parent != nullptr) {
- parent->UnregisterThread(this);
+ if (m_parent != nullptr) {
+ m_parent->UnregisterThread(this);
}
// If the thread has a local region, delete it.
- if (tls_address != 0) {
- ASSERT(parent->DeleteThreadLocalRegion(tls_address).IsSuccess());
+ if (m_tls_address != 0) {
+ ASSERT(m_parent->DeleteThreadLocalRegion(m_tls_address).IsSuccess());
}
// Release any waiters.
{
- ASSERT(lock_owner == nullptr);
- KScopedSchedulerLock sl{kernel};
+ ASSERT(m_waiting_lock_info == nullptr);
+ KScopedSchedulerLock sl{m_kernel};
+
+ // Check that we have no kernel waiters.
+ ASSERT(m_num_kernel_waiters == 0);
- auto it = waiter_list.begin();
- while (it != waiter_list.end()) {
- // Get the thread.
- KThread* const waiter = std::addressof(*it);
+ auto it = m_held_lock_info_list.begin();
+ while (it != m_held_lock_info_list.end()) {
+ // Get the lock info.
+ auto* const lock_info = std::addressof(*it);
- // The thread shouldn't be a kernel waiter.
- ASSERT(!IsKernelAddressKey(waiter->GetAddressKey()));
+ // The lock shouldn't have a kernel waiter.
+ ASSERT(!lock_info->GetIsKernelAddressKey());
- // Clear the lock owner.
- waiter->SetLockOwner(nullptr);
+ // Remove all waiters.
+ while (lock_info->GetWaiterCount() != 0) {
+ // Get the front waiter.
+ KThread* const waiter = lock_info->GetHighestPriorityWaiter();
- // Erase the waiter from our list.
- it = waiter_list.erase(it);
+ // Remove it from the lock.
+ if (lock_info->RemoveWaiter(waiter)) {
+ ASSERT(lock_info->GetWaiterCount() == 0);
+ }
+
+ // Cancel the thread's wait.
+ waiter->CancelWait(ResultInvalidState, true);
+ }
- // Cancel the thread's wait.
- waiter->CancelWait(ResultInvalidState, true);
+ // Remove the held lock from our list.
+ it = m_held_lock_info_list.erase(it);
+
+ // Free the lock info.
+ LockWithPriorityInheritanceInfo::Free(m_kernel, lock_info);
}
}
// Release host emulation members.
- host_context.reset();
+ m_host_context.reset();
// Perform inherited finalization.
KSynchronizationObject::Finalize();
}
bool KThread::IsSignaled() const {
- return signaled;
+ return m_signaled;
}
void KThread::OnTimer() {
- ASSERT(kernel.GlobalSchedulerContext().IsLocked());
+ ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(m_kernel));
// If we're waiting, cancel the wait.
- if (GetState() == ThreadState::Waiting) {
- wait_queue->CancelWait(this, ResultTimedOut, false);
+ if (this->GetState() == ThreadState::Waiting) {
+ m_wait_queue->CancelWait(this, ResultTimedOut, false);
}
}
void KThread::StartTermination() {
- ASSERT(kernel.GlobalSchedulerContext().IsLocked());
+ ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(m_kernel));
// Release user exception and unpin, if relevant.
- if (parent != nullptr) {
- parent->ReleaseUserException(this);
- if (parent->GetPinnedThread(GetCurrentCoreId(kernel)) == this) {
- parent->UnpinCurrentThread(core_id);
+ if (m_parent != nullptr) {
+ m_parent->ReleaseUserException(this);
+ if (m_parent->GetPinnedThread(GetCurrentCoreId(m_kernel)) == this) {
+ m_parent->UnpinCurrentThread(m_core_id);
}
}
// Set state to terminated.
- SetState(ThreadState::Terminated);
+ this->SetState(ThreadState::Terminated);
// Clear the thread's status as running in parent.
- if (parent != nullptr) {
- parent->ClearRunningThread(this);
+ if (m_parent != nullptr) {
+ m_parent->ClearRunningThread(this);
}
// Signal.
- signaled = true;
+ m_signaled = true;
KSynchronizationObject::NotifyAvailable();
// Clear previous thread in KScheduler.
- KScheduler::ClearPreviousThread(kernel, this);
+ KScheduler::ClearPreviousThread(m_kernel, this);
// Register terminated dpc flag.
- RegisterDpc(DpcFlag::Terminated);
+ this->RegisterDpc(DpcFlag::Terminated);
}
void KThread::FinishTermination() {
// Ensure that the thread is not executing on any core.
- if (parent != nullptr) {
+ if (m_parent != nullptr) {
for (std::size_t i = 0; i < static_cast<std::size_t>(Core::Hardware::NUM_CPU_CORES); ++i) {
KThread* core_thread{};
do {
- core_thread = kernel.Scheduler(i).GetSchedulerCurrentThread();
+ core_thread = m_kernel.Scheduler(i).GetSchedulerCurrentThread();
} while (core_thread == this);
}
}
@@ -414,182 +447,183 @@ void KThread::DoWorkerTaskImpl() {
}
void KThread::Pin(s32 current_core) {
- ASSERT(kernel.GlobalSchedulerContext().IsLocked());
+ ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(m_kernel));
// Set ourselves as pinned.
GetStackParameters().is_pinned = true;
// Disable core migration.
- ASSERT(num_core_migration_disables == 0);
+ ASSERT(m_num_core_migration_disables == 0);
{
- ++num_core_migration_disables;
+ ++m_num_core_migration_disables;
// Save our ideal state to restore when we're unpinned.
- original_physical_ideal_core_id = physical_ideal_core_id;
- original_physical_affinity_mask = physical_affinity_mask;
+ m_original_physical_ideal_core_id = m_physical_ideal_core_id;
+ m_original_physical_affinity_mask = m_physical_affinity_mask;
// Bind ourselves to this core.
- const s32 active_core = GetActiveCore();
+ const s32 active_core = this->GetActiveCore();
- SetActiveCore(current_core);
- physical_ideal_core_id = current_core;
- physical_affinity_mask.SetAffinityMask(1ULL << current_core);
+ this->SetActiveCore(current_core);
+ m_physical_ideal_core_id = current_core;
+ m_physical_affinity_mask.SetAffinityMask(1ULL << current_core);
- if (active_core != current_core || physical_affinity_mask.GetAffinityMask() !=
- original_physical_affinity_mask.GetAffinityMask()) {
- KScheduler::OnThreadAffinityMaskChanged(kernel, this, original_physical_affinity_mask,
- active_core);
+ if (active_core != current_core ||
+ m_physical_affinity_mask.GetAffinityMask() !=
+ m_original_physical_affinity_mask.GetAffinityMask()) {
+ KScheduler::OnThreadAffinityMaskChanged(m_kernel, this,
+ m_original_physical_affinity_mask, active_core);
}
}
// Disallow performing thread suspension.
{
// Update our allow flags.
- suspend_allowed_flags &= ~(1 << (static_cast<u32>(SuspendType::Thread) +
- static_cast<u32>(ThreadState::SuspendShift)));
+ m_suspend_allowed_flags &= ~(1 << (static_cast<u32>(SuspendType::Thread) +
+ static_cast<u32>(ThreadState::SuspendShift)));
// Update our state.
- UpdateState();
+ this->UpdateState();
}
// TODO(bunnei): Update our SVC access permissions.
- ASSERT(parent != nullptr);
+ ASSERT(m_parent != nullptr);
}
void KThread::Unpin() {
- ASSERT(kernel.GlobalSchedulerContext().IsLocked());
+ ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(m_kernel));
// Set ourselves as unpinned.
- GetStackParameters().is_pinned = false;
+ this->GetStackParameters().is_pinned = false;
// Enable core migration.
- ASSERT(num_core_migration_disables == 1);
+ ASSERT(m_num_core_migration_disables == 1);
{
- num_core_migration_disables--;
+ m_num_core_migration_disables--;
// Restore our original state.
- const KAffinityMask old_mask = physical_affinity_mask;
+ const KAffinityMask old_mask = m_physical_affinity_mask;
- physical_ideal_core_id = original_physical_ideal_core_id;
- physical_affinity_mask = original_physical_affinity_mask;
+ m_physical_ideal_core_id = m_original_physical_ideal_core_id;
+ m_physical_affinity_mask = m_original_physical_affinity_mask;
- if (physical_affinity_mask.GetAffinityMask() != old_mask.GetAffinityMask()) {
- const s32 active_core = GetActiveCore();
+ if (m_physical_affinity_mask.GetAffinityMask() != old_mask.GetAffinityMask()) {
+ const s32 active_core = this->GetActiveCore();
- if (!physical_affinity_mask.GetAffinity(active_core)) {
- if (physical_ideal_core_id >= 0) {
- SetActiveCore(physical_ideal_core_id);
+ if (!m_physical_affinity_mask.GetAffinity(active_core)) {
+ if (m_physical_ideal_core_id >= 0) {
+ this->SetActiveCore(m_physical_ideal_core_id);
} else {
- SetActiveCore(static_cast<s32>(
+ this->SetActiveCore(static_cast<s32>(
Common::BitSize<u64>() - 1 -
- std::countl_zero(physical_affinity_mask.GetAffinityMask())));
+ std::countl_zero(m_physical_affinity_mask.GetAffinityMask())));
}
}
- KScheduler::OnThreadAffinityMaskChanged(kernel, this, old_mask, active_core);
+ KScheduler::OnThreadAffinityMaskChanged(m_kernel, this, old_mask, active_core);
}
}
// Allow performing thread suspension (if termination hasn't been requested).
- if (!IsTerminationRequested()) {
+ if (!this->IsTerminationRequested()) {
// Update our allow flags.
- suspend_allowed_flags |= (1 << (static_cast<u32>(SuspendType::Thread) +
- static_cast<u32>(ThreadState::SuspendShift)));
+ m_suspend_allowed_flags |= (1 << (static_cast<u32>(SuspendType::Thread) +
+ static_cast<u32>(ThreadState::SuspendShift)));
// Update our state.
- UpdateState();
+ this->UpdateState();
}
// TODO(bunnei): Update our SVC access permissions.
- ASSERT(parent != nullptr);
+ ASSERT(m_parent != nullptr);
// Resume any threads that began waiting on us while we were pinned.
- for (auto it = pinned_waiter_list.begin(); it != pinned_waiter_list.end(); ++it) {
+ for (auto it = m_pinned_waiter_list.begin(); it != m_pinned_waiter_list.end(); ++it) {
it->EndWait(ResultSuccess);
}
}
u16 KThread::GetUserDisableCount() const {
- if (!IsUserThread()) {
+ if (!this->IsUserThread()) {
// We only emulate TLS for user threads
return {};
}
- auto& memory = kernel.System().Memory();
- return memory.Read16(tls_address + offsetof(ThreadLocalRegion, disable_count));
+ auto& memory = this->GetOwnerProcess()->GetMemory();
+ return memory.Read16(m_tls_address + offsetof(ThreadLocalRegion, disable_count));
}
void KThread::SetInterruptFlag() {
- if (!IsUserThread()) {
+ if (!this->IsUserThread()) {
// We only emulate TLS for user threads
return;
}
- auto& memory = kernel.System().Memory();
- memory.Write16(tls_address + offsetof(ThreadLocalRegion, interrupt_flag), 1);
+ auto& memory = this->GetOwnerProcess()->GetMemory();
+ memory.Write16(m_tls_address + offsetof(ThreadLocalRegion, interrupt_flag), 1);
}
void KThread::ClearInterruptFlag() {
- if (!IsUserThread()) {
+ if (!this->IsUserThread()) {
// We only emulate TLS for user threads
return;
}
- auto& memory = kernel.System().Memory();
- memory.Write16(tls_address + offsetof(ThreadLocalRegion, interrupt_flag), 0);
+ auto& memory = this->GetOwnerProcess()->GetMemory();
+ memory.Write16(m_tls_address + offsetof(ThreadLocalRegion, interrupt_flag), 0);
}
Result KThread::GetCoreMask(s32* out_ideal_core, u64* out_affinity_mask) {
- KScopedSchedulerLock sl{kernel};
+ KScopedSchedulerLock sl{m_kernel};
// Get the virtual mask.
- *out_ideal_core = virtual_ideal_core_id;
- *out_affinity_mask = virtual_affinity_mask;
+ *out_ideal_core = m_virtual_ideal_core_id;
+ *out_affinity_mask = m_virtual_affinity_mask;
R_SUCCEED();
}
Result KThread::GetPhysicalCoreMask(s32* out_ideal_core, u64* out_affinity_mask) {
- KScopedSchedulerLock sl{kernel};
- ASSERT(num_core_migration_disables >= 0);
+ KScopedSchedulerLock sl{m_kernel};
+ ASSERT(m_num_core_migration_disables >= 0);
// Select between core mask and original core mask.
- if (num_core_migration_disables == 0) {
- *out_ideal_core = physical_ideal_core_id;
- *out_affinity_mask = physical_affinity_mask.GetAffinityMask();
+ if (m_num_core_migration_disables == 0) {
+ *out_ideal_core = m_physical_ideal_core_id;
+ *out_affinity_mask = m_physical_affinity_mask.GetAffinityMask();
} else {
- *out_ideal_core = original_physical_ideal_core_id;
- *out_affinity_mask = original_physical_affinity_mask.GetAffinityMask();
+ *out_ideal_core = m_original_physical_ideal_core_id;
+ *out_affinity_mask = m_original_physical_affinity_mask.GetAffinityMask();
}
R_SUCCEED();
}
-Result KThread::SetCoreMask(s32 core_id_, u64 v_affinity_mask) {
- ASSERT(parent != nullptr);
+Result KThread::SetCoreMask(s32 core_id, u64 v_affinity_mask) {
+ ASSERT(m_parent != nullptr);
ASSERT(v_affinity_mask != 0);
- KScopedLightLock lk(activity_pause_lock);
+ KScopedLightLock lk(m_activity_pause_lock);
// Set the core mask.
u64 p_affinity_mask = 0;
{
- KScopedSchedulerLock sl(kernel);
- ASSERT(num_core_migration_disables >= 0);
+ KScopedSchedulerLock sl(m_kernel);
+ ASSERT(m_num_core_migration_disables >= 0);
// If we're updating, set our ideal virtual core.
- if (core_id_ != Svc::IdealCoreNoUpdate) {
- virtual_ideal_core_id = core_id_;
+ if (core_id != Svc::IdealCoreNoUpdate) {
+ m_virtual_ideal_core_id = core_id;
} else {
// Preserve our ideal core id.
- core_id_ = virtual_ideal_core_id;
- R_UNLESS(((1ULL << core_id_) & v_affinity_mask) != 0, ResultInvalidCombination);
+ core_id = m_virtual_ideal_core_id;
+ R_UNLESS(((1ULL << core_id) & v_affinity_mask) != 0, ResultInvalidCombination);
}
// Set our affinity mask.
- virtual_affinity_mask = v_affinity_mask;
+ m_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 (core_id >= 0) {
+ core_id = Core::Hardware::VirtualToPhysicalCoreMap[core_id];
}
// Translate the virtual affinity mask to a physical one.
@@ -600,43 +634,43 @@ Result KThread::SetCoreMask(s32 core_id_, u64 v_affinity_mask) {
}
// If we haven't disabled migration, perform an affinity change.
- if (num_core_migration_disables == 0) {
- const KAffinityMask old_mask = physical_affinity_mask;
+ if (m_num_core_migration_disables == 0) {
+ const KAffinityMask old_mask = m_physical_affinity_mask;
// Set our new ideals.
- physical_ideal_core_id = core_id_;
- physical_affinity_mask.SetAffinityMask(p_affinity_mask);
+ m_physical_ideal_core_id = core_id;
+ m_physical_affinity_mask.SetAffinityMask(p_affinity_mask);
- if (physical_affinity_mask.GetAffinityMask() != old_mask.GetAffinityMask()) {
+ if (m_physical_affinity_mask.GetAffinityMask() != old_mask.GetAffinityMask()) {
const s32 active_core = GetActiveCore();
- if (active_core >= 0 && !physical_affinity_mask.GetAffinity(active_core)) {
+ if (active_core >= 0 && !m_physical_affinity_mask.GetAffinity(active_core)) {
const s32 new_core = static_cast<s32>(
- physical_ideal_core_id >= 0
- ? physical_ideal_core_id
+ m_physical_ideal_core_id >= 0
+ ? m_physical_ideal_core_id
: Common::BitSize<u64>() - 1 -
- std::countl_zero(physical_affinity_mask.GetAffinityMask()));
+ std::countl_zero(m_physical_affinity_mask.GetAffinityMask()));
SetActiveCore(new_core);
}
- KScheduler::OnThreadAffinityMaskChanged(kernel, this, old_mask, active_core);
+ KScheduler::OnThreadAffinityMaskChanged(m_kernel, this, old_mask, active_core);
}
} else {
// Otherwise, we edit the original affinity for restoration later.
- original_physical_ideal_core_id = core_id_;
- original_physical_affinity_mask.SetAffinityMask(p_affinity_mask);
+ m_original_physical_ideal_core_id = core_id;
+ m_original_physical_affinity_mask.SetAffinityMask(p_affinity_mask);
}
}
// Update the pinned waiter list.
- ThreadQueueImplForKThreadSetProperty wait_queue_(kernel, std::addressof(pinned_waiter_list));
+ ThreadQueueImplForKThreadSetProperty wait_queue(m_kernel, std::addressof(m_pinned_waiter_list));
{
bool retry_update{};
do {
// Lock the scheduler.
- KScopedSchedulerLock sl(kernel);
+ KScopedSchedulerLock sl(m_kernel);
// Don't do any further management if our termination has been requested.
- R_SUCCEED_IF(IsTerminationRequested());
+ R_SUCCEED_IF(this->IsTerminationRequested());
// By default, we won't need to retry.
retry_update = false;
@@ -646,7 +680,7 @@ Result KThread::SetCoreMask(s32 core_id_, u64 v_affinity_mask) {
s32 thread_core;
for (thread_core = 0; thread_core < static_cast<s32>(Core::Hardware::NUM_CPU_CORES);
++thread_core) {
- if (kernel.Scheduler(thread_core).GetSchedulerCurrentThread() == this) {
+ if (m_kernel.Scheduler(thread_core).GetSchedulerCurrentThread() == this) {
thread_is_current = true;
break;
}
@@ -656,14 +690,14 @@ Result KThread::SetCoreMask(s32 core_id_, u64 v_affinity_mask) {
// new mask.
if (thread_is_current && ((1ULL << thread_core) & p_affinity_mask) == 0) {
// If the thread is pinned, we want to wait until it's not pinned.
- if (GetStackParameters().is_pinned) {
+ if (this->GetStackParameters().is_pinned) {
// Verify that the current thread isn't terminating.
- R_UNLESS(!GetCurrentThread(kernel).IsTerminationRequested(),
+ R_UNLESS(!GetCurrentThread(m_kernel).IsTerminationRequested(),
ResultTerminationRequested);
// Wait until the thread isn't pinned any more.
- pinned_waiter_list.push_back(GetCurrentThread(kernel));
- GetCurrentThread(kernel).BeginWait(std::addressof(wait_queue_));
+ m_pinned_waiter_list.push_back(GetCurrentThread(m_kernel));
+ GetCurrentThread(m_kernel).BeginWait(std::addressof(wait_queue));
} else {
// If the thread isn't pinned, release the scheduler lock and retry until it's
// not current.
@@ -679,111 +713,137 @@ Result KThread::SetCoreMask(s32 core_id_, u64 v_affinity_mask) {
void KThread::SetBasePriority(s32 value) {
ASSERT(Svc::HighestThreadPriority <= value && value <= Svc::LowestThreadPriority);
- KScopedSchedulerLock sl{kernel};
+ KScopedSchedulerLock sl{m_kernel};
// Change our base priority.
- base_priority = value;
+ m_base_priority = value;
// Perform a priority restoration.
- RestorePriority(kernel, this);
+ RestorePriority(m_kernel, this);
+}
+
+KThread* KThread::GetLockOwner() const {
+ return m_waiting_lock_info != nullptr ? m_waiting_lock_info->GetOwner() : nullptr;
+}
+
+void KThread::IncreaseBasePriority(s32 priority) {
+ ASSERT(Svc::HighestThreadPriority <= priority && priority <= Svc::LowestThreadPriority);
+ ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(m_kernel));
+ ASSERT(!this->GetStackParameters().is_pinned);
+
+ // Set our base priority.
+ if (m_base_priority > priority) {
+ m_base_priority = priority;
+
+ // Perform a priority restoration.
+ RestorePriority(m_kernel, this);
+ }
}
void KThread::RequestSuspend(SuspendType type) {
- KScopedSchedulerLock sl{kernel};
+ KScopedSchedulerLock sl{m_kernel};
// Note the request in our flags.
- suspend_request_flags |=
- (1u << (static_cast<u32>(ThreadState::SuspendShift) + static_cast<u32>(type)));
+ m_suspend_request_flags |=
+ (1U << (static_cast<u32>(ThreadState::SuspendShift) + static_cast<u32>(type)));
// Try to perform the suspend.
- TrySuspend();
+ this->TrySuspend();
}
void KThread::Resume(SuspendType type) {
- KScopedSchedulerLock sl{kernel};
+ KScopedSchedulerLock sl{m_kernel};
// Clear the request in our flags.
- suspend_request_flags &=
- ~(1u << (static_cast<u32>(ThreadState::SuspendShift) + static_cast<u32>(type)));
+ m_suspend_request_flags &=
+ ~(1U << (static_cast<u32>(ThreadState::SuspendShift) + static_cast<u32>(type)));
// Update our state.
this->UpdateState();
}
void KThread::WaitCancel() {
- KScopedSchedulerLock sl{kernel};
+ KScopedSchedulerLock sl{m_kernel};
// Check if we're waiting and cancellable.
- if (this->GetState() == ThreadState::Waiting && cancellable) {
- wait_cancelled = false;
- wait_queue->CancelWait(this, ResultCancelled, true);
+ if (this->GetState() == ThreadState::Waiting && m_cancellable) {
+ m_wait_cancelled = false;
+ m_wait_queue->CancelWait(this, ResultCancelled, true);
} else {
// Otherwise, note that we cancelled a wait.
- wait_cancelled = true;
+ m_wait_cancelled = true;
}
}
void KThread::TrySuspend() {
- ASSERT(kernel.GlobalSchedulerContext().IsLocked());
- ASSERT(IsSuspendRequested());
+ ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(m_kernel));
+ ASSERT(this->IsSuspendRequested());
// Ensure that we have no waiters.
- if (GetNumKernelWaiters() > 0) {
+ if (this->GetNumKernelWaiters() > 0) {
return;
}
- ASSERT(GetNumKernelWaiters() == 0);
+ ASSERT(this->GetNumKernelWaiters() == 0);
// Perform the suspend.
this->UpdateState();
}
void KThread::UpdateState() {
- ASSERT(kernel.GlobalSchedulerContext().IsLocked());
+ ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(m_kernel));
// Set our suspend flags in state.
- const ThreadState old_state = thread_state.load(std::memory_order_relaxed);
+ const ThreadState old_state = m_thread_state.load(std::memory_order_relaxed);
const auto new_state =
static_cast<ThreadState>(this->GetSuspendFlags()) | (old_state & ThreadState::Mask);
- thread_state.store(new_state, std::memory_order_relaxed);
+ m_thread_state.store(new_state, std::memory_order_relaxed);
// Note the state change in scheduler.
if (new_state != old_state) {
- KScheduler::OnThreadStateChanged(kernel, this, old_state);
+ KScheduler::OnThreadStateChanged(m_kernel, this, old_state);
}
}
void KThread::Continue() {
- ASSERT(kernel.GlobalSchedulerContext().IsLocked());
+ ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(m_kernel));
// Clear our suspend flags in state.
- const ThreadState old_state = thread_state.load(std::memory_order_relaxed);
- thread_state.store(old_state & ThreadState::Mask, std::memory_order_relaxed);
+ const ThreadState old_state = m_thread_state.load(std::memory_order_relaxed);
+ m_thread_state.store(old_state & ThreadState::Mask, std::memory_order_relaxed);
// Note the state change in scheduler.
- KScheduler::OnThreadStateChanged(kernel, this, old_state);
+ KScheduler::OnThreadStateChanged(m_kernel, this, old_state);
}
-void KThread::WaitUntilSuspended() {
- // Make sure we have a suspend requested.
- ASSERT(IsSuspendRequested());
+void KThread::CloneFpuStatus() {
+ // We shouldn't reach here when starting kernel threads.
+ ASSERT(this->GetOwnerProcess() != nullptr);
+ ASSERT(this->GetOwnerProcess() == GetCurrentProcessPointer(m_kernel));
- // Loop until the thread is not executing on any core.
- for (std::size_t i = 0; i < static_cast<std::size_t>(Core::Hardware::NUM_CPU_CORES); ++i) {
- KThread* core_thread{};
- do {
- core_thread = kernel.Scheduler(i).GetSchedulerCurrentThread();
- } while (core_thread == this);
+ if (this->GetOwnerProcess()->Is64BitProcess()) {
+ // Clone FPSR and FPCR.
+ ThreadContext64 cur_ctx{};
+ m_kernel.System().CurrentArmInterface().SaveContext(cur_ctx);
+
+ this->GetContext64().fpcr = cur_ctx.fpcr;
+ this->GetContext64().fpsr = cur_ctx.fpsr;
+ } else {
+ // Clone FPSCR.
+ ThreadContext32 cur_ctx{};
+ m_kernel.System().CurrentArmInterface().SaveContext(cur_ctx);
+
+ this->GetContext32().fpscr = cur_ctx.fpscr;
}
}
Result KThread::SetActivity(Svc::ThreadActivity activity) {
// Lock ourselves.
- KScopedLightLock lk(activity_pause_lock);
+ KScopedLightLock lk(m_activity_pause_lock);
// Set the activity.
{
// Lock the scheduler.
- KScopedSchedulerLock sl(kernel);
+ KScopedSchedulerLock sl(m_kernel);
// Verify our state.
const auto cur_state = this->GetState();
@@ -810,13 +870,13 @@ Result KThread::SetActivity(Svc::ThreadActivity activity) {
// If the thread is now paused, update the pinned waiter list.
if (activity == Svc::ThreadActivity::Paused) {
- ThreadQueueImplForKThreadSetProperty wait_queue_(kernel,
- std::addressof(pinned_waiter_list));
+ ThreadQueueImplForKThreadSetProperty wait_queue(m_kernel,
+ std::addressof(m_pinned_waiter_list));
- bool thread_is_current;
+ bool thread_is_current{};
do {
// Lock the scheduler.
- KScopedSchedulerLock sl(kernel);
+ KScopedSchedulerLock sl(m_kernel);
// Don't do any further management if our termination has been requested.
R_SUCCEED_IF(this->IsTerminationRequested());
@@ -827,17 +887,17 @@ Result KThread::SetActivity(Svc::ThreadActivity activity) {
// Check whether the thread is pinned.
if (this->GetStackParameters().is_pinned) {
// Verify that the current thread isn't terminating.
- R_UNLESS(!GetCurrentThread(kernel).IsTerminationRequested(),
+ R_UNLESS(!GetCurrentThread(m_kernel).IsTerminationRequested(),
ResultTerminationRequested);
// Wait until the thread isn't pinned any more.
- pinned_waiter_list.push_back(GetCurrentThread(kernel));
- GetCurrentThread(kernel).BeginWait(std::addressof(wait_queue_));
+ m_pinned_waiter_list.push_back(GetCurrentThread(m_kernel));
+ GetCurrentThread(m_kernel).BeginWait(std::addressof(wait_queue));
} else {
// Check if the thread is currently running.
// If it is, we'll need to retry.
for (auto i = 0; i < static_cast<s32>(Core::Hardware::NUM_CPU_CORES); ++i) {
- if (kernel.Scheduler(i).GetSchedulerCurrentThread() == this) {
+ if (m_kernel.Scheduler(i).GetSchedulerCurrentThread() == this) {
thread_is_current = true;
break;
}
@@ -849,34 +909,32 @@ Result KThread::SetActivity(Svc::ThreadActivity activity) {
R_SUCCEED();
}
-Result KThread::GetThreadContext3(std::vector<u8>& out) {
+Result KThread::GetThreadContext3(Common::ScratchBuffer<u8>& out) {
// Lock ourselves.
- KScopedLightLock lk{activity_pause_lock};
+ KScopedLightLock lk{m_activity_pause_lock};
// Get the context.
{
// Lock the scheduler.
- KScopedSchedulerLock sl{kernel};
+ KScopedSchedulerLock sl{m_kernel};
// Verify that we're suspended.
- R_UNLESS(IsSuspendRequested(SuspendType::Thread), ResultInvalidState);
+ R_UNLESS(this->IsSuspendRequested(SuspendType::Thread), ResultInvalidState);
// If we're not terminating, get the thread's user context.
- if (!IsTerminationRequested()) {
- if (parent->Is64BitProcess()) {
+ if (!this->IsTerminationRequested()) {
+ if (m_parent->Is64BitProcess()) {
// Mask away mode bits, interrupt bits, IL bit, and other reserved bits.
auto context = GetContext64();
context.pstate &= 0xFF0FFE20;
-
- out.resize(sizeof(context));
- std::memcpy(out.data(), &context, sizeof(context));
+ out.resize_destructive(sizeof(context));
+ std::memcpy(out.data(), std::addressof(context), sizeof(context));
} else {
// Mask away mode bits, interrupt bits, IL bit, and other reserved bits.
auto context = GetContext32();
context.cpsr &= 0xFF0FFE20;
-
- out.resize(sizeof(context));
- std::memcpy(out.data(), &context, sizeof(context));
+ out.resize_destructive(sizeof(context));
+ std::memcpy(out.data(), std::addressof(context), sizeof(context));
}
}
}
@@ -884,51 +942,89 @@ Result KThread::GetThreadContext3(std::vector<u8>& out) {
R_SUCCEED();
}
-void KThread::AddWaiterImpl(KThread* thread) {
- ASSERT(kernel.GlobalSchedulerContext().IsLocked());
+void KThread::AddHeldLock(LockWithPriorityInheritanceInfo* lock_info) {
+ ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(m_kernel));
+
+ // Set ourselves as the lock's owner.
+ lock_info->SetOwner(this);
+
+ // Add the lock to our held list.
+ m_held_lock_info_list.push_front(*lock_info);
+}
+
+KThread::LockWithPriorityInheritanceInfo* KThread::FindHeldLock(KProcessAddress address_key,
+ bool is_kernel_address_key) {
+ ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(m_kernel));
- // Find the right spot to insert the waiter.
- auto it = waiter_list.begin();
- while (it != waiter_list.end()) {
- if (it->GetPriority() > thread->GetPriority()) {
- break;
+ // Try to find an existing held lock.
+ for (auto& held_lock : m_held_lock_info_list) {
+ if (held_lock.GetAddressKey() == address_key &&
+ held_lock.GetIsKernelAddressKey() == is_kernel_address_key) {
+ return std::addressof(held_lock);
}
- it++;
}
+ return nullptr;
+}
+
+void KThread::AddWaiterImpl(KThread* thread) {
+ ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(m_kernel));
+ ASSERT(thread->GetConditionVariableTree() == nullptr);
+
+ // Get the thread's address key.
+ const auto address_key = thread->GetAddressKey();
+ const auto is_kernel_address_key = thread->GetIsKernelAddressKey();
+
// Keep track of how many kernel waiters we have.
- if (IsKernelAddressKey(thread->GetAddressKey())) {
- ASSERT((num_kernel_waiters++) >= 0);
- KScheduler::SetSchedulerUpdateNeeded(kernel);
+ if (is_kernel_address_key) {
+ ASSERT((m_num_kernel_waiters++) >= 0);
+ KScheduler::SetSchedulerUpdateNeeded(m_kernel);
+ }
+
+ // Get the relevant lock info.
+ auto* lock_info = this->FindHeldLock(address_key, is_kernel_address_key);
+ if (lock_info == nullptr) {
+ // Create a new lock for the address key.
+ lock_info =
+ LockWithPriorityInheritanceInfo::Create(m_kernel, address_key, is_kernel_address_key);
+
+ // Add the new lock to our list.
+ this->AddHeldLock(lock_info);
}
- // Insert the waiter.
- waiter_list.insert(it, *thread);
- thread->SetLockOwner(this);
+ // Add the thread as waiter to the lock info.
+ lock_info->AddWaiter(thread);
}
void KThread::RemoveWaiterImpl(KThread* thread) {
- ASSERT(kernel.GlobalSchedulerContext().IsLocked());
+ ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(m_kernel));
// Keep track of how many kernel waiters we have.
- if (IsKernelAddressKey(thread->GetAddressKey())) {
- ASSERT((num_kernel_waiters--) > 0);
- KScheduler::SetSchedulerUpdateNeeded(kernel);
+ if (thread->GetIsKernelAddressKey()) {
+ ASSERT((m_num_kernel_waiters--) > 0);
+ KScheduler::SetSchedulerUpdateNeeded(m_kernel);
}
+ // Get the info for the lock the thread is waiting on.
+ auto* lock_info = thread->GetWaitingLockInfo();
+ ASSERT(lock_info->GetOwner() == this);
+
// Remove the waiter.
- waiter_list.erase(waiter_list.iterator_to(*thread));
- thread->SetLockOwner(nullptr);
+ if (lock_info->RemoveWaiter(thread)) {
+ m_held_lock_info_list.erase(m_held_lock_info_list.iterator_to(*lock_info));
+ LockWithPriorityInheritanceInfo::Free(m_kernel, lock_info);
+ }
}
-void KThread::RestorePriority(KernelCore& kernel_ctx, KThread* thread) {
- ASSERT(kernel_ctx.GlobalSchedulerContext().IsLocked());
+void KThread::RestorePriority(KernelCore& kernel, KThread* thread) {
+ ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(kernel));
- while (true) {
+ while (thread != nullptr) {
// We want to inherit priority where possible.
s32 new_priority = thread->GetBasePriority();
- if (thread->HasWaiters()) {
- new_priority = std::min(new_priority, thread->waiter_list.front().GetPriority());
+ for (const auto& held_lock : thread->m_held_lock_info_list) {
+ new_priority =
+ std::min(new_priority, held_lock.GetHighestPriorityWaiter()->GetPriority());
}
// If the priority we would inherit is not different from ours, don't do anything.
@@ -936,9 +1032,18 @@ void KThread::RestorePriority(KernelCore& kernel_ctx, KThread* thread) {
return;
}
+ // Get the owner of whatever lock this thread is waiting on.
+ KThread* const lock_owner = thread->GetLockOwner();
+
+ // If the thread is waiting on some lock, remove it as a waiter to prevent violating red
+ // black tree invariants.
+ if (lock_owner != nullptr) {
+ lock_owner->RemoveWaiterImpl(thread);
+ }
+
// Ensure we don't violate condition variable red black tree invariants.
if (auto* cv_tree = thread->GetConditionVariableTree(); cv_tree != nullptr) {
- BeforeUpdatePriority(kernel_ctx, cv_tree, thread);
+ BeforeUpdatePriority(kernel, cv_tree, thread);
}
// Change the priority.
@@ -947,148 +1052,175 @@ void KThread::RestorePriority(KernelCore& kernel_ctx, KThread* thread) {
// Restore the condition variable, if relevant.
if (auto* cv_tree = thread->GetConditionVariableTree(); cv_tree != nullptr) {
- AfterUpdatePriority(kernel_ctx, cv_tree, thread);
+ AfterUpdatePriority(kernel, cv_tree, thread);
}
- // Update the scheduler.
- KScheduler::OnThreadPriorityChanged(kernel_ctx, thread, old_priority);
-
- // Keep the lock owner up to date.
- KThread* lock_owner = thread->GetLockOwner();
- if (lock_owner == nullptr) {
- return;
+ // If we removed the thread from some lock's waiting list, add it back.
+ if (lock_owner != nullptr) {
+ lock_owner->AddWaiterImpl(thread);
}
- // Update the thread in the lock owner's sorted list, and continue inheriting.
- lock_owner->RemoveWaiterImpl(thread);
- lock_owner->AddWaiterImpl(thread);
+ // Update the scheduler.
+ KScheduler::OnThreadPriorityChanged(kernel, thread, old_priority);
+
+ // Continue inheriting priority.
thread = lock_owner;
}
}
void KThread::AddWaiter(KThread* thread) {
- AddWaiterImpl(thread);
- RestorePriority(kernel, this);
+ this->AddWaiterImpl(thread);
+
+ // If the thread has a higher priority than us, we should inherit.
+ if (thread->GetPriority() < this->GetPriority()) {
+ RestorePriority(m_kernel, this);
+ }
}
void KThread::RemoveWaiter(KThread* thread) {
- RemoveWaiterImpl(thread);
- RestorePriority(kernel, this);
+ this->RemoveWaiterImpl(thread);
+
+ // If our priority is the same as the thread's (and we've inherited), we may need to restore to
+ // lower priority.
+ if (this->GetPriority() == thread->GetPriority() &&
+ this->GetPriority() < this->GetBasePriority()) {
+ RestorePriority(m_kernel, this);
+ }
}
-KThread* KThread::RemoveWaiterByKey(s32* out_num_waiters, VAddr key) {
- ASSERT(kernel.GlobalSchedulerContext().IsLocked());
+KThread* KThread::RemoveWaiterByKey(bool* out_has_waiters, KProcessAddress key,
+ bool is_kernel_address_key_) {
+ ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(m_kernel));
- s32 num_waiters{};
- KThread* next_lock_owner{};
- auto it = waiter_list.begin();
- while (it != waiter_list.end()) {
- if (it->GetAddressKey() == key) {
- KThread* thread = std::addressof(*it);
+ // Get the relevant lock info.
+ auto* lock_info = this->FindHeldLock(key, is_kernel_address_key_);
+ if (lock_info == nullptr) {
+ *out_has_waiters = false;
+ return nullptr;
+ }
- // Keep track of how many kernel waiters we have.
- if (IsKernelAddressKey(thread->GetAddressKey())) {
- ASSERT((num_kernel_waiters--) > 0);
- KScheduler::SetSchedulerUpdateNeeded(kernel);
- }
- it = waiter_list.erase(it);
+ // Remove the lock info from our held list.
+ m_held_lock_info_list.erase(m_held_lock_info_list.iterator_to(*lock_info));
- // Update the next lock owner.
- if (next_lock_owner == nullptr) {
- next_lock_owner = thread;
- next_lock_owner->SetLockOwner(nullptr);
- } else {
- next_lock_owner->AddWaiterImpl(thread);
- }
- num_waiters++;
- } else {
- it++;
+ // Keep track of how many kernel waiters we have.
+ if (lock_info->GetIsKernelAddressKey()) {
+ m_num_kernel_waiters -= lock_info->GetWaiterCount();
+ ASSERT(m_num_kernel_waiters >= 0);
+ KScheduler::SetSchedulerUpdateNeeded(m_kernel);
+ }
+
+ ASSERT(lock_info->GetWaiterCount() > 0);
+
+ // Remove the highest priority waiter from the lock to be the next owner.
+ KThread* next_lock_owner = lock_info->GetHighestPriorityWaiter();
+ if (lock_info->RemoveWaiter(next_lock_owner)) {
+ // The new owner was the only waiter.
+ *out_has_waiters = false;
+
+ // Free the lock info, since it has no waiters.
+ LockWithPriorityInheritanceInfo::Free(m_kernel, lock_info);
+ } else {
+ // There are additional waiters on the lock.
+ *out_has_waiters = true;
+
+ // Add the lock to the new owner's held list.
+ next_lock_owner->AddHeldLock(lock_info);
+
+ // Keep track of any kernel waiters for the new owner.
+ if (lock_info->GetIsKernelAddressKey()) {
+ next_lock_owner->m_num_kernel_waiters += lock_info->GetWaiterCount();
+ ASSERT(next_lock_owner->m_num_kernel_waiters > 0);
+
+ // NOTE: No need to set scheduler update needed, because we will have already done so
+ // when removing earlier.
}
}
- // Do priority updates, if we have a next owner.
- if (next_lock_owner) {
- RestorePriority(kernel, this);
- RestorePriority(kernel, next_lock_owner);
+ // If our priority is the same as the next owner's (and we've inherited), we may need to restore
+ // to lower priority.
+ if (this->GetPriority() == next_lock_owner->GetPriority() &&
+ this->GetPriority() < this->GetBasePriority()) {
+ RestorePriority(m_kernel, this);
+ // NOTE: No need to restore priority on the next lock owner, because it was already the
+ // highest priority waiter on the lock.
}
- // Return output.
- *out_num_waiters = num_waiters;
+ // Return the next lock owner.
return next_lock_owner;
}
Result KThread::Run() {
while (true) {
- KScopedSchedulerLock lk{kernel};
+ KScopedSchedulerLock lk{m_kernel};
// If either this thread or the current thread are requesting termination, note it.
- R_UNLESS(!IsTerminationRequested(), ResultTerminationRequested);
- R_UNLESS(!GetCurrentThread(kernel).IsTerminationRequested(), ResultTerminationRequested);
+ R_UNLESS(!this->IsTerminationRequested(), ResultTerminationRequested);
+ R_UNLESS(!GetCurrentThread(m_kernel).IsTerminationRequested(), ResultTerminationRequested);
// Ensure our thread state is correct.
- R_UNLESS(GetState() == ThreadState::Initialized, ResultInvalidState);
+ R_UNLESS(this->GetState() == ThreadState::Initialized, ResultInvalidState);
// If the current thread has been asked to suspend, suspend it and retry.
- if (GetCurrentThread(kernel).IsSuspended()) {
- GetCurrentThread(kernel).UpdateState();
+ if (GetCurrentThread(m_kernel).IsSuspended()) {
+ GetCurrentThread(m_kernel).UpdateState();
continue;
}
// If we're not a kernel thread and we've been asked to suspend, suspend ourselves.
if (KProcess* owner = this->GetOwnerProcess(); owner != nullptr) {
- if (IsUserThread() && IsSuspended()) {
+ if (this->IsUserThread() && this->IsSuspended()) {
this->UpdateState();
}
owner->IncrementRunningThreadCount();
}
// Set our state and finish.
- SetState(ThreadState::Runnable);
+ this->SetState(ThreadState::Runnable);
R_SUCCEED();
}
}
void KThread::Exit() {
- ASSERT(this == GetCurrentThreadPointer(kernel));
+ ASSERT(this == GetCurrentThreadPointer(m_kernel));
// Release the thread resource hint, running thread count from parent.
- if (parent != nullptr) {
- parent->GetResourceLimit()->Release(Kernel::LimitableResource::ThreadCountMax, 0, 1);
- resource_limit_release_hint = true;
- parent->DecrementRunningThreadCount();
+ if (m_parent != nullptr) {
+ m_parent->GetResourceLimit()->Release(Kernel::LimitableResource::ThreadCountMax, 0, 1);
+ m_resource_limit_release_hint = true;
+ m_parent->DecrementRunningThreadCount();
}
// Perform termination.
{
- KScopedSchedulerLock sl{kernel};
+ KScopedSchedulerLock sl{m_kernel};
// Disallow all suspension.
- suspend_allowed_flags = 0;
+ m_suspend_allowed_flags = 0;
this->UpdateState();
// Disallow all suspension.
- suspend_allowed_flags = 0;
+ m_suspend_allowed_flags = 0;
// Start termination.
- StartTermination();
+ this->StartTermination();
// Register the thread as a work task.
- KWorkerTaskManager::AddTask(kernel, KWorkerTaskManager::WorkerType::Exit, this);
+ KWorkerTaskManager::AddTask(m_kernel, KWorkerTaskManager::WorkerType::Exit, this);
}
UNREACHABLE_MSG("KThread::Exit() would return");
}
Result KThread::Terminate() {
- ASSERT(this != GetCurrentThreadPointer(kernel));
+ ASSERT(this != GetCurrentThreadPointer(m_kernel));
// Request the thread terminate if it hasn't already.
if (const auto new_state = this->RequestTerminate(); new_state != ThreadState::Terminated) {
// If the thread isn't terminated, wait for it to terminate.
s32 index;
KSynchronizationObject* objects[] = {this};
- R_TRY(KSynchronizationObject::Wait(kernel, std::addressof(index), objects, 1,
+ R_TRY(KSynchronizationObject::Wait(m_kernel, std::addressof(index), objects, 1,
Svc::WaitInfinite));
}
@@ -1096,22 +1228,22 @@ Result KThread::Terminate() {
}
ThreadState KThread::RequestTerminate() {
- ASSERT(this != GetCurrentThreadPointer(kernel));
+ ASSERT(this != GetCurrentThreadPointer(m_kernel));
- KScopedSchedulerLock sl{kernel};
+ KScopedSchedulerLock sl{m_kernel};
// Determine if this is the first termination request.
const bool first_request = [&]() -> bool {
// Perform an atomic compare-and-swap from false to true.
bool expected = false;
- return termination_requested.compare_exchange_strong(expected, true);
+ return m_termination_requested.compare_exchange_strong(expected, true);
}();
// If this is the first request, start termination procedure.
if (first_request) {
// If the thread is in initialized state, just change state to terminated.
if (this->GetState() == ThreadState::Initialized) {
- thread_state = ThreadState::Terminated;
+ m_thread_state = ThreadState::Terminated;
return ThreadState::Terminated;
}
@@ -1125,27 +1257,25 @@ ThreadState KThread::RequestTerminate() {
// If the thread is suspended, continue it.
if (this->IsSuspended()) {
- suspend_allowed_flags = 0;
+ m_suspend_allowed_flags = 0;
this->UpdateState();
}
// Change the thread's priority to be higher than any system thread's.
- if (this->GetBasePriority() >= Svc::SystemThreadPriorityHighest) {
- this->SetBasePriority(TerminatingThreadPriority);
- }
+ this->IncreaseBasePriority(TerminatingThreadPriority);
// If the thread is runnable, send a termination interrupt to other cores.
if (this->GetState() == ThreadState::Runnable) {
- if (const u64 core_mask =
- physical_affinity_mask.GetAffinityMask() & ~(1ULL << GetCurrentCoreId(kernel));
+ if (const u64 core_mask = m_physical_affinity_mask.GetAffinityMask() &
+ ~(1ULL << GetCurrentCoreId(m_kernel));
core_mask != 0) {
- Kernel::KInterruptManager::SendInterProcessorInterrupt(kernel, core_mask);
+ Kernel::KInterruptManager::SendInterProcessorInterrupt(m_kernel, core_mask);
}
}
// Wake up the thread.
if (this->GetState() == ThreadState::Waiting) {
- wait_queue->CancelWait(this, ResultTerminationRequested, true);
+ m_wait_queue->CancelWait(this, ResultTerminationRequested, true);
}
}
@@ -1153,14 +1283,15 @@ ThreadState KThread::RequestTerminate() {
}
Result KThread::Sleep(s64 timeout) {
- ASSERT(!kernel.GlobalSchedulerContext().IsLocked());
- ASSERT(this == GetCurrentThreadPointer(kernel));
+ ASSERT(!KScheduler::IsSchedulerLockedByCurrentThread(m_kernel));
+ ASSERT(this == GetCurrentThreadPointer(m_kernel));
ASSERT(timeout > 0);
- ThreadQueueImplForKThreadSleep wait_queue_(kernel);
+ ThreadQueueImplForKThreadSleep wait_queue(m_kernel);
+ KHardwareTimer* timer{};
{
// Setup the scheduling lock and sleep.
- KScopedSchedulerLockAndSleep slp(kernel, this, timeout);
+ KScopedSchedulerLockAndSleep slp(m_kernel, std::addressof(timer), this, timeout);
// Check if the thread should terminate.
if (this->IsTerminationRequested()) {
@@ -1169,102 +1300,107 @@ Result KThread::Sleep(s64 timeout) {
}
// Wait for the sleep to end.
- this->BeginWait(std::addressof(wait_queue_));
- SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Sleep);
+ wait_queue.SetHardwareTimer(timer);
+ this->BeginWait(std::addressof(wait_queue));
+ this->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Sleep);
}
R_SUCCEED();
}
void KThread::RequestDummyThreadWait() {
- ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(kernel));
+ ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(m_kernel));
ASSERT(this->IsDummyThread());
// We will block when the scheduler lock is released.
- dummy_thread_runnable.store(false);
+ std::scoped_lock lock{m_dummy_thread_mutex};
+ m_dummy_thread_runnable = false;
}
void KThread::DummyThreadBeginWait() {
- if (!this->IsDummyThread() || kernel.IsPhantomModeForSingleCore()) {
+ if (!this->IsDummyThread() || m_kernel.IsPhantomModeForSingleCore()) {
// Occurs in single core mode.
return;
}
// Block until runnable is no longer false.
- dummy_thread_runnable.wait(false);
+ std::unique_lock lock{m_dummy_thread_mutex};
+ m_dummy_thread_cv.wait(lock, [this] { return m_dummy_thread_runnable; });
}
void KThread::DummyThreadEndWait() {
- ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(kernel));
+ ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(m_kernel));
ASSERT(this->IsDummyThread());
// Wake up the waiting thread.
- dummy_thread_runnable.store(true);
- dummy_thread_runnable.notify_one();
+ {
+ std::scoped_lock lock{m_dummy_thread_mutex};
+ m_dummy_thread_runnable = true;
+ }
+ m_dummy_thread_cv.notify_one();
}
void KThread::BeginWait(KThreadQueue* queue) {
// Set our state as waiting.
- SetState(ThreadState::Waiting);
+ this->SetState(ThreadState::Waiting);
// Set our wait queue.
- wait_queue = queue;
+ m_wait_queue = queue;
}
-void KThread::NotifyAvailable(KSynchronizationObject* signaled_object, Result wait_result_) {
+void KThread::NotifyAvailable(KSynchronizationObject* signaled_object, Result wait_result) {
// Lock the scheduler.
- KScopedSchedulerLock sl(kernel);
+ KScopedSchedulerLock sl(m_kernel);
// If we're waiting, notify our queue that we're available.
- if (GetState() == ThreadState::Waiting) {
- wait_queue->NotifyAvailable(this, signaled_object, wait_result_);
+ if (this->GetState() == ThreadState::Waiting) {
+ m_wait_queue->NotifyAvailable(this, signaled_object, wait_result);
}
}
-void KThread::EndWait(Result wait_result_) {
+void KThread::EndWait(Result wait_result) {
// Lock the scheduler.
- KScopedSchedulerLock sl(kernel);
+ KScopedSchedulerLock sl(m_kernel);
// If we're waiting, notify our queue that we're available.
- if (GetState() == ThreadState::Waiting) {
- if (wait_queue == nullptr) {
+ if (this->GetState() == ThreadState::Waiting) {
+ if (m_wait_queue == nullptr) {
// This should never happen, but avoid a hard crash below to get this logged.
ASSERT_MSG(false, "wait_queue is nullptr!");
return;
}
- wait_queue->EndWait(this, wait_result_);
+ m_wait_queue->EndWait(this, wait_result);
}
}
-void KThread::CancelWait(Result wait_result_, bool cancel_timer_task) {
+void KThread::CancelWait(Result wait_result, bool cancel_timer_task) {
// Lock the scheduler.
- KScopedSchedulerLock sl(kernel);
+ KScopedSchedulerLock sl(m_kernel);
// If we're waiting, notify our queue that we're available.
- if (GetState() == ThreadState::Waiting) {
- wait_queue->CancelWait(this, wait_result_, cancel_timer_task);
+ if (this->GetState() == ThreadState::Waiting) {
+ m_wait_queue->CancelWait(this, wait_result, cancel_timer_task);
}
}
void KThread::SetState(ThreadState state) {
- KScopedSchedulerLock sl{kernel};
+ KScopedSchedulerLock sl{m_kernel};
// Clear debugging state
- SetMutexWaitAddressForDebugging({});
- SetWaitReasonForDebugging({});
+ this->SetWaitReasonForDebugging({});
- const ThreadState old_state = thread_state.load(std::memory_order_relaxed);
- thread_state.store(
+ const ThreadState old_state = m_thread_state.load(std::memory_order_relaxed);
+ m_thread_state.store(
static_cast<ThreadState>((old_state & ~ThreadState::Mask) | (state & ThreadState::Mask)),
std::memory_order_relaxed);
- if (thread_state.load(std::memory_order_relaxed) != old_state) {
- KScheduler::OnThreadStateChanged(kernel, this, old_state);
+ if (m_thread_state.load(std::memory_order_relaxed) != old_state) {
+ KScheduler::OnThreadStateChanged(m_kernel, this, old_state);
}
}
std::shared_ptr<Common::Fiber>& KThread::GetHostContext() {
- return host_context;
+ return m_host_context;
}
void SetCurrentThread(KernelCore& kernel, KThread* thread) {
@@ -1279,26 +1415,39 @@ KThread& GetCurrentThread(KernelCore& kernel) {
return *GetCurrentThreadPointer(kernel);
}
+KProcess* GetCurrentProcessPointer(KernelCore& kernel) {
+ return GetCurrentThread(kernel).GetOwnerProcess();
+}
+
+KProcess& GetCurrentProcess(KernelCore& kernel) {
+ return *GetCurrentProcessPointer(kernel);
+}
+
s32 GetCurrentCoreId(KernelCore& kernel) {
return GetCurrentThread(kernel).GetCurrentCore();
}
+Core::Memory::Memory& GetCurrentMemory(KernelCore& kernel) {
+ // TODO: per-process memory
+ return kernel.System().ApplicationMemory();
+}
+
KScopedDisableDispatch::~KScopedDisableDispatch() {
// If we are shutting down the kernel, none of this is relevant anymore.
- if (kernel.IsShuttingDown()) {
+ if (m_kernel.IsShuttingDown()) {
return;
}
- if (GetCurrentThread(kernel).GetDisableDispatchCount() <= 1) {
- auto* scheduler = kernel.CurrentScheduler();
+ if (GetCurrentThread(m_kernel).GetDisableDispatchCount() <= 1) {
+ auto* scheduler = m_kernel.CurrentScheduler();
- if (scheduler && !kernel.IsPhantomModeForSingleCore()) {
+ if (scheduler && !m_kernel.IsPhantomModeForSingleCore()) {
scheduler->RescheduleCurrentCore();
} else {
- KScheduler::RescheduleCurrentHLEThread(kernel);
+ KScheduler::RescheduleCurrentHLEThread(m_kernel);
}
} else {
- GetCurrentThread(kernel).EnableDispatch();
+ GetCurrentThread(m_kernel).EnableDispatch();
}
}
diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h
index 7cd94a340..dd662b3f8 100644
--- a/src/core/hle/kernel/k_thread.h
+++ b/src/core/hle/kernel/k_thread.h
@@ -12,10 +12,10 @@
#include <utility>
#include <vector>
-#include <boost/intrusive/list.hpp>
+#include "common/intrusive_list.h"
-#include "common/common_types.h"
#include "common/intrusive_red_black_tree.h"
+#include "common/scratch_buffer.h"
#include "common/spin_lock.h"
#include "core/arm/arm_interface.h"
#include "core/hle/kernel/k_affinity_mask.h"
@@ -23,6 +23,7 @@
#include "core/hle/kernel/k_spin_lock.h"
#include "core/hle/kernel/k_synchronization_object.h"
#include "core/hle/kernel/k_timer_task.h"
+#include "core/hle/kernel/k_typed_address.h"
#include "core/hle/kernel/k_worker_task.h"
#include "core/hle/kernel/slab_helpers.h"
#include "core/hle/kernel/svc_common.h"
@@ -34,6 +35,9 @@ class Fiber;
}
namespace Core {
+namespace Memory {
+class Memory;
+}
class ARM_Interface;
class System;
} // namespace Core
@@ -46,7 +50,7 @@ class KProcess;
class KScheduler;
class KThreadQueue;
-using KThreadFunction = VAddr;
+using KThreadFunction = KProcessAddress;
enum class ThreadType : u32 {
Main = 0,
@@ -108,12 +112,15 @@ enum class StepState : u32 {
};
void SetCurrentThread(KernelCore& kernel, KThread* thread);
-[[nodiscard]] KThread* GetCurrentThreadPointer(KernelCore& kernel);
-[[nodiscard]] KThread& GetCurrentThread(KernelCore& kernel);
-[[nodiscard]] s32 GetCurrentCoreId(KernelCore& kernel);
+KThread* GetCurrentThreadPointer(KernelCore& kernel);
+KThread& GetCurrentThread(KernelCore& kernel);
+KProcess* GetCurrentProcessPointer(KernelCore& kernel);
+KProcess& GetCurrentProcess(KernelCore& kernel);
+s32 GetCurrentCoreId(KernelCore& kernel);
+Core::Memory::Memory& GetCurrentMemory(KernelCore& kernel);
class KThread final : public KAutoObjectWithSlabHeapAndContainer<KThread, KWorkerTask>,
- public boost::intrusive::list_base_hook<>,
+ public Common::IntrusiveListBaseNode<KThread>,
public KTimerTask {
KERNEL_AUTOOBJECT_TRAITS(KThread, KSynchronizationObject);
@@ -126,24 +133,20 @@ public:
static constexpr s32 IdleThreadPriority = Svc::LowestThreadPriority + 1;
static constexpr s32 DummyThreadPriority = Svc::LowestThreadPriority + 2;
- explicit KThread(KernelCore& kernel_);
+ explicit KThread(KernelCore& kernel);
~KThread() override;
public:
using ThreadContext32 = Core::ARM_Interface::ThreadContext32;
using ThreadContext64 = Core::ARM_Interface::ThreadContext64;
- using WaiterList = boost::intrusive::list<KThread>;
-
- void SetName(std::string new_name) {
- name = std::move(new_name);
- }
+ using WaiterList = Common::IntrusiveListBaseTraits<KThread>::ListType;
/**
* Gets the thread's current priority
* @return The current thread's priority
*/
- [[nodiscard]] s32 GetPriority() const {
- return priority;
+ s32 GetPriority() const {
+ return m_priority;
}
/**
@@ -151,23 +154,23 @@ public:
* @param priority The new priority.
*/
void SetPriority(s32 value) {
- priority = value;
+ m_priority = value;
}
/**
* Gets the thread's nominal priority.
* @return The current thread's nominal priority.
*/
- [[nodiscard]] s32 GetBasePriority() const {
- return base_priority;
+ s32 GetBasePriority() const {
+ return m_base_priority;
}
/**
* Gets the thread's thread ID
* @return The thread's ID
*/
- [[nodiscard]] u64 GetThreadID() const {
- return thread_id;
+ u64 GetThreadId() const {
+ return m_thread_id;
}
void ContinueIfHasKernelWaiters() {
@@ -178,7 +181,7 @@ public:
void SetBasePriority(s32 value);
- [[nodiscard]] Result Run();
+ Result Run();
void Exit();
@@ -186,22 +189,22 @@ public:
ThreadState RequestTerminate();
- [[nodiscard]] u32 GetSuspendFlags() const {
- return suspend_allowed_flags & suspend_request_flags;
+ u32 GetSuspendFlags() const {
+ return m_suspend_allowed_flags & m_suspend_request_flags;
}
- [[nodiscard]] bool IsSuspended() const {
+ bool IsSuspended() const {
return GetSuspendFlags() != 0;
}
- [[nodiscard]] bool IsSuspendRequested(SuspendType type) const {
- return (suspend_request_flags &
- (1u << (static_cast<u32>(ThreadState::SuspendShift) + static_cast<u32>(type)))) !=
+ bool IsSuspendRequested(SuspendType type) const {
+ return (m_suspend_request_flags &
+ (1U << (static_cast<u32>(ThreadState::SuspendShift) + static_cast<u32>(type)))) !=
0;
}
- [[nodiscard]] bool IsSuspendRequested() const {
- return suspend_request_flags != 0;
+ bool IsSuspendRequested() const {
+ return m_suspend_request_flags != 0;
}
void RequestSuspend(SuspendType type);
@@ -214,202 +217,196 @@ public:
void Continue();
- void WaitUntilSuspended();
-
constexpr void SetSyncedIndex(s32 index) {
- synced_index = index;
+ m_synced_index = index;
}
- [[nodiscard]] constexpr s32 GetSyncedIndex() const {
- return synced_index;
+ constexpr s32 GetSyncedIndex() const {
+ return m_synced_index;
}
constexpr void SetWaitResult(Result wait_res) {
- wait_result = wait_res;
+ m_wait_result = wait_res;
}
- [[nodiscard]] constexpr Result GetWaitResult() const {
- return wait_result;
+ constexpr Result GetWaitResult() const {
+ return m_wait_result;
}
/*
* Returns the Thread Local Storage address of the current thread
- * @returns VAddr of the thread's TLS
+ * @returns Address of the thread's TLS
*/
- [[nodiscard]] VAddr GetTLSAddress() const {
- return tls_address;
+ KProcessAddress GetTlsAddress() const {
+ return m_tls_address;
}
/*
* Returns the value of the TPIDR_EL0 Read/Write system register for this thread.
* @returns The value of the TPIDR_EL0 register.
*/
- [[nodiscard]] u64 GetTPIDR_EL0() const {
- return thread_context_64.tpidr;
+ u64 GetTpidrEl0() const {
+ return m_thread_context_64.tpidr;
}
/// Sets the value of the TPIDR_EL0 Read/Write system register for this thread.
- void SetTPIDR_EL0(u64 value) {
- thread_context_64.tpidr = value;
- thread_context_32.tpidr = static_cast<u32>(value);
+ void SetTpidrEl0(u64 value) {
+ m_thread_context_64.tpidr = value;
+ m_thread_context_32.tpidr = static_cast<u32>(value);
}
- [[nodiscard]] ThreadContext32& GetContext32() {
- return thread_context_32;
+ void CloneFpuStatus();
+
+ ThreadContext32& GetContext32() {
+ return m_thread_context_32;
}
- [[nodiscard]] const ThreadContext32& GetContext32() const {
- return thread_context_32;
+ const ThreadContext32& GetContext32() const {
+ return m_thread_context_32;
}
- [[nodiscard]] ThreadContext64& GetContext64() {
- return thread_context_64;
+ ThreadContext64& GetContext64() {
+ return m_thread_context_64;
}
- [[nodiscard]] const ThreadContext64& GetContext64() const {
- return thread_context_64;
+ const ThreadContext64& GetContext64() const {
+ return m_thread_context_64;
}
- [[nodiscard]] std::shared_ptr<Common::Fiber>& GetHostContext();
+ std::shared_ptr<Common::Fiber>& GetHostContext();
- [[nodiscard]] ThreadState GetState() const {
- return thread_state.load(std::memory_order_relaxed) & ThreadState::Mask;
+ ThreadState GetState() const {
+ return m_thread_state.load(std::memory_order_relaxed) & ThreadState::Mask;
}
- [[nodiscard]] ThreadState GetRawState() const {
- return thread_state.load(std::memory_order_relaxed);
+ ThreadState GetRawState() const {
+ return m_thread_state.load(std::memory_order_relaxed);
}
void SetState(ThreadState state);
- [[nodiscard]] StepState GetStepState() const {
- return step_state;
+ StepState GetStepState() const {
+ return m_step_state;
}
void SetStepState(StepState state) {
- step_state = state;
+ m_step_state = state;
}
- [[nodiscard]] s64 GetLastScheduledTick() const {
- return last_scheduled_tick;
+ s64 GetLastScheduledTick() const {
+ return m_last_scheduled_tick;
}
void SetLastScheduledTick(s64 tick) {
- last_scheduled_tick = tick;
+ m_last_scheduled_tick = tick;
}
- void AddCpuTime([[maybe_unused]] s32 core_id_, s64 amount) {
- cpu_time += amount;
+ void AddCpuTime(s32 core_id, s64 amount) {
+ m_cpu_time += amount;
// TODO(bunnei): Debug kernels track per-core tick counts. Should we?
}
- [[nodiscard]] s64 GetCpuTime() const {
- return cpu_time;
+ s64 GetCpuTime() const {
+ return m_cpu_time;
}
- [[nodiscard]] s32 GetActiveCore() const {
- return core_id;
+ s32 GetActiveCore() const {
+ return m_core_id;
}
void SetActiveCore(s32 core) {
- core_id = core;
+ m_core_id = core;
}
- [[nodiscard]] s32 GetCurrentCore() const {
- return current_core_id;
+ s32 GetCurrentCore() const {
+ return m_current_core_id;
}
void SetCurrentCore(s32 core) {
- current_core_id = core;
+ m_current_core_id = core;
}
- [[nodiscard]] KProcess* GetOwnerProcess() {
- return parent;
+ KProcess* GetOwnerProcess() {
+ return m_parent;
}
- [[nodiscard]] const KProcess* GetOwnerProcess() const {
- return parent;
+ const KProcess* GetOwnerProcess() const {
+ return m_parent;
}
- [[nodiscard]] bool IsUserThread() const {
- return parent != nullptr;
+ bool IsUserThread() const {
+ return m_parent != nullptr;
}
u16 GetUserDisableCount() const;
void SetInterruptFlag();
void ClearInterruptFlag();
- [[nodiscard]] KThread* GetLockOwner() const {
- return lock_owner;
- }
-
- void SetLockOwner(KThread* owner) {
- lock_owner = owner;
- }
+ KThread* GetLockOwner() const;
- [[nodiscard]] const KAffinityMask& GetAffinityMask() const {
- return physical_affinity_mask;
+ const KAffinityMask& GetAffinityMask() const {
+ return m_physical_affinity_mask;
}
- [[nodiscard]] Result GetCoreMask(s32* out_ideal_core, u64* out_affinity_mask);
+ Result GetCoreMask(s32* out_ideal_core, u64* out_affinity_mask);
- [[nodiscard]] Result GetPhysicalCoreMask(s32* out_ideal_core, u64* out_affinity_mask);
+ Result GetPhysicalCoreMask(s32* out_ideal_core, u64* out_affinity_mask);
- [[nodiscard]] Result SetCoreMask(s32 cpu_core_id, u64 v_affinity_mask);
+ Result SetCoreMask(s32 cpu_core_id, u64 v_affinity_mask);
- [[nodiscard]] Result SetActivity(Svc::ThreadActivity activity);
+ Result SetActivity(Svc::ThreadActivity activity);
- [[nodiscard]] Result Sleep(s64 timeout);
+ Result Sleep(s64 timeout);
- [[nodiscard]] s64 GetYieldScheduleCount() const {
- return schedule_count;
+ s64 GetYieldScheduleCount() const {
+ return m_schedule_count;
}
void SetYieldScheduleCount(s64 count) {
- schedule_count = count;
+ m_schedule_count = count;
}
void WaitCancel();
- [[nodiscard]] bool IsWaitCancelled() const {
- return wait_cancelled;
+ bool IsWaitCancelled() const {
+ return m_wait_cancelled;
}
void ClearWaitCancelled() {
- wait_cancelled = false;
+ m_wait_cancelled = false;
}
- [[nodiscard]] bool IsCancellable() const {
- return cancellable;
+ bool IsCancellable() const {
+ return m_cancellable;
}
void SetCancellable() {
- cancellable = true;
+ m_cancellable = true;
}
void ClearCancellable() {
- cancellable = false;
+ m_cancellable = false;
}
- [[nodiscard]] bool IsTerminationRequested() const {
- return termination_requested || GetRawState() == ThreadState::Terminated;
+ bool IsTerminationRequested() const {
+ return m_termination_requested || GetRawState() == ThreadState::Terminated;
}
- [[nodiscard]] u64 GetId() const override {
- return this->GetThreadID();
+ u64 GetId() const override {
+ return this->GetThreadId();
}
- [[nodiscard]] bool IsInitialized() const override {
- return initialized;
+ bool IsInitialized() const override {
+ return m_initialized;
}
- [[nodiscard]] uintptr_t GetPostDestroyArgument() const override {
- return reinterpret_cast<uintptr_t>(parent) | (resource_limit_release_hint ? 1 : 0);
+ uintptr_t GetPostDestroyArgument() const override {
+ return reinterpret_cast<uintptr_t>(m_parent) | (m_resource_limit_release_hint ? 1 : 0);
}
void Finalize() override;
- [[nodiscard]] bool IsSignaled() const override;
+ bool IsSignaled() const override;
void OnTimer();
@@ -417,22 +414,22 @@ public:
static void PostDestroy(uintptr_t arg);
- [[nodiscard]] static Result InitializeDummyThread(KThread* thread, KProcess* owner);
+ static Result InitializeDummyThread(KThread* thread, KProcess* owner);
- [[nodiscard]] static Result InitializeMainThread(Core::System& system, KThread* thread,
- s32 virt_core);
+ static Result InitializeMainThread(Core::System& system, KThread* thread, s32 virt_core);
- [[nodiscard]] static Result InitializeIdleThread(Core::System& system, KThread* thread,
- s32 virt_core);
+ static Result InitializeIdleThread(Core::System& system, KThread* thread, s32 virt_core);
- [[nodiscard]] static Result InitializeHighPriorityThread(Core::System& system, KThread* thread,
- KThreadFunction func, uintptr_t arg,
- s32 virt_core);
+ static Result InitializeHighPriorityThread(Core::System& system, KThread* thread,
+ KThreadFunction func, uintptr_t arg, s32 virt_core);
- [[nodiscard]] static Result InitializeUserThread(Core::System& system, KThread* thread,
- KThreadFunction func, uintptr_t arg,
- VAddr user_stack_top, s32 prio, s32 virt_core,
- KProcess* owner);
+ static Result InitializeUserThread(Core::System& system, KThread* thread, KThreadFunction func,
+ uintptr_t arg, KProcessAddress user_stack_top, s32 prio,
+ s32 virt_core, KProcess* owner);
+
+ static Result InitializeServiceThread(Core::System& system, KThread* thread,
+ std::function<void()>&& thread_func, s32 prio,
+ s32 virt_core, KProcess* owner);
public:
struct StackParameters {
@@ -446,12 +443,12 @@ public:
KThread* cur_thread;
};
- [[nodiscard]] StackParameters& GetStackParameters() {
- return stack_parameters;
+ StackParameters& GetStackParameters() {
+ return m_stack_parameters;
}
- [[nodiscard]] const StackParameters& GetStackParameters() const {
- return stack_parameters;
+ const StackParameters& GetStackParameters() const {
+ return m_stack_parameters;
}
class QueueEntry {
@@ -459,47 +456,47 @@ public:
constexpr QueueEntry() = default;
constexpr void Initialize() {
- prev = nullptr;
- next = nullptr;
+ m_prev = nullptr;
+ m_next = nullptr;
}
constexpr KThread* GetPrev() const {
- return prev;
+ return m_prev;
}
constexpr KThread* GetNext() const {
- return next;
+ return m_next;
}
constexpr void SetPrev(KThread* thread) {
- prev = thread;
+ m_prev = thread;
}
constexpr void SetNext(KThread* thread) {
- next = thread;
+ m_next = thread;
}
private:
- KThread* prev{};
- KThread* next{};
+ KThread* m_prev{};
+ KThread* m_next{};
};
- [[nodiscard]] QueueEntry& GetPriorityQueueEntry(s32 core) {
- return per_core_priority_queue_entry[core];
+ QueueEntry& GetPriorityQueueEntry(s32 core) {
+ return m_per_core_priority_queue_entry[core];
}
- [[nodiscard]] const QueueEntry& GetPriorityQueueEntry(s32 core) const {
- return per_core_priority_queue_entry[core];
+ const QueueEntry& GetPriorityQueueEntry(s32 core) const {
+ return m_per_core_priority_queue_entry[core];
}
- [[nodiscard]] s32 GetDisableDispatchCount() const {
+ s32 GetDisableDispatchCount() const {
return this->GetStackParameters().disable_count;
}
void DisableDispatch() {
- ASSERT(GetCurrentThread(kernel).GetDisableDispatchCount() >= 0);
+ ASSERT(GetCurrentThread(m_kernel).GetDisableDispatchCount() >= 0);
this->GetStackParameters().disable_count++;
}
void EnableDispatch() {
- ASSERT(GetCurrentThread(kernel).GetDisableDispatchCount() > 0);
+ ASSERT(GetCurrentThread(m_kernel).GetDisableDispatchCount() > 0);
this->GetStackParameters().disable_count--;
}
@@ -515,7 +512,7 @@ public:
this->GetStackParameters().is_in_exception_handler = false;
}
- [[nodiscard]] bool IsInExceptionHandler() const {
+ bool IsInExceptionHandler() const {
return this->GetStackParameters().is_in_exception_handler;
}
@@ -527,11 +524,11 @@ public:
this->GetStackParameters().is_calling_svc = false;
}
- [[nodiscard]] bool IsCallingSvc() const {
+ bool IsCallingSvc() const {
return this->GetStackParameters().is_calling_svc;
}
- [[nodiscard]] u8 GetSvcId() const {
+ u8 GetSvcId() const {
return this->GetStackParameters().current_svc_id;
}
@@ -543,102 +540,94 @@ public:
this->GetStackParameters().dpc_flags &= ~static_cast<u8>(flag);
}
- [[nodiscard]] u8 GetDpc() const {
+ u8 GetDpc() const {
return this->GetStackParameters().dpc_flags;
}
- [[nodiscard]] bool HasDpc() const {
+ bool HasDpc() const {
return this->GetDpc() != 0;
}
void SetWaitReasonForDebugging(ThreadWaitReasonForDebugging reason) {
- wait_reason_for_debugging = reason;
+ m_wait_reason_for_debugging = reason;
}
- [[nodiscard]] ThreadWaitReasonForDebugging GetWaitReasonForDebugging() const {
- return wait_reason_for_debugging;
+ ThreadWaitReasonForDebugging GetWaitReasonForDebugging() const {
+ return m_wait_reason_for_debugging;
}
- [[nodiscard]] ThreadType GetThreadType() const {
- return thread_type;
+ ThreadType GetThreadType() const {
+ return m_thread_type;
}
- [[nodiscard]] bool IsDummyThread() const {
- return GetThreadType() == ThreadType::Dummy;
+ bool IsDummyThread() const {
+ return this->GetThreadType() == ThreadType::Dummy;
}
- void SetWaitObjectsForDebugging(const std::span<KSynchronizationObject*>& objects) {
- wait_objects_for_debugging.clear();
- wait_objects_for_debugging.reserve(objects.size());
- for (const auto& object : objects) {
- wait_objects_for_debugging.emplace_back(object);
- }
- }
+ void AddWaiter(KThread* thread);
- [[nodiscard]] const std::vector<KSynchronizationObject*>& GetWaitObjectsForDebugging() const {
- return wait_objects_for_debugging;
- }
+ void RemoveWaiter(KThread* thread);
- void SetMutexWaitAddressForDebugging(VAddr address) {
- mutex_wait_address_for_debugging = address;
- }
+ Result GetThreadContext3(Common::ScratchBuffer<u8>& out);
- [[nodiscard]] VAddr GetMutexWaitAddressForDebugging() const {
- return mutex_wait_address_for_debugging;
+ KThread* RemoveUserWaiterByKey(bool* out_has_waiters, KProcessAddress key) {
+ return this->RemoveWaiterByKey(out_has_waiters, key, false);
}
- [[nodiscard]] s32 GetIdealCoreForDebugging() const {
- return virtual_ideal_core_id;
+ KThread* RemoveKernelWaiterByKey(bool* out_has_waiters, KProcessAddress key) {
+ return this->RemoveWaiterByKey(out_has_waiters, key, true);
}
- void AddWaiter(KThread* thread);
-
- void RemoveWaiter(KThread* thread);
-
- [[nodiscard]] Result GetThreadContext3(std::vector<u8>& out);
-
- [[nodiscard]] KThread* RemoveWaiterByKey(s32* out_num_waiters, VAddr key);
+ KProcessAddress GetAddressKey() const {
+ return m_address_key;
+ }
- [[nodiscard]] VAddr GetAddressKey() const {
- return address_key;
+ u32 GetAddressKeyValue() const {
+ return m_address_key_value;
}
- [[nodiscard]] u32 GetAddressKeyValue() const {
- return address_key_value;
+ bool GetIsKernelAddressKey() const {
+ return m_is_kernel_address_key;
}
- void SetAddressKey(VAddr key) {
- address_key = key;
+ //! NB: intentional deviation from official kernel.
+ //
+ // Separate SetAddressKey into user and kernel versions
+ // to cope with arbitrary host pointers making their way
+ // into things.
+
+ void SetUserAddressKey(KProcessAddress key, u32 val) {
+ ASSERT(m_waiting_lock_info == nullptr);
+ m_address_key = key;
+ m_address_key_value = val;
+ m_is_kernel_address_key = false;
}
- void SetAddressKey(VAddr key, u32 val) {
- address_key = key;
- address_key_value = val;
+ void SetKernelAddressKey(KProcessAddress key) {
+ ASSERT(m_waiting_lock_info == nullptr);
+ m_address_key = key;
+ m_is_kernel_address_key = true;
}
void ClearWaitQueue() {
- wait_queue = nullptr;
+ m_wait_queue = nullptr;
}
void BeginWait(KThreadQueue* queue);
- void NotifyAvailable(KSynchronizationObject* signaled_object, Result wait_result_);
- void EndWait(Result wait_result_);
- void CancelWait(Result wait_result_, bool cancel_timer_task);
+ void NotifyAvailable(KSynchronizationObject* signaled_object, Result wait_result);
+ void EndWait(Result wait_result);
+ void CancelWait(Result wait_result, bool cancel_timer_task);
- [[nodiscard]] bool HasWaiters() const {
- return !waiter_list.empty();
+ s32 GetNumKernelWaiters() const {
+ return m_num_kernel_waiters;
}
- [[nodiscard]] s32 GetNumKernelWaiters() const {
- return num_kernel_waiters;
+ u64 GetConditionVariableKey() const {
+ return m_condvar_key;
}
- [[nodiscard]] u64 GetConditionVariableKey() const {
- return condvar_key;
- }
-
- [[nodiscard]] u64 GetAddressArbiterKey() const {
- return condvar_key;
+ u64 GetAddressArbiterKey() const {
+ return m_condvar_key;
}
// Dummy threads (used for HLE host threads) cannot wait based on the guest scheduler, and
@@ -649,20 +638,23 @@ public:
void DummyThreadBeginWait();
void DummyThreadEndWait();
- [[nodiscard]] uintptr_t GetArgument() const {
- return argument;
+ uintptr_t GetArgument() const {
+ return m_argument;
}
- [[nodiscard]] VAddr GetUserStackTop() const {
- return stack_top;
+ KProcessAddress GetUserStackTop() const {
+ return m_stack_top;
}
private:
+ KThread* RemoveWaiterByKey(bool* out_has_waiters, KProcessAddress key,
+ bool is_kernel_address_key);
+
static constexpr size_t PriorityInheritanceCountMax = 10;
union SyncObjectBuffer {
std::array<KSynchronizationObject*, Svc::ArgumentHandleCountMax> sync_objects{};
std::array<Handle,
- Svc::ArgumentHandleCountMax*(sizeof(KSynchronizationObject*) / sizeof(Handle))>
+ Svc::ArgumentHandleCountMax * (sizeof(KSynchronizationObject*) / sizeof(Handle))>
handles;
constexpr SyncObjectBuffer() {}
};
@@ -673,20 +665,18 @@ private:
u64 cv_key{};
s32 priority{};
- [[nodiscard]] constexpr u64 GetConditionVariableKey() const {
+ constexpr u64 GetConditionVariableKey() const {
return cv_key;
}
- [[nodiscard]] constexpr s32 GetPriority() const {
+ constexpr s32 GetPriority() const {
return priority;
}
};
template <typename T>
- requires(
- std::same_as<T, KThread> ||
- std::same_as<T, RedBlackKeyType>) static constexpr int Compare(const T& lhs,
- const KThread& rhs) {
+ requires(std::same_as<T, KThread> || std::same_as<T, RedBlackKeyType>)
+ static constexpr int Compare(const T& lhs, const KThread& rhs) {
const u64 l_key = lhs.GetConditionVariableKey();
const u64 r_key = rhs.GetConditionVariableKey();
@@ -703,134 +693,262 @@ private:
};
void AddWaiterImpl(KThread* thread);
-
void RemoveWaiterImpl(KThread* thread);
+ static void RestorePriority(KernelCore& kernel, KThread* thread);
void StartTermination();
-
void FinishTermination();
- [[nodiscard]] Result Initialize(KThreadFunction func, uintptr_t arg, VAddr user_stack_top,
- s32 prio, s32 virt_core, KProcess* owner, ThreadType type);
+ void IncreaseBasePriority(s32 priority);
- [[nodiscard]] static Result InitializeThread(KThread* thread, KThreadFunction func,
- uintptr_t arg, VAddr user_stack_top, s32 prio,
- s32 core, KProcess* owner, ThreadType type,
- std::function<void()>&& init_func);
+ Result Initialize(KThreadFunction func, uintptr_t arg, KProcessAddress user_stack_top, s32 prio,
+ s32 virt_core, KProcess* owner, ThreadType type);
- static void RestorePriority(KernelCore& kernel_ctx, KThread* thread);
+ static Result InitializeThread(KThread* thread, KThreadFunction func, uintptr_t arg,
+ KProcessAddress user_stack_top, s32 prio, s32 core,
+ KProcess* owner, ThreadType type,
+ std::function<void()>&& init_func);
// For core KThread implementation
- ThreadContext32 thread_context_32{};
- ThreadContext64 thread_context_64{};
- Common::IntrusiveRedBlackTreeNode condvar_arbiter_tree_node{};
- s32 priority{};
+ ThreadContext32 m_thread_context_32{};
+ ThreadContext64 m_thread_context_64{};
+ Common::IntrusiveRedBlackTreeNode m_condvar_arbiter_tree_node{};
+ s32 m_priority{};
using ConditionVariableThreadTreeTraits =
Common::IntrusiveRedBlackTreeMemberTraitsDeferredAssert<
- &KThread::condvar_arbiter_tree_node>;
+ &KThread::m_condvar_arbiter_tree_node>;
using ConditionVariableThreadTree =
ConditionVariableThreadTreeTraits::TreeType<ConditionVariableComparator>;
- ConditionVariableThreadTree* condvar_tree{};
- u64 condvar_key{};
- u64 virtual_affinity_mask{};
- KAffinityMask physical_affinity_mask{};
- u64 thread_id{};
- std::atomic<s64> cpu_time{};
- VAddr address_key{};
- KProcess* parent{};
- VAddr kernel_stack_top{};
- u32* light_ipc_data{};
- VAddr tls_address{};
- KLightLock activity_pause_lock;
- s64 schedule_count{};
- s64 last_scheduled_tick{};
- std::array<QueueEntry, Core::Hardware::NUM_CPU_CORES> per_core_priority_queue_entry{};
- KThreadQueue* wait_queue{};
- WaiterList waiter_list{};
- WaiterList pinned_waiter_list{};
- KThread* lock_owner{};
- u32 address_key_value{};
- u32 suspend_request_flags{};
- u32 suspend_allowed_flags{};
- s32 synced_index{};
- Result wait_result{ResultSuccess};
- s32 base_priority{};
- s32 physical_ideal_core_id{};
- s32 virtual_ideal_core_id{};
- s32 num_kernel_waiters{};
- s32 current_core_id{};
- s32 core_id{};
- KAffinityMask original_physical_affinity_mask{};
- s32 original_physical_ideal_core_id{};
- s32 num_core_migration_disables{};
- std::atomic<ThreadState> thread_state{};
- std::atomic<bool> termination_requested{};
- bool wait_cancelled{};
- bool cancellable{};
- bool signaled{};
- bool initialized{};
- bool debug_attached{};
- s8 priority_inheritance_count{};
- bool resource_limit_release_hint{};
- StackParameters stack_parameters{};
- Common::SpinLock context_guard{};
+
+private:
+ struct LockWithPriorityInheritanceComparator {
+ struct RedBlackKeyType {
+ s32 m_priority;
+
+ constexpr s32 GetPriority() const {
+ return m_priority;
+ }
+ };
+
+ template <typename T>
+ requires(std::same_as<T, KThread> || std::same_as<T, RedBlackKeyType>)
+ static constexpr int Compare(const T& lhs, const KThread& rhs) {
+ if (lhs.GetPriority() < rhs.GetPriority()) {
+ // Sort by priority.
+ return -1;
+ } else {
+ return 1;
+ }
+ }
+ };
+ static_assert(std::same_as<Common::RedBlackKeyType<LockWithPriorityInheritanceComparator, void>,
+ LockWithPriorityInheritanceComparator::RedBlackKeyType>);
+
+ using LockWithPriorityInheritanceThreadTreeTraits =
+ Common::IntrusiveRedBlackTreeMemberTraitsDeferredAssert<
+ &KThread::m_condvar_arbiter_tree_node>;
+ using LockWithPriorityInheritanceThreadTree =
+ ConditionVariableThreadTreeTraits::TreeType<LockWithPriorityInheritanceComparator>;
+
+public:
+ class LockWithPriorityInheritanceInfo
+ : public KSlabAllocated<LockWithPriorityInheritanceInfo>,
+ public Common::IntrusiveListBaseNode<LockWithPriorityInheritanceInfo> {
+ public:
+ explicit LockWithPriorityInheritanceInfo(KernelCore&) {}
+
+ static LockWithPriorityInheritanceInfo* Create(KernelCore& kernel,
+ KProcessAddress address_key,
+ bool is_kernel_address_key) {
+ // Create a new lock info.
+ auto* new_lock = LockWithPriorityInheritanceInfo::Allocate(kernel);
+ ASSERT(new_lock != nullptr);
+
+ // Set the new lock's address key.
+ new_lock->m_address_key = address_key;
+ new_lock->m_is_kernel_address_key = is_kernel_address_key;
+
+ return new_lock;
+ }
+
+ void SetOwner(KThread* new_owner) {
+ // Set new owner.
+ m_owner = new_owner;
+ }
+
+ void AddWaiter(KThread* waiter) {
+ // Insert the waiter.
+ m_tree.insert(*waiter);
+ m_waiter_count++;
+
+ waiter->SetWaitingLockInfo(this);
+ }
+
+ bool RemoveWaiter(KThread* waiter) {
+ m_tree.erase(m_tree.iterator_to(*waiter));
+
+ waiter->SetWaitingLockInfo(nullptr);
+
+ return (--m_waiter_count) == 0;
+ }
+
+ KThread* GetHighestPriorityWaiter() {
+ return std::addressof(m_tree.front());
+ }
+ const KThread* GetHighestPriorityWaiter() const {
+ return std::addressof(m_tree.front());
+ }
+
+ LockWithPriorityInheritanceThreadTree& GetThreadTree() {
+ return m_tree;
+ }
+ const LockWithPriorityInheritanceThreadTree& GetThreadTree() const {
+ return m_tree;
+ }
+
+ KProcessAddress GetAddressKey() const {
+ return m_address_key;
+ }
+ bool GetIsKernelAddressKey() const {
+ return m_is_kernel_address_key;
+ }
+ KThread* GetOwner() const {
+ return m_owner;
+ }
+ u32 GetWaiterCount() const {
+ return m_waiter_count;
+ }
+
+ private:
+ LockWithPriorityInheritanceThreadTree m_tree{};
+ KProcessAddress m_address_key{};
+ KThread* m_owner{};
+ u32 m_waiter_count{};
+ bool m_is_kernel_address_key{};
+ };
+
+ void SetWaitingLockInfo(LockWithPriorityInheritanceInfo* lock) {
+ m_waiting_lock_info = lock;
+ }
+
+ LockWithPriorityInheritanceInfo* GetWaitingLockInfo() {
+ return m_waiting_lock_info;
+ }
+
+ void AddHeldLock(LockWithPriorityInheritanceInfo* lock_info);
+ LockWithPriorityInheritanceInfo* FindHeldLock(KProcessAddress address_key,
+ bool is_kernel_address_key);
+
+private:
+ using LockWithPriorityInheritanceInfoList =
+ Common::IntrusiveListBaseTraits<LockWithPriorityInheritanceInfo>::ListType;
+
+ ConditionVariableThreadTree* m_condvar_tree{};
+ u64 m_condvar_key{};
+ u64 m_virtual_affinity_mask{};
+ KAffinityMask m_physical_affinity_mask{};
+ u64 m_thread_id{};
+ std::atomic<s64> m_cpu_time{};
+ KProcessAddress m_address_key{};
+ KProcess* m_parent{};
+ KVirtualAddress m_kernel_stack_top{};
+ u32* m_light_ipc_data{};
+ KProcessAddress m_tls_address{};
+ KLightLock m_activity_pause_lock;
+ s64 m_schedule_count{};
+ s64 m_last_scheduled_tick{};
+ std::array<QueueEntry, Core::Hardware::NUM_CPU_CORES> m_per_core_priority_queue_entry{};
+ KThreadQueue* m_wait_queue{};
+ LockWithPriorityInheritanceInfoList m_held_lock_info_list{};
+ LockWithPriorityInheritanceInfo* m_waiting_lock_info{};
+ WaiterList m_pinned_waiter_list{};
+ u32 m_address_key_value{};
+ u32 m_suspend_request_flags{};
+ u32 m_suspend_allowed_flags{};
+ s32 m_synced_index{};
+ Result m_wait_result{ResultSuccess};
+ s32 m_base_priority{};
+ s32 m_physical_ideal_core_id{};
+ s32 m_virtual_ideal_core_id{};
+ s32 m_num_kernel_waiters{};
+ s32 m_current_core_id{};
+ s32 m_core_id{};
+ KAffinityMask m_original_physical_affinity_mask{};
+ s32 m_original_physical_ideal_core_id{};
+ s32 m_num_core_migration_disables{};
+ std::atomic<ThreadState> m_thread_state{};
+ std::atomic<bool> m_termination_requested{};
+ bool m_wait_cancelled{};
+ bool m_cancellable{};
+ bool m_signaled{};
+ bool m_initialized{};
+ bool m_debug_attached{};
+ s8 m_priority_inheritance_count{};
+ bool m_resource_limit_release_hint{};
+ bool m_is_kernel_address_key{};
+ StackParameters m_stack_parameters{};
+ Common::SpinLock m_context_guard{};
// For emulation
- std::shared_ptr<Common::Fiber> host_context{};
- bool is_single_core{};
- ThreadType thread_type{};
- StepState step_state{};
- std::atomic<bool> dummy_thread_runnable{true};
+ std::shared_ptr<Common::Fiber> m_host_context{};
+ ThreadType m_thread_type{};
+ StepState m_step_state{};
+ bool m_dummy_thread_runnable{true};
+ std::mutex m_dummy_thread_mutex{};
+ std::condition_variable m_dummy_thread_cv{};
// For debugging
- std::vector<KSynchronizationObject*> wait_objects_for_debugging;
- VAddr mutex_wait_address_for_debugging{};
- ThreadWaitReasonForDebugging wait_reason_for_debugging{};
- uintptr_t argument{};
- VAddr stack_top{};
+ std::vector<KSynchronizationObject*> m_wait_objects_for_debugging{};
+ KProcessAddress m_mutex_wait_address_for_debugging{};
+ ThreadWaitReasonForDebugging m_wait_reason_for_debugging{};
+ uintptr_t m_argument{};
+ KProcessAddress m_stack_top{};
public:
using ConditionVariableThreadTreeType = ConditionVariableThreadTree;
- void SetConditionVariable(ConditionVariableThreadTree* tree, VAddr address, u64 cv_key,
- u32 value) {
- condvar_tree = tree;
- condvar_key = cv_key;
- address_key = address;
- address_key_value = value;
+ void SetConditionVariable(ConditionVariableThreadTree* tree, KProcessAddress address,
+ u64 cv_key, u32 value) {
+ ASSERT(m_waiting_lock_info == nullptr);
+ m_condvar_tree = tree;
+ m_condvar_key = cv_key;
+ m_address_key = address;
+ m_address_key_value = value;
+ m_is_kernel_address_key = false;
}
void ClearConditionVariable() {
- condvar_tree = nullptr;
+ m_condvar_tree = nullptr;
}
- [[nodiscard]] bool IsWaitingForConditionVariable() const {
- return condvar_tree != nullptr;
+ bool IsWaitingForConditionVariable() const {
+ return m_condvar_tree != nullptr;
}
void SetAddressArbiter(ConditionVariableThreadTree* tree, u64 address) {
- condvar_tree = tree;
- condvar_key = address;
+ ASSERT(m_waiting_lock_info == nullptr);
+ m_condvar_tree = tree;
+ m_condvar_key = address;
}
void ClearAddressArbiter() {
- condvar_tree = nullptr;
+ m_condvar_tree = nullptr;
}
- [[nodiscard]] bool IsWaitingForAddressArbiter() const {
- return condvar_tree != nullptr;
+ bool IsWaitingForAddressArbiter() const {
+ return m_condvar_tree != nullptr;
}
- [[nodiscard]] ConditionVariableThreadTree* GetConditionVariableTree() const {
- return condvar_tree;
+ ConditionVariableThreadTree* GetConditionVariableTree() const {
+ return m_condvar_tree;
}
};
class KScopedDisableDispatch {
public:
- [[nodiscard]] explicit KScopedDisableDispatch(KernelCore& kernel_) : kernel{kernel_} {
+ explicit KScopedDisableDispatch(KernelCore& kernel) : m_kernel{kernel} {
// If we are shutting down the kernel, none of this is relevant anymore.
- if (kernel.IsShuttingDown()) {
+ if (m_kernel.IsShuttingDown()) {
return;
}
GetCurrentThread(kernel).DisableDispatch();
@@ -839,7 +957,7 @@ public:
~KScopedDisableDispatch();
private:
- KernelCore& kernel;
+ KernelCore& m_kernel;
};
inline void KTimerTask::OnTimer() {
diff --git a/src/core/hle/kernel/k_thread_local_page.cpp b/src/core/hle/kernel/k_thread_local_page.cpp
index 563560114..b4a1e3cdb 100644
--- a/src/core/hle/kernel/k_thread_local_page.cpp
+++ b/src/core/hle/kernel/k_thread_local_page.cpp
@@ -16,7 +16,7 @@ namespace Kernel {
Result KThreadLocalPage::Initialize(KernelCore& kernel, KProcess* process) {
// Set that this process owns us.
m_owner = process;
- m_kernel = &kernel;
+ m_kernel = std::addressof(kernel);
// Allocate a new page.
KPageBuffer* page_buf = KPageBuffer::Allocate(kernel);
@@ -37,7 +37,7 @@ Result KThreadLocalPage::Initialize(KernelCore& kernel, KProcess* process) {
Result KThreadLocalPage::Finalize() {
// Get the physical address of the page.
- const PAddr phys_addr = m_owner->PageTable().GetPhysicalAddr(m_virt_addr);
+ const KPhysicalAddress phys_addr = m_owner->PageTable().GetPhysicalAddr(m_virt_addr);
ASSERT(phys_addr);
// Unmap the page.
@@ -49,7 +49,7 @@ Result KThreadLocalPage::Finalize() {
return ResultSuccess;
}
-VAddr KThreadLocalPage::Reserve() {
+KProcessAddress KThreadLocalPage::Reserve() {
for (size_t i = 0; i < m_is_region_free.size(); i++) {
if (m_is_region_free[i]) {
m_is_region_free[i] = false;
@@ -60,7 +60,7 @@ VAddr KThreadLocalPage::Reserve() {
return 0;
}
-void KThreadLocalPage::Release(VAddr addr) {
+void KThreadLocalPage::Release(KProcessAddress addr) {
m_is_region_free[this->GetRegionIndex(addr)] = true;
}
diff --git a/src/core/hle/kernel/k_thread_local_page.h b/src/core/hle/kernel/k_thread_local_page.h
index fe0cff084..813f32a7e 100644
--- a/src/core/hle/kernel/k_thread_local_page.h
+++ b/src/core/hle/kernel/k_thread_local_page.h
@@ -27,19 +27,20 @@ public:
static_assert(RegionsPerPage > 0);
public:
- constexpr explicit KThreadLocalPage(KernelCore&, VAddr addr = {}) : m_virt_addr(addr) {
+ constexpr explicit KThreadLocalPage(KernelCore&, KProcessAddress addr = {})
+ : m_virt_addr(addr) {
m_is_region_free.fill(true);
}
- constexpr VAddr GetAddress() const {
+ constexpr KProcessAddress GetAddress() const {
return m_virt_addr;
}
Result Initialize(KernelCore& kernel, KProcess* process);
Result Finalize();
- VAddr Reserve();
- void Release(VAddr addr);
+ KProcessAddress Reserve();
+ void Release(KProcessAddress addr);
bool IsAllUsed() const {
return std::ranges::all_of(m_is_region_free.begin(), m_is_region_free.end(),
@@ -60,7 +61,7 @@ public:
}
public:
- using RedBlackKeyType = VAddr;
+ using RedBlackKeyType = KProcessAddress;
static constexpr RedBlackKeyType GetRedBlackKey(const RedBlackKeyType& v) {
return v;
@@ -70,12 +71,10 @@ public:
}
template <typename T>
- requires(std::same_as<T, KThreadLocalPage> ||
- std::same_as<T, RedBlackKeyType>) static constexpr int Compare(const T& lhs,
- const KThreadLocalPage&
- rhs) {
- const VAddr lval = GetRedBlackKey(lhs);
- const VAddr rval = GetRedBlackKey(rhs);
+ requires(std::same_as<T, KThreadLocalPage> || std::same_as<T, RedBlackKeyType>)
+ static constexpr int Compare(const T& lhs, const KThreadLocalPage& rhs) {
+ const KProcessAddress lval = GetRedBlackKey(lhs);
+ const KProcessAddress rval = GetRedBlackKey(rhs);
if (lval < rval) {
return -1;
@@ -87,22 +86,22 @@ public:
}
private:
- constexpr VAddr GetRegionAddress(size_t i) const {
+ constexpr KProcessAddress GetRegionAddress(size_t i) const {
return this->GetAddress() + i * Svc::ThreadLocalRegionSize;
}
- constexpr bool Contains(VAddr addr) const {
+ constexpr bool Contains(KProcessAddress addr) const {
return this->GetAddress() <= addr && addr < this->GetAddress() + PageSize;
}
- constexpr size_t GetRegionIndex(VAddr addr) const {
- ASSERT(Common::IsAligned(addr, Svc::ThreadLocalRegionSize));
+ constexpr size_t GetRegionIndex(KProcessAddress addr) const {
+ ASSERT(Common::IsAligned(GetInteger(addr), Svc::ThreadLocalRegionSize));
ASSERT(this->Contains(addr));
return (addr - this->GetAddress()) / Svc::ThreadLocalRegionSize;
}
private:
- VAddr m_virt_addr{};
+ KProcessAddress m_virt_addr{};
KProcess* m_owner{};
KernelCore* m_kernel{};
std::array<bool, RegionsPerPage> m_is_region_free{};
diff --git a/src/core/hle/kernel/k_thread_queue.cpp b/src/core/hle/kernel/k_thread_queue.cpp
index 5f1dc97eb..61488f4ce 100644
--- a/src/core/hle/kernel/k_thread_queue.cpp
+++ b/src/core/hle/kernel/k_thread_queue.cpp
@@ -7,9 +7,10 @@
namespace Kernel {
-void KThreadQueue::NotifyAvailable([[maybe_unused]] KThread* waiting_thread,
- [[maybe_unused]] KSynchronizationObject* signaled_object,
- [[maybe_unused]] Result wait_result) {}
+void KThreadQueue::NotifyAvailable(KThread* waiting_thread, KSynchronizationObject* signaled_object,
+ Result wait_result) {
+ UNREACHABLE();
+}
void KThreadQueue::EndWait(KThread* waiting_thread, Result wait_result) {
// Set the thread's wait result.
@@ -22,7 +23,9 @@ void KThreadQueue::EndWait(KThread* waiting_thread, Result wait_result) {
waiting_thread->ClearWaitQueue();
// Cancel the thread task.
- kernel.HardwareTimer().CancelTask(waiting_thread);
+ if (m_hardware_timer != nullptr) {
+ m_hardware_timer->CancelTask(waiting_thread);
+ }
}
void KThreadQueue::CancelWait(KThread* waiting_thread, Result wait_result, bool cancel_timer_task) {
@@ -36,12 +39,13 @@ void KThreadQueue::CancelWait(KThread* waiting_thread, Result wait_result, bool
waiting_thread->ClearWaitQueue();
// Cancel the thread task.
- if (cancel_timer_task) {
- kernel.HardwareTimer().CancelTask(waiting_thread);
+ if (cancel_timer_task && m_hardware_timer != nullptr) {
+ m_hardware_timer->CancelTask(waiting_thread);
}
}
-void KThreadQueueWithoutEndWait::EndWait([[maybe_unused]] KThread* waiting_thread,
- [[maybe_unused]] Result wait_result) {}
+void KThreadQueueWithoutEndWait::EndWait(KThread* waiting_thread, Result wait_result) {
+ UNREACHABLE();
+}
} // namespace Kernel
diff --git a/src/core/hle/kernel/k_thread_queue.h b/src/core/hle/kernel/k_thread_queue.h
index 8d76ece81..117af0919 100644
--- a/src/core/hle/kernel/k_thread_queue.h
+++ b/src/core/hle/kernel/k_thread_queue.h
@@ -8,24 +8,30 @@
namespace Kernel {
+class KHardwareTimer;
+
class KThreadQueue {
public:
- explicit KThreadQueue(KernelCore& kernel_) : kernel{kernel_} {}
+ explicit KThreadQueue(KernelCore& kernel) : m_kernel{kernel}, m_hardware_timer{} {}
virtual ~KThreadQueue() = default;
+ void SetHardwareTimer(KHardwareTimer* timer) {
+ m_hardware_timer = timer;
+ }
+
virtual void NotifyAvailable(KThread* waiting_thread, KSynchronizationObject* signaled_object,
Result wait_result);
virtual void EndWait(KThread* waiting_thread, Result wait_result);
virtual void CancelWait(KThread* waiting_thread, Result wait_result, bool cancel_timer_task);
private:
- KernelCore& kernel;
- KThread::WaiterList wait_list{};
+ KernelCore& m_kernel;
+ KHardwareTimer* m_hardware_timer{};
};
class KThreadQueueWithoutEndWait : public KThreadQueue {
public:
- explicit KThreadQueueWithoutEndWait(KernelCore& kernel_) : KThreadQueue(kernel_) {}
+ explicit KThreadQueueWithoutEndWait(KernelCore& kernel) : KThreadQueue(kernel) {}
void EndWait(KThread* waiting_thread, Result wait_result) override final;
};
diff --git a/src/core/hle/kernel/k_transfer_memory.cpp b/src/core/hle/kernel/k_transfer_memory.cpp
index 9f34c2d46..13d34125c 100644
--- a/src/core/hle/kernel/k_transfer_memory.cpp
+++ b/src/core/hle/kernel/k_transfer_memory.cpp
@@ -8,32 +8,29 @@
namespace Kernel {
-KTransferMemory::KTransferMemory(KernelCore& kernel_)
- : KAutoObjectWithSlabHeapAndContainer{kernel_} {}
+KTransferMemory::KTransferMemory(KernelCore& kernel)
+ : KAutoObjectWithSlabHeapAndContainer{kernel} {}
KTransferMemory::~KTransferMemory() = default;
-Result KTransferMemory::Initialize(VAddr address_, std::size_t size_,
- Svc::MemoryPermission owner_perm_) {
+Result KTransferMemory::Initialize(KProcessAddress address, std::size_t size,
+ Svc::MemoryPermission owner_perm) {
// Set members.
- owner = kernel.CurrentProcess();
+ m_owner = GetCurrentProcessPointer(m_kernel);
// TODO(bunnei): Lock for transfer memory
// Set remaining tracking members.
- owner->Open();
- owner_perm = owner_perm_;
- address = address_;
- size = size_;
- is_initialized = true;
+ m_owner->Open();
+ m_owner_perm = owner_perm;
+ m_address = address;
+ m_size = size;
+ m_is_initialized = true;
- return ResultSuccess;
+ R_SUCCEED();
}
-void KTransferMemory::Finalize() {
- // Perform inherited finalization.
- KAutoObjectWithSlabHeapAndContainer<KTransferMemory, KAutoObjectWithList>::Finalize();
-}
+void KTransferMemory::Finalize() {}
void KTransferMemory::PostDestroy(uintptr_t arg) {
KProcess* owner = reinterpret_cast<KProcess*>(arg);
diff --git a/src/core/hle/kernel/k_transfer_memory.h b/src/core/hle/kernel/k_transfer_memory.h
index 85d508ee7..54f97ccb4 100644
--- a/src/core/hle/kernel/k_transfer_memory.h
+++ b/src/core/hle/kernel/k_transfer_memory.h
@@ -23,41 +23,41 @@ class KTransferMemory final
KERNEL_AUTOOBJECT_TRAITS(KTransferMemory, KAutoObject);
public:
- explicit KTransferMemory(KernelCore& kernel_);
+ explicit KTransferMemory(KernelCore& kernel);
~KTransferMemory() override;
- Result Initialize(VAddr address_, std::size_t size_, Svc::MemoryPermission owner_perm_);
+ Result Initialize(KProcessAddress address, std::size_t size, Svc::MemoryPermission owner_perm);
void Finalize() override;
bool IsInitialized() const override {
- return is_initialized;
+ return m_is_initialized;
}
uintptr_t GetPostDestroyArgument() const override {
- return reinterpret_cast<uintptr_t>(owner);
+ return reinterpret_cast<uintptr_t>(m_owner);
}
static void PostDestroy(uintptr_t arg);
KProcess* GetOwner() const override {
- return owner;
+ return m_owner;
}
- VAddr GetSourceAddress() const {
- return address;
+ KProcessAddress GetSourceAddress() const {
+ return m_address;
}
size_t GetSize() const {
- return is_initialized ? size : 0;
+ return m_is_initialized ? m_size : 0;
}
private:
- KProcess* owner{};
- VAddr address{};
- Svc::MemoryPermission owner_perm{};
- size_t size{};
- bool is_initialized{};
+ KProcess* m_owner{};
+ KProcessAddress m_address{};
+ Svc::MemoryPermission m_owner_perm{};
+ size_t m_size{};
+ bool m_is_initialized{};
};
} // namespace Kernel
diff --git a/src/core/hle/kernel/k_typed_address.h b/src/core/hle/kernel/k_typed_address.h
new file mode 100644
index 000000000..d57535ba0
--- /dev/null
+++ b/src/core/hle/kernel/k_typed_address.h
@@ -0,0 +1,12 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "common/typed_address.h"
+
+namespace Kernel {
+
+using KPhysicalAddress = Common::PhysicalAddress;
+using KVirtualAddress = Common::VirtualAddress;
+using KProcessAddress = Common::ProcessAddress;
+
+} // namespace Kernel
diff --git a/src/core/hle/kernel/k_worker_task.h b/src/core/hle/kernel/k_worker_task.h
index ef591d831..9a230c03c 100644
--- a/src/core/hle/kernel/k_worker_task.h
+++ b/src/core/hle/kernel/k_worker_task.h
@@ -9,7 +9,7 @@ namespace Kernel {
class KWorkerTask : public KSynchronizationObject {
public:
- explicit KWorkerTask(KernelCore& kernel_);
+ explicit KWorkerTask(KernelCore& kernel);
void DoWorkerTask();
};
diff --git a/src/core/hle/kernel/k_worker_task_manager.cpp b/src/core/hle/kernel/k_worker_task_manager.cpp
index 04042bf8f..8ead39591 100644
--- a/src/core/hle/kernel/k_worker_task_manager.cpp
+++ b/src/core/hle/kernel/k_worker_task_manager.cpp
@@ -10,7 +10,7 @@
namespace Kernel {
-KWorkerTask::KWorkerTask(KernelCore& kernel_) : KSynchronizationObject{kernel_} {}
+KWorkerTask::KWorkerTask(KernelCore& kernel) : KSynchronizationObject{kernel} {}
void KWorkerTask::DoWorkerTask() {
if (auto* const thread = this->DynamicCast<KThread*>(); thread != nullptr) {
diff --git a/src/core/hle/kernel/k_worker_task_manager.h b/src/core/hle/kernel/k_worker_task_manager.h
index f6618883e..8745a4ce2 100644
--- a/src/core/hle/kernel/k_worker_task_manager.h
+++ b/src/core/hle/kernel/k_worker_task_manager.h
@@ -20,7 +20,7 @@ public:
KWorkerTaskManager();
- static void AddTask(KernelCore& kernel_, WorkerType type, KWorkerTask* task);
+ static void AddTask(KernelCore& kernel, WorkerType type, KWorkerTask* task);
private:
void AddTask(KernelCore& kernel, KWorkerTask* task);
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 1fb25f221..f33600ca5 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -29,18 +29,20 @@
#include "core/hle/kernel/k_hardware_timer.h"
#include "core/hle/kernel/k_memory_layout.h"
#include "core/hle/kernel/k_memory_manager.h"
+#include "core/hle/kernel/k_object_name.h"
#include "core/hle/kernel/k_page_buffer.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_system_resource.h"
#include "core/hle/kernel/k_thread.h"
#include "core/hle/kernel/k_worker_task_manager.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/physical_core.h"
-#include "core/hle/kernel/service_thread.h"
#include "core/hle/result.h"
+#include "core/hle/service/server_manager.h"
#include "core/hle/service/sm/sm.h"
#include "core/memory.h"
@@ -54,9 +56,7 @@ struct KernelCore::Impl {
static constexpr size_t BlockInfoSlabHeapSize = 4000;
static constexpr size_t ReservedDynamicPageCount = 64;
- explicit Impl(Core::System& system_, KernelCore& kernel_)
- : service_threads_manager{1, "ServiceThreadsManager"},
- service_thread_barrier{2}, system{system_} {}
+ explicit Impl(Core::System& system_, KernelCore& kernel_) : system{system_} {}
void SetMulticore(bool is_multi) {
is_multicore = is_multi;
@@ -84,6 +84,7 @@ struct KernelCore::Impl {
InitializeShutdownThreads();
InitializePhysicalCores();
InitializePreemption(kernel);
+ InitializeGlobalData(kernel);
// Initialize the Dynamic Slab Heaps.
{
@@ -94,21 +95,19 @@ struct KernelCore::Impl {
pt_heap_region.GetSize());
}
- InitializeHackSharedMemory();
+ InitializeHackSharedMemory(kernel);
RegisterHostThread(nullptr);
-
- default_service_thread = &CreateServiceThread(kernel, "DefaultServiceThread");
}
void InitializeCores() {
for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) {
- cores[core_id]->Initialize((*current_process).Is64BitProcess());
- system.Memory().SetCurrentPageTable(*current_process, core_id);
+ cores[core_id]->Initialize((*application_process).Is64BitProcess());
+ system.ApplicationMemory().SetCurrentPageTable(*application_process, core_id);
}
}
- void CloseCurrentProcess() {
- KProcess* old_process = current_process.exchange(nullptr);
+ void CloseApplicationProcess() {
+ KProcess* old_process = application_process.exchange(nullptr);
if (old_process == nullptr) {
return;
}
@@ -138,11 +137,6 @@ struct KernelCore::Impl {
preemption_event = nullptr;
- for (auto& iter : named_ports) {
- iter.second->Close();
- }
- named_ports.clear();
-
exclusive_monitor.reset();
// Cleanup persistent kernel objects
@@ -182,7 +176,7 @@ struct KernelCore::Impl {
}
}
- CloseCurrentProcess();
+ CloseApplicationProcess();
// Track kernel objects that were not freed on shutdown
{
@@ -194,6 +188,8 @@ struct KernelCore::Impl {
}
}
+ object_name_global_data.reset();
+
// Ensure that the object list container is finalized and properly shutdown.
global_object_list_container->Finalize();
global_object_list_container.reset();
@@ -203,13 +199,14 @@ struct KernelCore::Impl {
}
void CloseServices() {
- // Ensures all service threads gracefully shutdown.
- ClearServiceThreads();
+ // Ensures all servers gracefully shutdown.
+ std::scoped_lock lk{server_lock};
+ server_managers.clear();
}
void InitializePhysicalCores() {
exclusive_monitor =
- Core::MakeExclusiveMonitor(system.Memory(), Core::Hardware::NUM_CPU_CORES);
+ Core::MakeExclusiveMonitor(system.ApplicationMemory(), Core::Hardware::NUM_CPU_CORES);
for (u32 i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
const s32 core{static_cast<s32>(i)};
@@ -217,13 +214,14 @@ struct KernelCore::Impl {
cores[i] = std::make_unique<Kernel::PhysicalCore>(i, system, *schedulers[i]);
auto* main_thread{Kernel::KThread::Create(system.Kernel())};
- main_thread->SetName(fmt::format("MainThread:{}", core));
main_thread->SetCurrentCore(core);
ASSERT(Kernel::KThread::InitializeMainThread(system, main_thread, core).IsSuccess());
+ KThread::Register(system.Kernel(), main_thread);
auto* idle_thread{Kernel::KThread::Create(system.Kernel())};
idle_thread->SetCurrentCore(core);
ASSERT(Kernel::KThread::InitializeIdleThread(system, idle_thread, core).IsSuccess());
+ KThread::Register(system.Kernel(), idle_thread);
schedulers[i]->Initialize(main_thread, idle_thread, core);
}
@@ -234,6 +232,7 @@ struct KernelCore::Impl {
const Core::Timing::CoreTiming& core_timing) {
system_resource_limit = KResourceLimit::Create(system.Kernel());
system_resource_limit->Initialize(&core_timing);
+ KResourceLimit::Register(kernel, system_resource_limit);
const auto sizes{memory_layout->GetTotalAndKernelMemorySizes()};
const auto total_size{sizes.first};
@@ -275,9 +274,9 @@ struct KernelCore::Impl {
system.CoreTiming().ScheduleLoopingEvent(time_interval, time_interval, preemption_event);
}
- void InitializeResourceManagers(KernelCore& kernel, VAddr address, size_t size) {
+ void InitializeResourceManagers(KernelCore& kernel, KVirtualAddress address, size_t size) {
// Ensure that the buffer is suitable for our use.
- ASSERT(Common::IsAligned(address, PageSize));
+ ASSERT(Common::IsAligned(GetInteger(address), PageSize));
ASSERT(Common::IsAligned(size, PageSize));
// Ensure that we have space for our reference counts.
@@ -359,55 +358,52 @@ struct KernelCore::Impl {
ASSERT(KThread::InitializeHighPriorityThread(system, shutdown_threads[core_id], {}, {},
core_id)
.IsSuccess());
- shutdown_threads[core_id]->SetName(fmt::format("SuspendThread:{}", core_id));
+ KThread::Register(system.Kernel(), shutdown_threads[core_id]);
}
}
- void MakeCurrentProcess(KProcess* process) {
- current_process = process;
+ void InitializeGlobalData(KernelCore& kernel) {
+ object_name_global_data = std::make_unique<KObjectNameGlobalData>(kernel);
}
- static inline thread_local u32 host_thread_id = UINT32_MAX;
+ void MakeApplicationProcess(KProcess* process) {
+ application_process = process;
+ }
- /// Gets the host thread ID for the caller, allocating a new one if this is the first time
- u32 GetHostThreadId(std::size_t core_id) {
- if (host_thread_id == UINT32_MAX) {
- // The first four slots are reserved for CPU core threads
- ASSERT(core_id < Core::Hardware::NUM_CPU_CORES);
- host_thread_id = static_cast<u32>(core_id);
- }
+ static inline thread_local u8 host_thread_id = UINT8_MAX;
+
+ /// Sets the host thread ID for the caller.
+ u32 SetHostThreadId(std::size_t core_id) {
+ // This should only be called during core init.
+ ASSERT(host_thread_id == UINT8_MAX);
+
+ // The first four slots are reserved for CPU core threads
+ ASSERT(core_id < Core::Hardware::NUM_CPU_CORES);
+ host_thread_id = static_cast<u8>(core_id);
return host_thread_id;
}
- /// Gets the host thread ID for the caller, allocating a new one if this is the first time
- u32 GetHostThreadId() {
- if (host_thread_id == UINT32_MAX) {
- host_thread_id = next_host_thread_id++;
- }
+ /// Gets the host thread ID for the caller
+ u32 GetHostThreadId() const {
return host_thread_id;
}
// Gets the dummy KThread for the caller, allocating a new one if this is the first time
KThread* GetHostDummyThread(KThread* existing_thread) {
- auto initialize = [this](KThread* thread) {
+ const auto initialize{[](KThread* thread) {
ASSERT(KThread::InitializeDummyThread(thread, nullptr).IsSuccess());
- thread->SetName(fmt::format("DummyThread:{}", GetHostThreadId()));
return thread;
- };
+ }};
thread_local KThread raw_thread{system.Kernel()};
- thread_local KThread* thread = nullptr;
- if (thread == nullptr) {
- thread = (existing_thread == nullptr) ? initialize(&raw_thread) : existing_thread;
- }
-
+ thread_local KThread* thread = existing_thread ? existing_thread : initialize(&raw_thread);
return thread;
}
/// Registers a CPU core thread by allocating a host thread ID for it
void RegisterCoreThread(std::size_t core_id) {
ASSERT(core_id < Core::Hardware::NUM_CPU_CORES);
- const auto this_id = GetHostThreadId(core_id);
+ const auto this_id = SetHostThreadId(core_id);
if (!is_multicore) {
single_core_thread_id = this_id;
}
@@ -415,7 +411,6 @@ struct KernelCore::Impl {
/// Registers a new host thread by allocating a host thread ID for it
void RegisterHostThread(KThread* existing_thread) {
- [[maybe_unused]] const auto this_id = GetHostThreadId();
[[maybe_unused]] const auto dummy_thread = GetHostDummyThread(existing_thread);
}
@@ -445,11 +440,9 @@ struct KernelCore::Impl {
static inline thread_local KThread* current_thread{nullptr};
KThread* GetCurrentEmuThread() {
- const auto thread_id = GetCurrentHostThreadID();
- if (thread_id >= Core::Hardware::NUM_CPU_CORES) {
- return GetHostDummyThread(nullptr);
+ if (!current_thread) {
+ current_thread = GetHostDummyThread(nullptr);
}
-
return current_thread;
}
@@ -473,29 +466,30 @@ struct KernelCore::Impl {
KernelPhysicalAddressSpaceBase + KernelPhysicalAddressSpaceSize - 1);
// Save start and end for ease of use.
- const VAddr code_start_virt_addr = KernelVirtualAddressCodeBase;
- const VAddr code_end_virt_addr = KernelVirtualAddressCodeEnd;
+ constexpr KVirtualAddress code_start_virt_addr = KernelVirtualAddressCodeBase;
+ constexpr KVirtualAddress code_end_virt_addr = KernelVirtualAddressCodeEnd;
// Setup the containing kernel region.
constexpr size_t KernelRegionSize = 1_GiB;
constexpr size_t KernelRegionAlign = 1_GiB;
- constexpr VAddr kernel_region_start =
- Common::AlignDown(code_start_virt_addr, KernelRegionAlign);
+ constexpr KVirtualAddress kernel_region_start =
+ Common::AlignDown(GetInteger(code_start_virt_addr), KernelRegionAlign);
size_t kernel_region_size = KernelRegionSize;
if (!(kernel_region_start + KernelRegionSize - 1 <= KernelVirtualAddressSpaceLast)) {
- kernel_region_size = KernelVirtualAddressSpaceEnd - kernel_region_start;
+ kernel_region_size = KernelVirtualAddressSpaceEnd - GetInteger(kernel_region_start);
}
ASSERT(memory_layout->GetVirtualMemoryRegionTree().Insert(
- kernel_region_start, kernel_region_size, KMemoryRegionType_Kernel));
+ GetInteger(kernel_region_start), kernel_region_size, KMemoryRegionType_Kernel));
// Setup the code region.
constexpr size_t CodeRegionAlign = PageSize;
- constexpr VAddr code_region_start =
- Common::AlignDown(code_start_virt_addr, CodeRegionAlign);
- constexpr VAddr code_region_end = Common::AlignUp(code_end_virt_addr, CodeRegionAlign);
+ constexpr KVirtualAddress code_region_start =
+ Common::AlignDown(GetInteger(code_start_virt_addr), CodeRegionAlign);
+ constexpr KVirtualAddress code_region_end =
+ Common::AlignUp(GetInteger(code_end_virt_addr), CodeRegionAlign);
constexpr size_t code_region_size = code_region_end - code_region_start;
ASSERT(memory_layout->GetVirtualMemoryRegionTree().Insert(
- code_region_start, code_region_size, KMemoryRegionType_KernelCode));
+ GetInteger(code_region_start), code_region_size, KMemoryRegionType_KernelCode));
// Setup board-specific device physical regions.
Init::SetupDevicePhysicalMemoryRegions(*memory_layout);
@@ -531,11 +525,11 @@ struct KernelCore::Impl {
ASSERT(misc_region_size > 0);
// Setup the misc region.
- const VAddr misc_region_start =
+ const KVirtualAddress misc_region_start =
memory_layout->GetVirtualMemoryRegionTree().GetRandomAlignedRegion(
misc_region_size, MiscRegionAlign, KMemoryRegionType_Kernel);
ASSERT(memory_layout->GetVirtualMemoryRegionTree().Insert(
- misc_region_start, misc_region_size, KMemoryRegionType_KernelMisc));
+ GetInteger(misc_region_start), misc_region_size, KMemoryRegionType_KernelMisc));
// Determine if we'll use extra thread resources.
const bool use_extra_resources = KSystemControl::Init::ShouldIncreaseThreadResourceLimit();
@@ -543,11 +537,11 @@ struct KernelCore::Impl {
// Setup the stack region.
constexpr size_t StackRegionSize = 14_MiB;
constexpr size_t StackRegionAlign = KernelAslrAlignment;
- const VAddr stack_region_start =
+ const KVirtualAddress stack_region_start =
memory_layout->GetVirtualMemoryRegionTree().GetRandomAlignedRegion(
StackRegionSize, StackRegionAlign, KMemoryRegionType_Kernel);
ASSERT(memory_layout->GetVirtualMemoryRegionTree().Insert(
- stack_region_start, StackRegionSize, KMemoryRegionType_KernelStack));
+ GetInteger(stack_region_start), StackRegionSize, KMemoryRegionType_KernelStack));
// Determine the size of the resource region.
const size_t resource_region_size =
@@ -559,29 +553,29 @@ struct KernelCore::Impl {
ASSERT(slab_region_size <= resource_region_size);
// Setup the slab region.
- const PAddr code_start_phys_addr = KernelPhysicalAddressCodeBase;
- const PAddr code_end_phys_addr = code_start_phys_addr + code_region_size;
- const PAddr slab_start_phys_addr = code_end_phys_addr;
- const PAddr slab_end_phys_addr = slab_start_phys_addr + slab_region_size;
+ const KPhysicalAddress code_start_phys_addr = KernelPhysicalAddressCodeBase;
+ const KPhysicalAddress code_end_phys_addr = code_start_phys_addr + code_region_size;
+ const KPhysicalAddress slab_start_phys_addr = code_end_phys_addr;
+ const KPhysicalAddress slab_end_phys_addr = slab_start_phys_addr + slab_region_size;
constexpr size_t SlabRegionAlign = KernelAslrAlignment;
const size_t slab_region_needed_size =
- Common::AlignUp(code_end_phys_addr + slab_region_size, SlabRegionAlign) -
- Common::AlignDown(code_end_phys_addr, SlabRegionAlign);
- const VAddr slab_region_start =
+ Common::AlignUp(GetInteger(code_end_phys_addr) + slab_region_size, SlabRegionAlign) -
+ Common::AlignDown(GetInteger(code_end_phys_addr), SlabRegionAlign);
+ const KVirtualAddress slab_region_start =
memory_layout->GetVirtualMemoryRegionTree().GetRandomAlignedRegion(
slab_region_needed_size, SlabRegionAlign, KMemoryRegionType_Kernel) +
- (code_end_phys_addr % SlabRegionAlign);
+ (GetInteger(code_end_phys_addr) % SlabRegionAlign);
ASSERT(memory_layout->GetVirtualMemoryRegionTree().Insert(
- slab_region_start, slab_region_size, KMemoryRegionType_KernelSlab));
+ GetInteger(slab_region_start), slab_region_size, KMemoryRegionType_KernelSlab));
// Setup the temp region.
constexpr size_t TempRegionSize = 128_MiB;
constexpr size_t TempRegionAlign = KernelAslrAlignment;
- const VAddr temp_region_start =
+ const KVirtualAddress temp_region_start =
memory_layout->GetVirtualMemoryRegionTree().GetRandomAlignedRegion(
TempRegionSize, TempRegionAlign, KMemoryRegionType_Kernel);
- ASSERT(memory_layout->GetVirtualMemoryRegionTree().Insert(temp_region_start, TempRegionSize,
- KMemoryRegionType_KernelTemp));
+ ASSERT(memory_layout->GetVirtualMemoryRegionTree().Insert(
+ GetInteger(temp_region_start), TempRegionSize, KMemoryRegionType_KernelTemp));
// Automatically map in devices that have auto-map attributes.
for (auto& region : memory_layout->GetPhysicalMemoryRegionTree()) {
@@ -607,35 +601,37 @@ struct KernelCore::Impl {
region.SetTypeAttribute(KMemoryRegionAttr_DidKernelMap);
// Create a virtual pair region and insert it into the tree.
- const PAddr map_phys_addr = Common::AlignDown(region.GetAddress(), PageSize);
+ const KPhysicalAddress map_phys_addr = Common::AlignDown(region.GetAddress(), PageSize);
const size_t map_size =
- Common::AlignUp(region.GetEndAddress(), PageSize) - map_phys_addr;
- const VAddr map_virt_addr =
+ Common::AlignUp(region.GetEndAddress(), PageSize) - GetInteger(map_phys_addr);
+ const KVirtualAddress map_virt_addr =
memory_layout->GetVirtualMemoryRegionTree().GetRandomAlignedRegionWithGuard(
map_size, PageSize, KMemoryRegionType_KernelMisc, PageSize);
ASSERT(memory_layout->GetVirtualMemoryRegionTree().Insert(
- map_virt_addr, map_size, KMemoryRegionType_KernelMiscMappedDevice));
- region.SetPairAddress(map_virt_addr + region.GetAddress() - map_phys_addr);
+ GetInteger(map_virt_addr), map_size, KMemoryRegionType_KernelMiscMappedDevice));
+ region.SetPairAddress(GetInteger(map_virt_addr) + region.GetAddress() -
+ GetInteger(map_phys_addr));
}
Init::SetupDramPhysicalMemoryRegions(*memory_layout);
// Insert a physical region for the kernel code region.
ASSERT(memory_layout->GetPhysicalMemoryRegionTree().Insert(
- code_start_phys_addr, code_region_size, KMemoryRegionType_DramKernelCode));
+ GetInteger(code_start_phys_addr), code_region_size, KMemoryRegionType_DramKernelCode));
// Insert a physical region for the kernel slab region.
ASSERT(memory_layout->GetPhysicalMemoryRegionTree().Insert(
- slab_start_phys_addr, slab_region_size, KMemoryRegionType_DramKernelSlab));
+ GetInteger(slab_start_phys_addr), slab_region_size, KMemoryRegionType_DramKernelSlab));
// Determine size available for kernel page table heaps, requiring > 8 MB.
- const PAddr resource_end_phys_addr = slab_start_phys_addr + resource_region_size;
+ const KPhysicalAddress resource_end_phys_addr = slab_start_phys_addr + resource_region_size;
const size_t page_table_heap_size = resource_end_phys_addr - slab_end_phys_addr;
ASSERT(page_table_heap_size / 4_MiB > 2);
// Insert a physical region for the kernel page table heap region
ASSERT(memory_layout->GetPhysicalMemoryRegionTree().Insert(
- slab_end_phys_addr, page_table_heap_size, KMemoryRegionType_DramKernelPtHeap));
+ GetInteger(slab_end_phys_addr), page_table_heap_size,
+ KMemoryRegionType_DramKernelPtHeap));
// All DRAM regions that we haven't tagged by this point will be mapped under the linear
// mapping. Tag them.
@@ -657,20 +653,21 @@ struct KernelCore::Impl {
// Setup the linear mapping region.
constexpr size_t LinearRegionAlign = 1_GiB;
- const PAddr aligned_linear_phys_start =
+ const KPhysicalAddress aligned_linear_phys_start =
Common::AlignDown(linear_extents.GetAddress(), LinearRegionAlign);
const size_t linear_region_size =
Common::AlignUp(linear_extents.GetEndAddress(), LinearRegionAlign) -
- aligned_linear_phys_start;
- const VAddr linear_region_start =
+ GetInteger(aligned_linear_phys_start);
+ const KVirtualAddress linear_region_start =
memory_layout->GetVirtualMemoryRegionTree().GetRandomAlignedRegionWithGuard(
linear_region_size, LinearRegionAlign, KMemoryRegionType_None, LinearRegionAlign);
- const u64 linear_region_phys_to_virt_diff = linear_region_start - aligned_linear_phys_start;
+ const u64 linear_region_phys_to_virt_diff =
+ GetInteger(linear_region_start) - GetInteger(aligned_linear_phys_start);
// Map and create regions for all the linearly-mapped data.
{
- PAddr cur_phys_addr = 0;
+ KPhysicalAddress cur_phys_addr = 0;
u64 cur_size = 0;
for (auto& region : memory_layout->GetPhysicalMemoryRegionTree()) {
if (!region.HasTypeAttribute(KMemoryRegionAttr_LinearMapped)) {
@@ -689,15 +686,16 @@ struct KernelCore::Impl {
cur_size = region.GetSize();
}
- const VAddr region_virt_addr =
+ const KVirtualAddress region_virt_addr =
region.GetAddress() + linear_region_phys_to_virt_diff;
ASSERT(memory_layout->GetVirtualMemoryRegionTree().Insert(
- region_virt_addr, region.GetSize(),
+ GetInteger(region_virt_addr), region.GetSize(),
GetTypeForVirtualLinearMapping(region.GetType())));
- region.SetPairAddress(region_virt_addr);
+ region.SetPairAddress(GetInteger(region_virt_addr));
KMemoryRegion* virt_region =
- memory_layout->GetVirtualMemoryRegionTree().FindModifiable(region_virt_addr);
+ memory_layout->GetVirtualMemoryRegionTree().FindModifiable(
+ GetInteger(region_virt_addr));
ASSERT(virt_region != nullptr);
virt_region->SetPairAddress(region.GetAddress());
}
@@ -705,10 +703,11 @@ struct KernelCore::Impl {
// Insert regions for the initial page table region.
ASSERT(memory_layout->GetPhysicalMemoryRegionTree().Insert(
- resource_end_phys_addr, KernelPageTableHeapSize, KMemoryRegionType_DramKernelInitPt));
+ GetInteger(resource_end_phys_addr), KernelPageTableHeapSize,
+ KMemoryRegionType_DramKernelInitPt));
ASSERT(memory_layout->GetVirtualMemoryRegionTree().Insert(
- resource_end_phys_addr + linear_region_phys_to_virt_diff, KernelPageTableHeapSize,
- KMemoryRegionType_VirtualDramKernelInitPt));
+ GetInteger(resource_end_phys_addr) + linear_region_phys_to_virt_diff,
+ KernelPageTableHeapSize, KMemoryRegionType_VirtualDramKernelInitPt));
// All linear-mapped DRAM regions that we haven't tagged by this point will be allocated to
// some pool partition. Tag them.
@@ -734,7 +733,7 @@ struct KernelCore::Impl {
memory_manager->Initialize(management_region.GetAddress(), management_region.GetSize());
}
- void InitializeHackSharedMemory() {
+ void InitializeHackSharedMemory(KernelCore& kernel) {
// Setup memory regions for emulated processes
// TODO(bunnei): These should not be hardcoded regions initialized within the kernel
constexpr std::size_t hid_size{0x40000};
@@ -750,65 +749,24 @@ struct KernelCore::Impl {
hidbus_shared_mem = KSharedMemory::Create(system.Kernel());
hid_shared_mem->Initialize(system.DeviceMemory(), nullptr, Svc::MemoryPermission::None,
- Svc::MemoryPermission::Read, hid_size, "HID:SharedMemory");
- font_shared_mem->Initialize(system.DeviceMemory(), nullptr, Svc::MemoryPermission::None,
- Svc::MemoryPermission::Read, font_size, "Font:SharedMemory");
- irs_shared_mem->Initialize(system.DeviceMemory(), nullptr, Svc::MemoryPermission::None,
- Svc::MemoryPermission::Read, irs_size, "IRS:SharedMemory");
- time_shared_mem->Initialize(system.DeviceMemory(), nullptr, Svc::MemoryPermission::None,
- Svc::MemoryPermission::Read, time_size, "Time:SharedMemory");
- hidbus_shared_mem->Initialize(system.DeviceMemory(), nullptr, Svc::MemoryPermission::None,
- Svc::MemoryPermission::Read, hidbus_size,
- "HidBus:SharedMemory");
- }
-
- KClientPort* CreateNamedServicePort(std::string name) {
- auto search = service_interface_factory.find(name);
- if (search == service_interface_factory.end()) {
- UNIMPLEMENTED();
- return {};
- }
-
- return &search->second(system.ServiceManager(), system);
- }
-
- void RegisterNamedServiceHandler(std::string name, KServerPort* server_port) {
- auto search = service_interface_handlers.find(name);
- if (search == service_interface_handlers.end()) {
- return;
- }
-
- search->second(system.ServiceManager(), server_port);
- }
+ Svc::MemoryPermission::Read, hid_size);
+ KSharedMemory::Register(kernel, hid_shared_mem);
- Kernel::ServiceThread& CreateServiceThread(KernelCore& kernel, const std::string& name) {
- auto* ptr = new ServiceThread(kernel, name);
-
- service_threads_manager.QueueWork(
- [this, ptr]() { service_threads.emplace(ptr, std::unique_ptr<ServiceThread>(ptr)); });
-
- return *ptr;
- }
-
- void ReleaseServiceThread(Kernel::ServiceThread& service_thread) {
- auto* ptr = &service_thread;
+ font_shared_mem->Initialize(system.DeviceMemory(), nullptr, Svc::MemoryPermission::None,
+ Svc::MemoryPermission::Read, font_size);
+ KSharedMemory::Register(kernel, font_shared_mem);
- if (ptr == default_service_thread) {
- // Nothing to do here, the service is using default_service_thread, which will be
- // released on shutdown.
- return;
- }
+ irs_shared_mem->Initialize(system.DeviceMemory(), nullptr, Svc::MemoryPermission::None,
+ Svc::MemoryPermission::Read, irs_size);
+ KSharedMemory::Register(kernel, irs_shared_mem);
- service_threads_manager.QueueWork([this, ptr]() { service_threads.erase(ptr); });
- }
+ time_shared_mem->Initialize(system.DeviceMemory(), nullptr, Svc::MemoryPermission::None,
+ Svc::MemoryPermission::Read, time_size);
+ KSharedMemory::Register(kernel, time_shared_mem);
- void ClearServiceThreads() {
- service_threads_manager.QueueWork([this] {
- service_threads.clear();
- default_service_thread = nullptr;
- service_thread_barrier.Sync();
- });
- service_thread_barrier.Sync();
+ hidbus_shared_mem->Initialize(system.DeviceMemory(), nullptr, Svc::MemoryPermission::None,
+ Svc::MemoryPermission::Read, hidbus_size);
+ KSharedMemory::Register(kernel, hidbus_shared_mem);
}
std::mutex registered_objects_lock;
@@ -821,7 +779,7 @@ struct KernelCore::Impl {
// Lists all processes that exist in the current session.
std::vector<KProcess*> process_list;
- std::atomic<KProcess*> current_process{};
+ std::atomic<KProcess*> application_process{};
std::unique_ptr<Kernel::GlobalSchedulerContext> global_scheduler_context;
std::unique_ptr<Kernel::KHardwareTimer> hardware_timer;
@@ -838,14 +796,14 @@ struct KernelCore::Impl {
std::unique_ptr<KAutoObjectWithListContainer> global_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;
- std::unordered_map<std::string, ServiceInterfaceHandlerFn> service_interface_handlers;
- NamedPortTable named_ports;
+ std::unique_ptr<KObjectNameGlobalData> object_name_global_data;
+
std::unordered_set<KAutoObject*> registered_objects;
std::unordered_set<KAutoObject*> registered_in_use_objects;
+ std::mutex server_lock;
+ std::vector<std::unique_ptr<Service::ServerManager>> server_managers;
+
std::unique_ptr<Core::ExclusiveMonitor> exclusive_monitor;
std::array<std::unique_ptr<Kernel::PhysicalCore>, Core::Hardware::NUM_CPU_CORES> cores;
@@ -880,12 +838,6 @@ struct KernelCore::Impl {
// Memory layout
std::unique_ptr<KMemoryLayout> memory_layout;
- // Threads used for services
- std::unordered_map<ServiceThread*, std::unique_ptr<ServiceThread>> service_threads;
- ServiceThread* default_service_thread{};
- Common::ThreadWorker service_threads_manager;
- Common::Barrier service_thread_barrier;
-
std::array<KThread*, Core::Hardware::NUM_CPU_CORES> shutdown_threads{};
std::array<std::unique_ptr<Kernel::KScheduler>, Core::Hardware::NUM_CPU_CORES> schedulers{};
@@ -941,20 +893,20 @@ void KernelCore::AppendNewProcess(KProcess* process) {
impl->process_list.push_back(process);
}
-void KernelCore::MakeCurrentProcess(KProcess* process) {
- impl->MakeCurrentProcess(process);
+void KernelCore::MakeApplicationProcess(KProcess* process) {
+ impl->MakeApplicationProcess(process);
}
-KProcess* KernelCore::CurrentProcess() {
- return impl->current_process;
+KProcess* KernelCore::ApplicationProcess() {
+ return impl->application_process;
}
-const KProcess* KernelCore::CurrentProcess() const {
- return impl->current_process;
+const KProcess* KernelCore::ApplicationProcess() const {
+ return impl->application_process;
}
-void KernelCore::CloseCurrentProcess() {
- impl->CloseCurrentProcess();
+void KernelCore::CloseApplicationProcess() {
+ impl->CloseApplicationProcess();
}
const std::vector<KProcess*>& KernelCore::GetProcessList() const {
@@ -1002,7 +954,7 @@ const Kernel::PhysicalCore& KernelCore::CurrentPhysicalCore() const {
}
Kernel::KScheduler* KernelCore::CurrentScheduler() {
- u32 core_id = impl->GetCurrentHostThreadID();
+ const u32 core_id = impl->GetCurrentHostThreadID();
if (core_id >= Core::Hardware::NUM_CPU_CORES) {
// This is expected when called from not a guest thread
return {};
@@ -1036,12 +988,12 @@ void KernelCore::InvalidateAllInstructionCaches() {
}
}
-void KernelCore::InvalidateCpuInstructionCacheRange(VAddr addr, std::size_t size) {
+void KernelCore::InvalidateCpuInstructionCacheRange(KProcessAddress addr, std::size_t size) {
for (auto& physical_core : impl->cores) {
if (!physical_core->IsInitialized()) {
continue;
}
- physical_core->ArmInterface().InvalidateCacheRange(addr, size);
+ physical_core->ArmInterface().InvalidateCacheRange(GetInteger(addr), size);
}
}
@@ -1049,23 +1001,6 @@ void KernelCore::PrepareReschedule(std::size_t id) {
// TODO: Reimplement, this
}
-void KernelCore::RegisterNamedService(std::string name, ServiceInterfaceFactory&& factory) {
- impl->service_interface_factory.emplace(std::move(name), factory);
-}
-
-void KernelCore::RegisterInterfaceForNamedService(std::string name,
- ServiceInterfaceHandlerFn&& handler) {
- impl->service_interface_handlers.emplace(std::move(name), handler);
-}
-
-KClientPort* KernelCore::CreateNamedServicePort(std::string name) {
- return impl->CreateNamedServicePort(std::move(name));
-}
-
-void KernelCore::RegisterNamedServiceHandler(std::string name, KServerPort* server_port) {
- impl->RegisterNamedServiceHandler(std::move(name), server_port);
-}
-
void KernelCore::RegisterKernelObject(KAutoObject* object) {
std::scoped_lock lk{impl->registered_objects_lock};
impl->registered_objects.insert(object);
@@ -1086,8 +1021,19 @@ void KernelCore::UnregisterInUseObject(KAutoObject* object) {
impl->registered_in_use_objects.erase(object);
}
-bool KernelCore::IsValidNamedPort(NamedPortTable::const_iterator port) const {
- return port != impl->named_ports.cend();
+void KernelCore::RunServer(std::unique_ptr<Service::ServerManager>&& server_manager) {
+ auto* manager = server_manager.get();
+
+ {
+ std::scoped_lock lk{impl->server_lock};
+ if (impl->is_shutting_down) {
+ return;
+ }
+
+ impl->server_managers.emplace_back(std::move(server_manager));
+ }
+
+ manager->LoopProcess();
}
u32 KernelCore::CreateNewObjectID() {
@@ -1126,6 +1072,99 @@ void KernelCore::RegisterHostThread(KThread* existing_thread) {
}
}
+static std::jthread RunHostThreadFunc(KernelCore& kernel, KProcess* process,
+ std::string&& thread_name, std::function<void()>&& func) {
+ // Reserve a new thread from the process resource limit.
+ KScopedResourceReservation thread_reservation(process, LimitableResource::ThreadCountMax);
+ ASSERT(thread_reservation.Succeeded());
+
+ // Initialize the thread.
+ KThread* thread = KThread::Create(kernel);
+ ASSERT(R_SUCCEEDED(KThread::InitializeDummyThread(thread, process)));
+
+ // Commit the thread reservation.
+ thread_reservation.Commit();
+
+ // Register the thread.
+ KThread::Register(kernel, thread);
+
+ return std::jthread(
+ [&kernel, thread, thread_name{std::move(thread_name)}, func{std::move(func)}] {
+ // Set the thread name.
+ Common::SetCurrentThreadName(thread_name.c_str());
+
+ // Set the thread as current.
+ kernel.RegisterHostThread(thread);
+
+ // Run the callback.
+ func();
+
+ // Close the thread.
+ // This will free the process if it is the last reference.
+ thread->Close();
+ });
+}
+
+std::jthread KernelCore::RunOnHostCoreProcess(std::string&& process_name,
+ std::function<void()> func) {
+ // Make a new process.
+ KProcess* process = KProcess::Create(*this);
+ ASSERT(R_SUCCEEDED(KProcess::Initialize(process, System(), "", KProcess::ProcessType::Userland,
+ GetSystemResourceLimit())));
+
+ // Ensure that we don't hold onto any extra references.
+ SCOPE_EXIT({ process->Close(); });
+
+ // Register the new process.
+ KProcess::Register(*this, process);
+
+ // Run the host thread.
+ return RunHostThreadFunc(*this, process, std::move(process_name), std::move(func));
+}
+
+std::jthread KernelCore::RunOnHostCoreThread(std::string&& thread_name,
+ std::function<void()> func) {
+ // Get the current process.
+ KProcess* process = GetCurrentProcessPointer(*this);
+
+ // Run the host thread.
+ return RunHostThreadFunc(*this, process, std::move(thread_name), std::move(func));
+}
+
+void KernelCore::RunOnGuestCoreProcess(std::string&& process_name, std::function<void()> func) {
+ constexpr s32 ServiceThreadPriority = 16;
+ constexpr s32 ServiceThreadCore = 3;
+
+ // Make a new process.
+ KProcess* process = KProcess::Create(*this);
+ ASSERT(R_SUCCEEDED(KProcess::Initialize(process, System(), "", KProcess::ProcessType::Userland,
+ GetSystemResourceLimit())));
+
+ // Ensure that we don't hold onto any extra references.
+ SCOPE_EXIT({ process->Close(); });
+
+ // Register the new process.
+ KProcess::Register(*this, process);
+
+ // Reserve a new thread from the process resource limit.
+ KScopedResourceReservation thread_reservation(process, LimitableResource::ThreadCountMax);
+ ASSERT(thread_reservation.Succeeded());
+
+ // Initialize the thread.
+ KThread* thread = KThread::Create(*this);
+ ASSERT(R_SUCCEEDED(KThread::InitializeServiceThread(
+ System(), thread, std::move(func), ServiceThreadPriority, ServiceThreadCore, process)));
+
+ // Commit the thread reservation.
+ thread_reservation.Commit();
+
+ // Register the new thread.
+ KThread::Register(*this, thread);
+
+ // Begin running the thread.
+ ASSERT(R_SUCCEEDED(thread->Run()));
+}
+
u32 KernelCore::GetCurrentHostThreadID() const {
return impl->GetCurrentHostThreadID();
}
@@ -1138,6 +1177,10 @@ void KernelCore::SetCurrentEmuThread(KThread* thread) {
impl->SetCurrentEmuThread(thread);
}
+KObjectNameGlobalData& KernelCore::ObjectNameGlobalData() {
+ return *impl->object_name_global_data;
+}
+
KMemoryManager& KernelCore::MemoryManager() {
return *impl->memory_manager;
}
@@ -1146,6 +1189,14 @@ const KMemoryManager& KernelCore::MemoryManager() const {
return *impl->memory_manager;
}
+KSystemResource& KernelCore::GetAppSystemResource() {
+ return *impl->app_system_resource;
+}
+
+const KSystemResource& KernelCore::GetAppSystemResource() const {
+ return *impl->app_system_resource;
+}
+
KSystemResource& KernelCore::GetSystemSystemResource() {
return *impl->sys_system_resource;
}
@@ -1194,32 +1245,39 @@ const Kernel::KSharedMemory& KernelCore::GetHidBusSharedMem() const {
return *impl->hidbus_shared_mem;
}
-void KernelCore::Suspend(bool suspended) {
+void KernelCore::SuspendApplication(bool suspended) {
const bool should_suspend{exception_exited || suspended};
const auto activity = should_suspend ? ProcessActivity::Paused : ProcessActivity::Runnable;
- std::vector<KScopedAutoObject<KThread>> process_threads;
- {
- KScopedSchedulerLock sl{*this};
+ // Get the application process.
+ KScopedAutoObject<KProcess> process = ApplicationProcess();
+ if (process.IsNull()) {
+ return;
+ }
- if (auto* process = CurrentProcess(); process != nullptr) {
- process->SetActivity(activity);
+ // Set the new activity.
+ process->SetActivity(activity);
- if (!should_suspend) {
- // Runnable now; no need to wait.
- return;
- }
+ // Wait for process execution to stop.
+ bool must_wait{should_suspend};
+
+ // KernelCore::SuspendApplication must be called from locked context,
+ // or we could race another call to SetActivity, interfering with waiting.
+ while (must_wait) {
+ KScopedSchedulerLock sl{*this};
+
+ // Assume that all threads have finished running.
+ must_wait = false;
- for (auto* thread : process->GetThreadList()) {
- process_threads.emplace_back(thread);
+ for (auto i = 0; i < static_cast<s32>(Core::Hardware::NUM_CPU_CORES); ++i) {
+ if (Scheduler(i).GetSchedulerCurrentThread()->GetOwnerProcess() ==
+ process.GetPointerUnsafe()) {
+ // A thread has not finished running yet.
+ // Continue waiting.
+ must_wait = true;
}
}
}
-
- // Wait for execution to stop.
- for (auto& thread : process_threads) {
- thread->WaitUntilSuspended();
- }
}
void KernelCore::ShutdownCores() {
@@ -1238,9 +1296,9 @@ bool KernelCore::IsShuttingDown() const {
return impl->IsShuttingDown();
}
-void KernelCore::ExceptionalExit() {
+void KernelCore::ExceptionalExitApplication() {
exception_exited = true;
- Suspend(true);
+ SuspendApplication(true);
}
void KernelCore::EnterSVCProfile() {
@@ -1251,18 +1309,6 @@ void KernelCore::ExitSVCProfile() {
MicroProfileLeave(MICROPROFILE_TOKEN(Kernel_SVC), impl->svc_ticks[CurrentPhysicalCoreIndex()]);
}
-Kernel::ServiceThread& KernelCore::CreateServiceThread(const std::string& name) {
- return impl->CreateServiceThread(*this, name);
-}
-
-Kernel::ServiceThread& KernelCore::GetDefaultServiceThread() const {
- return *impl->default_service_thread;
-}
-
-void KernelCore::ReleaseServiceThread(Kernel::ServiceThread& service_thread) {
- impl->ReleaseServiceThread(service_thread);
-}
-
Init::KSlabResourceCounts& KernelCore::SlabResourceCounts() {
return impl->slab_resource_counts;
}
@@ -1299,4 +1345,93 @@ const Core::System& KernelCore::System() const {
return impl->system;
}
+struct KernelCore::SlabHeapContainer {
+ KSlabHeap<KClientSession> client_session;
+ KSlabHeap<KEvent> event;
+ KSlabHeap<KPort> port;
+ KSlabHeap<KProcess> process;
+ KSlabHeap<KResourceLimit> resource_limit;
+ KSlabHeap<KSession> session;
+ KSlabHeap<KSharedMemory> shared_memory;
+ KSlabHeap<KSharedMemoryInfo> shared_memory_info;
+ KSlabHeap<KThread> thread;
+ KSlabHeap<KTransferMemory> transfer_memory;
+ KSlabHeap<KCodeMemory> code_memory;
+ KSlabHeap<KDeviceAddressSpace> device_address_space;
+ KSlabHeap<KPageBuffer> page_buffer;
+ KSlabHeap<KThreadLocalPage> thread_local_page;
+ KSlabHeap<KObjectName> object_name;
+ KSlabHeap<KSessionRequest> session_request;
+ KSlabHeap<KSecureSystemResource> secure_system_resource;
+ KSlabHeap<KThread::LockWithPriorityInheritanceInfo> lock_info;
+ KSlabHeap<KEventInfo> event_info;
+ KSlabHeap<KDebug> debug;
+};
+
+template <typename T>
+KSlabHeap<T>& KernelCore::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, 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, KSharedMemoryInfo>) {
+ return slab_heap_container->shared_memory_info;
+ } 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, KCodeMemory>) {
+ return slab_heap_container->code_memory;
+ } else if constexpr (std::is_same_v<T, KDeviceAddressSpace>) {
+ return slab_heap_container->device_address_space;
+ } else if constexpr (std::is_same_v<T, KPageBuffer>) {
+ return slab_heap_container->page_buffer;
+ } else if constexpr (std::is_same_v<T, KThreadLocalPage>) {
+ return slab_heap_container->thread_local_page;
+ } else if constexpr (std::is_same_v<T, KObjectName>) {
+ return slab_heap_container->object_name;
+ } else if constexpr (std::is_same_v<T, KSessionRequest>) {
+ return slab_heap_container->session_request;
+ } else if constexpr (std::is_same_v<T, KSecureSystemResource>) {
+ return slab_heap_container->secure_system_resource;
+ } else if constexpr (std::is_same_v<T, KThread::LockWithPriorityInheritanceInfo>) {
+ return slab_heap_container->lock_info;
+ } else if constexpr (std::is_same_v<T, KEventInfo>) {
+ return slab_heap_container->event_info;
+ } else if constexpr (std::is_same_v<T, KDebug>) {
+ return slab_heap_container->debug;
+ }
+}
+
+template KSlabHeap<KClientSession>& KernelCore::SlabHeap();
+template KSlabHeap<KEvent>& KernelCore::SlabHeap();
+template KSlabHeap<KPort>& KernelCore::SlabHeap();
+template KSlabHeap<KProcess>& KernelCore::SlabHeap();
+template KSlabHeap<KResourceLimit>& KernelCore::SlabHeap();
+template KSlabHeap<KSession>& KernelCore::SlabHeap();
+template KSlabHeap<KSharedMemory>& KernelCore::SlabHeap();
+template KSlabHeap<KSharedMemoryInfo>& KernelCore::SlabHeap();
+template KSlabHeap<KThread>& KernelCore::SlabHeap();
+template KSlabHeap<KTransferMemory>& KernelCore::SlabHeap();
+template KSlabHeap<KCodeMemory>& KernelCore::SlabHeap();
+template KSlabHeap<KDeviceAddressSpace>& KernelCore::SlabHeap();
+template KSlabHeap<KPageBuffer>& KernelCore::SlabHeap();
+template KSlabHeap<KThreadLocalPage>& KernelCore::SlabHeap();
+template KSlabHeap<KObjectName>& KernelCore::SlabHeap();
+template KSlabHeap<KSessionRequest>& KernelCore::SlabHeap();
+template KSlabHeap<KSecureSystemResource>& KernelCore::SlabHeap();
+template KSlabHeap<KThread::LockWithPriorityInheritanceInfo>& KernelCore::SlabHeap();
+template KSlabHeap<KEventInfo>& KernelCore::SlabHeap();
+template KSlabHeap<KDebug>& KernelCore::SlabHeap();
+
} // namespace Kernel
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 8d22f8d2c..d5b08eeb5 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -9,9 +9,12 @@
#include <string>
#include <unordered_map>
#include <vector>
+
+#include "common/polyfill_thread.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/k_typed_address.h"
#include "core/hle/kernel/svc_common.h"
namespace Core {
@@ -24,6 +27,10 @@ class CoreTiming;
struct EventType;
} // namespace Core::Timing
+namespace Service {
+class ServerManager;
+}
+
namespace Service::SM {
class ServiceManager;
}
@@ -35,14 +42,16 @@ class GlobalSchedulerContext;
class KAutoObjectWithListContainer;
class KClientSession;
class KDebug;
+class KDeviceAddressSpace;
class KDynamicPageManager;
class KEvent;
class KEventInfo;
class KHandleTable;
class KHardwareTimer;
-class KLinkedListNode;
class KMemoryLayout;
class KMemoryManager;
+class KObjectName;
+class KObjectNameGlobalData;
class KPageBuffer;
class KPageBufferSlabHeap;
class KPort;
@@ -62,13 +71,6 @@ class KTransferMemory;
class KWorkerTaskManager;
class KCodeMemory;
class PhysicalCore;
-class ServiceThread;
-class Synchronization;
-
-using ServiceInterfaceFactory =
- std::function<KClientPort&(Service::SM::ServiceManager&, Core::System&)>;
-
-using ServiceInterfaceHandlerFn = std::function<void(Service::SM::ServiceManager&, KServerPort*)>;
namespace Init {
struct KSlabResourceCounts;
@@ -77,15 +79,8 @@ struct KSlabResourceCounts;
template <typename T>
class KSlabHeap;
-using EmuThreadHandle = uintptr_t;
-constexpr EmuThreadHandle EmuThreadHandleInvalid{};
-constexpr EmuThreadHandle EmuThreadHandleReserved{1ULL << 63};
-
/// Represents a single instance of the kernel.
class KernelCore {
-private:
- using NamedPortTable = std::unordered_map<std::string, KClientPort*>;
-
public:
/// Constructs an instance of the kernel using the given System
/// instance as a context for any necessary system-related state,
@@ -130,17 +125,17 @@ public:
/// Adds the given shared pointer to an internal list of active processes.
void AppendNewProcess(KProcess* process);
- /// Makes the given process the new current process.
- void MakeCurrentProcess(KProcess* process);
+ /// Makes the given process the new application process.
+ void MakeApplicationProcess(KProcess* process);
- /// Retrieves a pointer to the current process.
- KProcess* CurrentProcess();
+ /// Retrieves a pointer to the application process.
+ KProcess* ApplicationProcess();
- /// Retrieves a const pointer to the current process.
- const KProcess* CurrentProcess() const;
+ /// Retrieves a const pointer to the application process.
+ const KProcess* ApplicationProcess() const;
- /// Closes the current process.
- void CloseCurrentProcess();
+ /// Closes the application process.
+ void CloseApplicationProcess();
/// Retrieves the list of processes.
const std::vector<KProcess*>& GetProcessList() const;
@@ -191,19 +186,7 @@ public:
void InvalidateAllInstructionCaches();
- void InvalidateCpuInstructionCacheRange(VAddr addr, std::size_t size);
-
- /// Registers a named HLE service, passing a factory used to open a port to that service.
- void RegisterNamedService(std::string name, ServiceInterfaceFactory&& factory);
-
- /// Registers a setup function for the named HLE service.
- void RegisterInterfaceForNamedService(std::string name, ServiceInterfaceHandlerFn&& handler);
-
- /// Opens a port to a service previously registered with RegisterNamedService.
- KClientPort* CreateNamedServicePort(std::string name);
-
- /// Accepts a session on a port created by CreateNamedServicePort.
- void RegisterNamedServiceHandler(std::string name, KServerPort* server_port);
+ void InvalidateCpuInstructionCacheRange(KProcessAddress addr, std::size_t size);
/// Registers all kernel objects with the global emulation state, this is purely for tracking
/// leaks after emulation has been shutdown.
@@ -221,8 +204,8 @@ public:
/// destroyed during the current emulation session.
void UnregisterInUseObject(KAutoObject* object);
- /// Determines whether or not the given port is a valid named port.
- bool IsValidNamedPort(NamedPortTable::const_iterator port) const;
+ // Runs the given server manager until shutdown.
+ void RunServer(std::unique_ptr<Service::ServerManager>&& server_manager);
/// Gets the current host_thread/guest_thread pointer.
KThread* GetCurrentEmuThread() const;
@@ -239,12 +222,27 @@ public:
/// Register the current thread as a non CPU core thread.
void RegisterHostThread(KThread* existing_thread = nullptr);
+ void RunOnGuestCoreProcess(std::string&& process_name, std::function<void()> func);
+
+ std::jthread RunOnHostCoreProcess(std::string&& process_name, std::function<void()> func);
+
+ std::jthread RunOnHostCoreThread(std::string&& thread_name, std::function<void()> func);
+
+ /// Gets global data for KObjectName.
+ KObjectNameGlobalData& ObjectNameGlobalData();
+
/// Gets the virtual memory manager for the kernel.
KMemoryManager& MemoryManager();
/// Gets the virtual memory manager for the kernel.
const KMemoryManager& MemoryManager() const;
+ /// Gets the application resource manager.
+ KSystemResource& GetAppSystemResource();
+
+ /// Gets the application resource manager.
+ const KSystemResource& GetAppSystemResource() const;
+
/// Gets the system resource manager.
KSystemResource& GetSystemSystemResource();
@@ -281,11 +279,11 @@ public:
/// Gets the shared memory object for HIDBus services.
const Kernel::KSharedMemory& GetHidBusSharedMem() const;
- /// Suspend/unsuspend all processes.
- void Suspend(bool suspend);
+ /// Suspend/unsuspend application process.
+ void SuspendApplication(bool suspend);
- /// Exceptional exit all processes.
- void ExceptionalExit();
+ /// Exceptional exit application process.
+ void ExceptionalExitApplication();
/// Notify emulated CPU cores to shut down.
void ShutdownCores();
@@ -298,33 +296,6 @@ public:
void ExitSVCProfile();
- /**
- * Creates a host thread to execute HLE service requests, 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. In general, most
- * services can just use the default service thread, and not need their own host service thread.
- * See GetDefaultServiceThread.
- * @param name String name for the ServerSession creating this thread, used for debug
- * purposes.
- * @returns A reference to the newly created service thread.
- */
- Kernel::ServiceThread& CreateServiceThread(const std::string& name);
-
- /**
- * Gets the default host service thread, which executes HLE service requests. Unless service
- * requests need to block on the host, the default service thread should be used in favor of
- * creating a new service thread.
- * @returns A reference to the default service thread.
- */
- Kernel::ServiceThread& GetDefaultServiceThread() const;
-
- /**
- * Releases a HLE service thread, instructing KernelCore to free it. This should be called when
- * the ServerSession associated with the thread is destroyed.
- * @param service_thread Service thread to release.
- */
- void ReleaseServiceThread(Kernel::ServiceThread& service_thread);
-
/// Workaround for single-core mode when preempting threads while idle.
bool IsPhantomModeForSingleCore() const;
void SetIsPhantomModeForSingleCore(bool value);
@@ -334,45 +305,7 @@ public:
/// 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, KSharedMemoryInfo>) {
- return slab_heap_container->shared_memory_info;
- } 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, KCodeMemory>) {
- return slab_heap_container->code_memory;
- } else if constexpr (std::is_same_v<T, KPageBuffer>) {
- return slab_heap_container->page_buffer;
- } else if constexpr (std::is_same_v<T, KThreadLocalPage>) {
- return slab_heap_container->thread_local_page;
- } else if constexpr (std::is_same_v<T, KSessionRequest>) {
- return slab_heap_container->session_request;
- } else if constexpr (std::is_same_v<T, KSecureSystemResource>) {
- return slab_heap_container->secure_system_resource;
- } else if constexpr (std::is_same_v<T, KEventInfo>) {
- return slab_heap_container->event_info;
- } else if constexpr (std::is_same_v<T, KDebug>) {
- return slab_heap_container->debug;
- }
- }
+ KSlabHeap<T>& SlabHeap();
/// Gets the current slab resource counts.
Init::KSlabResourceCounts& SlabResourceCounts();
@@ -418,26 +351,7 @@ private:
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<KSharedMemoryInfo> shared_memory_info;
- KSlabHeap<KThread> thread;
- KSlabHeap<KTransferMemory> transfer_memory;
- KSlabHeap<KCodeMemory> code_memory;
- KSlabHeap<KPageBuffer> page_buffer;
- KSlabHeap<KThreadLocalPage> thread_local_page;
- KSlabHeap<KSessionRequest> session_request;
- KSlabHeap<KSecureSystemResource> secure_system_resource;
- KSlabHeap<KEventInfo> event_info;
- KSlabHeap<KDebug> debug;
- };
+ struct SlabHeapContainer;
std::unique_ptr<SlabHeapContainer> slab_heap_container;
};
diff --git a/src/core/hle/kernel/memory_types.h b/src/core/hle/kernel/memory_types.h
index 92b8b37ac..18de675cc 100644
--- a/src/core/hle/kernel/memory_types.h
+++ b/src/core/hle/kernel/memory_types.h
@@ -6,6 +6,7 @@
#include <array>
#include "common/common_types.h"
+#include "core/hle/kernel/k_typed_address.h"
namespace Kernel {
@@ -14,7 +15,4 @@ constexpr std::size_t PageSize{1 << PageBits};
using Page = std::array<u8, PageSize>;
-using KPhysicalAddress = PAddr;
-using KProcessAddress = VAddr;
-
} // namespace Kernel
diff --git a/src/core/hle/kernel/physical_core.cpp b/src/core/hle/kernel/physical_core.cpp
index 3044922ac..2e0c36129 100644
--- a/src/core/hle/kernel/physical_core.cpp
+++ b/src/core/hle/kernel/physical_core.cpp
@@ -10,14 +10,14 @@
namespace Kernel {
-PhysicalCore::PhysicalCore(std::size_t core_index_, Core::System& system_, KScheduler& scheduler_)
- : core_index{core_index_}, system{system_}, scheduler{scheduler_} {
+PhysicalCore::PhysicalCore(std::size_t core_index, Core::System& system, KScheduler& scheduler)
+ : m_core_index{core_index}, m_system{system}, m_scheduler{scheduler} {
#if defined(ARCHITECTURE_x86_64) || defined(ARCHITECTURE_arm64)
// TODO(bunnei): Initialization relies on a core being available. We may later replace this with
// a 32-bit instance of Dynarmic. This should be abstracted out to a CPU manager.
auto& kernel = system.Kernel();
- arm_interface = std::make_unique<Core::ARM_Dynarmic_64>(
- system, kernel.IsMulticore(), kernel.GetExclusiveMonitor(), core_index);
+ m_arm_interface = std::make_unique<Core::ARM_Dynarmic_64>(
+ system, kernel.IsMulticore(), kernel.GetExclusiveMonitor(), m_core_index);
#else
#error Platform not supported yet.
#endif
@@ -25,13 +25,13 @@ PhysicalCore::PhysicalCore(std::size_t core_index_, Core::System& system_, KSche
PhysicalCore::~PhysicalCore() = default;
-void PhysicalCore::Initialize([[maybe_unused]] bool is_64_bit) {
+void PhysicalCore::Initialize(bool is_64_bit) {
#if defined(ARCHITECTURE_x86_64) || defined(ARCHITECTURE_arm64)
- auto& kernel = system.Kernel();
+ auto& kernel = m_system.Kernel();
if (!is_64_bit) {
// We already initialized a 64-bit core, replace with a 32-bit one.
- arm_interface = std::make_unique<Core::ARM_Dynarmic_32>(
- system, kernel.IsMulticore(), kernel.GetExclusiveMonitor(), core_index);
+ m_arm_interface = std::make_unique<Core::ARM_Dynarmic_32>(
+ m_system, kernel.IsMulticore(), kernel.GetExclusiveMonitor(), m_core_index);
}
#else
#error Platform not supported yet.
@@ -39,31 +39,30 @@ void PhysicalCore::Initialize([[maybe_unused]] bool is_64_bit) {
}
void PhysicalCore::Run() {
- arm_interface->Run();
- arm_interface->ClearExclusiveState();
+ m_arm_interface->Run();
+ m_arm_interface->ClearExclusiveState();
}
void PhysicalCore::Idle() {
- std::unique_lock lk{guard};
- on_interrupt.wait(lk, [this] { return is_interrupted; });
+ std::unique_lock lk{m_guard};
+ m_on_interrupt.wait(lk, [this] { return m_is_interrupted; });
}
bool PhysicalCore::IsInterrupted() const {
- return is_interrupted;
+ return m_is_interrupted;
}
void PhysicalCore::Interrupt() {
- std::unique_lock lk{guard};
- is_interrupted = true;
- arm_interface->SignalInterrupt();
- on_interrupt.notify_all();
+ std::unique_lock lk{m_guard};
+ m_is_interrupted = true;
+ m_arm_interface->SignalInterrupt();
+ m_on_interrupt.notify_all();
}
void PhysicalCore::ClearInterrupt() {
- std::unique_lock lk{guard};
- is_interrupted = false;
- arm_interface->ClearInterrupt();
- on_interrupt.notify_all();
+ std::unique_lock lk{m_guard};
+ m_is_interrupted = false;
+ m_arm_interface->ClearInterrupt();
}
} // namespace Kernel
diff --git a/src/core/hle/kernel/physical_core.h b/src/core/hle/kernel/physical_core.h
index fb2ba4c6b..5cb398fdc 100644
--- a/src/core/hle/kernel/physical_core.h
+++ b/src/core/hle/kernel/physical_core.h
@@ -3,6 +3,7 @@
#pragma once
+#include <condition_variable>
#include <cstddef>
#include <memory>
#include <mutex>
@@ -46,46 +47,38 @@ public:
bool IsInterrupted() const;
bool IsInitialized() const {
- return arm_interface != nullptr;
+ return m_arm_interface != nullptr;
}
Core::ARM_Interface& ArmInterface() {
- return *arm_interface;
+ return *m_arm_interface;
}
const Core::ARM_Interface& ArmInterface() const {
- return *arm_interface;
- }
-
- bool IsMainCore() const {
- return core_index == 0;
- }
-
- bool IsSystemCore() const {
- return core_index == 3;
+ return *m_arm_interface;
}
std::size_t CoreIndex() const {
- return core_index;
+ return m_core_index;
}
Kernel::KScheduler& Scheduler() {
- return scheduler;
+ return m_scheduler;
}
const Kernel::KScheduler& Scheduler() const {
- return scheduler;
+ return m_scheduler;
}
private:
- const std::size_t core_index;
- Core::System& system;
- Kernel::KScheduler& scheduler;
-
- std::mutex guard;
- std::condition_variable on_interrupt;
- std::unique_ptr<Core::ARM_Interface> arm_interface;
- bool is_interrupted{};
+ const std::size_t m_core_index;
+ Core::System& m_system;
+ Kernel::KScheduler& m_scheduler;
+
+ std::mutex m_guard;
+ std::condition_variable m_on_interrupt;
+ std::unique_ptr<Core::ARM_Interface> m_arm_interface;
+ bool m_is_interrupted{};
};
} // namespace Kernel
diff --git a/src/core/hle/kernel/service_thread.cpp b/src/core/hle/kernel/service_thread.cpp
deleted file mode 100644
index 38afa720b..000000000
--- a/src/core/hle/kernel/service_thread.cpp
+++ /dev/null
@@ -1,206 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#include <functional>
-#include <map>
-#include <mutex>
-#include <thread>
-#include <vector>
-
-#include "common/polyfill_thread.h"
-#include "common/scope_exit.h"
-#include "common/thread.h"
-#include "core/hle/ipc_helpers.h"
-#include "core/hle/kernel/hle_ipc.h"
-#include "core/hle/kernel/k_event.h"
-#include "core/hle/kernel/k_scoped_resource_reservation.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/service_thread.h"
-
-namespace Kernel {
-
-class ServiceThread::Impl final {
-public:
- explicit Impl(KernelCore& kernel, const std::string& service_name);
- ~Impl();
-
- void WaitAndProcessImpl();
- void SessionClosed(KServerSession* server_session,
- std::shared_ptr<SessionRequestManager> manager);
- void LoopProcess();
-
- void RegisterServerSession(KServerSession* session,
- std::shared_ptr<SessionRequestManager> manager);
-
-private:
- KernelCore& kernel;
- const std::string m_service_name;
-
- std::jthread m_host_thread{};
- std::mutex m_session_mutex{};
- std::map<KServerSession*, std::shared_ptr<SessionRequestManager>> m_sessions{};
- KEvent* m_wakeup_event{};
- KThread* m_thread{};
- std::atomic<bool> m_shutdown_requested{};
-};
-
-void ServiceThread::Impl::WaitAndProcessImpl() {
- // Create local list of waitable sessions.
- std::vector<KSynchronizationObject*> objs;
- std::vector<std::shared_ptr<SessionRequestManager>> managers;
-
- {
- // Lock to get the set.
- std::scoped_lock lk{m_session_mutex};
-
- // Reserve the needed quantity.
- objs.reserve(m_sessions.size() + 1);
- managers.reserve(m_sessions.size());
-
- // Copy to our local list.
- for (const auto& [session, manager] : m_sessions) {
- objs.push_back(session);
- managers.push_back(manager);
- }
-
- // Insert the wakeup event at the end.
- objs.push_back(&m_wakeup_event->GetReadableEvent());
- }
-
- // Wait on the list of sessions.
- s32 index{-1};
- Result rc = KSynchronizationObject::Wait(kernel, &index, objs.data(),
- static_cast<s32>(objs.size()), -1);
- ASSERT(!rc.IsFailure());
-
- // If this was the wakeup event, clear it and finish.
- if (index >= static_cast<s64>(objs.size() - 1)) {
- m_wakeup_event->Clear();
- return;
- }
-
- // This event is from a server session.
- auto* server_session = static_cast<KServerSession*>(objs[index]);
- auto& manager = managers[index];
-
- // Fetch the HLE request context.
- std::shared_ptr<HLERequestContext> context;
- rc = server_session->ReceiveRequest(&context, manager);
-
- // If the session was closed, handle that.
- if (rc == ResultSessionClosed) {
- SessionClosed(server_session, manager);
-
- // Finish.
- return;
- }
-
- // TODO: handle other cases
- ASSERT(rc == ResultSuccess);
-
- // Perform the request.
- Result service_rc = manager->CompleteSyncRequest(server_session, *context);
-
- // Reply to the client.
- rc = server_session->SendReplyHLE();
-
- if (rc == ResultSessionClosed || service_rc == IPC::ERR_REMOTE_PROCESS_DEAD) {
- SessionClosed(server_session, manager);
- return;
- }
-
- // TODO: handle other cases
- ASSERT(rc == ResultSuccess);
- ASSERT(service_rc == ResultSuccess);
-}
-
-void ServiceThread::Impl::SessionClosed(KServerSession* server_session,
- std::shared_ptr<SessionRequestManager> manager) {
- {
- // Lock to get the set.
- std::scoped_lock lk{m_session_mutex};
-
- // Erase the session.
- ASSERT(m_sessions.erase(server_session) == 1);
- }
-
- // Close our reference to the server session.
- server_session->Close();
-}
-
-void ServiceThread::Impl::LoopProcess() {
- Common::SetCurrentThreadName(m_service_name.c_str());
-
- kernel.RegisterHostThread(m_thread);
-
- while (!m_shutdown_requested.load()) {
- WaitAndProcessImpl();
- }
-}
-
-void ServiceThread::Impl::RegisterServerSession(KServerSession* server_session,
- std::shared_ptr<SessionRequestManager> manager) {
- // Open the server session.
- server_session->Open();
-
- {
- // Lock to get the set.
- std::scoped_lock lk{m_session_mutex};
-
- // Insert the session and manager.
- m_sessions[server_session] = manager;
- }
-
- // Signal the wakeup event.
- m_wakeup_event->Signal();
-}
-
-ServiceThread::Impl::~Impl() {
- // Shut down the processing thread.
- m_shutdown_requested.store(true);
- m_wakeup_event->Signal();
- m_host_thread.join();
-
- // Close all remaining sessions.
- for (const auto& [server_session, manager] : m_sessions) {
- server_session->Close();
- }
-
- // Destroy remaining managers.
- m_sessions.clear();
-
- // Close event.
- m_wakeup_event->GetReadableEvent().Close();
- m_wakeup_event->Close();
-
- // Close thread.
- m_thread->Close();
-}
-
-ServiceThread::Impl::Impl(KernelCore& kernel_, const std::string& service_name)
- : kernel{kernel_}, m_service_name{service_name} {
- // Initialize event.
- m_wakeup_event = KEvent::Create(kernel);
- m_wakeup_event->Initialize(nullptr);
-
- // Initialize thread.
- m_thread = KThread::Create(kernel);
- ASSERT(KThread::InitializeDummyThread(m_thread, nullptr).IsSuccess());
-
- // Start thread.
- m_host_thread = std::jthread([this] { LoopProcess(); });
-}
-
-ServiceThread::ServiceThread(KernelCore& kernel, const std::string& name)
- : impl{std::make_unique<Impl>(kernel, name)} {}
-
-ServiceThread::~ServiceThread() = default;
-
-void ServiceThread::RegisterServerSession(KServerSession* session,
- std::shared_ptr<SessionRequestManager> manager) {
- impl->RegisterServerSession(session, manager);
-}
-
-} // namespace Kernel
diff --git a/src/core/hle/kernel/service_thread.h b/src/core/hle/kernel/service_thread.h
deleted file mode 100644
index fb4325531..000000000
--- a/src/core/hle/kernel/service_thread.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#pragma once
-
-#include <memory>
-#include <string>
-
-namespace Kernel {
-
-class HLERequestContext;
-class KernelCore;
-class KSession;
-class SessionRequestManager;
-
-class ServiceThread final {
-public:
- explicit ServiceThread(KernelCore& kernel, const std::string& name);
- ~ServiceThread();
-
- void RegisterServerSession(KServerSession* session,
- std::shared_ptr<SessionRequestManager> manager);
-
-private:
- class Impl;
- std::unique_ptr<Impl> impl;
-};
-
-} // namespace Kernel
diff --git a/src/core/hle/kernel/slab_helpers.h b/src/core/hle/kernel/slab_helpers.h
index 0228ce188..d1bbc7670 100644
--- a/src/core/hle/kernel/slab_helpers.h
+++ b/src/core/hle/kernel/slab_helpers.h
@@ -66,7 +66,7 @@ private:
}
public:
- explicit KAutoObjectWithSlabHeap(KernelCore& kernel_) : Base(kernel_), kernel(kernel_) {}
+ explicit KAutoObjectWithSlabHeap(KernelCore& kernel) : Base(kernel) {}
virtual ~KAutoObjectWithSlabHeap() = default;
virtual void Destroy() override {
@@ -76,7 +76,7 @@ public:
arg = this->GetPostDestroyArgument();
this->Finalize();
}
- Free(kernel, static_cast<Derived*>(this));
+ Free(Base::m_kernel, static_cast<Derived*>(this));
if (is_initialized) {
Derived::PostDestroy(arg);
}
@@ -90,7 +90,7 @@ public:
}
size_t GetSlabIndex() const {
- return SlabHeap<Derived>(kernel).GetObjectIndex(static_cast<const Derived*>(this));
+ return SlabHeap<Derived>(Base::m_kernel).GetObjectIndex(static_cast<const Derived*>(this));
}
public:
@@ -125,14 +125,11 @@ public:
static size_t GetNumRemaining(KernelCore& kernel) {
return kernel.SlabHeap<Derived>().GetNumRemaining();
}
-
-protected:
- KernelCore& kernel;
};
template <typename Derived, typename Base>
class KAutoObjectWithSlabHeapAndContainer : public Base {
- static_assert(std::is_base_of<KAutoObjectWithList, Base>::value);
+ static_assert(std::is_base_of_v<KAutoObjectWithList, Base>);
private:
static Derived* Allocate(KernelCore& kernel) {
@@ -144,18 +141,18 @@ private:
}
public:
- KAutoObjectWithSlabHeapAndContainer(KernelCore& kernel_) : Base(kernel_), kernel(kernel_) {}
+ KAutoObjectWithSlabHeapAndContainer(KernelCore& kernel) : Base(kernel) {}
virtual ~KAutoObjectWithSlabHeapAndContainer() {}
virtual void Destroy() override {
const bool is_initialized = this->IsInitialized();
uintptr_t arg = 0;
if (is_initialized) {
- kernel.ObjectListContainer().Unregister(this);
+ Base::m_kernel.ObjectListContainer().Unregister(this);
arg = this->GetPostDestroyArgument();
this->Finalize();
}
- Free(kernel, static_cast<Derived*>(this));
+ Free(Base::m_kernel, static_cast<Derived*>(this));
if (is_initialized) {
Derived::PostDestroy(arg);
}
@@ -169,7 +166,7 @@ public:
}
size_t GetSlabIndex() const {
- return SlabHeap<Derived>(kernel).GetObjectIndex(static_cast<const Derived*>(this));
+ return SlabHeap<Derived>(Base::m_kernel).GetObjectIndex(static_cast<const Derived*>(this));
}
public:
@@ -209,9 +206,6 @@ public:
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 aca442196..871d541d4 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -1,3129 +1,4435 @@
-// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
-#include <algorithm>
-#include <cinttypes>
-#include <iterator>
-#include <mutex>
-#include <vector>
-
-#include "common/alignment.h"
-#include "common/assert.h"
-#include "common/common_funcs.h"
-#include "common/fiber.h"
-#include "common/logging/log.h"
-#include "common/scope_exit.h"
+// This file is automatically generated using svc_generator.py.
+
+#include <type_traits>
+
+#include "core/arm/arm_interface.h"
#include "core/core.h"
-#include "core/core_timing.h"
-#include "core/debugger/debugger.h"
-#include "core/hle/kernel/k_client_port.h"
-#include "core/hle/kernel/k_client_session.h"
-#include "core/hle/kernel/k_code_memory.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_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_scheduler.h"
-#include "core/hle/kernel/k_scoped_resource_reservation.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_thread_queue.h"
-#include "core/hle/kernel/k_transfer_memory.h"
-#include "core/hle/kernel/kernel.h"
-#include "core/hle/kernel/physical_core.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/result.h"
-#include "core/memory.h"
-#include "core/reporter.h"
namespace Kernel::Svc {
-namespace {
-
-// Checks if address + size is greater than the given address
-// This can return false if the size causes an overflow of a 64-bit type
-// or if the given size is zero.
-constexpr bool IsValidAddressRange(VAddr address, u64 size) {
- return address + size > address;
-}
-
-// Helper function that performs the common sanity checks for svcMapMemory
-// and svcUnmapMemory. This is doable, as both functions perform their sanitizing
-// in the same order.
-Result MapUnmapMemorySanityChecks(const KPageTable& manager, VAddr dst_addr, VAddr src_addr,
- u64 size) {
- if (!Common::Is4KBAligned(dst_addr)) {
- LOG_ERROR(Kernel_SVC, "Destination address is not aligned to 4KB, 0x{:016X}", dst_addr);
- return ResultInvalidAddress;
- }
- if (!Common::Is4KBAligned(src_addr)) {
- LOG_ERROR(Kernel_SVC, "Source address is not aligned to 4KB, 0x{:016X}", src_addr);
- return ResultInvalidSize;
- }
+static uint32_t GetReg32(Core::System& system, int n) {
+ return static_cast<uint32_t>(system.CurrentArmInterface().GetReg(n));
+}
- if (size == 0) {
- LOG_ERROR(Kernel_SVC, "Size is 0");
- return ResultInvalidSize;
- }
+static void SetReg32(Core::System& system, int n, uint32_t result) {
+ system.CurrentArmInterface().SetReg(n, static_cast<uint64_t>(result));
+}
- if (!Common::Is4KBAligned(size)) {
- LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, 0x{:016X}", size);
- return ResultInvalidSize;
- }
+static uint64_t GetReg64(Core::System& system, int n) {
+ return system.CurrentArmInterface().GetReg(n);
+}
- if (!IsValidAddressRange(dst_addr, size)) {
- LOG_ERROR(Kernel_SVC,
- "Destination is not a valid address range, addr=0x{:016X}, size=0x{:016X}",
- dst_addr, size);
- return ResultInvalidCurrentMemory;
- }
+static void SetReg64(Core::System& system, int n, uint64_t result) {
+ system.CurrentArmInterface().SetReg(n, result);
+}
- if (!IsValidAddressRange(src_addr, size)) {
- LOG_ERROR(Kernel_SVC, "Source is not a valid address range, addr=0x{:016X}, size=0x{:016X}",
- src_addr, size);
- return ResultInvalidCurrentMemory;
- }
+// Like bit_cast, but handles the case when the source and dest
+// are differently-sized.
+template <typename To, typename From>
+ requires(std::is_trivial_v<To> && std::is_trivially_copyable_v<From>)
+static To Convert(const From& from) {
+ To to{};
- if (!manager.IsInsideAddressSpace(src_addr, size)) {
- LOG_ERROR(Kernel_SVC,
- "Source is not within the address space, addr=0x{:016X}, size=0x{:016X}",
- src_addr, size);
- return ResultInvalidCurrentMemory;
+ if constexpr (sizeof(To) >= sizeof(From)) {
+ std::memcpy(std::addressof(to), std::addressof(from), sizeof(From));
+ } else {
+ std::memcpy(std::addressof(to), std::addressof(from), sizeof(To));
}
- if (manager.IsOutsideStackRegion(dst_addr, size)) {
- LOG_ERROR(Kernel_SVC,
- "Destination is not within the stack region, addr=0x{:016X}, size=0x{:016X}",
- dst_addr, size);
- return ResultInvalidMemoryRegion;
- }
+ return to;
+}
- if (manager.IsInsideHeapRegion(dst_addr, size)) {
- LOG_ERROR(Kernel_SVC,
- "Destination does not fit within the heap region, addr=0x{:016X}, "
- "size=0x{:016X}",
- dst_addr, size);
- return ResultInvalidMemoryRegion;
- }
+// clang-format off
+static_assert(sizeof(ArbitrationType) == 4);
+static_assert(sizeof(BreakReason) == 4);
+static_assert(sizeof(CodeMemoryOperation) == 4);
+static_assert(sizeof(DebugThreadParam) == 4);
+static_assert(sizeof(DeviceName) == 4);
+static_assert(sizeof(HardwareBreakPointRegisterName) == 4);
+static_assert(sizeof(Handle) == 4);
+static_assert(sizeof(InfoType) == 4);
+static_assert(sizeof(InterruptType) == 4);
+static_assert(sizeof(IoPoolType) == 4);
+static_assert(sizeof(KernelDebugType) == 4);
+static_assert(sizeof(KernelTraceState) == 4);
+static_assert(sizeof(LimitableResource) == 4);
+static_assert(sizeof(MemoryMapping) == 4);
+static_assert(sizeof(MemoryPermission) == 4);
+static_assert(sizeof(PageInfo) == 4);
+static_assert(sizeof(ProcessActivity) == 4);
+static_assert(sizeof(ProcessInfoType) == 4);
+static_assert(sizeof(Result) == 4);
+static_assert(sizeof(SignalType) == 4);
+static_assert(sizeof(SystemInfoType) == 4);
+static_assert(sizeof(ThreadActivity) == 4);
+static_assert(sizeof(ilp32::LastThreadContext) == 16);
+static_assert(sizeof(ilp32::PhysicalMemoryInfo) == 16);
+static_assert(sizeof(ilp32::SecureMonitorArguments) == 32);
+static_assert(sizeof(lp64::LastThreadContext) == 32);
+static_assert(sizeof(lp64::PhysicalMemoryInfo) == 24);
+static_assert(sizeof(lp64::SecureMonitorArguments) == 64);
+static_assert(sizeof(bool) == 1);
+static_assert(sizeof(int32_t) == 4);
+static_assert(sizeof(int64_t) == 8);
+static_assert(sizeof(uint32_t) == 4);
+static_assert(sizeof(uint64_t) == 8);
- if (manager.IsInsideAliasRegion(dst_addr, size)) {
- LOG_ERROR(Kernel_SVC,
- "Destination does not fit within the map region, addr=0x{:016X}, "
- "size=0x{:016X}",
- dst_addr, size);
- return ResultInvalidMemoryRegion;
- }
+static void SvcWrap_SetHeapSize64From32(Core::System& system) {
+ Result ret{};
+
+ uint64_t out_address{};
+ uint32_t size{};
+
+ size = Convert<uint32_t>(GetReg32(system, 1));
+
+ ret = SetHeapSize64From32(system, std::addressof(out_address), size);
- return ResultSuccess;
+ SetReg32(system, 0, Convert<uint32_t>(ret));
+ SetReg32(system, 1, Convert<uint32_t>(out_address));
}
-enum class ResourceLimitValueType {
- CurrentValue,
- LimitValue,
- PeakValue,
-};
+static void SvcWrap_SetMemoryPermission64From32(Core::System& system) {
+ Result ret{};
-} // Anonymous namespace
+ uint32_t address{};
+ uint32_t size{};
+ MemoryPermission perm{};
+
+ address = Convert<uint32_t>(GetReg32(system, 0));
+ size = Convert<uint32_t>(GetReg32(system, 1));
+ perm = Convert<MemoryPermission>(GetReg32(system, 2));
+
+ ret = SetMemoryPermission64From32(system, address, size, perm);
+
+ SetReg32(system, 0, Convert<uint32_t>(ret));
+}
-/// Set the process heap to a given Size. It can both extend and shrink the heap.
-static Result SetHeapSize(Core::System& system, VAddr* out_address, u64 size) {
- LOG_TRACE(Kernel_SVC, "called, heap_size=0x{:X}", size);
+static void SvcWrap_SetMemoryAttribute64From32(Core::System& system) {
+ Result ret{};
- // Validate size.
- R_UNLESS(Common::IsAligned(size, HeapSizeAlignment), ResultInvalidSize);
- R_UNLESS(size < MainMemorySizeMax, ResultInvalidSize);
+ uint32_t address{};
+ uint32_t size{};
+ uint32_t mask{};
+ uint32_t attr{};
- // Set the heap size.
- R_TRY(system.Kernel().CurrentProcess()->PageTable().SetHeapSize(out_address, size));
+ address = Convert<uint32_t>(GetReg32(system, 0));
+ size = Convert<uint32_t>(GetReg32(system, 1));
+ mask = Convert<uint32_t>(GetReg32(system, 2));
+ attr = Convert<uint32_t>(GetReg32(system, 3));
- return ResultSuccess;
+ ret = SetMemoryAttribute64From32(system, address, size, mask, attr);
+
+ SetReg32(system, 0, Convert<uint32_t>(ret));
}
-static Result SetHeapSize32(Core::System& system, u32* heap_addr, u32 heap_size) {
- VAddr temp_heap_addr{};
- const Result result{SetHeapSize(system, &temp_heap_addr, heap_size)};
- *heap_addr = static_cast<u32>(temp_heap_addr);
- return result;
+static void SvcWrap_MapMemory64From32(Core::System& system) {
+ Result ret{};
+
+ uint32_t dst_address{};
+ uint32_t src_address{};
+ uint32_t size{};
+
+ dst_address = Convert<uint32_t>(GetReg32(system, 0));
+ src_address = Convert<uint32_t>(GetReg32(system, 1));
+ size = Convert<uint32_t>(GetReg32(system, 2));
+
+ ret = MapMemory64From32(system, dst_address, src_address, size);
+
+ SetReg32(system, 0, Convert<uint32_t>(ret));
}
-constexpr bool IsValidSetMemoryPermission(MemoryPermission perm) {
- switch (perm) {
- case MemoryPermission::None:
- case MemoryPermission::Read:
- case MemoryPermission::ReadWrite:
- return true;
- default:
- return false;
- }
+static void SvcWrap_UnmapMemory64From32(Core::System& system) {
+ Result ret{};
+
+ uint32_t dst_address{};
+ uint32_t src_address{};
+ uint32_t size{};
+
+ dst_address = Convert<uint32_t>(GetReg32(system, 0));
+ src_address = Convert<uint32_t>(GetReg32(system, 1));
+ size = Convert<uint32_t>(GetReg32(system, 2));
+
+ ret = UnmapMemory64From32(system, dst_address, src_address, size);
+
+ SetReg32(system, 0, Convert<uint32_t>(ret));
}
-static Result SetMemoryPermission(Core::System& system, VAddr address, u64 size,
- MemoryPermission perm) {
- LOG_DEBUG(Kernel_SVC, "called, address=0x{:016X}, size=0x{:X}, perm=0x{:08X", address, size,
- perm);
+static void SvcWrap_QueryMemory64From32(Core::System& system) {
+ Result ret{};
- // Validate 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);
+ PageInfo out_page_info{};
+ uint32_t out_memory_info{};
+ uint32_t address{};
- // Validate the permission.
- R_UNLESS(IsValidSetMemoryPermission(perm), ResultInvalidNewMemoryPermission);
+ out_memory_info = Convert<uint32_t>(GetReg32(system, 0));
+ address = Convert<uint32_t>(GetReg32(system, 2));
- // Validate that the region is in range for the current process.
- auto& page_table = system.Kernel().CurrentProcess()->PageTable();
- R_UNLESS(page_table.Contains(address, size), ResultInvalidCurrentMemory);
+ ret = QueryMemory64From32(system, out_memory_info, std::addressof(out_page_info), address);
- // Set the memory attribute.
- return page_table.SetMemoryPermission(address, size, perm);
+ SetReg32(system, 0, Convert<uint32_t>(ret));
+ SetReg32(system, 1, Convert<uint32_t>(out_page_info));
}
-static Result SetMemoryAttribute(Core::System& system, VAddr address, u64 size, u32 mask,
- u32 attr) {
- LOG_DEBUG(Kernel_SVC,
- "called, address=0x{:016X}, size=0x{:X}, mask=0x{:08X}, attribute=0x{:08X}", address,
- size, mask, attr);
+static void SvcWrap_ExitProcess64From32(Core::System& system) {
+ ExitProcess64From32(system);
+}
+
+static void SvcWrap_CreateThread64From32(Core::System& system) {
+ Result ret{};
- // Validate 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);
+ Handle out_handle{};
+ uint32_t func{};
+ uint32_t arg{};
+ uint32_t stack_bottom{};
+ int32_t priority{};
+ int32_t core_id{};
- // Validate the attribute and mask.
- constexpr u32 SupportedMask = static_cast<u32>(MemoryAttribute::Uncached);
- R_UNLESS((mask | attr) == mask, ResultInvalidCombination);
- R_UNLESS((mask | attr | SupportedMask) == SupportedMask, ResultInvalidCombination);
+ func = Convert<uint32_t>(GetReg32(system, 1));
+ arg = Convert<uint32_t>(GetReg32(system, 2));
+ stack_bottom = Convert<uint32_t>(GetReg32(system, 3));
+ priority = Convert<int32_t>(GetReg32(system, 0));
+ core_id = Convert<int32_t>(GetReg32(system, 4));
- // Validate that the region is in range for the current process.
- auto& page_table{system.Kernel().CurrentProcess()->PageTable()};
- R_UNLESS(page_table.Contains(address, size), ResultInvalidCurrentMemory);
+ ret = CreateThread64From32(system, std::addressof(out_handle), func, arg, stack_bottom, priority, core_id);
- // Set the memory attribute.
- return page_table.SetMemoryAttribute(address, size, mask, attr);
+ SetReg32(system, 0, Convert<uint32_t>(ret));
+ SetReg32(system, 1, Convert<uint32_t>(out_handle));
}
-static Result SetMemoryAttribute32(Core::System& system, u32 address, u32 size, u32 mask,
- u32 attr) {
- return SetMemoryAttribute(system, address, size, mask, attr);
+static void SvcWrap_StartThread64From32(Core::System& system) {
+ Result ret{};
+
+ Handle thread_handle{};
+
+ thread_handle = Convert<Handle>(GetReg32(system, 0));
+
+ ret = StartThread64From32(system, thread_handle);
+
+ SetReg32(system, 0, Convert<uint32_t>(ret));
}
-/// Maps a memory range into a different range.
-static Result MapMemory(Core::System& system, VAddr dst_addr, VAddr src_addr, u64 size) {
- LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr,
- src_addr, size);
+static void SvcWrap_ExitThread64From32(Core::System& system) {
+ ExitThread64From32(system);
+}
- auto& page_table{system.Kernel().CurrentProcess()->PageTable()};
+static void SvcWrap_SleepThread64From32(Core::System& system) {
+ int64_t ns{};
- if (const Result result{MapUnmapMemorySanityChecks(page_table, dst_addr, src_addr, size)};
- result.IsError()) {
- return result;
- }
+ std::array<uint32_t, 2> ns_gather{};
+ ns_gather[0] = GetReg32(system, 0);
+ ns_gather[1] = GetReg32(system, 1);
+ ns = Convert<int64_t>(ns_gather);
- return page_table.MapMemory(dst_addr, src_addr, size);
+ SleepThread64From32(system, ns);
}
-static Result MapMemory32(Core::System& system, u32 dst_addr, u32 src_addr, u32 size) {
- return MapMemory(system, dst_addr, src_addr, size);
+static void SvcWrap_GetThreadPriority64From32(Core::System& system) {
+ Result ret{};
+
+ int32_t out_priority{};
+ Handle thread_handle{};
+
+ thread_handle = Convert<Handle>(GetReg32(system, 1));
+
+ ret = GetThreadPriority64From32(system, std::addressof(out_priority), thread_handle);
+
+ SetReg32(system, 0, Convert<uint32_t>(ret));
+ SetReg32(system, 1, Convert<uint32_t>(out_priority));
}
-/// Unmaps a region that was previously mapped with svcMapMemory
-static Result UnmapMemory(Core::System& system, VAddr dst_addr, VAddr src_addr, u64 size) {
- LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr,
- src_addr, size);
+static void SvcWrap_SetThreadPriority64From32(Core::System& system) {
+ Result ret{};
- auto& page_table{system.Kernel().CurrentProcess()->PageTable()};
+ Handle thread_handle{};
+ int32_t priority{};
- if (const Result result{MapUnmapMemorySanityChecks(page_table, dst_addr, src_addr, size)};
- result.IsError()) {
- return result;
- }
+ thread_handle = Convert<Handle>(GetReg32(system, 0));
+ priority = Convert<int32_t>(GetReg32(system, 1));
- return page_table.UnmapMemory(dst_addr, src_addr, size);
+ ret = SetThreadPriority64From32(system, thread_handle, priority);
+
+ SetReg32(system, 0, Convert<uint32_t>(ret));
}
-static Result UnmapMemory32(Core::System& system, u32 dst_addr, u32 src_addr, u32 size) {
- return UnmapMemory(system, dst_addr, src_addr, size);
+static void SvcWrap_GetThreadCoreMask64From32(Core::System& system) {
+ Result ret{};
+
+ int32_t out_core_id{};
+ uint64_t out_affinity_mask{};
+ Handle thread_handle{};
+
+ thread_handle = Convert<Handle>(GetReg32(system, 2));
+
+ ret = GetThreadCoreMask64From32(system, std::addressof(out_core_id), std::addressof(out_affinity_mask), thread_handle);
+
+ SetReg32(system, 0, Convert<uint32_t>(ret));
+ SetReg32(system, 1, Convert<uint32_t>(out_core_id));
+ auto out_affinity_mask_scatter = Convert<std::array<uint32_t, 2>>(out_affinity_mask);
+ SetReg32(system, 2, out_affinity_mask_scatter[0]);
+ SetReg32(system, 3, out_affinity_mask_scatter[1]);
}
-template <typename T>
-Result CreateSession(Core::System& system, Handle* out_server, Handle* out_client, u64 name) {
- auto& process = *system.CurrentProcess();
- auto& handle_table = process.GetHandleTable();
+static void SvcWrap_SetThreadCoreMask64From32(Core::System& system) {
+ Result ret{};
- // Declare the session we're going to allocate.
- T* session;
+ Handle thread_handle{};
+ int32_t core_id{};
+ uint64_t affinity_mask{};
- // Reserve a new session from the process resource limit.
- // FIXME: LimitableResource_SessionCountMax
- KScopedResourceReservation session_reservation(&process, LimitableResource::SessionCountMax);
- if (session_reservation.Succeeded()) {
- session = T::Create(system.Kernel());
- } else {
- return ResultLimitReached;
-
- // // We couldn't reserve a session. Check that we support dynamically expanding the
- // // resource limit.
- // R_UNLESS(process.GetResourceLimit() ==
- // &system.Kernel().GetSystemResourceLimit(), ResultLimitReached);
- // R_UNLESS(KTargetSystem::IsDynamicResourceLimitsEnabled(), ResultLimitReached());
-
- // // Try to allocate a session from unused slab memory.
- // session = T::CreateFromUnusedSlabMemory();
- // R_UNLESS(session != nullptr, ResultLimitReached);
- // ON_RESULT_FAILURE { session->Close(); };
-
- // // If we're creating a KSession, we want to add two KSessionRequests to the heap, to
- // // prevent request exhaustion.
- // // NOTE: Nintendo checks if session->DynamicCast<KSession *>() != nullptr, but there's
- // // no reason to not do this statically.
- // if constexpr (std::same_as<T, KSession>) {
- // for (size_t i = 0; i < 2; i++) {
- // KSessionRequest* request = KSessionRequest::CreateFromUnusedSlabMemory();
- // R_UNLESS(request != nullptr, ResultLimitReached);
- // request->Close();
- // }
- // }
-
- // We successfully allocated a session, so add the object we allocated to the resource
- // limit.
- // system.Kernel().GetSystemResourceLimit().Reserve(LimitableResource::SessionCountMax, 1);
- }
+ thread_handle = Convert<Handle>(GetReg32(system, 0));
+ core_id = Convert<int32_t>(GetReg32(system, 1));
+ std::array<uint32_t, 2> affinity_mask_gather{};
+ affinity_mask_gather[0] = GetReg32(system, 2);
+ affinity_mask_gather[1] = GetReg32(system, 3);
+ affinity_mask = Convert<uint64_t>(affinity_mask_gather);
- // Check that we successfully created a session.
- R_UNLESS(session != nullptr, ResultOutOfResource);
+ ret = SetThreadCoreMask64From32(system, thread_handle, core_id, affinity_mask);
- // Initialize the session.
- session->Initialize(nullptr, fmt::format("{}", name));
+ SetReg32(system, 0, Convert<uint32_t>(ret));
+}
- // Commit the session reservation.
- session_reservation.Commit();
+static void SvcWrap_GetCurrentProcessorNumber64From32(Core::System& system) {
+ int32_t ret{};
- // Ensure that we clean up the session (and its only references are handle table) on function
- // end.
- SCOPE_EXIT({
- session->GetClientSession().Close();
- session->GetServerSession().Close();
- });
+ ret = GetCurrentProcessorNumber64From32(system);
- // Register the session.
- T::Register(system.Kernel(), session);
+ SetReg32(system, 0, Convert<uint32_t>(ret));
+}
- // Add the server session to the handle table.
- R_TRY(handle_table.Add(out_server, &session->GetServerSession()));
+static void SvcWrap_SignalEvent64From32(Core::System& system) {
+ Result ret{};
- // Add the client session to the handle table.
- const auto result = handle_table.Add(out_client, &session->GetClientSession());
+ Handle event_handle{};
- if (!R_SUCCEEDED(result)) {
- // Ensure that we maintaing a clean handle state on exit.
- handle_table.Remove(*out_server);
- }
+ event_handle = Convert<Handle>(GetReg32(system, 0));
- return result;
+ ret = SignalEvent64From32(system, event_handle);
+
+ SetReg32(system, 0, Convert<uint32_t>(ret));
}
-static Result CreateSession(Core::System& system, Handle* out_server, Handle* out_client,
- u32 is_light, u64 name) {
- if (is_light) {
- // return CreateSession<KLightSession>(system, out_server, out_client, name);
- return ResultUnknown;
- } else {
- return CreateSession<KSession>(system, out_server, out_client, name);
- }
+static void SvcWrap_ClearEvent64From32(Core::System& system) {
+ Result ret{};
+
+ Handle event_handle{};
+
+ event_handle = Convert<Handle>(GetReg32(system, 0));
+
+ ret = ClearEvent64From32(system, event_handle);
+
+ SetReg32(system, 0, Convert<uint32_t>(ret));
}
-/// Connect to an OS service given the port name, returns the handle to the port to out
-static Result 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}",
- port_name_address);
- return ResultNotFound;
- }
+static void SvcWrap_MapSharedMemory64From32(Core::System& system) {
+ Result ret{};
- static constexpr std::size_t PortNameMaxLength = 11;
- // Read 1 char beyond the max allowed port name to detect names that are too long.
- const std::string port_name = memory.ReadCString(port_name_address, PortNameMaxLength + 1);
- if (port_name.size() > PortNameMaxLength) {
- LOG_ERROR(Kernel_SVC, "Port name is too long, expected {} but got {}", PortNameMaxLength,
- port_name.size());
- return ResultOutOfRange;
- }
+ Handle shmem_handle{};
+ uint32_t address{};
+ uint32_t size{};
+ MemoryPermission map_perm{};
- LOG_TRACE(Kernel_SVC, "called port_name={}", port_name);
+ shmem_handle = Convert<Handle>(GetReg32(system, 0));
+ address = Convert<uint32_t>(GetReg32(system, 1));
+ size = Convert<uint32_t>(GetReg32(system, 2));
+ map_perm = Convert<MemoryPermission>(GetReg32(system, 3));
- // Get the current handle table.
- auto& kernel = system.Kernel();
- auto& handle_table = kernel.CurrentProcess()->GetHandleTable();
+ ret = MapSharedMemory64From32(system, shmem_handle, address, size, map_perm);
- // 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;
- }
+ SetReg32(system, 0, Convert<uint32_t>(ret));
+}
- // 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); });
+static void SvcWrap_UnmapSharedMemory64From32(Core::System& system) {
+ Result ret{};
- // Create a session.
- KClientSession* session{};
- R_TRY(port->CreateSession(std::addressof(session)));
+ Handle shmem_handle{};
+ uint32_t address{};
+ uint32_t size{};
- kernel.RegisterNamedServiceHandler(port_name, &port->GetParent()->GetServerPort());
+ shmem_handle = Convert<Handle>(GetReg32(system, 0));
+ address = Convert<uint32_t>(GetReg32(system, 1));
+ size = Convert<uint32_t>(GetReg32(system, 2));
- // Register the session in the table, close the extra reference.
- handle_table.Register(*out, session);
- session->Close();
+ ret = UnmapSharedMemory64From32(system, shmem_handle, address, size);
- // We succeeded.
- handle_guard.Cancel();
- return ResultSuccess;
+ SetReg32(system, 0, Convert<uint32_t>(ret));
}
-static Result ConnectToNamedPort32(Core::System& system, Handle* out_handle,
- u32 port_name_address) {
+static void SvcWrap_CreateTransferMemory64From32(Core::System& system) {
+ Result ret{};
+
+ Handle out_handle{};
+ uint32_t address{};
+ uint32_t size{};
+ MemoryPermission map_perm{};
+
+ address = Convert<uint32_t>(GetReg32(system, 1));
+ size = Convert<uint32_t>(GetReg32(system, 2));
+ map_perm = Convert<MemoryPermission>(GetReg32(system, 3));
+
+ ret = CreateTransferMemory64From32(system, std::addressof(out_handle), address, size, map_perm);
- return ConnectToNamedPort(system, out_handle, port_name_address);
+ SetReg32(system, 0, Convert<uint32_t>(ret));
+ SetReg32(system, 1, Convert<uint32_t>(out_handle));
}
-/// Makes a blocking IPC call to a service.
-static Result SendSyncRequest(Core::System& system, Handle handle) {
- auto& kernel = system.Kernel();
+static void SvcWrap_CloseHandle64From32(Core::System& system) {
+ Result ret{};
- // Create the wait queue.
- KThreadQueue wait_queue(kernel);
+ Handle handle{};
- // Get the client session from its handle.
- KScopedAutoObject session =
- kernel.CurrentProcess()->GetHandleTable().GetObject<KClientSession>(handle);
- R_UNLESS(session.IsNotNull(), ResultInvalidHandle);
+ handle = Convert<Handle>(GetReg32(system, 0));
- LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName());
+ ret = CloseHandle64From32(system, handle);
- return session->SendSyncRequest();
+ SetReg32(system, 0, Convert<uint32_t>(ret));
}
-static Result SendSyncRequest32(Core::System& system, Handle handle) {
- return SendSyncRequest(system, handle);
+static void SvcWrap_ResetSignal64From32(Core::System& system) {
+ Result ret{};
+
+ Handle handle{};
+
+ handle = Convert<Handle>(GetReg32(system, 0));
+
+ ret = ResetSignal64From32(system, handle);
+
+ SetReg32(system, 0, Convert<uint32_t>(ret));
}
-static Result ReplyAndReceive(Core::System& system, s32* out_index, Handle* handles,
- s32 num_handles, Handle reply_target, s64 timeout_ns) {
- auto& kernel = system.Kernel();
- auto& handle_table = GetCurrentThread(kernel).GetOwnerProcess()->GetHandleTable();
-
- // Convert handle list to object table.
- std::vector<KSynchronizationObject*> objs(num_handles);
- R_UNLESS(
- handle_table.GetMultipleObjects<KSynchronizationObject>(objs.data(), handles, num_handles),
- ResultInvalidHandle);
-
- // Ensure handles are closed when we're done.
- SCOPE_EXIT({
- for (auto i = 0; i < num_handles; ++i) {
- objs[i]->Close();
- }
- });
-
- // Reply to the target, if one is specified.
- if (reply_target != InvalidHandle) {
- KScopedAutoObject session = handle_table.GetObject<KServerSession>(reply_target);
- R_UNLESS(session.IsNotNull(), ResultInvalidHandle);
-
- // If we fail to reply, we want to set the output index to -1.
- // ON_RESULT_FAILURE { *out_index = -1; };
-
- // Send the reply.
- // R_TRY(session->SendReply());
-
- Result rc = session->SendReply();
- if (!R_SUCCEEDED(rc)) {
- *out_index = -1;
- return rc;
- }
- }
+static void SvcWrap_WaitSynchronization64From32(Core::System& system) {
+ Result ret{};
- // Wait for a message.
- while (true) {
- // Wait for an object.
- s32 index;
- Result result = KSynchronizationObject::Wait(kernel, &index, objs.data(),
- static_cast<s32>(objs.size()), timeout_ns);
- if (result == ResultTimedOut) {
- return result;
- }
-
- // Receive the request.
- if (R_SUCCEEDED(result)) {
- KServerSession* session = objs[index]->DynamicCast<KServerSession*>();
- if (session != nullptr) {
- result = session->ReceiveRequest();
- if (result == ResultNotFound) {
- continue;
- }
- }
- }
-
- *out_index = index;
- return result;
- }
+ int32_t out_index{};
+ uint32_t handles{};
+ int32_t num_handles{};
+ int64_t timeout_ns{};
+
+ handles = Convert<uint32_t>(GetReg32(system, 1));
+ num_handles = Convert<int32_t>(GetReg32(system, 2));
+ std::array<uint32_t, 2> timeout_ns_gather{};
+ timeout_ns_gather[0] = GetReg32(system, 0);
+ timeout_ns_gather[1] = GetReg32(system, 3);
+ timeout_ns = Convert<int64_t>(timeout_ns_gather);
+
+ ret = WaitSynchronization64From32(system, std::addressof(out_index), handles, num_handles, timeout_ns);
+
+ SetReg32(system, 0, Convert<uint32_t>(ret));
+ SetReg32(system, 1, Convert<uint32_t>(out_index));
}
-/// Get the ID for the specified thread.
-static Result GetThreadId(Core::System& system, u64* out_thread_id, Handle thread_handle) {
- // Get the thread from its handle.
- KScopedAutoObject thread =
- system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KThread>(thread_handle);
- R_UNLESS(thread.IsNotNull(), ResultInvalidHandle);
+static void SvcWrap_CancelSynchronization64From32(Core::System& system) {
+ Result ret{};
- // Get the thread's id.
- *out_thread_id = thread->GetId();
- return ResultSuccess;
+ Handle handle{};
+
+ handle = Convert<Handle>(GetReg32(system, 0));
+
+ ret = CancelSynchronization64From32(system, handle);
+
+ SetReg32(system, 0, Convert<uint32_t>(ret));
}
-static Result GetThreadId32(Core::System& system, u32* out_thread_id_low, u32* out_thread_id_high,
- Handle thread_handle) {
- u64 out_thread_id{};
- const Result result{GetThreadId(system, &out_thread_id, thread_handle)};
+static void SvcWrap_ArbitrateLock64From32(Core::System& system) {
+ Result ret{};
+
+ Handle thread_handle{};
+ uint32_t address{};
+ uint32_t tag{};
- *out_thread_id_low = static_cast<u32>(out_thread_id >> 32);
- *out_thread_id_high = static_cast<u32>(out_thread_id & std::numeric_limits<u32>::max());
+ thread_handle = Convert<Handle>(GetReg32(system, 0));
+ address = Convert<uint32_t>(GetReg32(system, 1));
+ tag = Convert<uint32_t>(GetReg32(system, 2));
- return result;
+ ret = ArbitrateLock64From32(system, thread_handle, address, tag);
+
+ SetReg32(system, 0, Convert<uint32_t>(ret));
}
-/// Gets the ID of the specified process or a specified thread's owning process.
-static Result GetProcessId(Core::System& system, u64* out_process_id, Handle handle) {
- LOG_DEBUG(Kernel_SVC, "called handle=0x{:08X}", handle);
+static void SvcWrap_ArbitrateUnlock64From32(Core::System& system) {
+ Result ret{};
- // Get the object from the handle table.
- KScopedAutoObject obj =
- system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KAutoObject>(
- static_cast<Handle>(handle));
- R_UNLESS(obj.IsNotNull(), ResultInvalidHandle);
+ uint32_t address{};
- // 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");
- }
+ address = Convert<uint32_t>(GetReg32(system, 0));
- // Make sure the target process exists.
- R_UNLESS(process != nullptr, ResultInvalidHandle);
+ ret = ArbitrateUnlock64From32(system, address);
- // Get the process id.
- *out_process_id = process->GetId();
+ SetReg32(system, 0, Convert<uint32_t>(ret));
+}
+
+static void SvcWrap_WaitProcessWideKeyAtomic64From32(Core::System& system) {
+ Result ret{};
+
+ uint32_t address{};
+ uint32_t cv_key{};
+ uint32_t tag{};
+ int64_t timeout_ns{};
+
+ address = Convert<uint32_t>(GetReg32(system, 0));
+ cv_key = Convert<uint32_t>(GetReg32(system, 1));
+ tag = Convert<uint32_t>(GetReg32(system, 2));
+ std::array<uint32_t, 2> timeout_ns_gather{};
+ timeout_ns_gather[0] = GetReg32(system, 3);
+ timeout_ns_gather[1] = GetReg32(system, 4);
+ timeout_ns = Convert<int64_t>(timeout_ns_gather);
- return ResultSuccess;
+ ret = WaitProcessWideKeyAtomic64From32(system, address, cv_key, tag, timeout_ns);
+
+ SetReg32(system, 0, Convert<uint32_t>(ret));
}
-static Result 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;
+static void SvcWrap_SignalProcessWideKey64From32(Core::System& system) {
+ uint32_t cv_key{};
+ int32_t count{};
+
+ cv_key = Convert<uint32_t>(GetReg32(system, 0));
+ count = Convert<int32_t>(GetReg32(system, 1));
+
+ SignalProcessWideKey64From32(system, cv_key, count);
}
-/// Wait for the given handles to synchronize, timeout after the specified nanoseconds
-static Result WaitSynchronization(Core::System& system, s32* index, VAddr handles_address,
- s32 num_handles, s64 nano_seconds) {
- LOG_TRACE(Kernel_SVC, "called handles_address=0x{:X}, num_handles={}, nano_seconds={}",
- handles_address, num_handles, nano_seconds);
+static void SvcWrap_GetSystemTick64From32(Core::System& system) {
+ int64_t ret{};
- // Ensure number of handles is valid.
- R_UNLESS(0 <= num_handles && num_handles <= ArgumentHandleCountMax, ResultOutOfRange);
+ ret = GetSystemTick64From32(system);
- auto& kernel = system.Kernel();
- std::vector<KSynchronizationObject*> objs(num_handles);
- const auto& handle_table = kernel.CurrentProcess()->GetHandleTable();
- Handle* handles = system.Memory().GetPointer<Handle>(handles_address);
-
- // Copy user handles.
- if (num_handles > 0) {
- // Convert the handles to objects.
- R_UNLESS(handle_table.GetMultipleObjects<KSynchronizationObject>(objs.data(), handles,
- num_handles),
- ResultInvalidHandle);
- for (const auto& obj : objs) {
- kernel.RegisterInUseObject(obj);
- }
- }
+ auto ret_scatter = Convert<std::array<uint32_t, 2>>(ret);
+ SetReg32(system, 0, ret_scatter[0]);
+ SetReg32(system, 1, ret_scatter[1]);
+}
+
+static void SvcWrap_ConnectToNamedPort64From32(Core::System& system) {
+ Result ret{};
+
+ Handle out_handle{};
+ uint32_t name{};
- // Ensure handles are closed when we're done.
- SCOPE_EXIT({
- for (s32 i = 0; i < num_handles; ++i) {
- kernel.UnregisterInUseObject(objs[i]);
- objs[i]->Close();
- }
- });
+ name = Convert<uint32_t>(GetReg32(system, 1));
- return KSynchronizationObject::Wait(kernel, index, objs.data(), static_cast<s32>(objs.size()),
- nano_seconds);
+ ret = ConnectToNamedPort64From32(system, std::addressof(out_handle), name);
+
+ SetReg32(system, 0, Convert<uint32_t>(ret));
+ SetReg32(system, 1, Convert<uint32_t>(out_handle));
}
-static Result WaitSynchronization32(Core::System& system, u32 timeout_low, u32 handles_address,
- 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, num_handles, nano_seconds);
+static void SvcWrap_SendSyncRequest64From32(Core::System& system) {
+ Result ret{};
+
+ Handle session_handle{};
+
+ session_handle = Convert<Handle>(GetReg32(system, 0));
+
+ ret = SendSyncRequest64From32(system, session_handle);
+
+ SetReg32(system, 0, Convert<uint32_t>(ret));
}
-/// Resumes a thread waiting on WaitSynchronization
-static Result CancelSynchronization(Core::System& system, Handle handle) {
- LOG_TRACE(Kernel_SVC, "called handle=0x{:X}", handle);
+static void SvcWrap_SendSyncRequestWithUserBuffer64From32(Core::System& system) {
+ Result ret{};
+
+ uint32_t message_buffer{};
+ uint32_t message_buffer_size{};
+ Handle session_handle{};
+
+ message_buffer = Convert<uint32_t>(GetReg32(system, 0));
+ message_buffer_size = Convert<uint32_t>(GetReg32(system, 1));
+ session_handle = Convert<Handle>(GetReg32(system, 2));
- // Get the thread from its handle.
- KScopedAutoObject thread =
- system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KThread>(handle);
- R_UNLESS(thread.IsNotNull(), ResultInvalidHandle);
+ ret = SendSyncRequestWithUserBuffer64From32(system, message_buffer, message_buffer_size, session_handle);
- // Cancel the thread's wait.
- thread->WaitCancel();
- return ResultSuccess;
+ SetReg32(system, 0, Convert<uint32_t>(ret));
}
-static Result CancelSynchronization32(Core::System& system, Handle handle) {
- return CancelSynchronization(system, handle);
+static void SvcWrap_SendAsyncRequestWithUserBuffer64From32(Core::System& system) {
+ Result ret{};
+
+ Handle out_event_handle{};
+ uint32_t message_buffer{};
+ uint32_t message_buffer_size{};
+ Handle session_handle{};
+
+ message_buffer = Convert<uint32_t>(GetReg32(system, 1));
+ message_buffer_size = Convert<uint32_t>(GetReg32(system, 2));
+ session_handle = Convert<Handle>(GetReg32(system, 3));
+
+ ret = SendAsyncRequestWithUserBuffer64From32(system, std::addressof(out_event_handle), message_buffer, message_buffer_size, session_handle);
+
+ SetReg32(system, 0, Convert<uint32_t>(ret));
+ SetReg32(system, 1, Convert<uint32_t>(out_event_handle));
}
-/// Attempts to locks a mutex
-static Result ArbitrateLock(Core::System& system, Handle thread_handle, VAddr address, u32 tag) {
- LOG_TRACE(Kernel_SVC, "called thread_handle=0x{:08X}, address=0x{:X}, tag=0x{:08X}",
- thread_handle, address, tag);
+static void SvcWrap_GetProcessId64From32(Core::System& system) {
+ Result ret{};
- // Validate the input address.
- if (IsKernelAddress(address)) {
- LOG_ERROR(Kernel_SVC, "Attempting to arbitrate a lock on a kernel address (address={:08X})",
- address);
- return ResultInvalidCurrentMemory;
- }
- if (!Common::IsAligned(address, sizeof(u32))) {
- LOG_ERROR(Kernel_SVC, "Input address must be 4 byte aligned (address: {:08X})", address);
- return ResultInvalidAddress;
- }
+ uint64_t out_process_id{};
+ Handle process_handle{};
+
+ process_handle = Convert<Handle>(GetReg32(system, 1));
+
+ ret = GetProcessId64From32(system, std::addressof(out_process_id), process_handle);
- return system.Kernel().CurrentProcess()->WaitForAddress(thread_handle, address, tag);
+ SetReg32(system, 0, Convert<uint32_t>(ret));
+ auto out_process_id_scatter = Convert<std::array<uint32_t, 2>>(out_process_id);
+ SetReg32(system, 1, out_process_id_scatter[0]);
+ SetReg32(system, 2, out_process_id_scatter[1]);
}
-static Result ArbitrateLock32(Core::System& system, Handle thread_handle, u32 address, u32 tag) {
- return ArbitrateLock(system, thread_handle, address, tag);
+static void SvcWrap_GetThreadId64From32(Core::System& system) {
+ Result ret{};
+
+ uint64_t out_thread_id{};
+ Handle thread_handle{};
+
+ thread_handle = Convert<Handle>(GetReg32(system, 1));
+
+ ret = GetThreadId64From32(system, std::addressof(out_thread_id), thread_handle);
+
+ SetReg32(system, 0, Convert<uint32_t>(ret));
+ auto out_thread_id_scatter = Convert<std::array<uint32_t, 2>>(out_thread_id);
+ SetReg32(system, 1, out_thread_id_scatter[0]);
+ SetReg32(system, 2, out_thread_id_scatter[1]);
}
-/// Unlock a mutex
-static Result ArbitrateUnlock(Core::System& system, VAddr address) {
- LOG_TRACE(Kernel_SVC, "called address=0x{:X}", address);
+static void SvcWrap_Break64From32(Core::System& system) {
+ BreakReason break_reason{};
+ uint32_t arg{};
+ uint32_t size{};
- // Validate the input address.
- if (IsKernelAddress(address)) {
- LOG_ERROR(Kernel_SVC,
- "Attempting to arbitrate an unlock on a kernel address (address={:08X})",
- address);
- return ResultInvalidCurrentMemory;
- }
- if (!Common::IsAligned(address, sizeof(u32))) {
- LOG_ERROR(Kernel_SVC, "Input address must be 4 byte aligned (address: {:08X})", address);
- return ResultInvalidAddress;
- }
+ break_reason = Convert<BreakReason>(GetReg32(system, 0));
+ arg = Convert<uint32_t>(GetReg32(system, 1));
+ size = Convert<uint32_t>(GetReg32(system, 2));
- return system.Kernel().CurrentProcess()->SignalToAddress(address);
-}
-
-static Result ArbitrateUnlock32(Core::System& system, u32 address) {
- return ArbitrateUnlock(system, address);
-}
-
-/// Break program execution
-static void Break(Core::System& system, u32 reason, u64 info1, u64 info2) {
- BreakReason break_reason =
- static_cast<BreakReason>(reason & ~static_cast<u32>(BreakReason::NotificationOnlyFlag));
- bool notification_only = (reason & static_cast<u32>(BreakReason::NotificationOnlyFlag)) != 0;
-
- bool has_dumped_buffer{};
- std::vector<u8> debug_buffer;
-
- const auto handle_debug_buffer = [&](VAddr addr, u64 sz) {
- if (sz == 0 || addr == 0 || has_dumped_buffer) {
- return;
- }
-
- auto& memory = system.Memory();
-
- // This typically is an error code so we're going to assume this is the case
- if (sz == sizeof(u32)) {
- LOG_CRITICAL(Debug_Emulated, "debug_buffer_err_code={:X}", memory.Read32(addr));
- } else {
- // We don't know what's in here so we'll hexdump it
- debug_buffer.resize(sz);
- memory.ReadBlock(addr, debug_buffer.data(), sz);
- std::string hexdump;
- for (std::size_t i = 0; i < debug_buffer.size(); i++) {
- hexdump += fmt::format("{:02X} ", debug_buffer[i]);
- if (i != 0 && i % 16 == 0) {
- hexdump += '\n';
- }
- }
- LOG_CRITICAL(Debug_Emulated, "debug_buffer=\n{}", hexdump);
- }
- has_dumped_buffer = true;
- };
- switch (break_reason) {
- case BreakReason::Panic:
- LOG_CRITICAL(Debug_Emulated, "Userspace PANIC! info1=0x{:016X}, info2=0x{:016X}", info1,
- info2);
- handle_debug_buffer(info1, info2);
- break;
- case BreakReason::Assert:
- LOG_CRITICAL(Debug_Emulated, "Userspace Assertion failed! info1=0x{:016X}, info2=0x{:016X}",
- info1, info2);
- handle_debug_buffer(info1, info2);
- break;
- case BreakReason::User:
- LOG_WARNING(Debug_Emulated, "Userspace Break! 0x{:016X} with size 0x{:016X}", info1, info2);
- handle_debug_buffer(info1, info2);
- break;
- case BreakReason::PreLoadDll:
- LOG_INFO(Debug_Emulated,
- "Userspace Attempting to load an NRO at 0x{:016X} with size 0x{:016X}", info1,
- info2);
- break;
- case BreakReason::PostLoadDll:
- LOG_INFO(Debug_Emulated, "Userspace Loaded an NRO at 0x{:016X} with size 0x{:016X}", info1,
- info2);
- break;
- case BreakReason::PreUnloadDll:
- LOG_INFO(Debug_Emulated,
- "Userspace Attempting to unload an NRO at 0x{:016X} with size 0x{:016X}", info1,
- info2);
- break;
- case BreakReason::PostUnloadDll:
- LOG_INFO(Debug_Emulated, "Userspace Unloaded an NRO at 0x{:016X} with size 0x{:016X}",
- info1, info2);
- break;
- case BreakReason::CppException:
- LOG_CRITICAL(Debug_Emulated, "Signalling debugger. Uncaught C++ exception encountered.");
- break;
- default:
- LOG_WARNING(
- Debug_Emulated,
- "Signalling debugger, Unknown break reason {:#X}, info1=0x{:016X}, info2=0x{:016X}",
- reason, info1, info2);
- handle_debug_buffer(info1, info2);
- break;
- }
+ Break64From32(system, break_reason, arg, size);
+}
- system.GetReporter().SaveSvcBreakReport(reason, notification_only, info1, info2,
- has_dumped_buffer ? std::make_optional(debug_buffer)
- : std::nullopt);
+static void SvcWrap_OutputDebugString64From32(Core::System& system) {
+ Result ret{};
- if (!notification_only) {
- LOG_CRITICAL(
- Debug_Emulated,
- "Emulated program broke execution! reason=0x{:016X}, info1=0x{:016X}, info2=0x{:016X}",
- reason, info1, info2);
+ uint32_t debug_str{};
+ uint32_t len{};
- handle_debug_buffer(info1, info2);
+ debug_str = Convert<uint32_t>(GetReg32(system, 0));
+ len = Convert<uint32_t>(GetReg32(system, 1));
- auto* const current_thread = GetCurrentThreadPointer(system.Kernel());
- const auto thread_processor_id = current_thread->GetActiveCore();
- system.ArmInterface(static_cast<std::size_t>(thread_processor_id)).LogBacktrace();
- }
+ ret = OutputDebugString64From32(system, debug_str, len);
- if (system.DebuggerEnabled()) {
- auto* thread = system.Kernel().GetCurrentEmuThread();
- system.GetDebugger().NotifyThreadStopped(thread);
- thread->RequestSuspend(Kernel::SuspendType::Debug);
- }
+ SetReg32(system, 0, Convert<uint32_t>(ret));
}
-static void Break32(Core::System& system, u32 reason, u32 info1, u32 info2) {
- Break(system, reason, info1, info2);
+static void SvcWrap_ReturnFromException64From32(Core::System& system) {
+ Result result{};
+
+ result = Convert<Result>(GetReg32(system, 0));
+
+ ReturnFromException64From32(system, result);
}
-/// Used to output a message on a debug hardware unit - does nothing on a retail unit
-static void OutputDebugString(Core::System& system, VAddr address, u64 len) {
- if (len == 0) {
- return;
- }
+static void SvcWrap_GetInfo64From32(Core::System& system) {
+ Result ret{};
- std::string str(len, '\0');
- system.Memory().ReadBlock(address, str.data(), str.size());
- LOG_DEBUG(Debug_Emulated, "{}", str);
-}
-
-static void OutputDebugString32(Core::System& system, u32 address, u32 len) {
- OutputDebugString(system, address, len);
-}
-
-/// Gets system/memory information for the current process
-static Result GetInfo(Core::System& system, u64* result, u64 info_id, Handle handle,
- u64 info_sub_id) {
- LOG_TRACE(Kernel_SVC, "called info_id=0x{:X}, info_sub_id=0x{:X}, handle=0x{:08X}", info_id,
- info_sub_id, handle);
-
- const auto info_id_type = static_cast<InfoType>(info_id);
-
- switch (info_id_type) {
- case InfoType::CoreMask:
- case InfoType::PriorityMask:
- case InfoType::AliasRegionAddress:
- case InfoType::AliasRegionSize:
- case InfoType::HeapRegionAddress:
- case InfoType::HeapRegionSize:
- case InfoType::AslrRegionAddress:
- case InfoType::AslrRegionSize:
- case InfoType::StackRegionAddress:
- case InfoType::StackRegionSize:
- case InfoType::TotalMemorySize:
- case InfoType::UsedMemorySize:
- case InfoType::SystemResourceSizeTotal:
- case InfoType::SystemResourceSizeUsed:
- case InfoType::ProgramId:
- case InfoType::UserExceptionContextAddress:
- case InfoType::TotalNonSystemMemorySize:
- case InfoType::UsedNonSystemMemorySize:
- case InfoType::IsApplication:
- case InfoType::FreeThreadCount: {
- if (info_sub_id != 0) {
- LOG_ERROR(Kernel_SVC, "Info sub id is non zero! info_id={}, info_sub_id={}", info_id,
- info_sub_id);
- return ResultInvalidEnumValue;
- }
-
- 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;
- }
-
- switch (info_id_type) {
- case InfoType::CoreMask:
- *result = process->GetCoreMask();
- return ResultSuccess;
-
- case InfoType::PriorityMask:
- *result = process->GetPriorityMask();
- return ResultSuccess;
-
- case InfoType::AliasRegionAddress:
- *result = process->PageTable().GetAliasRegionStart();
- return ResultSuccess;
-
- case InfoType::AliasRegionSize:
- *result = process->PageTable().GetAliasRegionSize();
- return ResultSuccess;
-
- case InfoType::HeapRegionAddress:
- *result = process->PageTable().GetHeapRegionStart();
- return ResultSuccess;
-
- case InfoType::HeapRegionSize:
- *result = process->PageTable().GetHeapRegionSize();
- return ResultSuccess;
-
- case InfoType::AslrRegionAddress:
- *result = process->PageTable().GetAliasCodeRegionStart();
- return ResultSuccess;
-
- case InfoType::AslrRegionSize:
- *result = process->PageTable().GetAliasCodeRegionSize();
- return ResultSuccess;
-
- case InfoType::StackRegionAddress:
- *result = process->PageTable().GetStackRegionStart();
- return ResultSuccess;
-
- case InfoType::StackRegionSize:
- *result = process->PageTable().GetStackRegionSize();
- return ResultSuccess;
-
- case InfoType::TotalMemorySize:
- *result = process->GetTotalPhysicalMemoryAvailable();
- return ResultSuccess;
-
- case InfoType::UsedMemorySize:
- *result = process->GetTotalPhysicalMemoryUsed();
- return ResultSuccess;
-
- case InfoType::SystemResourceSizeTotal:
- *result = process->GetSystemResourceSize();
- return ResultSuccess;
-
- case InfoType::SystemResourceSizeUsed:
- LOG_WARNING(Kernel_SVC, "(STUBBED) Attempted to query system resource usage");
- *result = process->GetSystemResourceUsage();
- return ResultSuccess;
-
- case InfoType::ProgramId:
- *result = process->GetProgramID();
- return ResultSuccess;
-
- case InfoType::UserExceptionContextAddress:
- *result = process->GetProcessLocalRegionAddress();
- return ResultSuccess;
-
- case InfoType::TotalNonSystemMemorySize:
- *result = process->GetTotalPhysicalMemoryAvailableWithoutSystemResource();
- return ResultSuccess;
-
- case InfoType::UsedNonSystemMemorySize:
- *result = process->GetTotalPhysicalMemoryUsedWithoutSystemResource();
- return ResultSuccess;
-
- case InfoType::FreeThreadCount:
- *result = process->GetFreeThreadCount();
- return ResultSuccess;
-
- default:
- break;
- }
-
- LOG_ERROR(Kernel_SVC, "Unimplemented svcGetInfo id=0x{:016X}", info_id);
- return ResultInvalidEnumValue;
- }
+ uint64_t out{};
+ InfoType info_type{};
+ Handle handle{};
+ uint64_t info_subtype{};
- case InfoType::DebuggerAttached:
- *result = 0;
- return ResultSuccess;
-
- case InfoType::ResourceLimit: {
- if (handle != 0) {
- LOG_ERROR(Kernel, "Handle is non zero! handle={:08X}", handle);
- return ResultInvalidHandle;
- }
-
- if (info_sub_id != 0) {
- LOG_ERROR(Kernel, "Info sub id is non zero! info_id={}, info_sub_id={}", info_id,
- info_sub_id);
- return ResultInvalidCombination;
- }
-
- KProcess* const current_process = system.Kernel().CurrentProcess();
- KHandleTable& handle_table = current_process->GetHandleTable();
- const auto resource_limit = current_process->GetResourceLimit();
- if (!resource_limit) {
- *result = Svc::InvalidHandle;
- // Yes, the kernel considers this a successful operation.
- return ResultSuccess;
- }
-
- Handle resource_handle{};
- R_TRY(handle_table.Add(&resource_handle, resource_limit));
-
- *result = resource_handle;
- return ResultSuccess;
- }
+ info_type = Convert<InfoType>(GetReg32(system, 1));
+ handle = Convert<Handle>(GetReg32(system, 2));
+ std::array<uint32_t, 2> info_subtype_gather{};
+ info_subtype_gather[0] = GetReg32(system, 0);
+ info_subtype_gather[1] = GetReg32(system, 3);
+ info_subtype = Convert<uint64_t>(info_subtype_gather);
- case InfoType::RandomEntropy:
- if (handle != 0) {
- LOG_ERROR(Kernel_SVC, "Process Handle is non zero, expected 0 result but got {:016X}",
- handle);
- return ResultInvalidHandle;
- }
-
- if (info_sub_id >= KProcess::RANDOM_ENTROPY_SIZE) {
- LOG_ERROR(Kernel_SVC, "Entropy size is out of range, expected {} but got {}",
- KProcess::RANDOM_ENTROPY_SIZE, info_sub_id);
- return ResultInvalidCombination;
- }
-
- *result = system.Kernel().CurrentProcess()->GetRandomEntropy(info_sub_id);
- return ResultSuccess;
-
- case InfoType::InitialProcessIdRange:
- LOG_WARNING(Kernel_SVC,
- "(STUBBED) Attempted to query privileged process id bounds, returned 0");
- *result = 0;
- return ResultSuccess;
-
- case InfoType::ThreadTickCount: {
- constexpr u64 num_cpus = 4;
- if (info_sub_id != 0xFFFFFFFFFFFFFFFF && info_sub_id >= num_cpus) {
- LOG_ERROR(Kernel_SVC, "Core count is out of range, expected {} but got {}", num_cpus,
- info_sub_id);
- return ResultInvalidCombination;
- }
-
- 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;
- }
-
- const auto& core_timing = system.CoreTiming();
- const auto& scheduler = *system.Kernel().CurrentScheduler();
- const auto* const current_thread = GetCurrentThreadPointer(system.Kernel());
- const bool same_thread = current_thread == thread.GetPointerUnsafe();
-
- const u64 prev_ctx_ticks = scheduler.GetLastContextSwitchTime();
- u64 out_ticks = 0;
- if (same_thread && info_sub_id == 0xFFFFFFFFFFFFFFFF) {
- const u64 thread_ticks = current_thread->GetCpuTime();
-
- out_ticks = thread_ticks + (core_timing.GetCPUTicks() - prev_ctx_ticks);
- } else if (same_thread && info_sub_id == system.Kernel().CurrentPhysicalCoreIndex()) {
- out_ticks = core_timing.GetCPUTicks() - prev_ctx_ticks;
- }
-
- *result = out_ticks;
- return ResultSuccess;
- }
- case InfoType::IdleTickCount: {
- // Verify the input handle is invalid.
- R_UNLESS(handle == InvalidHandle, ResultInvalidHandle);
-
- // Verify the requested core is valid.
- const bool core_valid =
- (info_sub_id == 0xFFFFFFFFFFFFFFFF) ||
- (info_sub_id == static_cast<u64>(system.Kernel().CurrentPhysicalCoreIndex()));
- R_UNLESS(core_valid, ResultInvalidCombination);
-
- // Get the idle tick count.
- *result = system.Kernel().CurrentScheduler()->GetIdleThread()->GetCpuTime();
- return ResultSuccess;
- }
- case InfoType::MesosphereCurrentProcess: {
- // Verify the input handle is invalid.
- R_UNLESS(handle == InvalidHandle, ResultInvalidHandle);
+ ret = GetInfo64From32(system, std::addressof(out), info_type, handle, info_subtype);
- // Verify the sub-type is valid.
- R_UNLESS(info_sub_id == 0, ResultInvalidCombination);
+ SetReg32(system, 0, Convert<uint32_t>(ret));
+ auto out_scatter = Convert<std::array<uint32_t, 2>>(out);
+ SetReg32(system, 1, out_scatter[0]);
+ SetReg32(system, 2, out_scatter[1]);
+}
- // Get the handle table.
- KProcess* current_process = system.Kernel().CurrentProcess();
- KHandleTable& handle_table = current_process->GetHandleTable();
+static void SvcWrap_FlushEntireDataCache64From32(Core::System& system) {
+ FlushEntireDataCache64From32(system);
+}
- // Get a new handle for the current process.
- Handle tmp;
- R_TRY(handle_table.Add(&tmp, current_process));
+static void SvcWrap_FlushDataCache64From32(Core::System& system) {
+ Result ret{};
- // Set the output.
- *result = tmp;
+ uint32_t address{};
+ uint32_t size{};
- // We succeeded.
- return ResultSuccess;
- }
- default:
- LOG_ERROR(Kernel_SVC, "Unimplemented svcGetInfo id=0x{:016X}", info_id);
- return ResultInvalidEnumValue;
- }
+ address = Convert<uint32_t>(GetReg32(system, 0));
+ size = Convert<uint32_t>(GetReg32(system, 1));
+
+ ret = FlushDataCache64From32(system, address, size);
+
+ SetReg32(system, 0, Convert<uint32_t>(ret));
}
-static Result GetInfo32(Core::System& system, u32* result_low, u32* result_high, u32 sub_id_low,
- u32 info_id, u32 handle, u32 sub_id_high) {
- const u64 sub_id{u64{sub_id_low} | (u64{sub_id_high} << 32)};
- u64 res_value{};
+static void SvcWrap_MapPhysicalMemory64From32(Core::System& system) {
+ Result ret{};
+
+ uint32_t address{};
+ uint32_t size{};
- const Result result{GetInfo(system, &res_value, info_id, handle, sub_id)};
- *result_high = static_cast<u32>(res_value >> 32);
- *result_low = static_cast<u32>(res_value & std::numeric_limits<u32>::max());
+ address = Convert<uint32_t>(GetReg32(system, 0));
+ size = Convert<uint32_t>(GetReg32(system, 1));
- return result;
+ ret = MapPhysicalMemory64From32(system, address, size);
+
+ SetReg32(system, 0, Convert<uint32_t>(ret));
}
-/// Maps memory at a desired address
-static Result MapPhysicalMemory(Core::System& system, VAddr addr, u64 size) {
- LOG_DEBUG(Kernel_SVC, "called, addr=0x{:016X}, size=0x{:X}", addr, size);
+static void SvcWrap_UnmapPhysicalMemory64From32(Core::System& system) {
+ Result ret{};
- if (!Common::Is4KBAligned(addr)) {
- LOG_ERROR(Kernel_SVC, "Address is not aligned to 4KB, 0x{:016X}", addr);
- return ResultInvalidAddress;
- }
+ uint32_t address{};
+ uint32_t size{};
- if (!Common::Is4KBAligned(size)) {
- LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, 0x{:X}", size);
- return ResultInvalidSize;
- }
+ address = Convert<uint32_t>(GetReg32(system, 0));
+ size = Convert<uint32_t>(GetReg32(system, 1));
- if (size == 0) {
- LOG_ERROR(Kernel_SVC, "Size is zero");
- return ResultInvalidSize;
- }
+ ret = UnmapPhysicalMemory64From32(system, address, size);
- if (!(addr < addr + size)) {
- LOG_ERROR(Kernel_SVC, "Size causes 64-bit overflow of address");
- return ResultInvalidMemoryRegion;
- }
+ SetReg32(system, 0, Convert<uint32_t>(ret));
+}
- KProcess* const current_process{system.Kernel().CurrentProcess()};
- auto& page_table{current_process->PageTable()};
+static void SvcWrap_GetDebugFutureThreadInfo64From32(Core::System& system) {
+ Result ret{};
- if (current_process->GetSystemResourceSize() == 0) {
- LOG_ERROR(Kernel_SVC, "System Resource Size is zero");
- return ResultInvalidState;
- }
+ ilp32::LastThreadContext out_context{};
+ uint64_t out_thread_id{};
+ Handle debug_handle{};
+ int64_t ns{};
- if (!page_table.IsInsideAddressSpace(addr, size)) {
- LOG_ERROR(Kernel_SVC,
- "Address is not within the address space, addr=0x{:016X}, size=0x{:016X}", addr,
- size);
- return ResultInvalidMemoryRegion;
- }
+ debug_handle = Convert<Handle>(GetReg32(system, 2));
+ std::array<uint32_t, 2> ns_gather{};
+ ns_gather[0] = GetReg32(system, 0);
+ ns_gather[1] = GetReg32(system, 1);
+ ns = Convert<int64_t>(ns_gather);
- 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 ResultInvalidMemoryRegion;
- }
+ ret = GetDebugFutureThreadInfo64From32(system, std::addressof(out_context), std::addressof(out_thread_id), debug_handle, ns);
- return page_table.MapPhysicalMemory(addr, size);
+ SetReg32(system, 0, Convert<uint32_t>(ret));
+ auto out_context_scatter = Convert<std::array<uint32_t, 4>>(out_context);
+ SetReg32(system, 1, out_context_scatter[0]);
+ SetReg32(system, 2, out_context_scatter[1]);
+ SetReg32(system, 3, out_context_scatter[2]);
+ SetReg32(system, 4, out_context_scatter[3]);
+ auto out_thread_id_scatter = Convert<std::array<uint32_t, 2>>(out_thread_id);
+ SetReg32(system, 5, out_thread_id_scatter[0]);
+ SetReg32(system, 6, out_thread_id_scatter[1]);
}
-static Result MapPhysicalMemory32(Core::System& system, u32 addr, u32 size) {
- return MapPhysicalMemory(system, addr, size);
+static void SvcWrap_GetLastThreadInfo64From32(Core::System& system) {
+ Result ret{};
+
+ ilp32::LastThreadContext out_context{};
+ uint64_t out_tls_address{};
+ uint32_t out_flags{};
+
+ ret = GetLastThreadInfo64From32(system, std::addressof(out_context), std::addressof(out_tls_address), std::addressof(out_flags));
+
+ SetReg32(system, 0, Convert<uint32_t>(ret));
+ auto out_context_scatter = Convert<std::array<uint32_t, 4>>(out_context);
+ SetReg32(system, 1, out_context_scatter[0]);
+ SetReg32(system, 2, out_context_scatter[1]);
+ SetReg32(system, 3, out_context_scatter[2]);
+ SetReg32(system, 4, out_context_scatter[3]);
+ SetReg32(system, 5, Convert<uint32_t>(out_tls_address));
+ SetReg32(system, 6, Convert<uint32_t>(out_flags));
}
-/// Unmaps memory previously mapped via MapPhysicalMemory
-static Result UnmapPhysicalMemory(Core::System& system, VAddr addr, u64 size) {
- LOG_DEBUG(Kernel_SVC, "called, addr=0x{:016X}, size=0x{:X}", addr, size);
+static void SvcWrap_GetResourceLimitLimitValue64From32(Core::System& system) {
+ Result ret{};
- if (!Common::Is4KBAligned(addr)) {
- LOG_ERROR(Kernel_SVC, "Address is not aligned to 4KB, 0x{:016X}", addr);
- return ResultInvalidAddress;
- }
+ int64_t out_limit_value{};
+ Handle resource_limit_handle{};
+ LimitableResource which{};
- if (!Common::Is4KBAligned(size)) {
- LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, 0x{:X}", size);
- return ResultInvalidSize;
- }
+ resource_limit_handle = Convert<Handle>(GetReg32(system, 1));
+ which = Convert<LimitableResource>(GetReg32(system, 2));
- if (size == 0) {
- LOG_ERROR(Kernel_SVC, "Size is zero");
- return ResultInvalidSize;
- }
+ ret = GetResourceLimitLimitValue64From32(system, std::addressof(out_limit_value), resource_limit_handle, which);
- if (!(addr < addr + size)) {
- LOG_ERROR(Kernel_SVC, "Size causes 64-bit overflow of address");
- return ResultInvalidMemoryRegion;
- }
+ SetReg32(system, 0, Convert<uint32_t>(ret));
+ auto out_limit_value_scatter = Convert<std::array<uint32_t, 2>>(out_limit_value);
+ SetReg32(system, 1, out_limit_value_scatter[0]);
+ SetReg32(system, 2, out_limit_value_scatter[1]);
+}
- KProcess* const current_process{system.Kernel().CurrentProcess()};
- auto& page_table{current_process->PageTable()};
+static void SvcWrap_GetResourceLimitCurrentValue64From32(Core::System& system) {
+ Result ret{};
- if (current_process->GetSystemResourceSize() == 0) {
- LOG_ERROR(Kernel_SVC, "System Resource Size is zero");
- return ResultInvalidState;
- }
+ int64_t out_current_value{};
+ Handle resource_limit_handle{};
+ LimitableResource which{};
- if (!page_table.IsInsideAddressSpace(addr, size)) {
- LOG_ERROR(Kernel_SVC,
- "Address is not within the address space, addr=0x{:016X}, size=0x{:016X}", addr,
- size);
- return ResultInvalidMemoryRegion;
- }
+ resource_limit_handle = Convert<Handle>(GetReg32(system, 1));
+ which = Convert<LimitableResource>(GetReg32(system, 2));
- 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 ResultInvalidMemoryRegion;
- }
+ ret = GetResourceLimitCurrentValue64From32(system, std::addressof(out_current_value), resource_limit_handle, which);
- return page_table.UnmapPhysicalMemory(addr, size);
+ SetReg32(system, 0, Convert<uint32_t>(ret));
+ auto out_current_value_scatter = Convert<std::array<uint32_t, 2>>(out_current_value);
+ SetReg32(system, 1, out_current_value_scatter[0]);
+ SetReg32(system, 2, out_current_value_scatter[1]);
}
-static Result UnmapPhysicalMemory32(Core::System& system, u32 addr, u32 size) {
- return UnmapPhysicalMemory(system, addr, size);
+static void SvcWrap_SetThreadActivity64From32(Core::System& system) {
+ Result ret{};
+
+ Handle thread_handle{};
+ ThreadActivity thread_activity{};
+
+ thread_handle = Convert<Handle>(GetReg32(system, 0));
+ thread_activity = Convert<ThreadActivity>(GetReg32(system, 1));
+
+ ret = SetThreadActivity64From32(system, thread_handle, thread_activity);
+
+ SetReg32(system, 0, Convert<uint32_t>(ret));
+}
+
+static void SvcWrap_GetThreadContext364From32(Core::System& system) {
+ Result ret{};
+
+ uint32_t out_context{};
+ Handle thread_handle{};
+
+ out_context = Convert<uint32_t>(GetReg32(system, 0));
+ thread_handle = Convert<Handle>(GetReg32(system, 1));
+
+ ret = GetThreadContext364From32(system, out_context, thread_handle);
+
+ SetReg32(system, 0, Convert<uint32_t>(ret));
}
-/// Sets the thread activity
-static Result SetThreadActivity(Core::System& system, Handle thread_handle,
- ThreadActivity thread_activity) {
- LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, activity=0x{:08X}", thread_handle,
- thread_activity);
+static void SvcWrap_WaitForAddress64From32(Core::System& system) {
+ Result ret{};
+
+ uint32_t address{};
+ ArbitrationType arb_type{};
+ int32_t value{};
+ int64_t timeout_ns{};
+
+ address = Convert<uint32_t>(GetReg32(system, 0));
+ arb_type = Convert<ArbitrationType>(GetReg32(system, 1));
+ value = Convert<int32_t>(GetReg32(system, 2));
+ std::array<uint32_t, 2> timeout_ns_gather{};
+ timeout_ns_gather[0] = GetReg32(system, 3);
+ timeout_ns_gather[1] = GetReg32(system, 4);
+ timeout_ns = Convert<int64_t>(timeout_ns_gather);
- // Validate the activity.
- constexpr auto IsValidThreadActivity = [](ThreadActivity activity) {
- return activity == ThreadActivity::Runnable || activity == ThreadActivity::Paused;
- };
- R_UNLESS(IsValidThreadActivity(thread_activity), ResultInvalidEnumValue);
+ ret = WaitForAddress64From32(system, address, arb_type, value, timeout_ns);
- // Get the thread from its handle.
- KScopedAutoObject thread =
- system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KThread>(thread_handle);
- R_UNLESS(thread.IsNotNull(), ResultInvalidHandle);
+ SetReg32(system, 0, Convert<uint32_t>(ret));
+}
+
+static void SvcWrap_SignalToAddress64From32(Core::System& system) {
+ Result ret{};
- // Check that the activity is being set on a non-current thread for the current process.
- R_UNLESS(thread->GetOwnerProcess() == system.Kernel().CurrentProcess(), ResultInvalidHandle);
- R_UNLESS(thread.GetPointerUnsafe() != GetCurrentThreadPointer(system.Kernel()), ResultBusy);
+ uint32_t address{};
+ SignalType signal_type{};
+ int32_t value{};
+ int32_t count{};
- // Set the activity.
- R_TRY(thread->SetActivity(thread_activity));
+ address = Convert<uint32_t>(GetReg32(system, 0));
+ signal_type = Convert<SignalType>(GetReg32(system, 1));
+ value = Convert<int32_t>(GetReg32(system, 2));
+ count = Convert<int32_t>(GetReg32(system, 3));
- return ResultSuccess;
+ ret = SignalToAddress64From32(system, address, signal_type, value, count);
+
+ SetReg32(system, 0, Convert<uint32_t>(ret));
}
-static Result SetThreadActivity32(Core::System& system, Handle thread_handle,
- Svc::ThreadActivity thread_activity) {
- return SetThreadActivity(system, thread_handle, thread_activity);
+static void SvcWrap_SynchronizePreemptionState64From32(Core::System& system) {
+ SynchronizePreemptionState64From32(system);
}
-/// Gets the thread context
-static Result GetThreadContext(Core::System& system, VAddr out_context, Handle thread_handle) {
- LOG_DEBUG(Kernel_SVC, "called, out_context=0x{:08X}, thread_handle=0x{:X}", out_context,
- thread_handle);
+static void SvcWrap_GetResourceLimitPeakValue64From32(Core::System& system) {
+ Result ret{};
- auto& kernel = system.Kernel();
+ int64_t out_peak_value{};
+ Handle resource_limit_handle{};
+ LimitableResource which{};
- // Get the thread from its handle.
- KScopedAutoObject thread =
- kernel.CurrentProcess()->GetHandleTable().GetObject<KThread>(thread_handle);
- R_UNLESS(thread.IsNotNull(), ResultInvalidHandle);
+ resource_limit_handle = Convert<Handle>(GetReg32(system, 1));
+ which = Convert<LimitableResource>(GetReg32(system, 2));
- // Require the handle be to a non-current thread in the current process.
- const auto* current_process = kernel.CurrentProcess();
- R_UNLESS(current_process == thread->GetOwnerProcess(), ResultInvalidId);
+ ret = GetResourceLimitPeakValue64From32(system, std::addressof(out_peak_value), resource_limit_handle, which);
- // Verify that the thread isn't terminated.
- R_UNLESS(thread->GetState() != ThreadState::Terminated, ResultTerminationRequested);
+ SetReg32(system, 0, Convert<uint32_t>(ret));
+ auto out_peak_value_scatter = Convert<std::array<uint32_t, 2>>(out_peak_value);
+ SetReg32(system, 1, out_peak_value_scatter[0]);
+ SetReg32(system, 2, out_peak_value_scatter[1]);
+}
+
+static void SvcWrap_CreateIoPool64From32(Core::System& system) {
+ Result ret{};
- /// 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);
+ Handle out_handle{};
+ IoPoolType which{};
- // Try to get the thread context until the thread isn't current on any core.
- while (true) {
- KScopedSchedulerLock sl{kernel};
+ which = Convert<IoPoolType>(GetReg32(system, 1));
- // TODO(bunnei): Enforce that thread is suspended for debug here.
+ ret = CreateIoPool64From32(system, std::addressof(out_handle), which);
- // 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).GetSchedulerCurrentThread()) {
- current = true;
- break;
- }
- }
+ SetReg32(system, 0, Convert<uint32_t>(ret));
+ SetReg32(system, 1, Convert<uint32_t>(out_handle));
+}
- // If the thread is current, retry until it isn't.
- if (current) {
- continue;
- }
- }
+static void SvcWrap_CreateIoRegion64From32(Core::System& system) {
+ Result ret{};
- // Get the thread context.
- std::vector<u8> context;
- R_TRY(thread->GetThreadContext3(context));
+ Handle out_handle{};
+ Handle io_pool{};
+ uint64_t physical_address{};
+ uint32_t size{};
+ MemoryMapping mapping{};
+ MemoryPermission perm{};
- // Copy the thread context to user space.
- system.Memory().WriteBlock(out_context, context.data(), context.size());
+ io_pool = Convert<Handle>(GetReg32(system, 1));
+ std::array<uint32_t, 2> physical_address_gather{};
+ physical_address_gather[0] = GetReg32(system, 2);
+ physical_address_gather[1] = GetReg32(system, 3);
+ physical_address = Convert<uint64_t>(physical_address_gather);
+ size = Convert<uint32_t>(GetReg32(system, 0));
+ mapping = Convert<MemoryMapping>(GetReg32(system, 4));
+ perm = Convert<MemoryPermission>(GetReg32(system, 5));
- return ResultSuccess;
- }
+ ret = CreateIoRegion64From32(system, std::addressof(out_handle), io_pool, physical_address, size, mapping, perm);
- return ResultSuccess;
+ SetReg32(system, 0, Convert<uint32_t>(ret));
+ SetReg32(system, 1, Convert<uint32_t>(out_handle));
}
-static Result GetThreadContext32(Core::System& system, u32 out_context, Handle thread_handle) {
- return GetThreadContext(system, out_context, thread_handle);
+static void SvcWrap_KernelDebug64From32(Core::System& system) {
+ KernelDebugType kern_debug_type{};
+ uint64_t arg0{};
+ uint64_t arg1{};
+ uint64_t arg2{};
+
+ kern_debug_type = Convert<KernelDebugType>(GetReg32(system, 0));
+ std::array<uint32_t, 2> arg0_gather{};
+ arg0_gather[0] = GetReg32(system, 2);
+ arg0_gather[1] = GetReg32(system, 3);
+ arg0 = Convert<uint64_t>(arg0_gather);
+ std::array<uint32_t, 2> arg1_gather{};
+ arg1_gather[0] = GetReg32(system, 1);
+ arg1_gather[1] = GetReg32(system, 4);
+ arg1 = Convert<uint64_t>(arg1_gather);
+ std::array<uint32_t, 2> arg2_gather{};
+ arg2_gather[0] = GetReg32(system, 5);
+ arg2_gather[1] = GetReg32(system, 6);
+ arg2 = Convert<uint64_t>(arg2_gather);
+
+ KernelDebug64From32(system, kern_debug_type, arg0, arg1, arg2);
}
-/// Gets the priority for the specified thread
-static Result GetThreadPriority(Core::System& system, u32* out_priority, Handle handle) {
- LOG_TRACE(Kernel_SVC, "called");
+static void SvcWrap_ChangeKernelTraceState64From32(Core::System& system) {
+ KernelTraceState kern_trace_state{};
- // Get the thread from its handle.
- KScopedAutoObject thread =
- system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KThread>(handle);
- R_UNLESS(thread.IsNotNull(), ResultInvalidHandle);
+ kern_trace_state = Convert<KernelTraceState>(GetReg32(system, 0));
- // Get the thread's priority.
- *out_priority = thread->GetPriority();
- return ResultSuccess;
+ ChangeKernelTraceState64From32(system, kern_trace_state);
}
-static Result GetThreadPriority32(Core::System& system, u32* out_priority, Handle handle) {
- return GetThreadPriority(system, out_priority, handle);
+static void SvcWrap_CreateSession64From32(Core::System& system) {
+ Result ret{};
+
+ Handle out_server_session_handle{};
+ Handle out_client_session_handle{};
+ bool is_light{};
+ uint32_t name{};
+
+ is_light = Convert<bool>(GetReg32(system, 2));
+ name = Convert<uint32_t>(GetReg32(system, 3));
+
+ ret = CreateSession64From32(system, std::addressof(out_server_session_handle), std::addressof(out_client_session_handle), is_light, name);
+
+ SetReg32(system, 0, Convert<uint32_t>(ret));
+ SetReg32(system, 1, Convert<uint32_t>(out_server_session_handle));
+ SetReg32(system, 2, Convert<uint32_t>(out_client_session_handle));
}
-/// Sets the priority for the specified thread
-static Result SetThreadPriority(Core::System& system, Handle thread_handle, u32 priority) {
- // Get the current process.
- KProcess& process = *system.Kernel().CurrentProcess();
+static void SvcWrap_AcceptSession64From32(Core::System& system) {
+ Result ret{};
+
+ Handle out_handle{};
+ Handle port{};
- // Validate the priority.
- R_UNLESS(HighestThreadPriority <= priority && priority <= LowestThreadPriority,
- ResultInvalidPriority);
- R_UNLESS(process.CheckThreadPriority(priority), ResultInvalidPriority);
+ port = Convert<Handle>(GetReg32(system, 1));
- // Get the thread from its handle.
- KScopedAutoObject thread = process.GetHandleTable().GetObject<KThread>(thread_handle);
- R_UNLESS(thread.IsNotNull(), ResultInvalidHandle);
+ ret = AcceptSession64From32(system, std::addressof(out_handle), port);
- // Set the thread priority.
- thread->SetBasePriority(priority);
- return ResultSuccess;
+ SetReg32(system, 0, Convert<uint32_t>(ret));
+ SetReg32(system, 1, Convert<uint32_t>(out_handle));
}
-static Result SetThreadPriority32(Core::System& system, Handle thread_handle, u32 priority) {
- return SetThreadPriority(system, thread_handle, priority);
+static void SvcWrap_ReplyAndReceive64From32(Core::System& system) {
+ Result ret{};
+
+ int32_t out_index{};
+ uint32_t handles{};
+ int32_t num_handles{};
+ Handle reply_target{};
+ int64_t timeout_ns{};
+
+ handles = Convert<uint32_t>(GetReg32(system, 1));
+ num_handles = Convert<int32_t>(GetReg32(system, 2));
+ reply_target = Convert<Handle>(GetReg32(system, 3));
+ std::array<uint32_t, 2> timeout_ns_gather{};
+ timeout_ns_gather[0] = GetReg32(system, 0);
+ timeout_ns_gather[1] = GetReg32(system, 4);
+ timeout_ns = Convert<int64_t>(timeout_ns_gather);
+
+ ret = ReplyAndReceive64From32(system, std::addressof(out_index), handles, num_handles, reply_target, timeout_ns);
+
+ SetReg32(system, 0, Convert<uint32_t>(ret));
+ SetReg32(system, 1, Convert<uint32_t>(out_index));
}
-/// Get which CPU core is executing the current thread
-static u32 GetCurrentProcessorNumber(Core::System& system) {
- LOG_TRACE(Kernel_SVC, "called");
- return static_cast<u32>(system.CurrentPhysicalCore().CoreIndex());
+static void SvcWrap_ReplyAndReceiveWithUserBuffer64From32(Core::System& system) {
+ Result ret{};
+
+ int32_t out_index{};
+ uint32_t message_buffer{};
+ uint32_t message_buffer_size{};
+ uint32_t handles{};
+ int32_t num_handles{};
+ Handle reply_target{};
+ int64_t timeout_ns{};
+
+ message_buffer = Convert<uint32_t>(GetReg32(system, 1));
+ message_buffer_size = Convert<uint32_t>(GetReg32(system, 2));
+ handles = Convert<uint32_t>(GetReg32(system, 3));
+ num_handles = Convert<int32_t>(GetReg32(system, 0));
+ reply_target = Convert<Handle>(GetReg32(system, 4));
+ std::array<uint32_t, 2> timeout_ns_gather{};
+ timeout_ns_gather[0] = GetReg32(system, 5);
+ timeout_ns_gather[1] = GetReg32(system, 6);
+ timeout_ns = Convert<int64_t>(timeout_ns_gather);
+
+ ret = ReplyAndReceiveWithUserBuffer64From32(system, std::addressof(out_index), message_buffer, message_buffer_size, handles, num_handles, reply_target, timeout_ns);
+
+ SetReg32(system, 0, Convert<uint32_t>(ret));
+ SetReg32(system, 1, Convert<uint32_t>(out_index));
}
-static u32 GetCurrentProcessorNumber32(Core::System& system) {
- return GetCurrentProcessorNumber(system);
+static void SvcWrap_CreateEvent64From32(Core::System& system) {
+ Result ret{};
+
+ Handle out_write_handle{};
+ Handle out_read_handle{};
+
+ ret = CreateEvent64From32(system, std::addressof(out_write_handle), std::addressof(out_read_handle));
+
+ SetReg32(system, 0, Convert<uint32_t>(ret));
+ SetReg32(system, 1, Convert<uint32_t>(out_write_handle));
+ SetReg32(system, 2, Convert<uint32_t>(out_read_handle));
}
-namespace {
+static void SvcWrap_MapIoRegion64From32(Core::System& system) {
+ Result ret{};
-constexpr bool IsValidSharedMemoryPermission(Svc::MemoryPermission perm) {
- switch (perm) {
- case Svc::MemoryPermission::Read:
- case Svc::MemoryPermission::ReadWrite:
- return true;
- default:
- return false;
- }
+ Handle io_region{};
+ uint32_t address{};
+ uint32_t size{};
+ MemoryPermission perm{};
+
+ io_region = Convert<Handle>(GetReg32(system, 0));
+ address = Convert<uint32_t>(GetReg32(system, 1));
+ size = Convert<uint32_t>(GetReg32(system, 2));
+ perm = Convert<MemoryPermission>(GetReg32(system, 3));
+
+ ret = MapIoRegion64From32(system, io_region, address, size, perm);
+
+ SetReg32(system, 0, Convert<uint32_t>(ret));
}
-[[maybe_unused]] constexpr bool IsValidRemoteSharedMemoryPermission(Svc::MemoryPermission perm) {
- return IsValidSharedMemoryPermission(perm) || perm == Svc::MemoryPermission::DontCare;
+static void SvcWrap_UnmapIoRegion64From32(Core::System& system) {
+ Result ret{};
+
+ Handle io_region{};
+ uint32_t address{};
+ uint32_t size{};
+
+ io_region = Convert<Handle>(GetReg32(system, 0));
+ address = Convert<uint32_t>(GetReg32(system, 1));
+ size = Convert<uint32_t>(GetReg32(system, 2));
+
+ ret = UnmapIoRegion64From32(system, io_region, address, size);
+
+ SetReg32(system, 0, Convert<uint32_t>(ret));
}
-constexpr bool IsValidProcessMemoryPermission(Svc::MemoryPermission perm) {
- switch (perm) {
- case Svc::MemoryPermission::None:
- case Svc::MemoryPermission::Read:
- case Svc::MemoryPermission::ReadWrite:
- case Svc::MemoryPermission::ReadExecute:
- return true;
- default:
- return false;
- }
+static void SvcWrap_MapPhysicalMemoryUnsafe64From32(Core::System& system) {
+ Result ret{};
+
+ uint32_t address{};
+ uint32_t size{};
+
+ address = Convert<uint32_t>(GetReg32(system, 0));
+ size = Convert<uint32_t>(GetReg32(system, 1));
+
+ ret = MapPhysicalMemoryUnsafe64From32(system, address, size);
+
+ SetReg32(system, 0, Convert<uint32_t>(ret));
}
-constexpr bool IsValidMapCodeMemoryPermission(Svc::MemoryPermission perm) {
- return perm == Svc::MemoryPermission::ReadWrite;
+static void SvcWrap_UnmapPhysicalMemoryUnsafe64From32(Core::System& system) {
+ Result ret{};
+
+ uint32_t address{};
+ uint32_t size{};
+
+ address = Convert<uint32_t>(GetReg32(system, 0));
+ size = Convert<uint32_t>(GetReg32(system, 1));
+
+ ret = UnmapPhysicalMemoryUnsafe64From32(system, address, size);
+
+ SetReg32(system, 0, Convert<uint32_t>(ret));
}
-constexpr bool IsValidMapToOwnerCodeMemoryPermission(Svc::MemoryPermission perm) {
- return perm == Svc::MemoryPermission::Read || perm == Svc::MemoryPermission::ReadExecute;
+static void SvcWrap_SetUnsafeLimit64From32(Core::System& system) {
+ Result ret{};
+
+ uint32_t limit{};
+
+ limit = Convert<uint32_t>(GetReg32(system, 0));
+
+ ret = SetUnsafeLimit64From32(system, limit);
+
+ SetReg32(system, 0, Convert<uint32_t>(ret));
}
-constexpr bool IsValidUnmapCodeMemoryPermission(Svc::MemoryPermission perm) {
- return perm == Svc::MemoryPermission::None;
+static void SvcWrap_CreateCodeMemory64From32(Core::System& system) {
+ Result ret{};
+
+ Handle out_handle{};
+ uint32_t address{};
+ uint32_t size{};
+
+ address = Convert<uint32_t>(GetReg32(system, 1));
+ size = Convert<uint32_t>(GetReg32(system, 2));
+
+ ret = CreateCodeMemory64From32(system, std::addressof(out_handle), address, size);
+
+ SetReg32(system, 0, Convert<uint32_t>(ret));
+ SetReg32(system, 1, Convert<uint32_t>(out_handle));
}
-constexpr bool IsValidUnmapFromOwnerCodeMemoryPermission(Svc::MemoryPermission perm) {
- return perm == Svc::MemoryPermission::None;
+static void SvcWrap_ControlCodeMemory64From32(Core::System& system) {
+ Result ret{};
+
+ Handle code_memory_handle{};
+ CodeMemoryOperation operation{};
+ uint64_t address{};
+ uint64_t size{};
+ MemoryPermission perm{};
+
+ code_memory_handle = Convert<Handle>(GetReg32(system, 0));
+ operation = Convert<CodeMemoryOperation>(GetReg32(system, 1));
+ std::array<uint32_t, 2> address_gather{};
+ address_gather[0] = GetReg32(system, 2);
+ address_gather[1] = GetReg32(system, 3);
+ address = Convert<uint64_t>(address_gather);
+ std::array<uint32_t, 2> size_gather{};
+ size_gather[0] = GetReg32(system, 4);
+ size_gather[1] = GetReg32(system, 5);
+ size = Convert<uint64_t>(size_gather);
+ perm = Convert<MemoryPermission>(GetReg32(system, 6));
+
+ ret = ControlCodeMemory64From32(system, code_memory_handle, operation, address, size, perm);
+
+ SetReg32(system, 0, Convert<uint32_t>(ret));
}
-} // Anonymous namespace
+static void SvcWrap_SleepSystem64From32(Core::System& system) {
+ SleepSystem64From32(system);
+}
-static Result 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}",
- shmem_handle, address, size, map_perm);
+static void SvcWrap_ReadWriteRegister64From32(Core::System& system) {
+ Result ret{};
- // 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);
+ uint32_t out_value{};
+ uint64_t address{};
+ uint32_t mask{};
+ uint32_t value{};
- // Validate the permission.
- R_UNLESS(IsValidSharedMemoryPermission(map_perm), ResultInvalidNewMemoryPermission);
+ std::array<uint32_t, 2> address_gather{};
+ address_gather[0] = GetReg32(system, 2);
+ address_gather[1] = GetReg32(system, 3);
+ address = Convert<uint64_t>(address_gather);
+ mask = Convert<uint32_t>(GetReg32(system, 0));
+ value = Convert<uint32_t>(GetReg32(system, 1));
- // Get the current process.
- auto& process = *system.Kernel().CurrentProcess();
- auto& page_table = process.PageTable();
+ ret = ReadWriteRegister64From32(system, std::addressof(out_value), address, mask, value);
- // Get the shared memory.
- KScopedAutoObject shmem = process.GetHandleTable().GetObject<KSharedMemory>(shmem_handle);
- R_UNLESS(shmem.IsNotNull(), ResultInvalidHandle);
+ SetReg32(system, 0, Convert<uint32_t>(ret));
+ SetReg32(system, 1, Convert<uint32_t>(out_value));
+}
- // Verify that the mapping is in range.
- R_UNLESS(page_table.CanContain(address, size, KMemoryState::Shared), ResultInvalidMemoryRegion);
+static void SvcWrap_SetProcessActivity64From32(Core::System& system) {
+ Result ret{};
- // Add the shared memory to the process.
- R_TRY(process.AddSharedMemory(shmem.GetPointerUnsafe(), address, size));
+ Handle process_handle{};
+ ProcessActivity process_activity{};
- // Ensure that we clean up the shared memory if we fail to map it.
- auto guard =
- SCOPE_GUARD({ process.RemoveSharedMemory(shmem.GetPointerUnsafe(), address, size); });
+ process_handle = Convert<Handle>(GetReg32(system, 0));
+ process_activity = Convert<ProcessActivity>(GetReg32(system, 1));
- // Map the shared memory.
- R_TRY(shmem->Map(process, address, size, map_perm));
+ ret = SetProcessActivity64From32(system, process_handle, process_activity);
- // We succeeded.
- guard.Cancel();
- return ResultSuccess;
+ SetReg32(system, 0, Convert<uint32_t>(ret));
}
-static Result 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 void SvcWrap_CreateSharedMemory64From32(Core::System& system) {
+ Result ret{};
+
+ Handle out_handle{};
+ uint32_t size{};
+ MemoryPermission owner_perm{};
+ MemoryPermission remote_perm{};
+
+ size = Convert<uint32_t>(GetReg32(system, 1));
+ owner_perm = Convert<MemoryPermission>(GetReg32(system, 2));
+ remote_perm = Convert<MemoryPermission>(GetReg32(system, 3));
+
+ ret = CreateSharedMemory64From32(system, std::addressof(out_handle), size, owner_perm, remote_perm);
+
+ SetReg32(system, 0, Convert<uint32_t>(ret));
+ SetReg32(system, 1, Convert<uint32_t>(out_handle));
}
-static Result 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);
+static void SvcWrap_MapTransferMemory64From32(Core::System& system) {
+ Result ret{};
+
+ Handle trmem_handle{};
+ uint32_t address{};
+ uint32_t size{};
+ MemoryPermission owner_perm{};
- // Get the current process.
- auto& process = *system.Kernel().CurrentProcess();
- auto& page_table = process.PageTable();
+ trmem_handle = Convert<Handle>(GetReg32(system, 0));
+ address = Convert<uint32_t>(GetReg32(system, 1));
+ size = Convert<uint32_t>(GetReg32(system, 2));
+ owner_perm = Convert<MemoryPermission>(GetReg32(system, 3));
- // Get the shared memory.
- KScopedAutoObject shmem = process.GetHandleTable().GetObject<KSharedMemory>(shmem_handle);
- R_UNLESS(shmem.IsNotNull(), ResultInvalidHandle);
+ ret = MapTransferMemory64From32(system, trmem_handle, address, size, owner_perm);
- // Verify that the mapping is in range.
- R_UNLESS(page_table.CanContain(address, size, KMemoryState::Shared), ResultInvalidMemoryRegion);
+ SetReg32(system, 0, Convert<uint32_t>(ret));
+}
+
+static void SvcWrap_UnmapTransferMemory64From32(Core::System& system) {
+ Result ret{};
- // Unmap the shared memory.
- R_TRY(shmem->Unmap(process, address, size));
+ Handle trmem_handle{};
+ uint32_t address{};
+ uint32_t size{};
- // Remove the shared memory from the process.
- process.RemoveSharedMemory(shmem.GetPointerUnsafe(), address, size);
+ trmem_handle = Convert<Handle>(GetReg32(system, 0));
+ address = Convert<uint32_t>(GetReg32(system, 1));
+ size = Convert<uint32_t>(GetReg32(system, 2));
- return ResultSuccess;
+ ret = UnmapTransferMemory64From32(system, trmem_handle, address, size);
+
+ SetReg32(system, 0, Convert<uint32_t>(ret));
}
-static Result UnmapSharedMemory32(Core::System& system, Handle shmem_handle, u32 address,
- u32 size) {
- return UnmapSharedMemory(system, shmem_handle, address, size);
+static void SvcWrap_CreateInterruptEvent64From32(Core::System& system) {
+ Result ret{};
+
+ Handle out_read_handle{};
+ int32_t interrupt_id{};
+ InterruptType interrupt_type{};
+
+ interrupt_id = Convert<int32_t>(GetReg32(system, 1));
+ interrupt_type = Convert<InterruptType>(GetReg32(system, 2));
+
+ ret = CreateInterruptEvent64From32(system, std::addressof(out_read_handle), interrupt_id, interrupt_type);
+
+ SetReg32(system, 0, Convert<uint32_t>(ret));
+ SetReg32(system, 1, Convert<uint32_t>(out_read_handle));
}
-static Result SetProcessMemoryPermission(Core::System& system, Handle process_handle, VAddr address,
- u64 size, Svc::MemoryPermission perm) {
- LOG_TRACE(Kernel_SVC,
- "called, process_handle=0x{:X}, addr=0x{:X}, size=0x{:X}, permissions=0x{:08X}",
- process_handle, address, size, perm);
+static void SvcWrap_QueryPhysicalAddress64From32(Core::System& system) {
+ Result ret{};
- // 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);
- R_UNLESS(address == static_cast<uintptr_t>(address), ResultInvalidCurrentMemory);
- R_UNLESS(size == static_cast<size_t>(size), ResultInvalidCurrentMemory);
+ ilp32::PhysicalMemoryInfo out_info{};
+ uint32_t address{};
- // Validate the memory permission.
- R_UNLESS(IsValidProcessMemoryPermission(perm), ResultInvalidNewMemoryPermission);
+ address = Convert<uint32_t>(GetReg32(system, 1));
- // Get the process from its handle.
- KScopedAutoObject process =
- system.CurrentProcess()->GetHandleTable().GetObject<KProcess>(process_handle);
- R_UNLESS(process.IsNotNull(), ResultInvalidHandle);
+ ret = QueryPhysicalAddress64From32(system, std::addressof(out_info), address);
- // Validate that the address is in range.
- auto& page_table = process->PageTable();
- R_UNLESS(page_table.Contains(address, size), ResultInvalidCurrentMemory);
+ SetReg32(system, 0, Convert<uint32_t>(ret));
+ auto out_info_scatter = Convert<std::array<uint32_t, 4>>(out_info);
+ SetReg32(system, 1, out_info_scatter[0]);
+ SetReg32(system, 2, out_info_scatter[1]);
+ SetReg32(system, 3, out_info_scatter[2]);
+ SetReg32(system, 4, out_info_scatter[3]);
+}
- // Set the memory permission.
- return page_table.SetProcessMemoryPermission(address, size, perm);
+static void SvcWrap_QueryIoMapping64From32(Core::System& system) {
+ Result ret{};
+
+ uint64_t out_address{};
+ uint64_t out_size{};
+ uint64_t physical_address{};
+ uint32_t size{};
+
+ std::array<uint32_t, 2> physical_address_gather{};
+ physical_address_gather[0] = GetReg32(system, 2);
+ physical_address_gather[1] = GetReg32(system, 3);
+ physical_address = Convert<uint64_t>(physical_address_gather);
+ size = Convert<uint32_t>(GetReg32(system, 0));
+
+ ret = QueryIoMapping64From32(system, std::addressof(out_address), std::addressof(out_size), physical_address, size);
+
+ SetReg32(system, 0, Convert<uint32_t>(ret));
+ SetReg32(system, 1, Convert<uint32_t>(out_address));
+ SetReg32(system, 2, Convert<uint32_t>(out_size));
}
-static Result MapProcessMemory(Core::System& system, VAddr dst_address, Handle process_handle,
- VAddr src_address, u64 size) {
- LOG_TRACE(Kernel_SVC,
- "called, dst_address=0x{:X}, process_handle=0x{:X}, src_address=0x{:X}, size=0x{:X}",
- dst_address, process_handle, src_address, size);
+static void SvcWrap_CreateDeviceAddressSpace64From32(Core::System& system) {
+ Result ret{};
- // Validate the address/size.
- R_UNLESS(Common::IsAligned(dst_address, PageSize), ResultInvalidAddress);
- R_UNLESS(Common::IsAligned(src_address, PageSize), ResultInvalidAddress);
- R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize);
- R_UNLESS(size > 0, ResultInvalidSize);
- R_UNLESS((dst_address < dst_address + size), ResultInvalidCurrentMemory);
- R_UNLESS((src_address < src_address + size), ResultInvalidCurrentMemory);
+ Handle out_handle{};
+ uint64_t das_address{};
+ uint64_t das_size{};
- // Get the processes.
- KProcess* dst_process = system.CurrentProcess();
- KScopedAutoObject src_process =
- dst_process->GetHandleTable().GetObjectWithoutPseudoHandle<KProcess>(process_handle);
- R_UNLESS(src_process.IsNotNull(), ResultInvalidHandle);
+ std::array<uint32_t, 2> das_address_gather{};
+ das_address_gather[0] = GetReg32(system, 2);
+ das_address_gather[1] = GetReg32(system, 3);
+ das_address = Convert<uint64_t>(das_address_gather);
+ std::array<uint32_t, 2> das_size_gather{};
+ das_size_gather[0] = GetReg32(system, 0);
+ das_size_gather[1] = GetReg32(system, 1);
+ das_size = Convert<uint64_t>(das_size_gather);
- // Get the page tables.
- auto& dst_pt = dst_process->PageTable();
- auto& src_pt = src_process->PageTable();
+ ret = CreateDeviceAddressSpace64From32(system, std::addressof(out_handle), das_address, das_size);
- // Validate that the mapping is in range.
- R_UNLESS(src_pt.Contains(src_address, size), ResultInvalidCurrentMemory);
- R_UNLESS(dst_pt.CanContain(dst_address, size, KMemoryState::SharedCode),
- ResultInvalidMemoryRegion);
+ SetReg32(system, 0, Convert<uint32_t>(ret));
+ SetReg32(system, 1, Convert<uint32_t>(out_handle));
+}
+
+static void SvcWrap_AttachDeviceAddressSpace64From32(Core::System& system) {
+ Result ret{};
- // Create a new page group.
- KPageGroup pg{system.Kernel(), dst_pt.GetBlockInfoManager()};
- R_TRY(src_pt.MakeAndOpenPageGroup(
- std::addressof(pg), src_address, size / PageSize, KMemoryState::FlagCanMapProcess,
- KMemoryState::FlagCanMapProcess, KMemoryPermission::None, KMemoryPermission::None,
- KMemoryAttribute::All, KMemoryAttribute::None));
+ DeviceName device_name{};
+ Handle das_handle{};
- // Map the group.
- R_TRY(dst_pt.MapPages(dst_address, pg, KMemoryState::SharedCode,
- KMemoryPermission::UserReadWrite));
+ device_name = Convert<DeviceName>(GetReg32(system, 0));
+ das_handle = Convert<Handle>(GetReg32(system, 1));
- return ResultSuccess;
+ ret = AttachDeviceAddressSpace64From32(system, device_name, das_handle);
+
+ SetReg32(system, 0, Convert<uint32_t>(ret));
}
-static Result UnmapProcessMemory(Core::System& system, VAddr dst_address, Handle process_handle,
- VAddr src_address, u64 size) {
- LOG_TRACE(Kernel_SVC,
- "called, dst_address=0x{:X}, process_handle=0x{:X}, src_address=0x{:X}, size=0x{:X}",
- dst_address, process_handle, src_address, size);
+static void SvcWrap_DetachDeviceAddressSpace64From32(Core::System& system) {
+ Result ret{};
- // Validate the address/size.
- R_UNLESS(Common::IsAligned(dst_address, PageSize), ResultInvalidAddress);
- R_UNLESS(Common::IsAligned(src_address, PageSize), ResultInvalidAddress);
- R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize);
- R_UNLESS(size > 0, ResultInvalidSize);
- R_UNLESS((dst_address < dst_address + size), ResultInvalidCurrentMemory);
- R_UNLESS((src_address < src_address + size), ResultInvalidCurrentMemory);
+ DeviceName device_name{};
+ Handle das_handle{};
- // Get the processes.
- KProcess* dst_process = system.CurrentProcess();
- KScopedAutoObject src_process =
- dst_process->GetHandleTable().GetObjectWithoutPseudoHandle<KProcess>(process_handle);
- R_UNLESS(src_process.IsNotNull(), ResultInvalidHandle);
-
- // Get the page tables.
- auto& dst_pt = dst_process->PageTable();
- auto& src_pt = src_process->PageTable();
-
- // Validate that the mapping is in range.
- R_UNLESS(src_pt.Contains(src_address, size), ResultInvalidCurrentMemory);
- R_UNLESS(dst_pt.CanContain(dst_address, size, KMemoryState::SharedCode),
- ResultInvalidMemoryRegion);
-
- // Unmap the memory.
- R_TRY(dst_pt.UnmapProcessMemory(dst_address, size, src_pt, src_address));
-
- return ResultSuccess;
-}
-
-static Result CreateCodeMemory(Core::System& system, Handle* out, VAddr address, size_t size) {
- LOG_TRACE(Kernel_SVC, "called, address=0x{:X}, size=0x{:X}", address, size);
-
- // Get kernel instance.
- auto& kernel = system.Kernel();
+ device_name = Convert<DeviceName>(GetReg32(system, 0));
+ das_handle = Convert<Handle>(GetReg32(system, 1));
- // Validate 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);
+ ret = DetachDeviceAddressSpace64From32(system, device_name, das_handle);
- // Create the code memory.
+ SetReg32(system, 0, Convert<uint32_t>(ret));
+}
+
+static void SvcWrap_MapDeviceAddressSpaceByForce64From32(Core::System& system) {
+ Result ret{};
- KCodeMemory* code_mem = KCodeMemory::Create(kernel);
- R_UNLESS(code_mem != nullptr, ResultOutOfResource);
+ Handle das_handle{};
+ Handle process_handle{};
+ uint64_t process_address{};
+ uint32_t size{};
+ uint64_t device_address{};
+ uint32_t option{};
- // Verify that the region is in range.
- R_UNLESS(system.CurrentProcess()->PageTable().Contains(address, size),
- ResultInvalidCurrentMemory);
+ das_handle = Convert<Handle>(GetReg32(system, 0));
+ process_handle = Convert<Handle>(GetReg32(system, 1));
+ std::array<uint32_t, 2> process_address_gather{};
+ process_address_gather[0] = GetReg32(system, 2);
+ process_address_gather[1] = GetReg32(system, 3);
+ process_address = Convert<uint64_t>(process_address_gather);
+ size = Convert<uint32_t>(GetReg32(system, 4));
+ std::array<uint32_t, 2> device_address_gather{};
+ device_address_gather[0] = GetReg32(system, 5);
+ device_address_gather[1] = GetReg32(system, 6);
+ device_address = Convert<uint64_t>(device_address_gather);
+ option = Convert<uint32_t>(GetReg32(system, 7));
- // Initialize the code memory.
- R_TRY(code_mem->Initialize(system.DeviceMemory(), address, size));
+ ret = MapDeviceAddressSpaceByForce64From32(system, das_handle, process_handle, process_address, size, device_address, option);
+
+ SetReg32(system, 0, Convert<uint32_t>(ret));
+}
- // Register the code memory.
- KCodeMemory::Register(kernel, code_mem);
+static void SvcWrap_MapDeviceAddressSpaceAligned64From32(Core::System& system) {
+ Result ret{};
- // Add the code memory to the handle table.
- R_TRY(system.CurrentProcess()->GetHandleTable().Add(out, code_mem));
+ Handle das_handle{};
+ Handle process_handle{};
+ uint64_t process_address{};
+ uint32_t size{};
+ uint64_t device_address{};
+ uint32_t option{};
- code_mem->Close();
+ das_handle = Convert<Handle>(GetReg32(system, 0));
+ process_handle = Convert<Handle>(GetReg32(system, 1));
+ std::array<uint32_t, 2> process_address_gather{};
+ process_address_gather[0] = GetReg32(system, 2);
+ process_address_gather[1] = GetReg32(system, 3);
+ process_address = Convert<uint64_t>(process_address_gather);
+ size = Convert<uint32_t>(GetReg32(system, 4));
+ std::array<uint32_t, 2> device_address_gather{};
+ device_address_gather[0] = GetReg32(system, 5);
+ device_address_gather[1] = GetReg32(system, 6);
+ device_address = Convert<uint64_t>(device_address_gather);
+ option = Convert<uint32_t>(GetReg32(system, 7));
- return ResultSuccess;
+ ret = MapDeviceAddressSpaceAligned64From32(system, das_handle, process_handle, process_address, size, device_address, option);
+
+ SetReg32(system, 0, Convert<uint32_t>(ret));
}
-static Result CreateCodeMemory32(Core::System& system, Handle* out, u32 address, u32 size) {
- return CreateCodeMemory(system, out, address, size);
+static void SvcWrap_UnmapDeviceAddressSpace64From32(Core::System& system) {
+ Result ret{};
+
+ Handle das_handle{};
+ Handle process_handle{};
+ uint64_t process_address{};
+ uint32_t size{};
+ uint64_t device_address{};
+
+ das_handle = Convert<Handle>(GetReg32(system, 0));
+ process_handle = Convert<Handle>(GetReg32(system, 1));
+ std::array<uint32_t, 2> process_address_gather{};
+ process_address_gather[0] = GetReg32(system, 2);
+ process_address_gather[1] = GetReg32(system, 3);
+ process_address = Convert<uint64_t>(process_address_gather);
+ size = Convert<uint32_t>(GetReg32(system, 4));
+ std::array<uint32_t, 2> device_address_gather{};
+ device_address_gather[0] = GetReg32(system, 5);
+ device_address_gather[1] = GetReg32(system, 6);
+ device_address = Convert<uint64_t>(device_address_gather);
+
+ ret = UnmapDeviceAddressSpace64From32(system, das_handle, process_handle, process_address, size, device_address);
+
+ SetReg32(system, 0, Convert<uint32_t>(ret));
}
-static Result ControlCodeMemory(Core::System& system, Handle code_memory_handle, u32 operation,
- VAddr address, size_t size, Svc::MemoryPermission perm) {
+static void SvcWrap_InvalidateProcessDataCache64From32(Core::System& system) {
+ Result ret{};
- LOG_TRACE(Kernel_SVC,
- "called, code_memory_handle=0x{:X}, operation=0x{:X}, address=0x{:X}, size=0x{:X}, "
- "permission=0x{:X}",
- code_memory_handle, operation, address, size, perm);
+ Handle process_handle{};
+ uint64_t address{};
+ uint64_t 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);
+ process_handle = Convert<Handle>(GetReg32(system, 0));
+ std::array<uint32_t, 2> address_gather{};
+ address_gather[0] = GetReg32(system, 2);
+ address_gather[1] = GetReg32(system, 3);
+ address = Convert<uint64_t>(address_gather);
+ std::array<uint32_t, 2> size_gather{};
+ size_gather[0] = GetReg32(system, 1);
+ size_gather[1] = GetReg32(system, 4);
+ size = Convert<uint64_t>(size_gather);
- // Get the code memory from its handle.
- KScopedAutoObject code_mem =
- system.CurrentProcess()->GetHandleTable().GetObject<KCodeMemory>(code_memory_handle);
- R_UNLESS(code_mem.IsNotNull(), ResultInvalidHandle);
+ ret = InvalidateProcessDataCache64From32(system, process_handle, address, size);
+
+ SetReg32(system, 0, Convert<uint32_t>(ret));
+}
- // NOTE: Here, Atmosphere extends the SVC to allow code memory operations on one's own process.
- // This enables homebrew usage of these SVCs for JIT.
+static void SvcWrap_StoreProcessDataCache64From32(Core::System& system) {
+ Result ret{};
- // Perform the operation.
- switch (static_cast<CodeMemoryOperation>(operation)) {
- case CodeMemoryOperation::Map: {
- // Check that the region is in range.
- R_UNLESS(
- system.CurrentProcess()->PageTable().CanContain(address, size, KMemoryState::CodeOut),
- ResultInvalidMemoryRegion);
+ Handle process_handle{};
+ uint64_t address{};
+ uint64_t size{};
- // Check the memory permission.
- R_UNLESS(IsValidMapCodeMemoryPermission(perm), ResultInvalidNewMemoryPermission);
+ process_handle = Convert<Handle>(GetReg32(system, 0));
+ std::array<uint32_t, 2> address_gather{};
+ address_gather[0] = GetReg32(system, 2);
+ address_gather[1] = GetReg32(system, 3);
+ address = Convert<uint64_t>(address_gather);
+ std::array<uint32_t, 2> size_gather{};
+ size_gather[0] = GetReg32(system, 1);
+ size_gather[1] = GetReg32(system, 4);
+ size = Convert<uint64_t>(size_gather);
- // Map the memory.
- R_TRY(code_mem->Map(address, size));
- } break;
- case CodeMemoryOperation::Unmap: {
- // Check that the region is in range.
- R_UNLESS(
- system.CurrentProcess()->PageTable().CanContain(address, size, KMemoryState::CodeOut),
- ResultInvalidMemoryRegion);
+ ret = StoreProcessDataCache64From32(system, process_handle, address, size);
- // Check the memory permission.
- R_UNLESS(IsValidUnmapCodeMemoryPermission(perm), ResultInvalidNewMemoryPermission);
+ SetReg32(system, 0, Convert<uint32_t>(ret));
+}
- // Unmap the memory.
- R_TRY(code_mem->Unmap(address, size));
- } break;
- case CodeMemoryOperation::MapToOwner: {
- // Check that the region is in range.
- R_UNLESS(code_mem->GetOwner()->PageTable().CanContain(address, size,
- KMemoryState::GeneratedCode),
- ResultInvalidMemoryRegion);
+static void SvcWrap_FlushProcessDataCache64From32(Core::System& system) {
+ Result ret{};
- // Check the memory permission.
- R_UNLESS(IsValidMapToOwnerCodeMemoryPermission(perm), ResultInvalidNewMemoryPermission);
+ Handle process_handle{};
+ uint64_t address{};
+ uint64_t size{};
- // Map the memory to its owner.
- R_TRY(code_mem->MapToOwner(address, size, perm));
- } break;
- case CodeMemoryOperation::UnmapFromOwner: {
- // Check that the region is in range.
- R_UNLESS(code_mem->GetOwner()->PageTable().CanContain(address, size,
- KMemoryState::GeneratedCode),
- ResultInvalidMemoryRegion);
+ process_handle = Convert<Handle>(GetReg32(system, 0));
+ std::array<uint32_t, 2> address_gather{};
+ address_gather[0] = GetReg32(system, 2);
+ address_gather[1] = GetReg32(system, 3);
+ address = Convert<uint64_t>(address_gather);
+ std::array<uint32_t, 2> size_gather{};
+ size_gather[0] = GetReg32(system, 1);
+ size_gather[1] = GetReg32(system, 4);
+ size = Convert<uint64_t>(size_gather);
- // Check the memory permission.
- R_UNLESS(IsValidUnmapFromOwnerCodeMemoryPermission(perm), ResultInvalidNewMemoryPermission);
-
- // Unmap the memory from its owner.
- R_TRY(code_mem->UnmapFromOwner(address, size));
- } break;
- default:
- return ResultInvalidEnumValue;
- }
+ ret = FlushProcessDataCache64From32(system, process_handle, address, size);
- return ResultSuccess;
+ SetReg32(system, 0, Convert<uint32_t>(ret));
}
-static Result ControlCodeMemory32(Core::System& system, Handle code_memory_handle, u32 operation,
- u64 address, u64 size, Svc::MemoryPermission perm) {
- return ControlCodeMemory(system, code_memory_handle, operation, address, size, perm);
+static void SvcWrap_DebugActiveProcess64From32(Core::System& system) {
+ Result ret{};
+
+ Handle out_handle{};
+ uint64_t process_id{};
+
+ std::array<uint32_t, 2> process_id_gather{};
+ process_id_gather[0] = GetReg32(system, 2);
+ process_id_gather[1] = GetReg32(system, 3);
+ process_id = Convert<uint64_t>(process_id_gather);
+
+ ret = DebugActiveProcess64From32(system, std::addressof(out_handle), process_id);
+
+ SetReg32(system, 0, Convert<uint32_t>(ret));
+ SetReg32(system, 1, Convert<uint32_t>(out_handle));
}
-static Result QueryProcessMemory(Core::System& system, VAddr memory_info_address,
- VAddr page_info_address, Handle process_handle, VAddr address) {
- LOG_TRACE(Kernel_SVC, "called process=0x{:08X} address={:X}", process_handle, address);
- const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
- 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;
- }
+static void SvcWrap_BreakDebugProcess64From32(Core::System& system) {
+ Result ret{};
- auto& memory{system.Memory()};
- const auto memory_info{process->PageTable().QueryInfo(address).GetSvcMemoryInfo()};
+ Handle debug_handle{};
- memory.Write64(memory_info_address + 0x00, memory_info.base_address);
- memory.Write64(memory_info_address + 0x08, memory_info.size);
- memory.Write32(memory_info_address + 0x10, static_cast<u32>(memory_info.state) & 0xff);
- memory.Write32(memory_info_address + 0x14, static_cast<u32>(memory_info.attribute));
- memory.Write32(memory_info_address + 0x18, static_cast<u32>(memory_info.permission));
- memory.Write32(memory_info_address + 0x1c, memory_info.ipc_count);
- memory.Write32(memory_info_address + 0x20, memory_info.device_count);
- memory.Write32(memory_info_address + 0x24, 0);
+ debug_handle = Convert<Handle>(GetReg32(system, 0));
- // Page info appears to be currently unused by the kernel and is always set to zero.
- memory.Write32(page_info_address, 0);
+ ret = BreakDebugProcess64From32(system, debug_handle);
- return ResultSuccess;
+ SetReg32(system, 0, Convert<uint32_t>(ret));
}
-static Result QueryMemory(Core::System& system, VAddr memory_info_address, VAddr page_info_address,
- VAddr query_address) {
- LOG_TRACE(Kernel_SVC,
- "called, memory_info_address=0x{:016X}, page_info_address=0x{:016X}, "
- "query_address=0x{:016X}",
- memory_info_address, page_info_address, query_address);
+static void SvcWrap_TerminateDebugProcess64From32(Core::System& system) {
+ Result ret{};
+
+ Handle debug_handle{};
+
+ debug_handle = Convert<Handle>(GetReg32(system, 0));
+
+ ret = TerminateDebugProcess64From32(system, debug_handle);
- return QueryProcessMemory(system, memory_info_address, page_info_address, CurrentProcess,
- query_address);
+ SetReg32(system, 0, Convert<uint32_t>(ret));
}
-static Result QueryMemory32(Core::System& system, u32 memory_info_address, u32 page_info_address,
- u32 query_address) {
- return QueryMemory(system, memory_info_address, page_info_address, query_address);
+static void SvcWrap_GetDebugEvent64From32(Core::System& system) {
+ Result ret{};
+
+ uint32_t out_info{};
+ Handle debug_handle{};
+
+ out_info = Convert<uint32_t>(GetReg32(system, 0));
+ debug_handle = Convert<Handle>(GetReg32(system, 1));
+
+ ret = GetDebugEvent64From32(system, out_info, debug_handle);
+
+ SetReg32(system, 0, Convert<uint32_t>(ret));
}
-static Result MapProcessCodeMemory(Core::System& system, Handle process_handle, u64 dst_address,
- u64 src_address, u64 size) {
- LOG_DEBUG(Kernel_SVC,
- "called. process_handle=0x{:08X}, dst_address=0x{:016X}, "
- "src_address=0x{:016X}, size=0x{:016X}",
- process_handle, dst_address, src_address, size);
+static void SvcWrap_ContinueDebugEvent64From32(Core::System& system) {
+ Result ret{};
- if (!Common::Is4KBAligned(src_address)) {
- LOG_ERROR(Kernel_SVC, "src_address is not page-aligned (src_address=0x{:016X}).",
- src_address);
- return ResultInvalidAddress;
- }
+ Handle debug_handle{};
+ uint32_t flags{};
+ uint32_t thread_ids{};
+ int32_t num_thread_ids{};
- if (!Common::Is4KBAligned(dst_address)) {
- LOG_ERROR(Kernel_SVC, "dst_address is not page-aligned (dst_address=0x{:016X}).",
- dst_address);
- return ResultInvalidAddress;
- }
+ debug_handle = Convert<Handle>(GetReg32(system, 0));
+ flags = Convert<uint32_t>(GetReg32(system, 1));
+ thread_ids = Convert<uint32_t>(GetReg32(system, 2));
+ num_thread_ids = Convert<int32_t>(GetReg32(system, 3));
- if (size == 0 || !Common::Is4KBAligned(size)) {
- LOG_ERROR(Kernel_SVC, "Size is zero or not page-aligned (size=0x{:016X})", size);
- return ResultInvalidSize;
- }
+ ret = ContinueDebugEvent64From32(system, debug_handle, flags, thread_ids, num_thread_ids);
- if (!IsValidAddressRange(dst_address, size)) {
- LOG_ERROR(Kernel_SVC,
- "Destination address range overflows the address space (dst_address=0x{:016X}, "
- "size=0x{:016X}).",
- dst_address, size);
- return ResultInvalidCurrentMemory;
- }
+ SetReg32(system, 0, Convert<uint32_t>(ret));
+}
- if (!IsValidAddressRange(src_address, size)) {
- LOG_ERROR(Kernel_SVC,
- "Source address range overflows the address space (src_address=0x{:016X}, "
- "size=0x{:016X}).",
- src_address, size);
- return ResultInvalidCurrentMemory;
- }
+static void SvcWrap_GetProcessList64From32(Core::System& system) {
+ Result ret{};
- const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
- 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;
- }
+ int32_t out_num_processes{};
+ uint32_t out_process_ids{};
+ int32_t max_out_count{};
- auto& page_table = process->PageTable();
- if (!page_table.IsInsideAddressSpace(src_address, size)) {
- LOG_ERROR(Kernel_SVC,
- "Source address range is not within the address space (src_address=0x{:016X}, "
- "size=0x{:016X}).",
- src_address, size);
- return ResultInvalidCurrentMemory;
- }
+ out_process_ids = Convert<uint32_t>(GetReg32(system, 1));
+ max_out_count = Convert<int32_t>(GetReg32(system, 2));
- if (!page_table.IsInsideASLRRegion(dst_address, size)) {
- LOG_ERROR(Kernel_SVC,
- "Destination address range is not within the ASLR region (dst_address=0x{:016X}, "
- "size=0x{:016X}).",
- dst_address, size);
- return ResultInvalidMemoryRegion;
- }
+ ret = GetProcessList64From32(system, std::addressof(out_num_processes), out_process_ids, max_out_count);
- return page_table.MapCodeMemory(dst_address, src_address, size);
+ SetReg32(system, 0, Convert<uint32_t>(ret));
+ SetReg32(system, 1, Convert<uint32_t>(out_num_processes));
}
-static Result UnmapProcessCodeMemory(Core::System& system, Handle process_handle, u64 dst_address,
- u64 src_address, u64 size) {
- LOG_DEBUG(Kernel_SVC,
- "called. process_handle=0x{:08X}, dst_address=0x{:016X}, src_address=0x{:016X}, "
- "size=0x{:016X}",
- process_handle, dst_address, src_address, size);
+static void SvcWrap_GetThreadList64From32(Core::System& system) {
+ Result ret{};
- if (!Common::Is4KBAligned(dst_address)) {
- LOG_ERROR(Kernel_SVC, "dst_address is not page-aligned (dst_address=0x{:016X}).",
- dst_address);
- return ResultInvalidAddress;
- }
+ int32_t out_num_threads{};
+ uint32_t out_thread_ids{};
+ int32_t max_out_count{};
+ Handle debug_handle{};
- if (!Common::Is4KBAligned(src_address)) {
- LOG_ERROR(Kernel_SVC, "src_address is not page-aligned (src_address=0x{:016X}).",
- src_address);
- return ResultInvalidAddress;
- }
+ out_thread_ids = Convert<uint32_t>(GetReg32(system, 1));
+ max_out_count = Convert<int32_t>(GetReg32(system, 2));
+ debug_handle = Convert<Handle>(GetReg32(system, 3));
- if (size == 0 || !Common::Is4KBAligned(size)) {
- LOG_ERROR(Kernel_SVC, "Size is zero or not page-aligned (size=0x{:016X}).", size);
- return ResultInvalidSize;
- }
+ ret = GetThreadList64From32(system, std::addressof(out_num_threads), out_thread_ids, max_out_count, debug_handle);
- if (!IsValidAddressRange(dst_address, size)) {
- LOG_ERROR(Kernel_SVC,
- "Destination address range overflows the address space (dst_address=0x{:016X}, "
- "size=0x{:016X}).",
- dst_address, size);
- return ResultInvalidCurrentMemory;
- }
+ SetReg32(system, 0, Convert<uint32_t>(ret));
+ SetReg32(system, 1, Convert<uint32_t>(out_num_threads));
+}
- if (!IsValidAddressRange(src_address, size)) {
- LOG_ERROR(Kernel_SVC,
- "Source address range overflows the address space (src_address=0x{:016X}, "
- "size=0x{:016X}).",
- src_address, size);
- return ResultInvalidCurrentMemory;
- }
+static void SvcWrap_GetDebugThreadContext64From32(Core::System& system) {
+ Result ret{};
- const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
- 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;
- }
+ uint32_t out_context{};
+ Handle debug_handle{};
+ uint64_t thread_id{};
+ uint32_t context_flags{};
- auto& page_table = process->PageTable();
- if (!page_table.IsInsideAddressSpace(src_address, size)) {
- LOG_ERROR(Kernel_SVC,
- "Source address range is not within the address space (src_address=0x{:016X}, "
- "size=0x{:016X}).",
- src_address, size);
- return ResultInvalidCurrentMemory;
- }
+ out_context = Convert<uint32_t>(GetReg32(system, 0));
+ debug_handle = Convert<Handle>(GetReg32(system, 1));
+ std::array<uint32_t, 2> thread_id_gather{};
+ thread_id_gather[0] = GetReg32(system, 2);
+ thread_id_gather[1] = GetReg32(system, 3);
+ thread_id = Convert<uint64_t>(thread_id_gather);
+ context_flags = Convert<uint32_t>(GetReg32(system, 4));
- if (!page_table.IsInsideASLRRegion(dst_address, size)) {
- LOG_ERROR(Kernel_SVC,
- "Destination address range is not within the ASLR region (dst_address=0x{:016X}, "
- "size=0x{:016X}).",
- dst_address, size);
- return ResultInvalidMemoryRegion;
- }
+ ret = GetDebugThreadContext64From32(system, out_context, debug_handle, thread_id, context_flags);
- return page_table.UnmapCodeMemory(dst_address, src_address, size,
- KPageTable::ICacheInvalidationStrategy::InvalidateAll);
+ SetReg32(system, 0, Convert<uint32_t>(ret));
}
-/// Exits the current process
-static void ExitProcess(Core::System& system) {
- auto* current_process = system.Kernel().CurrentProcess();
+static void SvcWrap_SetDebugThreadContext64From32(Core::System& system) {
+ Result ret{};
+
+ Handle debug_handle{};
+ uint64_t thread_id{};
+ uint32_t context{};
+ uint32_t context_flags{};
- LOG_INFO(Kernel_SVC, "Process {} exiting", current_process->GetProcessID());
- ASSERT_MSG(current_process->GetState() == KProcess::State::Running,
- "Process has already exited");
+ debug_handle = Convert<Handle>(GetReg32(system, 0));
+ std::array<uint32_t, 2> thread_id_gather{};
+ thread_id_gather[0] = GetReg32(system, 2);
+ thread_id_gather[1] = GetReg32(system, 3);
+ thread_id = Convert<uint64_t>(thread_id_gather);
+ context = Convert<uint32_t>(GetReg32(system, 1));
+ context_flags = Convert<uint32_t>(GetReg32(system, 4));
- system.Exit();
+ ret = SetDebugThreadContext64From32(system, debug_handle, thread_id, context, context_flags);
+
+ SetReg32(system, 0, Convert<uint32_t>(ret));
}
-static void ExitProcess32(Core::System& system) {
- ExitProcess(system);
+static void SvcWrap_QueryDebugProcessMemory64From32(Core::System& system) {
+ Result ret{};
+
+ PageInfo out_page_info{};
+ uint32_t out_memory_info{};
+ Handle process_handle{};
+ uint32_t address{};
+
+ out_memory_info = Convert<uint32_t>(GetReg32(system, 0));
+ process_handle = Convert<Handle>(GetReg32(system, 2));
+ address = Convert<uint32_t>(GetReg32(system, 3));
+
+ ret = QueryDebugProcessMemory64From32(system, out_memory_info, std::addressof(out_page_info), process_handle, address);
+
+ SetReg32(system, 0, Convert<uint32_t>(ret));
+ SetReg32(system, 1, Convert<uint32_t>(out_page_info));
}
-namespace {
+static void SvcWrap_ReadDebugProcessMemory64From32(Core::System& system) {
+ Result ret{};
+
+ uint32_t buffer{};
+ Handle debug_handle{};
+ uint32_t address{};
+ uint32_t size{};
+
+ buffer = Convert<uint32_t>(GetReg32(system, 0));
+ debug_handle = Convert<Handle>(GetReg32(system, 1));
+ address = Convert<uint32_t>(GetReg32(system, 2));
+ size = Convert<uint32_t>(GetReg32(system, 3));
-constexpr bool IsValidVirtualCoreId(int32_t core_id) {
- return (0 <= core_id && core_id < static_cast<int32_t>(Core::Hardware::NUM_CPU_CORES));
+ ret = ReadDebugProcessMemory64From32(system, buffer, debug_handle, address, size);
+
+ SetReg32(system, 0, Convert<uint32_t>(ret));
}
-} // Anonymous namespace
+static void SvcWrap_WriteDebugProcessMemory64From32(Core::System& system) {
+ Result ret{};
-/// Creates a new thread
-static Result CreateThread(Core::System& system, Handle* out_handle, VAddr entry_point, u64 arg,
- VAddr stack_bottom, u32 priority, s32 core_id) {
- LOG_DEBUG(Kernel_SVC,
- "called entry_point=0x{:08X}, arg=0x{:08X}, stack_bottom=0x{:08X}, "
- "priority=0x{:08X}, core_id=0x{:08X}",
- entry_point, arg, stack_bottom, priority, core_id);
+ Handle debug_handle{};
+ uint32_t buffer{};
+ uint32_t address{};
+ uint32_t size{};
- // Adjust core id, if it's the default magic.
- auto& kernel = system.Kernel();
- auto& process = *kernel.CurrentProcess();
- if (core_id == IdealCoreUseProcessValue) {
- core_id = process.GetIdealCoreId();
- }
+ debug_handle = Convert<Handle>(GetReg32(system, 0));
+ buffer = Convert<uint32_t>(GetReg32(system, 1));
+ address = Convert<uint32_t>(GetReg32(system, 2));
+ size = Convert<uint32_t>(GetReg32(system, 3));
- // Validate arguments.
- if (!IsValidVirtualCoreId(core_id)) {
- LOG_ERROR(Kernel_SVC, "Invalid Core ID specified (id={})", core_id);
- return ResultInvalidCoreId;
- }
- if (((1ULL << core_id) & process.GetCoreMask()) == 0) {
- LOG_ERROR(Kernel_SVC, "Core ID doesn't fall within allowable cores (id={})", core_id);
- return ResultInvalidCoreId;
- }
+ ret = WriteDebugProcessMemory64From32(system, debug_handle, buffer, address, size);
- if (HighestThreadPriority > priority || priority > LowestThreadPriority) {
- LOG_ERROR(Kernel_SVC, "Invalid priority specified (priority={})", priority);
- return ResultInvalidPriority;
- }
- if (!process.CheckThreadPriority(priority)) {
- LOG_ERROR(Kernel_SVC, "Invalid allowable thread priority (priority={})", priority);
- return ResultInvalidPriority;
- }
+ SetReg32(system, 0, Convert<uint32_t>(ret));
+}
- // Reserve a new thread from the process resource limit (waiting up to 100ms).
- KScopedResourceReservation thread_reservation(
- kernel.CurrentProcess(), LimitableResource::ThreadCountMax, 1,
- system.CoreTiming().GetGlobalTimeNs().count() + 100000000);
- if (!thread_reservation.Succeeded()) {
- LOG_ERROR(Kernel_SVC, "Could not reserve a new thread");
- return ResultLimitReached;
- }
+static void SvcWrap_SetHardwareBreakPoint64From32(Core::System& system) {
+ Result ret{};
- // 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(); });
+ HardwareBreakPointRegisterName name{};
+ uint64_t flags{};
+ uint64_t value{};
- // Initialize the thread.
- {
- KScopedLightLock lk{process.GetStateLock()};
- R_TRY(KThread::InitializeUserThread(system, thread, entry_point, arg, stack_bottom,
- priority, core_id, &process));
- }
+ name = Convert<HardwareBreakPointRegisterName>(GetReg32(system, 0));
+ std::array<uint32_t, 2> flags_gather{};
+ flags_gather[0] = GetReg32(system, 2);
+ flags_gather[1] = GetReg32(system, 3);
+ flags = Convert<uint64_t>(flags_gather);
+ std::array<uint32_t, 2> value_gather{};
+ value_gather[0] = GetReg32(system, 1);
+ value_gather[1] = GetReg32(system, 4);
+ value = Convert<uint64_t>(value_gather);
- // Set the thread name for debugging purposes.
- thread->SetName(fmt::format("thread[entry_point={:X}, handle={:X}]", entry_point, *out_handle));
+ ret = SetHardwareBreakPoint64From32(system, name, flags, value);
- // Commit the thread reservation.
- thread_reservation.Commit();
+ SetReg32(system, 0, Convert<uint32_t>(ret));
+}
- // Register the new thread.
- KThread::Register(kernel, thread);
+static void SvcWrap_GetDebugThreadParam64From32(Core::System& system) {
+ Result ret{};
- // Add the thread to the handle table.
- R_TRY(process.GetHandleTable().Add(out_handle, thread));
+ uint64_t out_64{};
+ uint32_t out_32{};
+ Handle debug_handle{};
+ uint64_t thread_id{};
+ DebugThreadParam param{};
- return ResultSuccess;
+ debug_handle = Convert<Handle>(GetReg32(system, 2));
+ std::array<uint32_t, 2> thread_id_gather{};
+ thread_id_gather[0] = GetReg32(system, 0);
+ thread_id_gather[1] = GetReg32(system, 1);
+ thread_id = Convert<uint64_t>(thread_id_gather);
+ param = Convert<DebugThreadParam>(GetReg32(system, 3));
+
+ ret = GetDebugThreadParam64From32(system, std::addressof(out_64), std::addressof(out_32), debug_handle, thread_id, param);
+
+ SetReg32(system, 0, Convert<uint32_t>(ret));
+ auto out_64_scatter = Convert<std::array<uint32_t, 2>>(out_64);
+ SetReg32(system, 1, out_64_scatter[0]);
+ SetReg32(system, 2, out_64_scatter[1]);
+ SetReg32(system, 3, Convert<uint32_t>(out_32));
}
-static Result CreateThread32(Core::System& system, Handle* out_handle, u32 priority,
- u32 entry_point, u32 arg, u32 stack_top, s32 processor_id) {
- return CreateThread(system, out_handle, entry_point, arg, stack_top, priority, processor_id);
+static void SvcWrap_GetSystemInfo64From32(Core::System& system) {
+ Result ret{};
+
+ uint64_t out{};
+ SystemInfoType info_type{};
+ Handle handle{};
+ uint64_t info_subtype{};
+
+ info_type = Convert<SystemInfoType>(GetReg32(system, 1));
+ handle = Convert<Handle>(GetReg32(system, 2));
+ std::array<uint32_t, 2> info_subtype_gather{};
+ info_subtype_gather[0] = GetReg32(system, 0);
+ info_subtype_gather[1] = GetReg32(system, 3);
+ info_subtype = Convert<uint64_t>(info_subtype_gather);
+
+ ret = GetSystemInfo64From32(system, std::addressof(out), info_type, handle, info_subtype);
+
+ SetReg32(system, 0, Convert<uint32_t>(ret));
+ auto out_scatter = Convert<std::array<uint32_t, 2>>(out);
+ SetReg32(system, 1, out_scatter[0]);
+ SetReg32(system, 2, out_scatter[1]);
}
-/// Starts the thread for the provided handle
-static Result StartThread(Core::System& system, Handle thread_handle) {
- LOG_DEBUG(Kernel_SVC, "called thread=0x{:08X}", thread_handle);
+static void SvcWrap_CreatePort64From32(Core::System& system) {
+ Result ret{};
- // Get the thread from its handle.
- KScopedAutoObject thread =
- system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KThread>(thread_handle);
- R_UNLESS(thread.IsNotNull(), ResultInvalidHandle);
+ Handle out_server_handle{};
+ Handle out_client_handle{};
+ int32_t max_sessions{};
+ bool is_light{};
+ uint32_t name{};
- // Try to start the thread.
- R_TRY(thread->Run());
+ max_sessions = Convert<int32_t>(GetReg32(system, 2));
+ is_light = Convert<bool>(GetReg32(system, 3));
+ name = Convert<uint32_t>(GetReg32(system, 0));
- // If we succeeded, persist a reference to the thread.
- thread->Open();
- system.Kernel().RegisterInUseObject(thread.GetPointerUnsafe());
+ ret = CreatePort64From32(system, std::addressof(out_server_handle), std::addressof(out_client_handle), max_sessions, is_light, name);
- return ResultSuccess;
+ SetReg32(system, 0, Convert<uint32_t>(ret));
+ SetReg32(system, 1, Convert<uint32_t>(out_server_handle));
+ SetReg32(system, 2, Convert<uint32_t>(out_client_handle));
}
-static Result StartThread32(Core::System& system, Handle thread_handle) {
- return StartThread(system, thread_handle);
+static void SvcWrap_ManageNamedPort64From32(Core::System& system) {
+ Result ret{};
+
+ Handle out_server_handle{};
+ uint32_t name{};
+ int32_t max_sessions{};
+
+ name = Convert<uint32_t>(GetReg32(system, 1));
+ max_sessions = Convert<int32_t>(GetReg32(system, 2));
+
+ ret = ManageNamedPort64From32(system, std::addressof(out_server_handle), name, max_sessions);
+
+ SetReg32(system, 0, Convert<uint32_t>(ret));
+ SetReg32(system, 1, Convert<uint32_t>(out_server_handle));
}
-/// Called when a thread exits
-static void ExitThread(Core::System& system) {
- LOG_DEBUG(Kernel_SVC, "called, pc=0x{:08X}", system.CurrentArmInterface().GetPC());
+static void SvcWrap_ConnectToPort64From32(Core::System& system) {
+ Result ret{};
+
+ Handle out_handle{};
+ Handle port{};
- auto* const current_thread = GetCurrentThreadPointer(system.Kernel());
- system.GlobalSchedulerContext().RemoveThread(current_thread);
- current_thread->Exit();
- system.Kernel().UnregisterInUseObject(current_thread);
+ port = Convert<Handle>(GetReg32(system, 1));
+
+ ret = ConnectToPort64From32(system, std::addressof(out_handle), port);
+
+ SetReg32(system, 0, Convert<uint32_t>(ret));
+ SetReg32(system, 1, Convert<uint32_t>(out_handle));
}
-static void ExitThread32(Core::System& system) {
- ExitThread(system);
+static void SvcWrap_SetProcessMemoryPermission64From32(Core::System& system) {
+ Result ret{};
+
+ Handle process_handle{};
+ uint64_t address{};
+ uint64_t size{};
+ MemoryPermission perm{};
+
+ process_handle = Convert<Handle>(GetReg32(system, 0));
+ std::array<uint32_t, 2> address_gather{};
+ address_gather[0] = GetReg32(system, 2);
+ address_gather[1] = GetReg32(system, 3);
+ address = Convert<uint64_t>(address_gather);
+ std::array<uint32_t, 2> size_gather{};
+ size_gather[0] = GetReg32(system, 1);
+ size_gather[1] = GetReg32(system, 4);
+ size = Convert<uint64_t>(size_gather);
+ perm = Convert<MemoryPermission>(GetReg32(system, 5));
+
+ ret = SetProcessMemoryPermission64From32(system, process_handle, address, size, perm);
+
+ SetReg32(system, 0, Convert<uint32_t>(ret));
}
-/// Sleep the current thread
-static void SleepThread(Core::System& system, s64 nanoseconds) {
- auto& kernel = system.Kernel();
- const auto yield_type = static_cast<Svc::YieldType>(nanoseconds);
-
- LOG_TRACE(Kernel_SVC, "called nanoseconds={}", nanoseconds);
-
- // When the input tick is positive, sleep.
- if (nanoseconds > 0) {
- // Convert the timeout from nanoseconds to ticks.
- // NOTE: Nintendo does not use this conversion logic in WaitSynchronization...
-
- // Sleep.
- // NOTE: Nintendo does not check the result of this sleep.
- static_cast<void>(GetCurrentThread(kernel).Sleep(nanoseconds));
- } else if (yield_type == Svc::YieldType::WithoutCoreMigration) {
- KScheduler::YieldWithoutCoreMigration(kernel);
- } else if (yield_type == Svc::YieldType::WithCoreMigration) {
- KScheduler::YieldWithCoreMigration(kernel);
- } else if (yield_type == Svc::YieldType::ToAnyThread) {
- KScheduler::YieldToAnyThread(kernel);
- } else {
- // Nintendo does nothing at all if an otherwise invalid value is passed.
- ASSERT_MSG(false, "Unimplemented sleep yield type '{:016X}'!", nanoseconds);
- }
+static void SvcWrap_MapProcessMemory64From32(Core::System& system) {
+ Result ret{};
+
+ uint32_t dst_address{};
+ Handle process_handle{};
+ uint64_t src_address{};
+ uint32_t size{};
+
+ dst_address = Convert<uint32_t>(GetReg32(system, 0));
+ process_handle = Convert<Handle>(GetReg32(system, 1));
+ std::array<uint32_t, 2> src_address_gather{};
+ src_address_gather[0] = GetReg32(system, 2);
+ src_address_gather[1] = GetReg32(system, 3);
+ src_address = Convert<uint64_t>(src_address_gather);
+ size = Convert<uint32_t>(GetReg32(system, 4));
+
+ ret = MapProcessMemory64From32(system, dst_address, process_handle, src_address, size);
+
+ SetReg32(system, 0, Convert<uint32_t>(ret));
}
-static void SleepThread32(Core::System& system, u32 nanoseconds_low, u32 nanoseconds_high) {
- const auto nanoseconds = static_cast<s64>(u64{nanoseconds_low} | (u64{nanoseconds_high} << 32));
- SleepThread(system, nanoseconds);
+static void SvcWrap_UnmapProcessMemory64From32(Core::System& system) {
+ Result ret{};
+
+ uint32_t dst_address{};
+ Handle process_handle{};
+ uint64_t src_address{};
+ uint32_t size{};
+
+ dst_address = Convert<uint32_t>(GetReg32(system, 0));
+ process_handle = Convert<Handle>(GetReg32(system, 1));
+ std::array<uint32_t, 2> src_address_gather{};
+ src_address_gather[0] = GetReg32(system, 2);
+ src_address_gather[1] = GetReg32(system, 3);
+ src_address = Convert<uint64_t>(src_address_gather);
+ size = Convert<uint32_t>(GetReg32(system, 4));
+
+ ret = UnmapProcessMemory64From32(system, dst_address, process_handle, src_address, size);
+
+ SetReg32(system, 0, Convert<uint32_t>(ret));
}
-/// Wait process wide key atomic
-static Result WaitProcessWideKeyAtomic(Core::System& system, VAddr address, VAddr cv_key, u32 tag,
- s64 timeout_ns) {
- LOG_TRACE(Kernel_SVC, "called address={:X}, cv_key={:X}, tag=0x{:08X}, timeout_ns={}", address,
- cv_key, tag, timeout_ns);
+static void SvcWrap_QueryProcessMemory64From32(Core::System& system) {
+ Result ret{};
- // Validate input.
- if (IsKernelAddress(address)) {
- LOG_ERROR(Kernel_SVC, "Attempted to wait on kernel address (address={:08X})", address);
- return ResultInvalidCurrentMemory;
- }
- if (!Common::IsAligned(address, sizeof(s32))) {
- LOG_ERROR(Kernel_SVC, "Address must be 4 byte aligned (address={:08X})", address);
- return ResultInvalidAddress;
- }
+ PageInfo out_page_info{};
+ uint32_t out_memory_info{};
+ Handle process_handle{};
+ uint64_t address{};
- // Convert timeout from nanoseconds to ticks.
- s64 timeout{};
- if (timeout_ns > 0) {
- const s64 offset_tick(timeout_ns);
- if (offset_tick > 0) {
- timeout = offset_tick + 2;
- if (timeout <= 0) {
- timeout = std::numeric_limits<s64>::max();
- }
- } else {
- timeout = std::numeric_limits<s64>::max();
- }
- } else {
- timeout = timeout_ns;
- }
+ out_memory_info = Convert<uint32_t>(GetReg32(system, 0));
+ process_handle = Convert<Handle>(GetReg32(system, 2));
+ std::array<uint32_t, 2> address_gather{};
+ address_gather[0] = GetReg32(system, 1);
+ address_gather[1] = GetReg32(system, 3);
+ address = Convert<uint64_t>(address_gather);
+
+ ret = QueryProcessMemory64From32(system, out_memory_info, std::addressof(out_page_info), process_handle, address);
- // Wait on the condition variable.
- return system.Kernel().CurrentProcess()->WaitConditionVariable(
- address, Common::AlignDown(cv_key, sizeof(u32)), tag, timeout);
+ SetReg32(system, 0, Convert<uint32_t>(ret));
+ SetReg32(system, 1, Convert<uint32_t>(out_page_info));
}
-static Result WaitProcessWideKeyAtomic32(Core::System& system, u32 address, u32 cv_key, u32 tag,
- u32 timeout_ns_low, u32 timeout_ns_high) {
- const auto timeout_ns = static_cast<s64>(timeout_ns_low | (u64{timeout_ns_high} << 32));
- return WaitProcessWideKeyAtomic(system, address, cv_key, tag, timeout_ns);
+static void SvcWrap_MapProcessCodeMemory64From32(Core::System& system) {
+ Result ret{};
+
+ Handle process_handle{};
+ uint64_t dst_address{};
+ uint64_t src_address{};
+ uint64_t size{};
+
+ process_handle = Convert<Handle>(GetReg32(system, 0));
+ std::array<uint32_t, 2> dst_address_gather{};
+ dst_address_gather[0] = GetReg32(system, 2);
+ dst_address_gather[1] = GetReg32(system, 3);
+ dst_address = Convert<uint64_t>(dst_address_gather);
+ std::array<uint32_t, 2> src_address_gather{};
+ src_address_gather[0] = GetReg32(system, 1);
+ src_address_gather[1] = GetReg32(system, 4);
+ src_address = Convert<uint64_t>(src_address_gather);
+ std::array<uint32_t, 2> size_gather{};
+ size_gather[0] = GetReg32(system, 5);
+ size_gather[1] = GetReg32(system, 6);
+ size = Convert<uint64_t>(size_gather);
+
+ ret = MapProcessCodeMemory64From32(system, process_handle, dst_address, src_address, size);
+
+ SetReg32(system, 0, Convert<uint32_t>(ret));
}
-/// Signal process wide key
-static void SignalProcessWideKey(Core::System& system, VAddr cv_key, s32 count) {
- LOG_TRACE(Kernel_SVC, "called, cv_key=0x{:X}, count=0x{:08X}", cv_key, count);
+static void SvcWrap_UnmapProcessCodeMemory64From32(Core::System& system) {
+ Result ret{};
- // Signal the condition variable.
- return system.Kernel().CurrentProcess()->SignalConditionVariable(
- Common::AlignDown(cv_key, sizeof(u32)), count);
+ Handle process_handle{};
+ uint64_t dst_address{};
+ uint64_t src_address{};
+ uint64_t size{};
+
+ process_handle = Convert<Handle>(GetReg32(system, 0));
+ std::array<uint32_t, 2> dst_address_gather{};
+ dst_address_gather[0] = GetReg32(system, 2);
+ dst_address_gather[1] = GetReg32(system, 3);
+ dst_address = Convert<uint64_t>(dst_address_gather);
+ std::array<uint32_t, 2> src_address_gather{};
+ src_address_gather[0] = GetReg32(system, 1);
+ src_address_gather[1] = GetReg32(system, 4);
+ src_address = Convert<uint64_t>(src_address_gather);
+ std::array<uint32_t, 2> size_gather{};
+ size_gather[0] = GetReg32(system, 5);
+ size_gather[1] = GetReg32(system, 6);
+ size = Convert<uint64_t>(size_gather);
+
+ ret = UnmapProcessCodeMemory64From32(system, process_handle, dst_address, src_address, size);
+
+ SetReg32(system, 0, Convert<uint32_t>(ret));
}
-static void SignalProcessWideKey32(Core::System& system, u32 cv_key, s32 count) {
- SignalProcessWideKey(system, cv_key, count);
+static void SvcWrap_CreateProcess64From32(Core::System& system) {
+ Result ret{};
+
+ Handle out_handle{};
+ uint32_t parameters{};
+ uint32_t caps{};
+ int32_t num_caps{};
+
+ parameters = Convert<uint32_t>(GetReg32(system, 1));
+ caps = Convert<uint32_t>(GetReg32(system, 2));
+ num_caps = Convert<int32_t>(GetReg32(system, 3));
+
+ ret = CreateProcess64From32(system, std::addressof(out_handle), parameters, caps, num_caps);
+
+ SetReg32(system, 0, Convert<uint32_t>(ret));
+ SetReg32(system, 1, Convert<uint32_t>(out_handle));
}
-namespace {
+static void SvcWrap_StartProcess64From32(Core::System& system) {
+ Result ret{};
-constexpr bool IsValidSignalType(Svc::SignalType type) {
- switch (type) {
- case Svc::SignalType::Signal:
- case Svc::SignalType::SignalAndIncrementIfEqual:
- case Svc::SignalType::SignalAndModifyByWaitingCountIfEqual:
- return true;
- default:
- return false;
- }
+ Handle process_handle{};
+ int32_t priority{};
+ int32_t core_id{};
+ uint64_t main_thread_stack_size{};
+
+ process_handle = Convert<Handle>(GetReg32(system, 0));
+ priority = Convert<int32_t>(GetReg32(system, 1));
+ core_id = Convert<int32_t>(GetReg32(system, 2));
+ std::array<uint32_t, 2> main_thread_stack_size_gather{};
+ main_thread_stack_size_gather[0] = GetReg32(system, 3);
+ main_thread_stack_size_gather[1] = GetReg32(system, 4);
+ main_thread_stack_size = Convert<uint64_t>(main_thread_stack_size_gather);
+
+ ret = StartProcess64From32(system, process_handle, priority, core_id, main_thread_stack_size);
+
+ SetReg32(system, 0, Convert<uint32_t>(ret));
}
-constexpr bool IsValidArbitrationType(Svc::ArbitrationType type) {
- switch (type) {
- case Svc::ArbitrationType::WaitIfLessThan:
- case Svc::ArbitrationType::DecrementAndWaitIfLessThan:
- case Svc::ArbitrationType::WaitIfEqual:
- return true;
- default:
- return false;
- }
+static void SvcWrap_TerminateProcess64From32(Core::System& system) {
+ Result ret{};
+
+ Handle process_handle{};
+
+ process_handle = Convert<Handle>(GetReg32(system, 0));
+
+ ret = TerminateProcess64From32(system, process_handle);
+
+ SetReg32(system, 0, Convert<uint32_t>(ret));
}
-} // namespace
+static void SvcWrap_GetProcessInfo64From32(Core::System& system) {
+ Result ret{};
-// Wait for an address (via Address Arbiter)
-static Result WaitForAddress(Core::System& system, VAddr address, Svc::ArbitrationType arb_type,
- s32 value, s64 timeout_ns) {
- LOG_TRACE(Kernel_SVC, "called, address=0x{:X}, arb_type=0x{:X}, value=0x{:X}, timeout_ns={}",
- address, arb_type, value, timeout_ns);
+ int64_t out_info{};
+ Handle process_handle{};
+ ProcessInfoType info_type{};
- // Validate input.
- if (IsKernelAddress(address)) {
- LOG_ERROR(Kernel_SVC, "Attempting to wait on kernel address (address={:08X})", address);
- return ResultInvalidCurrentMemory;
- }
- if (!Common::IsAligned(address, sizeof(s32))) {
- LOG_ERROR(Kernel_SVC, "Wait address must be 4 byte aligned (address={:08X})", address);
- return ResultInvalidAddress;
- }
- if (!IsValidArbitrationType(arb_type)) {
- LOG_ERROR(Kernel_SVC, "Invalid arbitration type specified (type={})", arb_type);
- return ResultInvalidEnumValue;
- }
+ process_handle = Convert<Handle>(GetReg32(system, 1));
+ info_type = Convert<ProcessInfoType>(GetReg32(system, 2));
- // Convert timeout from nanoseconds to ticks.
- s64 timeout{};
- if (timeout_ns > 0) {
- const s64 offset_tick(timeout_ns);
- if (offset_tick > 0) {
- timeout = offset_tick + 2;
- if (timeout <= 0) {
- timeout = std::numeric_limits<s64>::max();
- }
- } else {
- timeout = std::numeric_limits<s64>::max();
- }
- } else {
- timeout = timeout_ns;
- }
+ ret = GetProcessInfo64From32(system, std::addressof(out_info), process_handle, info_type);
+
+ SetReg32(system, 0, Convert<uint32_t>(ret));
+ auto out_info_scatter = Convert<std::array<uint32_t, 2>>(out_info);
+ SetReg32(system, 1, out_info_scatter[0]);
+ SetReg32(system, 2, out_info_scatter[1]);
+}
+
+static void SvcWrap_CreateResourceLimit64From32(Core::System& system) {
+ Result ret{};
- return system.Kernel().CurrentProcess()->WaitAddressArbiter(address, arb_type, value, timeout);
+ Handle out_handle{};
+
+ ret = CreateResourceLimit64From32(system, std::addressof(out_handle));
+
+ SetReg32(system, 0, Convert<uint32_t>(ret));
+ SetReg32(system, 1, Convert<uint32_t>(out_handle));
}
-static Result WaitForAddress32(Core::System& system, u32 address, Svc::ArbitrationType arb_type,
- s32 value, u32 timeout_ns_low, u32 timeout_ns_high) {
- const auto timeout = static_cast<s64>(timeout_ns_low | (u64{timeout_ns_high} << 32));
- return WaitForAddress(system, address, arb_type, value, timeout);
+static void SvcWrap_SetResourceLimitLimitValue64From32(Core::System& system) {
+ Result ret{};
+
+ Handle resource_limit_handle{};
+ LimitableResource which{};
+ int64_t limit_value{};
+
+ resource_limit_handle = Convert<Handle>(GetReg32(system, 0));
+ which = Convert<LimitableResource>(GetReg32(system, 1));
+ std::array<uint32_t, 2> limit_value_gather{};
+ limit_value_gather[0] = GetReg32(system, 2);
+ limit_value_gather[1] = GetReg32(system, 3);
+ limit_value = Convert<int64_t>(limit_value_gather);
+
+ ret = SetResourceLimitLimitValue64From32(system, resource_limit_handle, which, limit_value);
+
+ SetReg32(system, 0, Convert<uint32_t>(ret));
}
-// Signals to an address (via Address Arbiter)
-static Result SignalToAddress(Core::System& system, VAddr address, Svc::SignalType signal_type,
- s32 value, s32 count) {
- LOG_TRACE(Kernel_SVC, "called, address=0x{:X}, signal_type=0x{:X}, value=0x{:X}, count=0x{:X}",
- address, signal_type, value, count);
+static void SvcWrap_MapInsecureMemory64From32(Core::System& system) {
+ Result ret{};
- // Validate input.
- if (IsKernelAddress(address)) {
- LOG_ERROR(Kernel_SVC, "Attempting to signal to a kernel address (address={:08X})", address);
- return ResultInvalidCurrentMemory;
- }
- if (!Common::IsAligned(address, sizeof(s32))) {
- LOG_ERROR(Kernel_SVC, "Signaled address must be 4 byte aligned (address={:08X})", address);
- return ResultInvalidAddress;
- }
- if (!IsValidSignalType(signal_type)) {
- LOG_ERROR(Kernel_SVC, "Invalid signal type specified (type={})", signal_type);
- return ResultInvalidEnumValue;
- }
+ uint32_t address{};
+ uint32_t size{};
+
+ address = Convert<uint32_t>(GetReg32(system, 0));
+ size = Convert<uint32_t>(GetReg32(system, 1));
- return system.Kernel().CurrentProcess()->SignalAddressArbiter(address, signal_type, value,
- count);
+ ret = MapInsecureMemory64From32(system, address, size);
+
+ SetReg32(system, 0, Convert<uint32_t>(ret));
}
-static void SynchronizePreemptionState(Core::System& system) {
- auto& kernel = system.Kernel();
+static void SvcWrap_UnmapInsecureMemory64From32(Core::System& system) {
+ Result ret{};
- // Lock the scheduler.
- KScopedSchedulerLock sl{kernel};
+ uint32_t address{};
+ uint32_t size{};
- // If the current thread is pinned, unpin it.
- KProcess* cur_process = system.Kernel().CurrentProcess();
- const auto core_id = GetCurrentCoreId(kernel);
+ address = Convert<uint32_t>(GetReg32(system, 0));
+ size = Convert<uint32_t>(GetReg32(system, 1));
- if (cur_process->GetPinnedThread(core_id) == GetCurrentThreadPointer(kernel)) {
- // Clear the current thread's interrupt flag.
- GetCurrentThread(kernel).ClearInterruptFlag();
+ ret = UnmapInsecureMemory64From32(system, address, size);
- // Unpin the current thread.
- cur_process->UnpinCurrentThread(core_id);
- }
+ SetReg32(system, 0, Convert<uint32_t>(ret));
}
-static Result SignalToAddress32(Core::System& system, u32 address, Svc::SignalType signal_type,
- s32 value, s32 count) {
- return SignalToAddress(system, address, signal_type, value, count);
+static void SvcWrap_SetHeapSize64(Core::System& system) {
+ Result ret{};
+
+ uint64_t out_address{};
+ uint64_t size{};
+
+ size = Convert<uint64_t>(GetReg64(system, 1));
+
+ ret = SetHeapSize64(system, std::addressof(out_address), size);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+ SetReg64(system, 1, Convert<uint64_t>(out_address));
}
-static void KernelDebug([[maybe_unused]] Core::System& system,
- [[maybe_unused]] u32 kernel_debug_type, [[maybe_unused]] u64 param1,
- [[maybe_unused]] u64 param2, [[maybe_unused]] u64 param3) {
- // Intentionally do nothing, as this does nothing in released kernel binaries.
+static void SvcWrap_SetMemoryPermission64(Core::System& system) {
+ Result ret{};
+
+ uint64_t address{};
+ uint64_t size{};
+ MemoryPermission perm{};
+
+ address = Convert<uint64_t>(GetReg64(system, 0));
+ size = Convert<uint64_t>(GetReg64(system, 1));
+ perm = Convert<MemoryPermission>(GetReg64(system, 2));
+
+ ret = SetMemoryPermission64(system, address, size, perm);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
}
-static void ChangeKernelTraceState([[maybe_unused]] Core::System& system,
- [[maybe_unused]] u32 trace_state) {
- // Intentionally do nothing, as this does nothing in released kernel binaries.
+static void SvcWrap_SetMemoryAttribute64(Core::System& system) {
+ Result ret{};
+
+ uint64_t address{};
+ uint64_t size{};
+ uint32_t mask{};
+ uint32_t attr{};
+
+ address = Convert<uint64_t>(GetReg64(system, 0));
+ size = Convert<uint64_t>(GetReg64(system, 1));
+ mask = Convert<uint32_t>(GetReg64(system, 2));
+ attr = Convert<uint32_t>(GetReg64(system, 3));
+
+ ret = SetMemoryAttribute64(system, address, size, mask, attr);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
}
-/// This returns the total CPU ticks elapsed since the CPU was powered-on
-static u64 GetSystemTick(Core::System& system) {
- LOG_TRACE(Kernel_SVC, "called");
+static void SvcWrap_MapMemory64(Core::System& system) {
+ Result ret{};
- auto& core_timing = system.CoreTiming();
+ uint64_t dst_address{};
+ uint64_t src_address{};
+ uint64_t size{};
- // Returns the value of cntpct_el0 (https://switchbrew.org/wiki/SVC#svcGetSystemTick)
- const u64 result{core_timing.GetClockTicks()};
+ dst_address = Convert<uint64_t>(GetReg64(system, 0));
+ src_address = Convert<uint64_t>(GetReg64(system, 1));
+ size = Convert<uint64_t>(GetReg64(system, 2));
- if (!system.Kernel().IsMulticore()) {
- core_timing.AddTicks(400U);
- }
+ ret = MapMemory64(system, dst_address, src_address, size);
- return result;
+ SetReg64(system, 0, Convert<uint64_t>(ret));
}
-static void GetSystemTick32(Core::System& system, u32* time_low, u32* time_high) {
- const auto time = GetSystemTick(system);
- *time_low = static_cast<u32>(time);
- *time_high = static_cast<u32>(time >> 32);
+static void SvcWrap_UnmapMemory64(Core::System& system) {
+ Result ret{};
+
+ uint64_t dst_address{};
+ uint64_t src_address{};
+ uint64_t size{};
+
+ dst_address = Convert<uint64_t>(GetReg64(system, 0));
+ src_address = Convert<uint64_t>(GetReg64(system, 1));
+ size = Convert<uint64_t>(GetReg64(system, 2));
+
+ ret = UnmapMemory64(system, dst_address, src_address, size);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
}
-/// Close a handle
-static Result CloseHandle(Core::System& system, Handle handle) {
- LOG_TRACE(Kernel_SVC, "Closing handle 0x{:08X}", handle);
+static void SvcWrap_QueryMemory64(Core::System& system) {
+ Result ret{};
- // Remove the handle.
- R_UNLESS(system.Kernel().CurrentProcess()->GetHandleTable().Remove(handle),
- ResultInvalidHandle);
+ PageInfo out_page_info{};
+ uint64_t out_memory_info{};
+ uint64_t address{};
- return ResultSuccess;
+ out_memory_info = Convert<uint64_t>(GetReg64(system, 0));
+ address = Convert<uint64_t>(GetReg64(system, 2));
+
+ ret = QueryMemory64(system, out_memory_info, std::addressof(out_page_info), address);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+ SetReg64(system, 1, Convert<uint64_t>(out_page_info));
}
-static Result CloseHandle32(Core::System& system, Handle handle) {
- return CloseHandle(system, handle);
+static void SvcWrap_ExitProcess64(Core::System& system) {
+ ExitProcess64(system);
}
-/// Clears the signaled state of an event or process.
-static Result ResetSignal(Core::System& system, Handle handle) {
- LOG_DEBUG(Kernel_SVC, "called handle 0x{:08X}", handle);
+static void SvcWrap_CreateThread64(Core::System& system) {
+ Result ret{};
- // Get the current handle table.
- const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
+ Handle out_handle{};
+ uint64_t func{};
+ uint64_t arg{};
+ uint64_t stack_bottom{};
+ int32_t priority{};
+ int32_t core_id{};
- // Try to reset as readable event.
- {
- KScopedAutoObject readable_event = handle_table.GetObject<KReadableEvent>(handle);
- if (readable_event.IsNotNull()) {
- return readable_event->Reset();
- }
- }
+ func = Convert<uint64_t>(GetReg64(system, 1));
+ arg = Convert<uint64_t>(GetReg64(system, 2));
+ stack_bottom = Convert<uint64_t>(GetReg64(system, 3));
+ priority = Convert<int32_t>(GetReg64(system, 4));
+ core_id = Convert<int32_t>(GetReg64(system, 5));
- // Try to reset as process.
- {
- KScopedAutoObject process = handle_table.GetObject<KProcess>(handle);
- if (process.IsNotNull()) {
- return process->Reset();
- }
- }
+ ret = CreateThread64(system, std::addressof(out_handle), func, arg, stack_bottom, priority, core_id);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+ SetReg64(system, 1, Convert<uint64_t>(out_handle));
+}
+
+static void SvcWrap_StartThread64(Core::System& system) {
+ Result ret{};
+
+ Handle thread_handle{};
- LOG_ERROR(Kernel_SVC, "invalid handle (0x{:08X})", handle);
+ thread_handle = Convert<Handle>(GetReg64(system, 0));
- return ResultInvalidHandle;
+ ret = StartThread64(system, thread_handle);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
}
-static Result ResetSignal32(Core::System& system, Handle handle) {
- return ResetSignal(system, handle);
+static void SvcWrap_ExitThread64(Core::System& system) {
+ ExitThread64(system);
}
-namespace {
+static void SvcWrap_SleepThread64(Core::System& system) {
+ int64_t ns{};
-constexpr bool IsValidTransferMemoryPermission(MemoryPermission perm) {
- switch (perm) {
- case MemoryPermission::None:
- case MemoryPermission::Read:
- case MemoryPermission::ReadWrite:
- return true;
- default:
- return false;
- }
+ ns = Convert<int64_t>(GetReg64(system, 0));
+
+ SleepThread64(system, ns);
}
-} // Anonymous namespace
+static void SvcWrap_GetThreadPriority64(Core::System& system) {
+ Result ret{};
-/// Creates a TransferMemory object
-static Result CreateTransferMemory(Core::System& system, Handle* out, VAddr address, u64 size,
- MemoryPermission map_perm) {
- auto& kernel = system.Kernel();
+ int32_t out_priority{};
+ Handle thread_handle{};
+
+ thread_handle = Convert<Handle>(GetReg64(system, 1));
+
+ ret = GetThreadPriority64(system, std::addressof(out_priority), thread_handle);
- // 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);
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+ SetReg64(system, 1, Convert<uint64_t>(out_priority));
+}
+
+static void SvcWrap_SetThreadPriority64(Core::System& system) {
+ Result ret{};
+
+ Handle thread_handle{};
+ int32_t priority{};
+
+ thread_handle = Convert<Handle>(GetReg64(system, 0));
+ priority = Convert<int32_t>(GetReg64(system, 1));
- // Validate the permissions.
- R_UNLESS(IsValidTransferMemoryPermission(map_perm), ResultInvalidNewMemoryPermission);
+ ret = SetThreadPriority64(system, thread_handle, priority);
- // Get the current process and handle table.
- auto& process = *kernel.CurrentProcess();
- auto& handle_table = process.GetHandleTable();
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+}
+
+static void SvcWrap_GetThreadCoreMask64(Core::System& system) {
+ Result ret{};
- // Reserve a new transfer memory from the process resource limit.
- KScopedResourceReservation trmem_reservation(kernel.CurrentProcess(),
- LimitableResource::TransferMemoryCountMax);
- R_UNLESS(trmem_reservation.Succeeded(), ResultLimitReached);
+ int32_t out_core_id{};
+ uint64_t out_affinity_mask{};
+ Handle thread_handle{};
- // Create the transfer memory.
- KTransferMemory* trmem = KTransferMemory::Create(kernel);
- R_UNLESS(trmem != nullptr, ResultOutOfResource);
+ thread_handle = Convert<Handle>(GetReg64(system, 2));
- // Ensure the only reference is in the handle table when we're done.
- SCOPE_EXIT({ trmem->Close(); });
+ ret = GetThreadCoreMask64(system, std::addressof(out_core_id), std::addressof(out_affinity_mask), thread_handle);
- // Ensure that the region is in range.
- R_UNLESS(process.PageTable().Contains(address, size), ResultInvalidCurrentMemory);
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+ SetReg64(system, 1, Convert<uint64_t>(out_core_id));
+ SetReg64(system, 2, Convert<uint64_t>(out_affinity_mask));
+}
- // Initialize the transfer memory.
- R_TRY(trmem->Initialize(address, size, map_perm));
+static void SvcWrap_SetThreadCoreMask64(Core::System& system) {
+ Result ret{};
- // Commit the reservation.
- trmem_reservation.Commit();
+ Handle thread_handle{};
+ int32_t core_id{};
+ uint64_t affinity_mask{};
- // Register the transfer memory.
- KTransferMemory::Register(kernel, trmem);
+ thread_handle = Convert<Handle>(GetReg64(system, 0));
+ core_id = Convert<int32_t>(GetReg64(system, 1));
+ affinity_mask = Convert<uint64_t>(GetReg64(system, 2));
- // Add the transfer memory to the handle table.
- R_TRY(handle_table.Add(out, trmem));
+ ret = SetThreadCoreMask64(system, thread_handle, core_id, affinity_mask);
- return ResultSuccess;
+ SetReg64(system, 0, Convert<uint64_t>(ret));
}
-static Result CreateTransferMemory32(Core::System& system, Handle* out, u32 address, u32 size,
- MemoryPermission map_perm) {
- return CreateTransferMemory(system, out, address, size, map_perm);
+static void SvcWrap_GetCurrentProcessorNumber64(Core::System& system) {
+ int32_t ret{};
+
+ ret = GetCurrentProcessorNumber64(system);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
}
-static Result GetThreadCoreMask(Core::System& system, Handle thread_handle, s32* out_core_id,
- u64* out_affinity_mask) {
- LOG_TRACE(Kernel_SVC, "called, handle=0x{:08X}", thread_handle);
+static void SvcWrap_SignalEvent64(Core::System& system) {
+ Result ret{};
+
+ Handle event_handle{};
- // Get the thread from its handle.
- KScopedAutoObject thread =
- system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KThread>(thread_handle);
- R_UNLESS(thread.IsNotNull(), ResultInvalidHandle);
+ event_handle = Convert<Handle>(GetReg64(system, 0));
- // Get the core mask.
- R_TRY(thread->GetCoreMask(out_core_id, out_affinity_mask));
+ ret = SignalEvent64(system, event_handle);
- return ResultSuccess;
+ SetReg64(system, 0, Convert<uint64_t>(ret));
}
-static Result GetThreadCoreMask32(Core::System& system, Handle thread_handle, s32* out_core_id,
- u32* out_affinity_mask_low, u32* out_affinity_mask_high) {
- u64 out_affinity_mask{};
- const auto result = GetThreadCoreMask(system, thread_handle, out_core_id, &out_affinity_mask);
- *out_affinity_mask_high = static_cast<u32>(out_affinity_mask >> 32);
- *out_affinity_mask_low = static_cast<u32>(out_affinity_mask);
- return result;
+static void SvcWrap_ClearEvent64(Core::System& system) {
+ Result ret{};
+
+ Handle event_handle{};
+
+ event_handle = Convert<Handle>(GetReg64(system, 0));
+
+ ret = ClearEvent64(system, event_handle);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
}
-static Result SetThreadCoreMask(Core::System& system, Handle thread_handle, s32 core_id,
- u64 affinity_mask) {
- // Determine the core id/affinity mask.
- 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 = 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 (IsValidVirtualCoreId(core_id)) {
- R_UNLESS(((1ULL << core_id) & affinity_mask) != 0, ResultInvalidCombination);
- } else {
- R_UNLESS(core_id == IdealCoreNoUpdate || core_id == IdealCoreDontCare,
- ResultInvalidCoreId);
- }
- }
+static void SvcWrap_MapSharedMemory64(Core::System& system) {
+ Result ret{};
+
+ Handle shmem_handle{};
+ uint64_t address{};
+ uint64_t size{};
+ MemoryPermission map_perm{};
- // Get the thread from its handle.
- KScopedAutoObject thread =
- system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KThread>(thread_handle);
- R_UNLESS(thread.IsNotNull(), ResultInvalidHandle);
+ shmem_handle = Convert<Handle>(GetReg64(system, 0));
+ address = Convert<uint64_t>(GetReg64(system, 1));
+ size = Convert<uint64_t>(GetReg64(system, 2));
+ map_perm = Convert<MemoryPermission>(GetReg64(system, 3));
- // Set the core mask.
- R_TRY(thread->SetCoreMask(core_id, affinity_mask));
+ ret = MapSharedMemory64(system, shmem_handle, address, size, map_perm);
- return ResultSuccess;
+ SetReg64(system, 0, Convert<uint64_t>(ret));
}
-static Result SetThreadCoreMask32(Core::System& system, Handle thread_handle, s32 core_id,
- u32 affinity_mask_low, u32 affinity_mask_high) {
- const auto affinity_mask = u64{affinity_mask_low} | (u64{affinity_mask_high} << 32);
- return SetThreadCoreMask(system, thread_handle, core_id, affinity_mask);
+static void SvcWrap_UnmapSharedMemory64(Core::System& system) {
+ Result ret{};
+
+ Handle shmem_handle{};
+ uint64_t address{};
+ uint64_t size{};
+
+ shmem_handle = Convert<Handle>(GetReg64(system, 0));
+ address = Convert<uint64_t>(GetReg64(system, 1));
+ size = Convert<uint64_t>(GetReg64(system, 2));
+
+ ret = UnmapSharedMemory64(system, shmem_handle, address, size);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
}
-static Result SignalEvent(Core::System& system, Handle event_handle) {
- LOG_DEBUG(Kernel_SVC, "called, event_handle=0x{:08X}", event_handle);
+static void SvcWrap_CreateTransferMemory64(Core::System& system) {
+ Result ret{};
- // Get the current handle table.
- const KHandleTable& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
+ Handle out_handle{};
+ uint64_t address{};
+ uint64_t size{};
+ MemoryPermission map_perm{};
- // Get the event.
- KScopedAutoObject event = handle_table.GetObject<KEvent>(event_handle);
- R_UNLESS(event.IsNotNull(), ResultInvalidHandle);
+ address = Convert<uint64_t>(GetReg64(system, 1));
+ size = Convert<uint64_t>(GetReg64(system, 2));
+ map_perm = Convert<MemoryPermission>(GetReg64(system, 3));
- return event->Signal();
+ ret = CreateTransferMemory64(system, std::addressof(out_handle), address, size, map_perm);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+ SetReg64(system, 1, Convert<uint64_t>(out_handle));
}
-static Result SignalEvent32(Core::System& system, Handle event_handle) {
- return SignalEvent(system, event_handle);
+static void SvcWrap_CloseHandle64(Core::System& system) {
+ Result ret{};
+
+ Handle handle{};
+
+ handle = Convert<Handle>(GetReg64(system, 0));
+
+ ret = CloseHandle64(system, handle);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
}
-static Result ClearEvent(Core::System& system, Handle event_handle) {
- LOG_TRACE(Kernel_SVC, "called, event_handle=0x{:08X}", event_handle);
+static void SvcWrap_ResetSignal64(Core::System& system) {
+ Result ret{};
- // Get the current handle table.
- const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
+ Handle handle{};
- // Try to clear the writable event.
- {
- KScopedAutoObject event = handle_table.GetObject<KEvent>(event_handle);
- if (event.IsNotNull()) {
- return event->Clear();
- }
- }
+ handle = Convert<Handle>(GetReg64(system, 0));
- // Try to clear the readable event.
- {
- KScopedAutoObject readable_event = handle_table.GetObject<KReadableEvent>(event_handle);
- if (readable_event.IsNotNull()) {
- return readable_event->Clear();
- }
- }
+ ret = ResetSignal64(system, handle);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+}
- LOG_ERROR(Kernel_SVC, "Event handle does not exist, event_handle=0x{:08X}", event_handle);
+static void SvcWrap_WaitSynchronization64(Core::System& system) {
+ Result ret{};
- return ResultInvalidHandle;
+ int32_t out_index{};
+ uint64_t handles{};
+ int32_t num_handles{};
+ int64_t timeout_ns{};
+
+ handles = Convert<uint64_t>(GetReg64(system, 1));
+ num_handles = Convert<int32_t>(GetReg64(system, 2));
+ timeout_ns = Convert<int64_t>(GetReg64(system, 3));
+
+ ret = WaitSynchronization64(system, std::addressof(out_index), handles, num_handles, timeout_ns);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+ SetReg64(system, 1, Convert<uint64_t>(out_index));
}
-static Result ClearEvent32(Core::System& system, Handle event_handle) {
- return ClearEvent(system, event_handle);
+static void SvcWrap_CancelSynchronization64(Core::System& system) {
+ Result ret{};
+
+ Handle handle{};
+
+ handle = Convert<Handle>(GetReg64(system, 0));
+
+ ret = CancelSynchronization64(system, handle);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
}
-static Result CreateEvent(Core::System& system, Handle* out_write, Handle* out_read) {
- LOG_DEBUG(Kernel_SVC, "called");
+static void SvcWrap_ArbitrateLock64(Core::System& system) {
+ Result ret{};
- // Get the kernel reference and handle table.
- auto& kernel = system.Kernel();
- auto& handle_table = kernel.CurrentProcess()->GetHandleTable();
+ Handle thread_handle{};
+ uint64_t address{};
+ uint32_t tag{};
- // Reserve a new event from the process resource limit
- KScopedResourceReservation event_reservation(kernel.CurrentProcess(),
- LimitableResource::EventCountMax);
- R_UNLESS(event_reservation.Succeeded(), ResultLimitReached);
+ thread_handle = Convert<Handle>(GetReg64(system, 0));
+ address = Convert<uint64_t>(GetReg64(system, 1));
+ tag = Convert<uint32_t>(GetReg64(system, 2));
- // Create a new event.
- KEvent* event = KEvent::Create(kernel);
- R_UNLESS(event != nullptr, ResultOutOfResource);
+ ret = ArbitrateLock64(system, thread_handle, address, tag);
- // Initialize the event.
- event->Initialize(kernel.CurrentProcess());
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+}
+
+static void SvcWrap_ArbitrateUnlock64(Core::System& system) {
+ Result ret{};
- // Commit the thread reservation.
- event_reservation.Commit();
+ uint64_t address{};
- // Ensure that we clean up the event (and its only references are handle table) on function end.
- SCOPE_EXIT({
- event->GetReadableEvent().Close();
- event->Close();
- });
+ address = Convert<uint64_t>(GetReg64(system, 0));
- // Register the event.
- KEvent::Register(kernel, event);
+ ret = ArbitrateUnlock64(system, address);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+}
- // Add the event to the handle table.
- R_TRY(handle_table.Add(out_write, event));
+static void SvcWrap_WaitProcessWideKeyAtomic64(Core::System& system) {
+ Result ret{};
- // Ensure that we maintaing a clean handle state on exit.
- auto handle_guard = SCOPE_GUARD({ handle_table.Remove(*out_write); });
+ uint64_t address{};
+ uint64_t cv_key{};
+ uint32_t tag{};
+ int64_t timeout_ns{};
- // Add the readable event to the handle table.
- R_TRY(handle_table.Add(out_read, std::addressof(event->GetReadableEvent())));
+ address = Convert<uint64_t>(GetReg64(system, 0));
+ cv_key = Convert<uint64_t>(GetReg64(system, 1));
+ tag = Convert<uint32_t>(GetReg64(system, 2));
+ timeout_ns = Convert<int64_t>(GetReg64(system, 3));
- // We succeeded.
- handle_guard.Cancel();
- return ResultSuccess;
+ ret = WaitProcessWideKeyAtomic64(system, address, cv_key, tag, timeout_ns);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
}
-static Result CreateEvent32(Core::System& system, Handle* out_write, Handle* out_read) {
- return CreateEvent(system, out_write, out_read);
+static void SvcWrap_SignalProcessWideKey64(Core::System& system) {
+ uint64_t cv_key{};
+ int32_t count{};
+
+ cv_key = Convert<uint64_t>(GetReg64(system, 0));
+ count = Convert<int32_t>(GetReg64(system, 1));
+
+ SignalProcessWideKey64(system, cv_key, count);
}
-static Result GetProcessInfo(Core::System& system, u64* out, Handle process_handle, u32 type) {
- LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, type=0x{:X}", process_handle, type);
+static void SvcWrap_GetSystemTick64(Core::System& system) {
+ int64_t ret{};
- const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
- 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;
- }
+ ret = GetSystemTick64(system);
- const auto info_type = static_cast<ProcessInfoType>(type);
- if (info_type != ProcessInfoType::ProcessState) {
- LOG_ERROR(Kernel_SVC, "Expected info_type to be ProcessState but got {} instead", type);
- return ResultInvalidEnumValue;
- }
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+}
+
+static void SvcWrap_ConnectToNamedPort64(Core::System& system) {
+ Result ret{};
- *out = static_cast<u64>(process->GetState());
- return ResultSuccess;
+ Handle out_handle{};
+ uint64_t name{};
+
+ name = Convert<uint64_t>(GetReg64(system, 1));
+
+ ret = ConnectToNamedPort64(system, std::addressof(out_handle), name);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+ SetReg64(system, 1, Convert<uint64_t>(out_handle));
}
-static Result CreateResourceLimit(Core::System& system, Handle* out_handle) {
- LOG_DEBUG(Kernel_SVC, "called");
+static void SvcWrap_SendSyncRequest64(Core::System& system) {
+ Result ret{};
- // Create a new resource limit.
- auto& kernel = system.Kernel();
- KResourceLimit* resource_limit = KResourceLimit::Create(kernel);
- R_UNLESS(resource_limit != nullptr, ResultOutOfResource);
+ Handle session_handle{};
- // Ensure we don't leak a reference to the limit.
- SCOPE_EXIT({ resource_limit->Close(); });
+ session_handle = Convert<Handle>(GetReg64(system, 0));
- // Initialize the resource limit.
- resource_limit->Initialize(&system.CoreTiming());
+ ret = SendSyncRequest64(system, session_handle);
- // Register the limit.
- KResourceLimit::Register(kernel, resource_limit);
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+}
+
+static void SvcWrap_SendSyncRequestWithUserBuffer64(Core::System& system) {
+ Result ret{};
+
+ uint64_t message_buffer{};
+ uint64_t message_buffer_size{};
+ Handle session_handle{};
+
+ message_buffer = Convert<uint64_t>(GetReg64(system, 0));
+ message_buffer_size = Convert<uint64_t>(GetReg64(system, 1));
+ session_handle = Convert<Handle>(GetReg64(system, 2));
- // Add the limit to the handle table.
- R_TRY(kernel.CurrentProcess()->GetHandleTable().Add(out_handle, resource_limit));
+ ret = SendSyncRequestWithUserBuffer64(system, message_buffer, message_buffer_size, session_handle);
- return ResultSuccess;
+ SetReg64(system, 0, Convert<uint64_t>(ret));
}
-static Result 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);
+static void SvcWrap_SendAsyncRequestWithUserBuffer64(Core::System& system) {
+ Result ret{};
- // Validate the resource.
- R_UNLESS(IsValidResourceType(which), ResultInvalidEnumValue);
+ Handle out_event_handle{};
+ uint64_t message_buffer{};
+ uint64_t message_buffer_size{};
+ Handle session_handle{};
- // 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);
+ message_buffer = Convert<uint64_t>(GetReg64(system, 1));
+ message_buffer_size = Convert<uint64_t>(GetReg64(system, 2));
+ session_handle = Convert<Handle>(GetReg64(system, 3));
- // Get the limit value.
- *out_limit_value = resource_limit->GetLimitValue(which);
+ ret = SendAsyncRequestWithUserBuffer64(system, std::addressof(out_event_handle), message_buffer, message_buffer_size, session_handle);
- return ResultSuccess;
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+ SetReg64(system, 1, Convert<uint64_t>(out_event_handle));
}
-static Result 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);
+static void SvcWrap_GetProcessId64(Core::System& system) {
+ Result ret{};
- // Validate the resource.
- R_UNLESS(IsValidResourceType(which), ResultInvalidEnumValue);
+ uint64_t out_process_id{};
+ Handle process_handle{};
- // 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);
+ process_handle = Convert<Handle>(GetReg64(system, 1));
- // Get the current value.
- *out_current_value = resource_limit->GetCurrentValue(which);
+ ret = GetProcessId64(system, std::addressof(out_process_id), process_handle);
- return ResultSuccess;
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+ SetReg64(system, 1, Convert<uint64_t>(out_process_id));
}
-static Result 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);
+static void SvcWrap_GetThreadId64(Core::System& system) {
+ Result ret{};
- // Validate the resource.
- R_UNLESS(IsValidResourceType(which), ResultInvalidEnumValue);
+ uint64_t out_thread_id{};
+ Handle thread_handle{};
- // 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);
+ thread_handle = Convert<Handle>(GetReg64(system, 1));
- // Set the limit value.
- R_TRY(resource_limit->SetLimitValue(which, limit_value));
+ ret = GetThreadId64(system, std::addressof(out_thread_id), thread_handle);
- return ResultSuccess;
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+ SetReg64(system, 1, Convert<uint64_t>(out_thread_id));
}
-static Result GetProcessList(Core::System& system, u32* out_num_processes, VAddr out_process_ids,
- u32 out_process_ids_size) {
- LOG_DEBUG(Kernel_SVC, "called. out_process_ids=0x{:016X}, out_process_ids_size={}",
- out_process_ids, out_process_ids_size);
+static void SvcWrap_Break64(Core::System& system) {
+ BreakReason break_reason{};
+ uint64_t arg{};
+ uint64_t size{};
- // If the supplied size is negative or greater than INT32_MAX / sizeof(u64), bail.
- if ((out_process_ids_size & 0xF0000000) != 0) {
- LOG_ERROR(Kernel_SVC,
- "Supplied size outside [0, 0x0FFFFFFF] range. out_process_ids_size={}",
- out_process_ids_size);
- return ResultOutOfRange;
- }
+ break_reason = Convert<BreakReason>(GetReg64(system, 0));
+ arg = Convert<uint64_t>(GetReg64(system, 1));
+ size = Convert<uint64_t>(GetReg64(system, 2));
- const auto& kernel = system.Kernel();
- const auto total_copy_size = out_process_ids_size * sizeof(u64);
+ Break64(system, break_reason, arg, size);
+}
- if (out_process_ids_size > 0 && !kernel.CurrentProcess()->PageTable().IsInsideAddressSpace(
- out_process_ids, total_copy_size)) {
- LOG_ERROR(Kernel_SVC, "Address range outside address space. begin=0x{:016X}, end=0x{:016X}",
- out_process_ids, out_process_ids + total_copy_size);
- return ResultInvalidCurrentMemory;
- }
+static void SvcWrap_OutputDebugString64(Core::System& system) {
+ Result ret{};
- auto& memory = system.Memory();
- const auto& process_list = kernel.GetProcessList();
- const auto num_processes = process_list.size();
- const auto copy_amount = std::min(std::size_t{out_process_ids_size}, num_processes);
+ uint64_t debug_str{};
+ uint64_t len{};
- for (std::size_t i = 0; i < copy_amount; ++i) {
- memory.Write64(out_process_ids, process_list[i]->GetProcessID());
- out_process_ids += sizeof(u64);
- }
+ debug_str = Convert<uint64_t>(GetReg64(system, 0));
+ len = Convert<uint64_t>(GetReg64(system, 1));
+
+ ret = OutputDebugString64(system, debug_str, len);
- *out_num_processes = static_cast<u32>(num_processes);
- return ResultSuccess;
+ SetReg64(system, 0, Convert<uint64_t>(ret));
}
-static Result GetThreadList(Core::System& system, u32* out_num_threads, VAddr out_thread_ids,
- u32 out_thread_ids_size, Handle debug_handle) {
- // TODO: Handle this case when debug events are supported.
- UNIMPLEMENTED_IF(debug_handle != InvalidHandle);
+static void SvcWrap_ReturnFromException64(Core::System& system) {
+ Result result{};
- LOG_DEBUG(Kernel_SVC, "called. out_thread_ids=0x{:016X}, out_thread_ids_size={}",
- out_thread_ids, out_thread_ids_size);
+ result = Convert<Result>(GetReg64(system, 0));
- // If the size is negative or larger than INT32_MAX / sizeof(u64)
- if ((out_thread_ids_size & 0xF0000000) != 0) {
- LOG_ERROR(Kernel_SVC, "Supplied size outside [0, 0x0FFFFFFF] range. size={}",
- out_thread_ids_size);
- return ResultOutOfRange;
- }
+ ReturnFromException64(system, result);
+}
- auto* const current_process = system.Kernel().CurrentProcess();
- const auto total_copy_size = out_thread_ids_size * sizeof(u64);
+static void SvcWrap_GetInfo64(Core::System& system) {
+ Result ret{};
- if (out_thread_ids_size > 0 &&
- !current_process->PageTable().IsInsideAddressSpace(out_thread_ids, total_copy_size)) {
- LOG_ERROR(Kernel_SVC, "Address range outside address space. begin=0x{:016X}, end=0x{:016X}",
- out_thread_ids, out_thread_ids + total_copy_size);
- return ResultInvalidCurrentMemory;
- }
+ uint64_t out{};
+ InfoType info_type{};
+ Handle handle{};
+ uint64_t info_subtype{};
- auto& memory = system.Memory();
- const auto& thread_list = current_process->GetThreadList();
- const auto num_threads = thread_list.size();
- const auto copy_amount = std::min(std::size_t{out_thread_ids_size}, num_threads);
+ info_type = Convert<InfoType>(GetReg64(system, 1));
+ handle = Convert<Handle>(GetReg64(system, 2));
+ info_subtype = Convert<uint64_t>(GetReg64(system, 3));
- auto list_iter = thread_list.cbegin();
- for (std::size_t i = 0; i < copy_amount; ++i, ++list_iter) {
- memory.Write64(out_thread_ids, (*list_iter)->GetThreadID());
- out_thread_ids += sizeof(u64);
- }
+ ret = GetInfo64(system, std::addressof(out), info_type, handle, info_subtype);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+ SetReg64(system, 1, Convert<uint64_t>(out));
+}
+
+static void SvcWrap_FlushEntireDataCache64(Core::System& system) {
+ FlushEntireDataCache64(system);
+}
+
+static void SvcWrap_FlushDataCache64(Core::System& system) {
+ Result ret{};
+
+ uint64_t address{};
+ uint64_t size{};
+
+ address = Convert<uint64_t>(GetReg64(system, 0));
+ size = Convert<uint64_t>(GetReg64(system, 1));
+
+ ret = FlushDataCache64(system, address, size);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+}
+
+static void SvcWrap_MapPhysicalMemory64(Core::System& system) {
+ Result ret{};
+
+ uint64_t address{};
+ uint64_t size{};
+
+ address = Convert<uint64_t>(GetReg64(system, 0));
+ size = Convert<uint64_t>(GetReg64(system, 1));
+
+ ret = MapPhysicalMemory64(system, address, size);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+}
+
+static void SvcWrap_UnmapPhysicalMemory64(Core::System& system) {
+ Result ret{};
+
+ uint64_t address{};
+ uint64_t size{};
+
+ address = Convert<uint64_t>(GetReg64(system, 0));
+ size = Convert<uint64_t>(GetReg64(system, 1));
+
+ ret = UnmapPhysicalMemory64(system, address, size);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+}
+
+static void SvcWrap_GetDebugFutureThreadInfo64(Core::System& system) {
+ Result ret{};
+
+ lp64::LastThreadContext out_context{};
+ uint64_t out_thread_id{};
+ Handle debug_handle{};
+ int64_t ns{};
+
+ debug_handle = Convert<Handle>(GetReg64(system, 2));
+ ns = Convert<int64_t>(GetReg64(system, 3));
+
+ ret = GetDebugFutureThreadInfo64(system, std::addressof(out_context), std::addressof(out_thread_id), debug_handle, ns);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+ auto out_context_scatter = Convert<std::array<uint64_t, 4>>(out_context);
+ SetReg64(system, 1, out_context_scatter[0]);
+ SetReg64(system, 2, out_context_scatter[1]);
+ SetReg64(system, 3, out_context_scatter[2]);
+ SetReg64(system, 4, out_context_scatter[3]);
+ SetReg64(system, 5, Convert<uint64_t>(out_thread_id));
+}
+
+static void SvcWrap_GetLastThreadInfo64(Core::System& system) {
+ Result ret{};
+
+ lp64::LastThreadContext out_context{};
+ uint64_t out_tls_address{};
+ uint32_t out_flags{};
+
+ ret = GetLastThreadInfo64(system, std::addressof(out_context), std::addressof(out_tls_address), std::addressof(out_flags));
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+ auto out_context_scatter = Convert<std::array<uint64_t, 4>>(out_context);
+ SetReg64(system, 1, out_context_scatter[0]);
+ SetReg64(system, 2, out_context_scatter[1]);
+ SetReg64(system, 3, out_context_scatter[2]);
+ SetReg64(system, 4, out_context_scatter[3]);
+ SetReg64(system, 5, Convert<uint64_t>(out_tls_address));
+ SetReg64(system, 6, Convert<uint64_t>(out_flags));
+}
+
+static void SvcWrap_GetResourceLimitLimitValue64(Core::System& system) {
+ Result ret{};
+
+ int64_t out_limit_value{};
+ Handle resource_limit_handle{};
+ LimitableResource which{};
+
+ resource_limit_handle = Convert<Handle>(GetReg64(system, 1));
+ which = Convert<LimitableResource>(GetReg64(system, 2));
+
+ ret = GetResourceLimitLimitValue64(system, std::addressof(out_limit_value), resource_limit_handle, which);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+ SetReg64(system, 1, Convert<uint64_t>(out_limit_value));
+}
+
+static void SvcWrap_GetResourceLimitCurrentValue64(Core::System& system) {
+ Result ret{};
+
+ int64_t out_current_value{};
+ Handle resource_limit_handle{};
+ LimitableResource which{};
+
+ resource_limit_handle = Convert<Handle>(GetReg64(system, 1));
+ which = Convert<LimitableResource>(GetReg64(system, 2));
+
+ ret = GetResourceLimitCurrentValue64(system, std::addressof(out_current_value), resource_limit_handle, which);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+ SetReg64(system, 1, Convert<uint64_t>(out_current_value));
+}
+
+static void SvcWrap_SetThreadActivity64(Core::System& system) {
+ Result ret{};
+
+ Handle thread_handle{};
+ ThreadActivity thread_activity{};
+
+ thread_handle = Convert<Handle>(GetReg64(system, 0));
+ thread_activity = Convert<ThreadActivity>(GetReg64(system, 1));
+
+ ret = SetThreadActivity64(system, thread_handle, thread_activity);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+}
+
+static void SvcWrap_GetThreadContext364(Core::System& system) {
+ Result ret{};
+
+ uint64_t out_context{};
+ Handle thread_handle{};
+
+ out_context = Convert<uint64_t>(GetReg64(system, 0));
+ thread_handle = Convert<Handle>(GetReg64(system, 1));
+
+ ret = GetThreadContext364(system, out_context, thread_handle);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+}
+
+static void SvcWrap_WaitForAddress64(Core::System& system) {
+ Result ret{};
+
+ uint64_t address{};
+ ArbitrationType arb_type{};
+ int32_t value{};
+ int64_t timeout_ns{};
+
+ address = Convert<uint64_t>(GetReg64(system, 0));
+ arb_type = Convert<ArbitrationType>(GetReg64(system, 1));
+ value = Convert<int32_t>(GetReg64(system, 2));
+ timeout_ns = Convert<int64_t>(GetReg64(system, 3));
+
+ ret = WaitForAddress64(system, address, arb_type, value, timeout_ns);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+}
+
+static void SvcWrap_SignalToAddress64(Core::System& system) {
+ Result ret{};
+
+ uint64_t address{};
+ SignalType signal_type{};
+ int32_t value{};
+ int32_t count{};
+
+ address = Convert<uint64_t>(GetReg64(system, 0));
+ signal_type = Convert<SignalType>(GetReg64(system, 1));
+ value = Convert<int32_t>(GetReg64(system, 2));
+ count = Convert<int32_t>(GetReg64(system, 3));
+
+ ret = SignalToAddress64(system, address, signal_type, value, count);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+}
+
+static void SvcWrap_SynchronizePreemptionState64(Core::System& system) {
+ SynchronizePreemptionState64(system);
+}
+
+static void SvcWrap_GetResourceLimitPeakValue64(Core::System& system) {
+ Result ret{};
+
+ int64_t out_peak_value{};
+ Handle resource_limit_handle{};
+ LimitableResource which{};
+
+ resource_limit_handle = Convert<Handle>(GetReg64(system, 1));
+ which = Convert<LimitableResource>(GetReg64(system, 2));
+
+ ret = GetResourceLimitPeakValue64(system, std::addressof(out_peak_value), resource_limit_handle, which);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+ SetReg64(system, 1, Convert<uint64_t>(out_peak_value));
+}
+
+static void SvcWrap_CreateIoPool64(Core::System& system) {
+ Result ret{};
+
+ Handle out_handle{};
+ IoPoolType which{};
+
+ which = Convert<IoPoolType>(GetReg64(system, 1));
+
+ ret = CreateIoPool64(system, std::addressof(out_handle), which);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+ SetReg64(system, 1, Convert<uint64_t>(out_handle));
+}
+
+static void SvcWrap_CreateIoRegion64(Core::System& system) {
+ Result ret{};
+
+ Handle out_handle{};
+ Handle io_pool{};
+ uint64_t physical_address{};
+ uint64_t size{};
+ MemoryMapping mapping{};
+ MemoryPermission perm{};
+
+ io_pool = Convert<Handle>(GetReg64(system, 1));
+ physical_address = Convert<uint64_t>(GetReg64(system, 2));
+ size = Convert<uint64_t>(GetReg64(system, 3));
+ mapping = Convert<MemoryMapping>(GetReg64(system, 4));
+ perm = Convert<MemoryPermission>(GetReg64(system, 5));
+
+ ret = CreateIoRegion64(system, std::addressof(out_handle), io_pool, physical_address, size, mapping, perm);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+ SetReg64(system, 1, Convert<uint64_t>(out_handle));
+}
+
+static void SvcWrap_KernelDebug64(Core::System& system) {
+ KernelDebugType kern_debug_type{};
+ uint64_t arg0{};
+ uint64_t arg1{};
+ uint64_t arg2{};
+
+ kern_debug_type = Convert<KernelDebugType>(GetReg64(system, 0));
+ arg0 = Convert<uint64_t>(GetReg64(system, 1));
+ arg1 = Convert<uint64_t>(GetReg64(system, 2));
+ arg2 = Convert<uint64_t>(GetReg64(system, 3));
+
+ KernelDebug64(system, kern_debug_type, arg0, arg1, arg2);
+}
+
+static void SvcWrap_ChangeKernelTraceState64(Core::System& system) {
+ KernelTraceState kern_trace_state{};
+
+ kern_trace_state = Convert<KernelTraceState>(GetReg64(system, 0));
+
+ ChangeKernelTraceState64(system, kern_trace_state);
+}
- *out_num_threads = static_cast<u32>(num_threads);
- return ResultSuccess;
-}
-
-static Result FlushProcessDataCache32(Core::System& system, Handle process_handle, u64 address,
- u64 size) {
- // Validate address/size.
- R_UNLESS(size > 0, ResultInvalidSize);
- R_UNLESS(address == static_cast<uintptr_t>(address), ResultInvalidCurrentMemory);
- R_UNLESS(size == static_cast<size_t>(size), ResultInvalidCurrentMemory);
-
- // Get the process from its handle.
- KScopedAutoObject process =
- system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KProcess>(process_handle);
- R_UNLESS(process.IsNotNull(), ResultInvalidHandle);
-
- // Verify the region is within range.
- auto& page_table = process->PageTable();
- R_UNLESS(page_table.Contains(address, size), ResultInvalidCurrentMemory);
-
- // Perform the operation.
- R_RETURN(system.Memory().FlushDataCache(*process, address, size));
-}
-
-namespace {
-struct FunctionDef {
- using Func = void(Core::System&);
-
- u32 id;
- Func* func;
- const char* name;
-};
-} // namespace
-
-static const FunctionDef SVC_Table_32[] = {
- {0x00, nullptr, "Unknown0"},
- {0x01, SvcWrap32<SetHeapSize32>, "SetHeapSize32"},
- {0x02, nullptr, "SetMemoryPermission32"},
- {0x03, SvcWrap32<SetMemoryAttribute32>, "SetMemoryAttribute32"},
- {0x04, SvcWrap32<MapMemory32>, "MapMemory32"},
- {0x05, SvcWrap32<UnmapMemory32>, "UnmapMemory32"},
- {0x06, SvcWrap32<QueryMemory32>, "QueryMemory32"},
- {0x07, SvcWrap32<ExitProcess32>, "ExitProcess32"},
- {0x08, SvcWrap32<CreateThread32>, "CreateThread32"},
- {0x09, SvcWrap32<StartThread32>, "StartThread32"},
- {0x0a, SvcWrap32<ExitThread32>, "ExitThread32"},
- {0x0b, SvcWrap32<SleepThread32>, "SleepThread32"},
- {0x0c, SvcWrap32<GetThreadPriority32>, "GetThreadPriority32"},
- {0x0d, SvcWrap32<SetThreadPriority32>, "SetThreadPriority32"},
- {0x0e, SvcWrap32<GetThreadCoreMask32>, "GetThreadCoreMask32"},
- {0x0f, SvcWrap32<SetThreadCoreMask32>, "SetThreadCoreMask32"},
- {0x10, SvcWrap32<GetCurrentProcessorNumber32>, "GetCurrentProcessorNumber32"},
- {0x11, SvcWrap32<SignalEvent32>, "SignalEvent32"},
- {0x12, SvcWrap32<ClearEvent32>, "ClearEvent32"},
- {0x13, SvcWrap32<MapSharedMemory32>, "MapSharedMemory32"},
- {0x14, SvcWrap32<UnmapSharedMemory32>, "UnmapSharedMemory32"},
- {0x15, SvcWrap32<CreateTransferMemory32>, "CreateTransferMemory32"},
- {0x16, SvcWrap32<CloseHandle32>, "CloseHandle32"},
- {0x17, SvcWrap32<ResetSignal32>, "ResetSignal32"},
- {0x18, SvcWrap32<WaitSynchronization32>, "WaitSynchronization32"},
- {0x19, SvcWrap32<CancelSynchronization32>, "CancelSynchronization32"},
- {0x1a, SvcWrap32<ArbitrateLock32>, "ArbitrateLock32"},
- {0x1b, SvcWrap32<ArbitrateUnlock32>, "ArbitrateUnlock32"},
- {0x1c, SvcWrap32<WaitProcessWideKeyAtomic32>, "WaitProcessWideKeyAtomic32"},
- {0x1d, SvcWrap32<SignalProcessWideKey32>, "SignalProcessWideKey32"},
- {0x1e, SvcWrap32<GetSystemTick32>, "GetSystemTick32"},
- {0x1f, SvcWrap32<ConnectToNamedPort32>, "ConnectToNamedPort32"},
- {0x20, nullptr, "SendSyncRequestLight32"},
- {0x21, SvcWrap32<SendSyncRequest32>, "SendSyncRequest32"},
- {0x22, nullptr, "SendSyncRequestWithUserBuffer32"},
- {0x23, nullptr, "SendAsyncRequestWithUserBuffer32"},
- {0x24, SvcWrap32<GetProcessId32>, "GetProcessId32"},
- {0x25, SvcWrap32<GetThreadId32>, "GetThreadId32"},
- {0x26, SvcWrap32<Break32>, "Break32"},
- {0x27, SvcWrap32<OutputDebugString32>, "OutputDebugString32"},
- {0x28, nullptr, "ReturnFromException32"},
- {0x29, SvcWrap32<GetInfo32>, "GetInfo32"},
- {0x2a, nullptr, "FlushEntireDataCache32"},
- {0x2b, nullptr, "FlushDataCache32"},
- {0x2c, SvcWrap32<MapPhysicalMemory32>, "MapPhysicalMemory32"},
- {0x2d, SvcWrap32<UnmapPhysicalMemory32>, "UnmapPhysicalMemory32"},
- {0x2e, nullptr, "GetDebugFutureThreadInfo32"},
- {0x2f, nullptr, "GetLastThreadInfo32"},
- {0x30, nullptr, "GetResourceLimitLimitValue32"},
- {0x31, nullptr, "GetResourceLimitCurrentValue32"},
- {0x32, SvcWrap32<SetThreadActivity32>, "SetThreadActivity32"},
- {0x33, SvcWrap32<GetThreadContext32>, "GetThreadContext32"},
- {0x34, SvcWrap32<WaitForAddress32>, "WaitForAddress32"},
- {0x35, SvcWrap32<SignalToAddress32>, "SignalToAddress32"},
- {0x36, SvcWrap32<SynchronizePreemptionState>, "SynchronizePreemptionState32"},
- {0x37, nullptr, "GetResourceLimitPeakValue32"},
- {0x38, nullptr, "Unknown38"},
- {0x39, nullptr, "CreateIoPool32"},
- {0x3a, nullptr, "CreateIoRegion32"},
- {0x3b, nullptr, "Unknown3b"},
- {0x3c, nullptr, "KernelDebug32"},
- {0x3d, nullptr, "ChangeKernelTraceState32"},
- {0x3e, nullptr, "Unknown3e"},
- {0x3f, nullptr, "Unknown3f"},
- {0x40, nullptr, "CreateSession32"},
- {0x41, nullptr, "AcceptSession32"},
- {0x42, nullptr, "ReplyAndReceiveLight32"},
- {0x43, nullptr, "ReplyAndReceive32"},
- {0x44, nullptr, "ReplyAndReceiveWithUserBuffer32"},
- {0x45, SvcWrap32<CreateEvent32>, "CreateEvent32"},
- {0x46, nullptr, "MapIoRegion32"},
- {0x47, nullptr, "UnmapIoRegion32"},
- {0x48, nullptr, "MapPhysicalMemoryUnsafe32"},
- {0x49, nullptr, "UnmapPhysicalMemoryUnsafe32"},
- {0x4a, nullptr, "SetUnsafeLimit32"},
- {0x4b, SvcWrap32<CreateCodeMemory32>, "CreateCodeMemory32"},
- {0x4c, SvcWrap32<ControlCodeMemory32>, "ControlCodeMemory32"},
- {0x4d, nullptr, "SleepSystem32"},
- {0x4e, nullptr, "ReadWriteRegister32"},
- {0x4f, nullptr, "SetProcessActivity32"},
- {0x50, nullptr, "CreateSharedMemory32"},
- {0x51, nullptr, "MapTransferMemory32"},
- {0x52, nullptr, "UnmapTransferMemory32"},
- {0x53, nullptr, "CreateInterruptEvent32"},
- {0x54, nullptr, "QueryPhysicalAddress32"},
- {0x55, nullptr, "QueryIoMapping32"},
- {0x56, nullptr, "CreateDeviceAddressSpace32"},
- {0x57, nullptr, "AttachDeviceAddressSpace32"},
- {0x58, nullptr, "DetachDeviceAddressSpace32"},
- {0x59, nullptr, "MapDeviceAddressSpaceByForce32"},
- {0x5a, nullptr, "MapDeviceAddressSpaceAligned32"},
- {0x5b, nullptr, "MapDeviceAddressSpace32"},
- {0x5c, nullptr, "UnmapDeviceAddressSpace32"},
- {0x5d, nullptr, "InvalidateProcessDataCache32"},
- {0x5e, nullptr, "StoreProcessDataCache32"},
- {0x5F, SvcWrap32<FlushProcessDataCache32>, "FlushProcessDataCache32"},
- {0x60, nullptr, "StoreProcessDataCache32"},
- {0x61, nullptr, "BreakDebugProcess32"},
- {0x62, nullptr, "TerminateDebugProcess32"},
- {0x63, nullptr, "GetDebugEvent32"},
- {0x64, nullptr, "ContinueDebugEvent32"},
- {0x65, nullptr, "GetProcessList32"},
- {0x66, nullptr, "GetThreadList"},
- {0x67, nullptr, "GetDebugThreadContext32"},
- {0x68, nullptr, "SetDebugThreadContext32"},
- {0x69, nullptr, "QueryDebugProcessMemory32"},
- {0x6A, nullptr, "ReadDebugProcessMemory32"},
- {0x6B, nullptr, "WriteDebugProcessMemory32"},
- {0x6C, nullptr, "SetHardwareBreakPoint32"},
- {0x6D, nullptr, "GetDebugThreadParam32"},
- {0x6E, nullptr, "Unknown6E"},
- {0x6f, nullptr, "GetSystemInfo32"},
- {0x70, nullptr, "CreatePort32"},
- {0x71, nullptr, "ManageNamedPort32"},
- {0x72, nullptr, "ConnectToPort32"},
- {0x73, nullptr, "SetProcessMemoryPermission32"},
- {0x74, nullptr, "MapProcessMemory32"},
- {0x75, nullptr, "UnmapProcessMemory32"},
- {0x76, nullptr, "QueryProcessMemory32"},
- {0x77, nullptr, "MapProcessCodeMemory32"},
- {0x78, nullptr, "UnmapProcessCodeMemory32"},
- {0x79, nullptr, "CreateProcess32"},
- {0x7A, nullptr, "StartProcess32"},
- {0x7B, nullptr, "TerminateProcess32"},
- {0x7C, nullptr, "GetProcessInfo32"},
- {0x7D, nullptr, "CreateResourceLimit32"},
- {0x7E, nullptr, "SetResourceLimitLimitValue32"},
- {0x7F, nullptr, "CallSecureMonitor32"},
- {0x80, nullptr, "Unknown"},
- {0x81, nullptr, "Unknown"},
- {0x82, nullptr, "Unknown"},
- {0x83, nullptr, "Unknown"},
- {0x84, nullptr, "Unknown"},
- {0x85, nullptr, "Unknown"},
- {0x86, nullptr, "Unknown"},
- {0x87, nullptr, "Unknown"},
- {0x88, nullptr, "Unknown"},
- {0x89, nullptr, "Unknown"},
- {0x8A, nullptr, "Unknown"},
- {0x8B, nullptr, "Unknown"},
- {0x8C, nullptr, "Unknown"},
- {0x8D, nullptr, "Unknown"},
- {0x8E, nullptr, "Unknown"},
- {0x8F, nullptr, "Unknown"},
- {0x90, nullptr, "Unknown"},
- {0x91, nullptr, "Unknown"},
- {0x92, nullptr, "Unknown"},
- {0x93, nullptr, "Unknown"},
- {0x94, nullptr, "Unknown"},
- {0x95, nullptr, "Unknown"},
- {0x96, nullptr, "Unknown"},
- {0x97, nullptr, "Unknown"},
- {0x98, nullptr, "Unknown"},
- {0x99, nullptr, "Unknown"},
- {0x9A, nullptr, "Unknown"},
- {0x9B, nullptr, "Unknown"},
- {0x9C, nullptr, "Unknown"},
- {0x9D, nullptr, "Unknown"},
- {0x9E, nullptr, "Unknown"},
- {0x9F, nullptr, "Unknown"},
- {0xA0, nullptr, "Unknown"},
- {0xA1, nullptr, "Unknown"},
- {0xA2, nullptr, "Unknown"},
- {0xA3, nullptr, "Unknown"},
- {0xA4, nullptr, "Unknown"},
- {0xA5, nullptr, "Unknown"},
- {0xA6, nullptr, "Unknown"},
- {0xA7, nullptr, "Unknown"},
- {0xA8, nullptr, "Unknown"},
- {0xA9, nullptr, "Unknown"},
- {0xAA, nullptr, "Unknown"},
- {0xAB, nullptr, "Unknown"},
- {0xAC, nullptr, "Unknown"},
- {0xAD, nullptr, "Unknown"},
- {0xAE, nullptr, "Unknown"},
- {0xAF, nullptr, "Unknown"},
- {0xB0, nullptr, "Unknown"},
- {0xB1, nullptr, "Unknown"},
- {0xB2, nullptr, "Unknown"},
- {0xB3, nullptr, "Unknown"},
- {0xB4, nullptr, "Unknown"},
- {0xB5, nullptr, "Unknown"},
- {0xB6, nullptr, "Unknown"},
- {0xB7, nullptr, "Unknown"},
- {0xB8, nullptr, "Unknown"},
- {0xB9, nullptr, "Unknown"},
- {0xBA, nullptr, "Unknown"},
- {0xBB, nullptr, "Unknown"},
- {0xBC, nullptr, "Unknown"},
- {0xBD, nullptr, "Unknown"},
- {0xBE, nullptr, "Unknown"},
- {0xBF, nullptr, "Unknown"},
-};
-
-static const FunctionDef SVC_Table_64[] = {
- {0x00, nullptr, "Unknown0"},
- {0x01, SvcWrap64<SetHeapSize>, "SetHeapSize"},
- {0x02, SvcWrap64<SetMemoryPermission>, "SetMemoryPermission"},
- {0x03, SvcWrap64<SetMemoryAttribute>, "SetMemoryAttribute"},
- {0x04, SvcWrap64<MapMemory>, "MapMemory"},
- {0x05, SvcWrap64<UnmapMemory>, "UnmapMemory"},
- {0x06, SvcWrap64<QueryMemory>, "QueryMemory"},
- {0x07, SvcWrap64<ExitProcess>, "ExitProcess"},
- {0x08, SvcWrap64<CreateThread>, "CreateThread"},
- {0x09, SvcWrap64<StartThread>, "StartThread"},
- {0x0A, SvcWrap64<ExitThread>, "ExitThread"},
- {0x0B, SvcWrap64<SleepThread>, "SleepThread"},
- {0x0C, SvcWrap64<GetThreadPriority>, "GetThreadPriority"},
- {0x0D, SvcWrap64<SetThreadPriority>, "SetThreadPriority"},
- {0x0E, SvcWrap64<GetThreadCoreMask>, "GetThreadCoreMask"},
- {0x0F, SvcWrap64<SetThreadCoreMask>, "SetThreadCoreMask"},
- {0x10, SvcWrap64<GetCurrentProcessorNumber>, "GetCurrentProcessorNumber"},
- {0x11, SvcWrap64<SignalEvent>, "SignalEvent"},
- {0x12, SvcWrap64<ClearEvent>, "ClearEvent"},
- {0x13, SvcWrap64<MapSharedMemory>, "MapSharedMemory"},
- {0x14, SvcWrap64<UnmapSharedMemory>, "UnmapSharedMemory"},
- {0x15, SvcWrap64<CreateTransferMemory>, "CreateTransferMemory"},
- {0x16, SvcWrap64<CloseHandle>, "CloseHandle"},
- {0x17, SvcWrap64<ResetSignal>, "ResetSignal"},
- {0x18, SvcWrap64<WaitSynchronization>, "WaitSynchronization"},
- {0x19, SvcWrap64<CancelSynchronization>, "CancelSynchronization"},
- {0x1A, SvcWrap64<ArbitrateLock>, "ArbitrateLock"},
- {0x1B, SvcWrap64<ArbitrateUnlock>, "ArbitrateUnlock"},
- {0x1C, SvcWrap64<WaitProcessWideKeyAtomic>, "WaitProcessWideKeyAtomic"},
- {0x1D, SvcWrap64<SignalProcessWideKey>, "SignalProcessWideKey"},
- {0x1E, SvcWrap64<GetSystemTick>, "GetSystemTick"},
- {0x1F, SvcWrap64<ConnectToNamedPort>, "ConnectToNamedPort"},
- {0x20, nullptr, "SendSyncRequestLight"},
- {0x21, SvcWrap64<SendSyncRequest>, "SendSyncRequest"},
- {0x22, nullptr, "SendSyncRequestWithUserBuffer"},
- {0x23, nullptr, "SendAsyncRequestWithUserBuffer"},
- {0x24, SvcWrap64<GetProcessId>, "GetProcessId"},
- {0x25, SvcWrap64<GetThreadId>, "GetThreadId"},
- {0x26, SvcWrap64<Break>, "Break"},
- {0x27, SvcWrap64<OutputDebugString>, "OutputDebugString"},
- {0x28, nullptr, "ReturnFromException"},
- {0x29, SvcWrap64<GetInfo>, "GetInfo"},
- {0x2A, nullptr, "FlushEntireDataCache"},
- {0x2B, nullptr, "FlushDataCache"},
- {0x2C, SvcWrap64<MapPhysicalMemory>, "MapPhysicalMemory"},
- {0x2D, SvcWrap64<UnmapPhysicalMemory>, "UnmapPhysicalMemory"},
- {0x2E, nullptr, "GetFutureThreadInfo"},
- {0x2F, nullptr, "GetLastThreadInfo"},
- {0x30, SvcWrap64<GetResourceLimitLimitValue>, "GetResourceLimitLimitValue"},
- {0x31, SvcWrap64<GetResourceLimitCurrentValue>, "GetResourceLimitCurrentValue"},
- {0x32, SvcWrap64<SetThreadActivity>, "SetThreadActivity"},
- {0x33, SvcWrap64<GetThreadContext>, "GetThreadContext"},
- {0x34, SvcWrap64<WaitForAddress>, "WaitForAddress"},
- {0x35, SvcWrap64<SignalToAddress>, "SignalToAddress"},
- {0x36, SvcWrap64<SynchronizePreemptionState>, "SynchronizePreemptionState"},
- {0x37, nullptr, "GetResourceLimitPeakValue"},
- {0x38, nullptr, "Unknown38"},
- {0x39, nullptr, "CreateIoPool"},
- {0x3A, nullptr, "CreateIoRegion"},
- {0x3B, nullptr, "Unknown3B"},
- {0x3C, SvcWrap64<KernelDebug>, "KernelDebug"},
- {0x3D, SvcWrap64<ChangeKernelTraceState>, "ChangeKernelTraceState"},
- {0x3E, nullptr, "Unknown3e"},
- {0x3F, nullptr, "Unknown3f"},
- {0x40, SvcWrap64<CreateSession>, "CreateSession"},
- {0x41, nullptr, "AcceptSession"},
- {0x42, nullptr, "ReplyAndReceiveLight"},
- {0x43, SvcWrap64<ReplyAndReceive>, "ReplyAndReceive"},
- {0x44, nullptr, "ReplyAndReceiveWithUserBuffer"},
- {0x45, SvcWrap64<CreateEvent>, "CreateEvent"},
- {0x46, nullptr, "MapIoRegion"},
- {0x47, nullptr, "UnmapIoRegion"},
- {0x48, nullptr, "MapPhysicalMemoryUnsafe"},
- {0x49, nullptr, "UnmapPhysicalMemoryUnsafe"},
- {0x4A, nullptr, "SetUnsafeLimit"},
- {0x4B, SvcWrap64<CreateCodeMemory>, "CreateCodeMemory"},
- {0x4C, SvcWrap64<ControlCodeMemory>, "ControlCodeMemory"},
- {0x4D, nullptr, "SleepSystem"},
- {0x4E, nullptr, "ReadWriteRegister"},
- {0x4F, nullptr, "SetProcessActivity"},
- {0x50, nullptr, "CreateSharedMemory"},
- {0x51, nullptr, "MapTransferMemory"},
- {0x52, nullptr, "UnmapTransferMemory"},
- {0x53, nullptr, "CreateInterruptEvent"},
- {0x54, nullptr, "QueryPhysicalAddress"},
- {0x55, nullptr, "QueryIoMapping"},
- {0x56, nullptr, "CreateDeviceAddressSpace"},
- {0x57, nullptr, "AttachDeviceAddressSpace"},
- {0x58, nullptr, "DetachDeviceAddressSpace"},
- {0x59, nullptr, "MapDeviceAddressSpaceByForce"},
- {0x5A, nullptr, "MapDeviceAddressSpaceAligned"},
- {0x5B, nullptr, "MapDeviceAddressSpace"},
- {0x5C, nullptr, "UnmapDeviceAddressSpace"},
- {0x5D, nullptr, "InvalidateProcessDataCache"},
- {0x5E, nullptr, "StoreProcessDataCache"},
- {0x5F, nullptr, "FlushProcessDataCache"},
- {0x60, nullptr, "DebugActiveProcess"},
- {0x61, nullptr, "BreakDebugProcess"},
- {0x62, nullptr, "TerminateDebugProcess"},
- {0x63, nullptr, "GetDebugEvent"},
- {0x64, nullptr, "ContinueDebugEvent"},
- {0x65, SvcWrap64<GetProcessList>, "GetProcessList"},
- {0x66, SvcWrap64<GetThreadList>, "GetThreadList"},
- {0x67, nullptr, "GetDebugThreadContext"},
- {0x68, nullptr, "SetDebugThreadContext"},
- {0x69, nullptr, "QueryDebugProcessMemory"},
- {0x6A, nullptr, "ReadDebugProcessMemory"},
- {0x6B, nullptr, "WriteDebugProcessMemory"},
- {0x6C, nullptr, "SetHardwareBreakPoint"},
- {0x6D, nullptr, "GetDebugThreadParam"},
- {0x6E, nullptr, "Unknown6E"},
- {0x6F, nullptr, "GetSystemInfo"},
- {0x70, nullptr, "CreatePort"},
- {0x71, nullptr, "ManageNamedPort"},
- {0x72, nullptr, "ConnectToPort"},
- {0x73, SvcWrap64<SetProcessMemoryPermission>, "SetProcessMemoryPermission"},
- {0x74, SvcWrap64<MapProcessMemory>, "MapProcessMemory"},
- {0x75, SvcWrap64<UnmapProcessMemory>, "UnmapProcessMemory"},
- {0x76, SvcWrap64<QueryProcessMemory>, "QueryProcessMemory"},
- {0x77, SvcWrap64<MapProcessCodeMemory>, "MapProcessCodeMemory"},
- {0x78, SvcWrap64<UnmapProcessCodeMemory>, "UnmapProcessCodeMemory"},
- {0x79, nullptr, "CreateProcess"},
- {0x7A, nullptr, "StartProcess"},
- {0x7B, nullptr, "TerminateProcess"},
- {0x7C, SvcWrap64<GetProcessInfo>, "GetProcessInfo"},
- {0x7D, SvcWrap64<CreateResourceLimit>, "CreateResourceLimit"},
- {0x7E, SvcWrap64<SetResourceLimitLimitValue>, "SetResourceLimitLimitValue"},
- {0x7F, nullptr, "CallSecureMonitor"},
- {0x80, nullptr, "Unknown"},
- {0x81, nullptr, "Unknown"},
- {0x82, nullptr, "Unknown"},
- {0x83, nullptr, "Unknown"},
- {0x84, nullptr, "Unknown"},
- {0x85, nullptr, "Unknown"},
- {0x86, nullptr, "Unknown"},
- {0x87, nullptr, "Unknown"},
- {0x88, nullptr, "Unknown"},
- {0x89, nullptr, "Unknown"},
- {0x8A, nullptr, "Unknown"},
- {0x8B, nullptr, "Unknown"},
- {0x8C, nullptr, "Unknown"},
- {0x8D, nullptr, "Unknown"},
- {0x8E, nullptr, "Unknown"},
- {0x8F, nullptr, "Unknown"},
- {0x90, nullptr, "Unknown"},
- {0x91, nullptr, "Unknown"},
- {0x92, nullptr, "Unknown"},
- {0x93, nullptr, "Unknown"},
- {0x94, nullptr, "Unknown"},
- {0x95, nullptr, "Unknown"},
- {0x96, nullptr, "Unknown"},
- {0x97, nullptr, "Unknown"},
- {0x98, nullptr, "Unknown"},
- {0x99, nullptr, "Unknown"},
- {0x9A, nullptr, "Unknown"},
- {0x9B, nullptr, "Unknown"},
- {0x9C, nullptr, "Unknown"},
- {0x9D, nullptr, "Unknown"},
- {0x9E, nullptr, "Unknown"},
- {0x9F, nullptr, "Unknown"},
- {0xA0, nullptr, "Unknown"},
- {0xA1, nullptr, "Unknown"},
- {0xA2, nullptr, "Unknown"},
- {0xA3, nullptr, "Unknown"},
- {0xA4, nullptr, "Unknown"},
- {0xA5, nullptr, "Unknown"},
- {0xA6, nullptr, "Unknown"},
- {0xA7, nullptr, "Unknown"},
- {0xA8, nullptr, "Unknown"},
- {0xA9, nullptr, "Unknown"},
- {0xAA, nullptr, "Unknown"},
- {0xAB, nullptr, "Unknown"},
- {0xAC, nullptr, "Unknown"},
- {0xAD, nullptr, "Unknown"},
- {0xAE, nullptr, "Unknown"},
- {0xAF, nullptr, "Unknown"},
- {0xB0, nullptr, "Unknown"},
- {0xB1, nullptr, "Unknown"},
- {0xB2, nullptr, "Unknown"},
- {0xB3, nullptr, "Unknown"},
- {0xB4, nullptr, "Unknown"},
- {0xB5, nullptr, "Unknown"},
- {0xB6, nullptr, "Unknown"},
- {0xB7, nullptr, "Unknown"},
- {0xB8, nullptr, "Unknown"},
- {0xB9, nullptr, "Unknown"},
- {0xBA, nullptr, "Unknown"},
- {0xBB, nullptr, "Unknown"},
- {0xBC, nullptr, "Unknown"},
- {0xBD, nullptr, "Unknown"},
- {0xBE, nullptr, "Unknown"},
- {0xBF, nullptr, "Unknown"},
-};
-
-static const FunctionDef* GetSVCInfo32(u32 func_num) {
- if (func_num >= std::size(SVC_Table_32)) {
- LOG_ERROR(Kernel_SVC, "Unknown svc=0x{:02X}", func_num);
- return nullptr;
+static void SvcWrap_CreateSession64(Core::System& system) {
+ Result ret{};
+
+ Handle out_server_session_handle{};
+ Handle out_client_session_handle{};
+ bool is_light{};
+ uint64_t name{};
+
+ is_light = Convert<bool>(GetReg64(system, 2));
+ name = Convert<uint64_t>(GetReg64(system, 3));
+
+ ret = CreateSession64(system, std::addressof(out_server_session_handle), std::addressof(out_client_session_handle), is_light, name);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+ SetReg64(system, 1, Convert<uint64_t>(out_server_session_handle));
+ SetReg64(system, 2, Convert<uint64_t>(out_client_session_handle));
+}
+
+static void SvcWrap_AcceptSession64(Core::System& system) {
+ Result ret{};
+
+ Handle out_handle{};
+ Handle port{};
+
+ port = Convert<Handle>(GetReg64(system, 1));
+
+ ret = AcceptSession64(system, std::addressof(out_handle), port);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+ SetReg64(system, 1, Convert<uint64_t>(out_handle));
+}
+
+static void SvcWrap_ReplyAndReceive64(Core::System& system) {
+ Result ret{};
+
+ int32_t out_index{};
+ uint64_t handles{};
+ int32_t num_handles{};
+ Handle reply_target{};
+ int64_t timeout_ns{};
+
+ handles = Convert<uint64_t>(GetReg64(system, 1));
+ num_handles = Convert<int32_t>(GetReg64(system, 2));
+ reply_target = Convert<Handle>(GetReg64(system, 3));
+ timeout_ns = Convert<int64_t>(GetReg64(system, 4));
+
+ ret = ReplyAndReceive64(system, std::addressof(out_index), handles, num_handles, reply_target, timeout_ns);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+ SetReg64(system, 1, Convert<uint64_t>(out_index));
+}
+
+static void SvcWrap_ReplyAndReceiveWithUserBuffer64(Core::System& system) {
+ Result ret{};
+
+ int32_t out_index{};
+ uint64_t message_buffer{};
+ uint64_t message_buffer_size{};
+ uint64_t handles{};
+ int32_t num_handles{};
+ Handle reply_target{};
+ int64_t timeout_ns{};
+
+ message_buffer = Convert<uint64_t>(GetReg64(system, 1));
+ message_buffer_size = Convert<uint64_t>(GetReg64(system, 2));
+ handles = Convert<uint64_t>(GetReg64(system, 3));
+ num_handles = Convert<int32_t>(GetReg64(system, 4));
+ reply_target = Convert<Handle>(GetReg64(system, 5));
+ timeout_ns = Convert<int64_t>(GetReg64(system, 6));
+
+ ret = ReplyAndReceiveWithUserBuffer64(system, std::addressof(out_index), message_buffer, message_buffer_size, handles, num_handles, reply_target, timeout_ns);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+ SetReg64(system, 1, Convert<uint64_t>(out_index));
+}
+
+static void SvcWrap_CreateEvent64(Core::System& system) {
+ Result ret{};
+
+ Handle out_write_handle{};
+ Handle out_read_handle{};
+
+ ret = CreateEvent64(system, std::addressof(out_write_handle), std::addressof(out_read_handle));
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+ SetReg64(system, 1, Convert<uint64_t>(out_write_handle));
+ SetReg64(system, 2, Convert<uint64_t>(out_read_handle));
+}
+
+static void SvcWrap_MapIoRegion64(Core::System& system) {
+ Result ret{};
+
+ Handle io_region{};
+ uint64_t address{};
+ uint64_t size{};
+ MemoryPermission perm{};
+
+ io_region = Convert<Handle>(GetReg64(system, 0));
+ address = Convert<uint64_t>(GetReg64(system, 1));
+ size = Convert<uint64_t>(GetReg64(system, 2));
+ perm = Convert<MemoryPermission>(GetReg64(system, 3));
+
+ ret = MapIoRegion64(system, io_region, address, size, perm);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+}
+
+static void SvcWrap_UnmapIoRegion64(Core::System& system) {
+ Result ret{};
+
+ Handle io_region{};
+ uint64_t address{};
+ uint64_t size{};
+
+ io_region = Convert<Handle>(GetReg64(system, 0));
+ address = Convert<uint64_t>(GetReg64(system, 1));
+ size = Convert<uint64_t>(GetReg64(system, 2));
+
+ ret = UnmapIoRegion64(system, io_region, address, size);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+}
+
+static void SvcWrap_MapPhysicalMemoryUnsafe64(Core::System& system) {
+ Result ret{};
+
+ uint64_t address{};
+ uint64_t size{};
+
+ address = Convert<uint64_t>(GetReg64(system, 0));
+ size = Convert<uint64_t>(GetReg64(system, 1));
+
+ ret = MapPhysicalMemoryUnsafe64(system, address, size);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+}
+
+static void SvcWrap_UnmapPhysicalMemoryUnsafe64(Core::System& system) {
+ Result ret{};
+
+ uint64_t address{};
+ uint64_t size{};
+
+ address = Convert<uint64_t>(GetReg64(system, 0));
+ size = Convert<uint64_t>(GetReg64(system, 1));
+
+ ret = UnmapPhysicalMemoryUnsafe64(system, address, size);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+}
+
+static void SvcWrap_SetUnsafeLimit64(Core::System& system) {
+ Result ret{};
+
+ uint64_t limit{};
+
+ limit = Convert<uint64_t>(GetReg64(system, 0));
+
+ ret = SetUnsafeLimit64(system, limit);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+}
+
+static void SvcWrap_CreateCodeMemory64(Core::System& system) {
+ Result ret{};
+
+ Handle out_handle{};
+ uint64_t address{};
+ uint64_t size{};
+
+ address = Convert<uint64_t>(GetReg64(system, 1));
+ size = Convert<uint64_t>(GetReg64(system, 2));
+
+ ret = CreateCodeMemory64(system, std::addressof(out_handle), address, size);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+ SetReg64(system, 1, Convert<uint64_t>(out_handle));
+}
+
+static void SvcWrap_ControlCodeMemory64(Core::System& system) {
+ Result ret{};
+
+ Handle code_memory_handle{};
+ CodeMemoryOperation operation{};
+ uint64_t address{};
+ uint64_t size{};
+ MemoryPermission perm{};
+
+ code_memory_handle = Convert<Handle>(GetReg64(system, 0));
+ operation = Convert<CodeMemoryOperation>(GetReg64(system, 1));
+ address = Convert<uint64_t>(GetReg64(system, 2));
+ size = Convert<uint64_t>(GetReg64(system, 3));
+ perm = Convert<MemoryPermission>(GetReg64(system, 4));
+
+ ret = ControlCodeMemory64(system, code_memory_handle, operation, address, size, perm);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+}
+
+static void SvcWrap_SleepSystem64(Core::System& system) {
+ SleepSystem64(system);
+}
+
+static void SvcWrap_ReadWriteRegister64(Core::System& system) {
+ Result ret{};
+
+ uint32_t out_value{};
+ uint64_t address{};
+ uint32_t mask{};
+ uint32_t value{};
+
+ address = Convert<uint64_t>(GetReg64(system, 1));
+ mask = Convert<uint32_t>(GetReg64(system, 2));
+ value = Convert<uint32_t>(GetReg64(system, 3));
+
+ ret = ReadWriteRegister64(system, std::addressof(out_value), address, mask, value);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+ SetReg64(system, 1, Convert<uint64_t>(out_value));
+}
+
+static void SvcWrap_SetProcessActivity64(Core::System& system) {
+ Result ret{};
+
+ Handle process_handle{};
+ ProcessActivity process_activity{};
+
+ process_handle = Convert<Handle>(GetReg64(system, 0));
+ process_activity = Convert<ProcessActivity>(GetReg64(system, 1));
+
+ ret = SetProcessActivity64(system, process_handle, process_activity);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+}
+
+static void SvcWrap_CreateSharedMemory64(Core::System& system) {
+ Result ret{};
+
+ Handle out_handle{};
+ uint64_t size{};
+ MemoryPermission owner_perm{};
+ MemoryPermission remote_perm{};
+
+ size = Convert<uint64_t>(GetReg64(system, 1));
+ owner_perm = Convert<MemoryPermission>(GetReg64(system, 2));
+ remote_perm = Convert<MemoryPermission>(GetReg64(system, 3));
+
+ ret = CreateSharedMemory64(system, std::addressof(out_handle), size, owner_perm, remote_perm);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+ SetReg64(system, 1, Convert<uint64_t>(out_handle));
+}
+
+static void SvcWrap_MapTransferMemory64(Core::System& system) {
+ Result ret{};
+
+ Handle trmem_handle{};
+ uint64_t address{};
+ uint64_t size{};
+ MemoryPermission owner_perm{};
+
+ trmem_handle = Convert<Handle>(GetReg64(system, 0));
+ address = Convert<uint64_t>(GetReg64(system, 1));
+ size = Convert<uint64_t>(GetReg64(system, 2));
+ owner_perm = Convert<MemoryPermission>(GetReg64(system, 3));
+
+ ret = MapTransferMemory64(system, trmem_handle, address, size, owner_perm);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+}
+
+static void SvcWrap_UnmapTransferMemory64(Core::System& system) {
+ Result ret{};
+
+ Handle trmem_handle{};
+ uint64_t address{};
+ uint64_t size{};
+
+ trmem_handle = Convert<Handle>(GetReg64(system, 0));
+ address = Convert<uint64_t>(GetReg64(system, 1));
+ size = Convert<uint64_t>(GetReg64(system, 2));
+
+ ret = UnmapTransferMemory64(system, trmem_handle, address, size);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+}
+
+static void SvcWrap_CreateInterruptEvent64(Core::System& system) {
+ Result ret{};
+
+ Handle out_read_handle{};
+ int32_t interrupt_id{};
+ InterruptType interrupt_type{};
+
+ interrupt_id = Convert<int32_t>(GetReg64(system, 1));
+ interrupt_type = Convert<InterruptType>(GetReg64(system, 2));
+
+ ret = CreateInterruptEvent64(system, std::addressof(out_read_handle), interrupt_id, interrupt_type);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+ SetReg64(system, 1, Convert<uint64_t>(out_read_handle));
+}
+
+static void SvcWrap_QueryPhysicalAddress64(Core::System& system) {
+ Result ret{};
+
+ lp64::PhysicalMemoryInfo out_info{};
+ uint64_t address{};
+
+ address = Convert<uint64_t>(GetReg64(system, 1));
+
+ ret = QueryPhysicalAddress64(system, std::addressof(out_info), address);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+ auto out_info_scatter = Convert<std::array<uint64_t, 3>>(out_info);
+ SetReg64(system, 1, out_info_scatter[0]);
+ SetReg64(system, 2, out_info_scatter[1]);
+ SetReg64(system, 3, out_info_scatter[2]);
+}
+
+static void SvcWrap_QueryIoMapping64(Core::System& system) {
+ Result ret{};
+
+ uint64_t out_address{};
+ uint64_t out_size{};
+ uint64_t physical_address{};
+ uint64_t size{};
+
+ physical_address = Convert<uint64_t>(GetReg64(system, 2));
+ size = Convert<uint64_t>(GetReg64(system, 3));
+
+ ret = QueryIoMapping64(system, std::addressof(out_address), std::addressof(out_size), physical_address, size);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+ SetReg64(system, 1, Convert<uint64_t>(out_address));
+ SetReg64(system, 2, Convert<uint64_t>(out_size));
+}
+
+static void SvcWrap_CreateDeviceAddressSpace64(Core::System& system) {
+ Result ret{};
+
+ Handle out_handle{};
+ uint64_t das_address{};
+ uint64_t das_size{};
+
+ das_address = Convert<uint64_t>(GetReg64(system, 1));
+ das_size = Convert<uint64_t>(GetReg64(system, 2));
+
+ ret = CreateDeviceAddressSpace64(system, std::addressof(out_handle), das_address, das_size);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+ SetReg64(system, 1, Convert<uint64_t>(out_handle));
+}
+
+static void SvcWrap_AttachDeviceAddressSpace64(Core::System& system) {
+ Result ret{};
+
+ DeviceName device_name{};
+ Handle das_handle{};
+
+ device_name = Convert<DeviceName>(GetReg64(system, 0));
+ das_handle = Convert<Handle>(GetReg64(system, 1));
+
+ ret = AttachDeviceAddressSpace64(system, device_name, das_handle);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+}
+
+static void SvcWrap_DetachDeviceAddressSpace64(Core::System& system) {
+ Result ret{};
+
+ DeviceName device_name{};
+ Handle das_handle{};
+
+ device_name = Convert<DeviceName>(GetReg64(system, 0));
+ das_handle = Convert<Handle>(GetReg64(system, 1));
+
+ ret = DetachDeviceAddressSpace64(system, device_name, das_handle);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+}
+
+static void SvcWrap_MapDeviceAddressSpaceByForce64(Core::System& system) {
+ Result ret{};
+
+ Handle das_handle{};
+ Handle process_handle{};
+ uint64_t process_address{};
+ uint64_t size{};
+ uint64_t device_address{};
+ uint32_t option{};
+
+ das_handle = Convert<Handle>(GetReg64(system, 0));
+ process_handle = Convert<Handle>(GetReg64(system, 1));
+ process_address = Convert<uint64_t>(GetReg64(system, 2));
+ size = Convert<uint64_t>(GetReg64(system, 3));
+ device_address = Convert<uint64_t>(GetReg64(system, 4));
+ option = Convert<uint32_t>(GetReg64(system, 5));
+
+ ret = MapDeviceAddressSpaceByForce64(system, das_handle, process_handle, process_address, size, device_address, option);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+}
+
+static void SvcWrap_MapDeviceAddressSpaceAligned64(Core::System& system) {
+ Result ret{};
+
+ Handle das_handle{};
+ Handle process_handle{};
+ uint64_t process_address{};
+ uint64_t size{};
+ uint64_t device_address{};
+ uint32_t option{};
+
+ das_handle = Convert<Handle>(GetReg64(system, 0));
+ process_handle = Convert<Handle>(GetReg64(system, 1));
+ process_address = Convert<uint64_t>(GetReg64(system, 2));
+ size = Convert<uint64_t>(GetReg64(system, 3));
+ device_address = Convert<uint64_t>(GetReg64(system, 4));
+ option = Convert<uint32_t>(GetReg64(system, 5));
+
+ ret = MapDeviceAddressSpaceAligned64(system, das_handle, process_handle, process_address, size, device_address, option);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+}
+
+static void SvcWrap_UnmapDeviceAddressSpace64(Core::System& system) {
+ Result ret{};
+
+ Handle das_handle{};
+ Handle process_handle{};
+ uint64_t process_address{};
+ uint64_t size{};
+ uint64_t device_address{};
+
+ das_handle = Convert<Handle>(GetReg64(system, 0));
+ process_handle = Convert<Handle>(GetReg64(system, 1));
+ process_address = Convert<uint64_t>(GetReg64(system, 2));
+ size = Convert<uint64_t>(GetReg64(system, 3));
+ device_address = Convert<uint64_t>(GetReg64(system, 4));
+
+ ret = UnmapDeviceAddressSpace64(system, das_handle, process_handle, process_address, size, device_address);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+}
+
+static void SvcWrap_InvalidateProcessDataCache64(Core::System& system) {
+ Result ret{};
+
+ Handle process_handle{};
+ uint64_t address{};
+ uint64_t size{};
+
+ process_handle = Convert<Handle>(GetReg64(system, 0));
+ address = Convert<uint64_t>(GetReg64(system, 1));
+ size = Convert<uint64_t>(GetReg64(system, 2));
+
+ ret = InvalidateProcessDataCache64(system, process_handle, address, size);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+}
+
+static void SvcWrap_StoreProcessDataCache64(Core::System& system) {
+ Result ret{};
+
+ Handle process_handle{};
+ uint64_t address{};
+ uint64_t size{};
+
+ process_handle = Convert<Handle>(GetReg64(system, 0));
+ address = Convert<uint64_t>(GetReg64(system, 1));
+ size = Convert<uint64_t>(GetReg64(system, 2));
+
+ ret = StoreProcessDataCache64(system, process_handle, address, size);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+}
+
+static void SvcWrap_FlushProcessDataCache64(Core::System& system) {
+ Result ret{};
+
+ Handle process_handle{};
+ uint64_t address{};
+ uint64_t size{};
+
+ process_handle = Convert<Handle>(GetReg64(system, 0));
+ address = Convert<uint64_t>(GetReg64(system, 1));
+ size = Convert<uint64_t>(GetReg64(system, 2));
+
+ ret = FlushProcessDataCache64(system, process_handle, address, size);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+}
+
+static void SvcWrap_DebugActiveProcess64(Core::System& system) {
+ Result ret{};
+
+ Handle out_handle{};
+ uint64_t process_id{};
+
+ process_id = Convert<uint64_t>(GetReg64(system, 1));
+
+ ret = DebugActiveProcess64(system, std::addressof(out_handle), process_id);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+ SetReg64(system, 1, Convert<uint64_t>(out_handle));
+}
+
+static void SvcWrap_BreakDebugProcess64(Core::System& system) {
+ Result ret{};
+
+ Handle debug_handle{};
+
+ debug_handle = Convert<Handle>(GetReg64(system, 0));
+
+ ret = BreakDebugProcess64(system, debug_handle);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+}
+
+static void SvcWrap_TerminateDebugProcess64(Core::System& system) {
+ Result ret{};
+
+ Handle debug_handle{};
+
+ debug_handle = Convert<Handle>(GetReg64(system, 0));
+
+ ret = TerminateDebugProcess64(system, debug_handle);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+}
+
+static void SvcWrap_GetDebugEvent64(Core::System& system) {
+ Result ret{};
+
+ uint64_t out_info{};
+ Handle debug_handle{};
+
+ out_info = Convert<uint64_t>(GetReg64(system, 0));
+ debug_handle = Convert<Handle>(GetReg64(system, 1));
+
+ ret = GetDebugEvent64(system, out_info, debug_handle);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+}
+
+static void SvcWrap_ContinueDebugEvent64(Core::System& system) {
+ Result ret{};
+
+ Handle debug_handle{};
+ uint32_t flags{};
+ uint64_t thread_ids{};
+ int32_t num_thread_ids{};
+
+ debug_handle = Convert<Handle>(GetReg64(system, 0));
+ flags = Convert<uint32_t>(GetReg64(system, 1));
+ thread_ids = Convert<uint64_t>(GetReg64(system, 2));
+ num_thread_ids = Convert<int32_t>(GetReg64(system, 3));
+
+ ret = ContinueDebugEvent64(system, debug_handle, flags, thread_ids, num_thread_ids);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+}
+
+static void SvcWrap_GetProcessList64(Core::System& system) {
+ Result ret{};
+
+ int32_t out_num_processes{};
+ uint64_t out_process_ids{};
+ int32_t max_out_count{};
+
+ out_process_ids = Convert<uint64_t>(GetReg64(system, 1));
+ max_out_count = Convert<int32_t>(GetReg64(system, 2));
+
+ ret = GetProcessList64(system, std::addressof(out_num_processes), out_process_ids, max_out_count);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+ SetReg64(system, 1, Convert<uint64_t>(out_num_processes));
+}
+
+static void SvcWrap_GetThreadList64(Core::System& system) {
+ Result ret{};
+
+ int32_t out_num_threads{};
+ uint64_t out_thread_ids{};
+ int32_t max_out_count{};
+ Handle debug_handle{};
+
+ out_thread_ids = Convert<uint64_t>(GetReg64(system, 1));
+ max_out_count = Convert<int32_t>(GetReg64(system, 2));
+ debug_handle = Convert<Handle>(GetReg64(system, 3));
+
+ ret = GetThreadList64(system, std::addressof(out_num_threads), out_thread_ids, max_out_count, debug_handle);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+ SetReg64(system, 1, Convert<uint64_t>(out_num_threads));
+}
+
+static void SvcWrap_GetDebugThreadContext64(Core::System& system) {
+ Result ret{};
+
+ uint64_t out_context{};
+ Handle debug_handle{};
+ uint64_t thread_id{};
+ uint32_t context_flags{};
+
+ out_context = Convert<uint64_t>(GetReg64(system, 0));
+ debug_handle = Convert<Handle>(GetReg64(system, 1));
+ thread_id = Convert<uint64_t>(GetReg64(system, 2));
+ context_flags = Convert<uint32_t>(GetReg64(system, 3));
+
+ ret = GetDebugThreadContext64(system, out_context, debug_handle, thread_id, context_flags);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+}
+
+static void SvcWrap_SetDebugThreadContext64(Core::System& system) {
+ Result ret{};
+
+ Handle debug_handle{};
+ uint64_t thread_id{};
+ uint64_t context{};
+ uint32_t context_flags{};
+
+ debug_handle = Convert<Handle>(GetReg64(system, 0));
+ thread_id = Convert<uint64_t>(GetReg64(system, 1));
+ context = Convert<uint64_t>(GetReg64(system, 2));
+ context_flags = Convert<uint32_t>(GetReg64(system, 3));
+
+ ret = SetDebugThreadContext64(system, debug_handle, thread_id, context, context_flags);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+}
+
+static void SvcWrap_QueryDebugProcessMemory64(Core::System& system) {
+ Result ret{};
+
+ PageInfo out_page_info{};
+ uint64_t out_memory_info{};
+ Handle process_handle{};
+ uint64_t address{};
+
+ out_memory_info = Convert<uint64_t>(GetReg64(system, 0));
+ process_handle = Convert<Handle>(GetReg64(system, 2));
+ address = Convert<uint64_t>(GetReg64(system, 3));
+
+ ret = QueryDebugProcessMemory64(system, out_memory_info, std::addressof(out_page_info), process_handle, address);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+ SetReg64(system, 1, Convert<uint64_t>(out_page_info));
+}
+
+static void SvcWrap_ReadDebugProcessMemory64(Core::System& system) {
+ Result ret{};
+
+ uint64_t buffer{};
+ Handle debug_handle{};
+ uint64_t address{};
+ uint64_t size{};
+
+ buffer = Convert<uint64_t>(GetReg64(system, 0));
+ debug_handle = Convert<Handle>(GetReg64(system, 1));
+ address = Convert<uint64_t>(GetReg64(system, 2));
+ size = Convert<uint64_t>(GetReg64(system, 3));
+
+ ret = ReadDebugProcessMemory64(system, buffer, debug_handle, address, size);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+}
+
+static void SvcWrap_WriteDebugProcessMemory64(Core::System& system) {
+ Result ret{};
+
+ Handle debug_handle{};
+ uint64_t buffer{};
+ uint64_t address{};
+ uint64_t size{};
+
+ debug_handle = Convert<Handle>(GetReg64(system, 0));
+ buffer = Convert<uint64_t>(GetReg64(system, 1));
+ address = Convert<uint64_t>(GetReg64(system, 2));
+ size = Convert<uint64_t>(GetReg64(system, 3));
+
+ ret = WriteDebugProcessMemory64(system, debug_handle, buffer, address, size);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+}
+
+static void SvcWrap_SetHardwareBreakPoint64(Core::System& system) {
+ Result ret{};
+
+ HardwareBreakPointRegisterName name{};
+ uint64_t flags{};
+ uint64_t value{};
+
+ name = Convert<HardwareBreakPointRegisterName>(GetReg64(system, 0));
+ flags = Convert<uint64_t>(GetReg64(system, 1));
+ value = Convert<uint64_t>(GetReg64(system, 2));
+
+ ret = SetHardwareBreakPoint64(system, name, flags, value);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+}
+
+static void SvcWrap_GetDebugThreadParam64(Core::System& system) {
+ Result ret{};
+
+ uint64_t out_64{};
+ uint32_t out_32{};
+ Handle debug_handle{};
+ uint64_t thread_id{};
+ DebugThreadParam param{};
+
+ debug_handle = Convert<Handle>(GetReg64(system, 2));
+ thread_id = Convert<uint64_t>(GetReg64(system, 3));
+ param = Convert<DebugThreadParam>(GetReg64(system, 4));
+
+ ret = GetDebugThreadParam64(system, std::addressof(out_64), std::addressof(out_32), debug_handle, thread_id, param);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+ SetReg64(system, 1, Convert<uint64_t>(out_64));
+ SetReg64(system, 2, Convert<uint64_t>(out_32));
+}
+
+static void SvcWrap_GetSystemInfo64(Core::System& system) {
+ Result ret{};
+
+ uint64_t out{};
+ SystemInfoType info_type{};
+ Handle handle{};
+ uint64_t info_subtype{};
+
+ info_type = Convert<SystemInfoType>(GetReg64(system, 1));
+ handle = Convert<Handle>(GetReg64(system, 2));
+ info_subtype = Convert<uint64_t>(GetReg64(system, 3));
+
+ ret = GetSystemInfo64(system, std::addressof(out), info_type, handle, info_subtype);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+ SetReg64(system, 1, Convert<uint64_t>(out));
+}
+
+static void SvcWrap_CreatePort64(Core::System& system) {
+ Result ret{};
+
+ Handle out_server_handle{};
+ Handle out_client_handle{};
+ int32_t max_sessions{};
+ bool is_light{};
+ uint64_t name{};
+
+ max_sessions = Convert<int32_t>(GetReg64(system, 2));
+ is_light = Convert<bool>(GetReg64(system, 3));
+ name = Convert<uint64_t>(GetReg64(system, 4));
+
+ ret = CreatePort64(system, std::addressof(out_server_handle), std::addressof(out_client_handle), max_sessions, is_light, name);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+ SetReg64(system, 1, Convert<uint64_t>(out_server_handle));
+ SetReg64(system, 2, Convert<uint64_t>(out_client_handle));
+}
+
+static void SvcWrap_ManageNamedPort64(Core::System& system) {
+ Result ret{};
+
+ Handle out_server_handle{};
+ uint64_t name{};
+ int32_t max_sessions{};
+
+ name = Convert<uint64_t>(GetReg64(system, 1));
+ max_sessions = Convert<int32_t>(GetReg64(system, 2));
+
+ ret = ManageNamedPort64(system, std::addressof(out_server_handle), name, max_sessions);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+ SetReg64(system, 1, Convert<uint64_t>(out_server_handle));
+}
+
+static void SvcWrap_ConnectToPort64(Core::System& system) {
+ Result ret{};
+
+ Handle out_handle{};
+ Handle port{};
+
+ port = Convert<Handle>(GetReg64(system, 1));
+
+ ret = ConnectToPort64(system, std::addressof(out_handle), port);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+ SetReg64(system, 1, Convert<uint64_t>(out_handle));
+}
+
+static void SvcWrap_SetProcessMemoryPermission64(Core::System& system) {
+ Result ret{};
+
+ Handle process_handle{};
+ uint64_t address{};
+ uint64_t size{};
+ MemoryPermission perm{};
+
+ process_handle = Convert<Handle>(GetReg64(system, 0));
+ address = Convert<uint64_t>(GetReg64(system, 1));
+ size = Convert<uint64_t>(GetReg64(system, 2));
+ perm = Convert<MemoryPermission>(GetReg64(system, 3));
+
+ ret = SetProcessMemoryPermission64(system, process_handle, address, size, perm);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+}
+
+static void SvcWrap_MapProcessMemory64(Core::System& system) {
+ Result ret{};
+
+ uint64_t dst_address{};
+ Handle process_handle{};
+ uint64_t src_address{};
+ uint64_t size{};
+
+ dst_address = Convert<uint64_t>(GetReg64(system, 0));
+ process_handle = Convert<Handle>(GetReg64(system, 1));
+ src_address = Convert<uint64_t>(GetReg64(system, 2));
+ size = Convert<uint64_t>(GetReg64(system, 3));
+
+ ret = MapProcessMemory64(system, dst_address, process_handle, src_address, size);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+}
+
+static void SvcWrap_UnmapProcessMemory64(Core::System& system) {
+ Result ret{};
+
+ uint64_t dst_address{};
+ Handle process_handle{};
+ uint64_t src_address{};
+ uint64_t size{};
+
+ dst_address = Convert<uint64_t>(GetReg64(system, 0));
+ process_handle = Convert<Handle>(GetReg64(system, 1));
+ src_address = Convert<uint64_t>(GetReg64(system, 2));
+ size = Convert<uint64_t>(GetReg64(system, 3));
+
+ ret = UnmapProcessMemory64(system, dst_address, process_handle, src_address, size);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+}
+
+static void SvcWrap_QueryProcessMemory64(Core::System& system) {
+ Result ret{};
+
+ PageInfo out_page_info{};
+ uint64_t out_memory_info{};
+ Handle process_handle{};
+ uint64_t address{};
+
+ out_memory_info = Convert<uint64_t>(GetReg64(system, 0));
+ process_handle = Convert<Handle>(GetReg64(system, 2));
+ address = Convert<uint64_t>(GetReg64(system, 3));
+
+ ret = QueryProcessMemory64(system, out_memory_info, std::addressof(out_page_info), process_handle, address);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+ SetReg64(system, 1, Convert<uint64_t>(out_page_info));
+}
+
+static void SvcWrap_MapProcessCodeMemory64(Core::System& system) {
+ Result ret{};
+
+ Handle process_handle{};
+ uint64_t dst_address{};
+ uint64_t src_address{};
+ uint64_t size{};
+
+ process_handle = Convert<Handle>(GetReg64(system, 0));
+ dst_address = Convert<uint64_t>(GetReg64(system, 1));
+ src_address = Convert<uint64_t>(GetReg64(system, 2));
+ size = Convert<uint64_t>(GetReg64(system, 3));
+
+ ret = MapProcessCodeMemory64(system, process_handle, dst_address, src_address, size);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+}
+
+static void SvcWrap_UnmapProcessCodeMemory64(Core::System& system) {
+ Result ret{};
+
+ Handle process_handle{};
+ uint64_t dst_address{};
+ uint64_t src_address{};
+ uint64_t size{};
+
+ process_handle = Convert<Handle>(GetReg64(system, 0));
+ dst_address = Convert<uint64_t>(GetReg64(system, 1));
+ src_address = Convert<uint64_t>(GetReg64(system, 2));
+ size = Convert<uint64_t>(GetReg64(system, 3));
+
+ ret = UnmapProcessCodeMemory64(system, process_handle, dst_address, src_address, size);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+}
+
+static void SvcWrap_CreateProcess64(Core::System& system) {
+ Result ret{};
+
+ Handle out_handle{};
+ uint64_t parameters{};
+ uint64_t caps{};
+ int32_t num_caps{};
+
+ parameters = Convert<uint64_t>(GetReg64(system, 1));
+ caps = Convert<uint64_t>(GetReg64(system, 2));
+ num_caps = Convert<int32_t>(GetReg64(system, 3));
+
+ ret = CreateProcess64(system, std::addressof(out_handle), parameters, caps, num_caps);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+ SetReg64(system, 1, Convert<uint64_t>(out_handle));
+}
+
+static void SvcWrap_StartProcess64(Core::System& system) {
+ Result ret{};
+
+ Handle process_handle{};
+ int32_t priority{};
+ int32_t core_id{};
+ uint64_t main_thread_stack_size{};
+
+ process_handle = Convert<Handle>(GetReg64(system, 0));
+ priority = Convert<int32_t>(GetReg64(system, 1));
+ core_id = Convert<int32_t>(GetReg64(system, 2));
+ main_thread_stack_size = Convert<uint64_t>(GetReg64(system, 3));
+
+ ret = StartProcess64(system, process_handle, priority, core_id, main_thread_stack_size);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+}
+
+static void SvcWrap_TerminateProcess64(Core::System& system) {
+ Result ret{};
+
+ Handle process_handle{};
+
+ process_handle = Convert<Handle>(GetReg64(system, 0));
+
+ ret = TerminateProcess64(system, process_handle);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+}
+
+static void SvcWrap_GetProcessInfo64(Core::System& system) {
+ Result ret{};
+
+ int64_t out_info{};
+ Handle process_handle{};
+ ProcessInfoType info_type{};
+
+ process_handle = Convert<Handle>(GetReg64(system, 1));
+ info_type = Convert<ProcessInfoType>(GetReg64(system, 2));
+
+ ret = GetProcessInfo64(system, std::addressof(out_info), process_handle, info_type);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+ SetReg64(system, 1, Convert<uint64_t>(out_info));
+}
+
+static void SvcWrap_CreateResourceLimit64(Core::System& system) {
+ Result ret{};
+
+ Handle out_handle{};
+
+ ret = CreateResourceLimit64(system, std::addressof(out_handle));
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+ SetReg64(system, 1, Convert<uint64_t>(out_handle));
+}
+
+static void SvcWrap_SetResourceLimitLimitValue64(Core::System& system) {
+ Result ret{};
+
+ Handle resource_limit_handle{};
+ LimitableResource which{};
+ int64_t limit_value{};
+
+ resource_limit_handle = Convert<Handle>(GetReg64(system, 0));
+ which = Convert<LimitableResource>(GetReg64(system, 1));
+ limit_value = Convert<int64_t>(GetReg64(system, 2));
+
+ ret = SetResourceLimitLimitValue64(system, resource_limit_handle, which, limit_value);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+}
+
+static void SvcWrap_MapInsecureMemory64(Core::System& system) {
+ Result ret{};
+
+ uint64_t address{};
+ uint64_t size{};
+
+ address = Convert<uint64_t>(GetReg64(system, 0));
+ size = Convert<uint64_t>(GetReg64(system, 1));
+
+ ret = MapInsecureMemory64(system, address, size);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+}
+
+static void SvcWrap_UnmapInsecureMemory64(Core::System& system) {
+ Result ret{};
+
+ uint64_t address{};
+ uint64_t size{};
+
+ address = Convert<uint64_t>(GetReg64(system, 0));
+ size = Convert<uint64_t>(GetReg64(system, 1));
+
+ ret = UnmapInsecureMemory64(system, address, size);
+
+ SetReg64(system, 0, Convert<uint64_t>(ret));
+}
+
+static void Call32(Core::System& system, u32 imm) {
+ switch (static_cast<SvcId>(imm)) {
+ case SvcId::SetHeapSize:
+ return SvcWrap_SetHeapSize64From32(system);
+ case SvcId::SetMemoryPermission:
+ return SvcWrap_SetMemoryPermission64From32(system);
+ case SvcId::SetMemoryAttribute:
+ return SvcWrap_SetMemoryAttribute64From32(system);
+ case SvcId::MapMemory:
+ return SvcWrap_MapMemory64From32(system);
+ case SvcId::UnmapMemory:
+ return SvcWrap_UnmapMemory64From32(system);
+ case SvcId::QueryMemory:
+ return SvcWrap_QueryMemory64From32(system);
+ case SvcId::ExitProcess:
+ return SvcWrap_ExitProcess64From32(system);
+ case SvcId::CreateThread:
+ return SvcWrap_CreateThread64From32(system);
+ case SvcId::StartThread:
+ return SvcWrap_StartThread64From32(system);
+ case SvcId::ExitThread:
+ return SvcWrap_ExitThread64From32(system);
+ case SvcId::SleepThread:
+ return SvcWrap_SleepThread64From32(system);
+ case SvcId::GetThreadPriority:
+ return SvcWrap_GetThreadPriority64From32(system);
+ case SvcId::SetThreadPriority:
+ return SvcWrap_SetThreadPriority64From32(system);
+ case SvcId::GetThreadCoreMask:
+ return SvcWrap_GetThreadCoreMask64From32(system);
+ case SvcId::SetThreadCoreMask:
+ return SvcWrap_SetThreadCoreMask64From32(system);
+ case SvcId::GetCurrentProcessorNumber:
+ return SvcWrap_GetCurrentProcessorNumber64From32(system);
+ case SvcId::SignalEvent:
+ return SvcWrap_SignalEvent64From32(system);
+ case SvcId::ClearEvent:
+ return SvcWrap_ClearEvent64From32(system);
+ case SvcId::MapSharedMemory:
+ return SvcWrap_MapSharedMemory64From32(system);
+ case SvcId::UnmapSharedMemory:
+ return SvcWrap_UnmapSharedMemory64From32(system);
+ case SvcId::CreateTransferMemory:
+ return SvcWrap_CreateTransferMemory64From32(system);
+ case SvcId::CloseHandle:
+ return SvcWrap_CloseHandle64From32(system);
+ case SvcId::ResetSignal:
+ return SvcWrap_ResetSignal64From32(system);
+ case SvcId::WaitSynchronization:
+ return SvcWrap_WaitSynchronization64From32(system);
+ case SvcId::CancelSynchronization:
+ return SvcWrap_CancelSynchronization64From32(system);
+ case SvcId::ArbitrateLock:
+ return SvcWrap_ArbitrateLock64From32(system);
+ case SvcId::ArbitrateUnlock:
+ return SvcWrap_ArbitrateUnlock64From32(system);
+ case SvcId::WaitProcessWideKeyAtomic:
+ return SvcWrap_WaitProcessWideKeyAtomic64From32(system);
+ case SvcId::SignalProcessWideKey:
+ return SvcWrap_SignalProcessWideKey64From32(system);
+ case SvcId::GetSystemTick:
+ return SvcWrap_GetSystemTick64From32(system);
+ case SvcId::ConnectToNamedPort:
+ return SvcWrap_ConnectToNamedPort64From32(system);
+ case SvcId::SendSyncRequestLight:
+ return SvcWrap_SendSyncRequestLight64From32(system);
+ case SvcId::SendSyncRequest:
+ return SvcWrap_SendSyncRequest64From32(system);
+ case SvcId::SendSyncRequestWithUserBuffer:
+ return SvcWrap_SendSyncRequestWithUserBuffer64From32(system);
+ case SvcId::SendAsyncRequestWithUserBuffer:
+ return SvcWrap_SendAsyncRequestWithUserBuffer64From32(system);
+ case SvcId::GetProcessId:
+ return SvcWrap_GetProcessId64From32(system);
+ case SvcId::GetThreadId:
+ return SvcWrap_GetThreadId64From32(system);
+ case SvcId::Break:
+ return SvcWrap_Break64From32(system);
+ case SvcId::OutputDebugString:
+ return SvcWrap_OutputDebugString64From32(system);
+ case SvcId::ReturnFromException:
+ return SvcWrap_ReturnFromException64From32(system);
+ case SvcId::GetInfo:
+ return SvcWrap_GetInfo64From32(system);
+ case SvcId::FlushEntireDataCache:
+ return SvcWrap_FlushEntireDataCache64From32(system);
+ case SvcId::FlushDataCache:
+ return SvcWrap_FlushDataCache64From32(system);
+ case SvcId::MapPhysicalMemory:
+ return SvcWrap_MapPhysicalMemory64From32(system);
+ case SvcId::UnmapPhysicalMemory:
+ return SvcWrap_UnmapPhysicalMemory64From32(system);
+ case SvcId::GetDebugFutureThreadInfo:
+ return SvcWrap_GetDebugFutureThreadInfo64From32(system);
+ case SvcId::GetLastThreadInfo:
+ return SvcWrap_GetLastThreadInfo64From32(system);
+ case SvcId::GetResourceLimitLimitValue:
+ return SvcWrap_GetResourceLimitLimitValue64From32(system);
+ case SvcId::GetResourceLimitCurrentValue:
+ return SvcWrap_GetResourceLimitCurrentValue64From32(system);
+ case SvcId::SetThreadActivity:
+ return SvcWrap_SetThreadActivity64From32(system);
+ case SvcId::GetThreadContext3:
+ return SvcWrap_GetThreadContext364From32(system);
+ case SvcId::WaitForAddress:
+ return SvcWrap_WaitForAddress64From32(system);
+ case SvcId::SignalToAddress:
+ return SvcWrap_SignalToAddress64From32(system);
+ case SvcId::SynchronizePreemptionState:
+ return SvcWrap_SynchronizePreemptionState64From32(system);
+ case SvcId::GetResourceLimitPeakValue:
+ return SvcWrap_GetResourceLimitPeakValue64From32(system);
+ case SvcId::CreateIoPool:
+ return SvcWrap_CreateIoPool64From32(system);
+ case SvcId::CreateIoRegion:
+ return SvcWrap_CreateIoRegion64From32(system);
+ case SvcId::KernelDebug:
+ return SvcWrap_KernelDebug64From32(system);
+ case SvcId::ChangeKernelTraceState:
+ return SvcWrap_ChangeKernelTraceState64From32(system);
+ case SvcId::CreateSession:
+ return SvcWrap_CreateSession64From32(system);
+ case SvcId::AcceptSession:
+ return SvcWrap_AcceptSession64From32(system);
+ case SvcId::ReplyAndReceiveLight:
+ return SvcWrap_ReplyAndReceiveLight64From32(system);
+ case SvcId::ReplyAndReceive:
+ return SvcWrap_ReplyAndReceive64From32(system);
+ case SvcId::ReplyAndReceiveWithUserBuffer:
+ return SvcWrap_ReplyAndReceiveWithUserBuffer64From32(system);
+ case SvcId::CreateEvent:
+ return SvcWrap_CreateEvent64From32(system);
+ case SvcId::MapIoRegion:
+ return SvcWrap_MapIoRegion64From32(system);
+ case SvcId::UnmapIoRegion:
+ return SvcWrap_UnmapIoRegion64From32(system);
+ case SvcId::MapPhysicalMemoryUnsafe:
+ return SvcWrap_MapPhysicalMemoryUnsafe64From32(system);
+ case SvcId::UnmapPhysicalMemoryUnsafe:
+ return SvcWrap_UnmapPhysicalMemoryUnsafe64From32(system);
+ case SvcId::SetUnsafeLimit:
+ return SvcWrap_SetUnsafeLimit64From32(system);
+ case SvcId::CreateCodeMemory:
+ return SvcWrap_CreateCodeMemory64From32(system);
+ case SvcId::ControlCodeMemory:
+ return SvcWrap_ControlCodeMemory64From32(system);
+ case SvcId::SleepSystem:
+ return SvcWrap_SleepSystem64From32(system);
+ case SvcId::ReadWriteRegister:
+ return SvcWrap_ReadWriteRegister64From32(system);
+ case SvcId::SetProcessActivity:
+ return SvcWrap_SetProcessActivity64From32(system);
+ case SvcId::CreateSharedMemory:
+ return SvcWrap_CreateSharedMemory64From32(system);
+ case SvcId::MapTransferMemory:
+ return SvcWrap_MapTransferMemory64From32(system);
+ case SvcId::UnmapTransferMemory:
+ return SvcWrap_UnmapTransferMemory64From32(system);
+ case SvcId::CreateInterruptEvent:
+ return SvcWrap_CreateInterruptEvent64From32(system);
+ case SvcId::QueryPhysicalAddress:
+ return SvcWrap_QueryPhysicalAddress64From32(system);
+ case SvcId::QueryIoMapping:
+ return SvcWrap_QueryIoMapping64From32(system);
+ case SvcId::CreateDeviceAddressSpace:
+ return SvcWrap_CreateDeviceAddressSpace64From32(system);
+ case SvcId::AttachDeviceAddressSpace:
+ return SvcWrap_AttachDeviceAddressSpace64From32(system);
+ case SvcId::DetachDeviceAddressSpace:
+ return SvcWrap_DetachDeviceAddressSpace64From32(system);
+ case SvcId::MapDeviceAddressSpaceByForce:
+ return SvcWrap_MapDeviceAddressSpaceByForce64From32(system);
+ case SvcId::MapDeviceAddressSpaceAligned:
+ return SvcWrap_MapDeviceAddressSpaceAligned64From32(system);
+ case SvcId::UnmapDeviceAddressSpace:
+ return SvcWrap_UnmapDeviceAddressSpace64From32(system);
+ case SvcId::InvalidateProcessDataCache:
+ return SvcWrap_InvalidateProcessDataCache64From32(system);
+ case SvcId::StoreProcessDataCache:
+ return SvcWrap_StoreProcessDataCache64From32(system);
+ case SvcId::FlushProcessDataCache:
+ return SvcWrap_FlushProcessDataCache64From32(system);
+ case SvcId::DebugActiveProcess:
+ return SvcWrap_DebugActiveProcess64From32(system);
+ case SvcId::BreakDebugProcess:
+ return SvcWrap_BreakDebugProcess64From32(system);
+ case SvcId::TerminateDebugProcess:
+ return SvcWrap_TerminateDebugProcess64From32(system);
+ case SvcId::GetDebugEvent:
+ return SvcWrap_GetDebugEvent64From32(system);
+ case SvcId::ContinueDebugEvent:
+ return SvcWrap_ContinueDebugEvent64From32(system);
+ case SvcId::GetProcessList:
+ return SvcWrap_GetProcessList64From32(system);
+ case SvcId::GetThreadList:
+ return SvcWrap_GetThreadList64From32(system);
+ case SvcId::GetDebugThreadContext:
+ return SvcWrap_GetDebugThreadContext64From32(system);
+ case SvcId::SetDebugThreadContext:
+ return SvcWrap_SetDebugThreadContext64From32(system);
+ case SvcId::QueryDebugProcessMemory:
+ return SvcWrap_QueryDebugProcessMemory64From32(system);
+ case SvcId::ReadDebugProcessMemory:
+ return SvcWrap_ReadDebugProcessMemory64From32(system);
+ case SvcId::WriteDebugProcessMemory:
+ return SvcWrap_WriteDebugProcessMemory64From32(system);
+ case SvcId::SetHardwareBreakPoint:
+ return SvcWrap_SetHardwareBreakPoint64From32(system);
+ case SvcId::GetDebugThreadParam:
+ return SvcWrap_GetDebugThreadParam64From32(system);
+ case SvcId::GetSystemInfo:
+ return SvcWrap_GetSystemInfo64From32(system);
+ case SvcId::CreatePort:
+ return SvcWrap_CreatePort64From32(system);
+ case SvcId::ManageNamedPort:
+ return SvcWrap_ManageNamedPort64From32(system);
+ case SvcId::ConnectToPort:
+ return SvcWrap_ConnectToPort64From32(system);
+ case SvcId::SetProcessMemoryPermission:
+ return SvcWrap_SetProcessMemoryPermission64From32(system);
+ case SvcId::MapProcessMemory:
+ return SvcWrap_MapProcessMemory64From32(system);
+ case SvcId::UnmapProcessMemory:
+ return SvcWrap_UnmapProcessMemory64From32(system);
+ case SvcId::QueryProcessMemory:
+ return SvcWrap_QueryProcessMemory64From32(system);
+ case SvcId::MapProcessCodeMemory:
+ return SvcWrap_MapProcessCodeMemory64From32(system);
+ case SvcId::UnmapProcessCodeMemory:
+ return SvcWrap_UnmapProcessCodeMemory64From32(system);
+ case SvcId::CreateProcess:
+ return SvcWrap_CreateProcess64From32(system);
+ case SvcId::StartProcess:
+ return SvcWrap_StartProcess64From32(system);
+ case SvcId::TerminateProcess:
+ return SvcWrap_TerminateProcess64From32(system);
+ case SvcId::GetProcessInfo:
+ return SvcWrap_GetProcessInfo64From32(system);
+ case SvcId::CreateResourceLimit:
+ return SvcWrap_CreateResourceLimit64From32(system);
+ case SvcId::SetResourceLimitLimitValue:
+ return SvcWrap_SetResourceLimitLimitValue64From32(system);
+ case SvcId::CallSecureMonitor:
+ return SvcWrap_CallSecureMonitor64From32(system);
+ case SvcId::MapInsecureMemory:
+ return SvcWrap_MapInsecureMemory64From32(system);
+ case SvcId::UnmapInsecureMemory:
+ return SvcWrap_UnmapInsecureMemory64From32(system);
+ default:
+ LOG_CRITICAL(Kernel_SVC, "Unknown SVC {:x}!", imm);
+ break;
}
- return &SVC_Table_32[func_num];
}
-static const FunctionDef* GetSVCInfo64(u32 func_num) {
- if (func_num >= std::size(SVC_Table_64)) {
- LOG_ERROR(Kernel_SVC, "Unknown svc=0x{:02X}", func_num);
- return nullptr;
+static void Call64(Core::System& system, u32 imm) {
+ switch (static_cast<SvcId>(imm)) {
+ case SvcId::SetHeapSize:
+ return SvcWrap_SetHeapSize64(system);
+ case SvcId::SetMemoryPermission:
+ return SvcWrap_SetMemoryPermission64(system);
+ case SvcId::SetMemoryAttribute:
+ return SvcWrap_SetMemoryAttribute64(system);
+ case SvcId::MapMemory:
+ return SvcWrap_MapMemory64(system);
+ case SvcId::UnmapMemory:
+ return SvcWrap_UnmapMemory64(system);
+ case SvcId::QueryMemory:
+ return SvcWrap_QueryMemory64(system);
+ case SvcId::ExitProcess:
+ return SvcWrap_ExitProcess64(system);
+ case SvcId::CreateThread:
+ return SvcWrap_CreateThread64(system);
+ case SvcId::StartThread:
+ return SvcWrap_StartThread64(system);
+ case SvcId::ExitThread:
+ return SvcWrap_ExitThread64(system);
+ case SvcId::SleepThread:
+ return SvcWrap_SleepThread64(system);
+ case SvcId::GetThreadPriority:
+ return SvcWrap_GetThreadPriority64(system);
+ case SvcId::SetThreadPriority:
+ return SvcWrap_SetThreadPriority64(system);
+ case SvcId::GetThreadCoreMask:
+ return SvcWrap_GetThreadCoreMask64(system);
+ case SvcId::SetThreadCoreMask:
+ return SvcWrap_SetThreadCoreMask64(system);
+ case SvcId::GetCurrentProcessorNumber:
+ return SvcWrap_GetCurrentProcessorNumber64(system);
+ case SvcId::SignalEvent:
+ return SvcWrap_SignalEvent64(system);
+ case SvcId::ClearEvent:
+ return SvcWrap_ClearEvent64(system);
+ case SvcId::MapSharedMemory:
+ return SvcWrap_MapSharedMemory64(system);
+ case SvcId::UnmapSharedMemory:
+ return SvcWrap_UnmapSharedMemory64(system);
+ case SvcId::CreateTransferMemory:
+ return SvcWrap_CreateTransferMemory64(system);
+ case SvcId::CloseHandle:
+ return SvcWrap_CloseHandle64(system);
+ case SvcId::ResetSignal:
+ return SvcWrap_ResetSignal64(system);
+ case SvcId::WaitSynchronization:
+ return SvcWrap_WaitSynchronization64(system);
+ case SvcId::CancelSynchronization:
+ return SvcWrap_CancelSynchronization64(system);
+ case SvcId::ArbitrateLock:
+ return SvcWrap_ArbitrateLock64(system);
+ case SvcId::ArbitrateUnlock:
+ return SvcWrap_ArbitrateUnlock64(system);
+ case SvcId::WaitProcessWideKeyAtomic:
+ return SvcWrap_WaitProcessWideKeyAtomic64(system);
+ case SvcId::SignalProcessWideKey:
+ return SvcWrap_SignalProcessWideKey64(system);
+ case SvcId::GetSystemTick:
+ return SvcWrap_GetSystemTick64(system);
+ case SvcId::ConnectToNamedPort:
+ return SvcWrap_ConnectToNamedPort64(system);
+ case SvcId::SendSyncRequestLight:
+ return SvcWrap_SendSyncRequestLight64(system);
+ case SvcId::SendSyncRequest:
+ return SvcWrap_SendSyncRequest64(system);
+ case SvcId::SendSyncRequestWithUserBuffer:
+ return SvcWrap_SendSyncRequestWithUserBuffer64(system);
+ case SvcId::SendAsyncRequestWithUserBuffer:
+ return SvcWrap_SendAsyncRequestWithUserBuffer64(system);
+ case SvcId::GetProcessId:
+ return SvcWrap_GetProcessId64(system);
+ case SvcId::GetThreadId:
+ return SvcWrap_GetThreadId64(system);
+ case SvcId::Break:
+ return SvcWrap_Break64(system);
+ case SvcId::OutputDebugString:
+ return SvcWrap_OutputDebugString64(system);
+ case SvcId::ReturnFromException:
+ return SvcWrap_ReturnFromException64(system);
+ case SvcId::GetInfo:
+ return SvcWrap_GetInfo64(system);
+ case SvcId::FlushEntireDataCache:
+ return SvcWrap_FlushEntireDataCache64(system);
+ case SvcId::FlushDataCache:
+ return SvcWrap_FlushDataCache64(system);
+ case SvcId::MapPhysicalMemory:
+ return SvcWrap_MapPhysicalMemory64(system);
+ case SvcId::UnmapPhysicalMemory:
+ return SvcWrap_UnmapPhysicalMemory64(system);
+ case SvcId::GetDebugFutureThreadInfo:
+ return SvcWrap_GetDebugFutureThreadInfo64(system);
+ case SvcId::GetLastThreadInfo:
+ return SvcWrap_GetLastThreadInfo64(system);
+ case SvcId::GetResourceLimitLimitValue:
+ return SvcWrap_GetResourceLimitLimitValue64(system);
+ case SvcId::GetResourceLimitCurrentValue:
+ return SvcWrap_GetResourceLimitCurrentValue64(system);
+ case SvcId::SetThreadActivity:
+ return SvcWrap_SetThreadActivity64(system);
+ case SvcId::GetThreadContext3:
+ return SvcWrap_GetThreadContext364(system);
+ case SvcId::WaitForAddress:
+ return SvcWrap_WaitForAddress64(system);
+ case SvcId::SignalToAddress:
+ return SvcWrap_SignalToAddress64(system);
+ case SvcId::SynchronizePreemptionState:
+ return SvcWrap_SynchronizePreemptionState64(system);
+ case SvcId::GetResourceLimitPeakValue:
+ return SvcWrap_GetResourceLimitPeakValue64(system);
+ case SvcId::CreateIoPool:
+ return SvcWrap_CreateIoPool64(system);
+ case SvcId::CreateIoRegion:
+ return SvcWrap_CreateIoRegion64(system);
+ case SvcId::KernelDebug:
+ return SvcWrap_KernelDebug64(system);
+ case SvcId::ChangeKernelTraceState:
+ return SvcWrap_ChangeKernelTraceState64(system);
+ case SvcId::CreateSession:
+ return SvcWrap_CreateSession64(system);
+ case SvcId::AcceptSession:
+ return SvcWrap_AcceptSession64(system);
+ case SvcId::ReplyAndReceiveLight:
+ return SvcWrap_ReplyAndReceiveLight64(system);
+ case SvcId::ReplyAndReceive:
+ return SvcWrap_ReplyAndReceive64(system);
+ case SvcId::ReplyAndReceiveWithUserBuffer:
+ return SvcWrap_ReplyAndReceiveWithUserBuffer64(system);
+ case SvcId::CreateEvent:
+ return SvcWrap_CreateEvent64(system);
+ case SvcId::MapIoRegion:
+ return SvcWrap_MapIoRegion64(system);
+ case SvcId::UnmapIoRegion:
+ return SvcWrap_UnmapIoRegion64(system);
+ case SvcId::MapPhysicalMemoryUnsafe:
+ return SvcWrap_MapPhysicalMemoryUnsafe64(system);
+ case SvcId::UnmapPhysicalMemoryUnsafe:
+ return SvcWrap_UnmapPhysicalMemoryUnsafe64(system);
+ case SvcId::SetUnsafeLimit:
+ return SvcWrap_SetUnsafeLimit64(system);
+ case SvcId::CreateCodeMemory:
+ return SvcWrap_CreateCodeMemory64(system);
+ case SvcId::ControlCodeMemory:
+ return SvcWrap_ControlCodeMemory64(system);
+ case SvcId::SleepSystem:
+ return SvcWrap_SleepSystem64(system);
+ case SvcId::ReadWriteRegister:
+ return SvcWrap_ReadWriteRegister64(system);
+ case SvcId::SetProcessActivity:
+ return SvcWrap_SetProcessActivity64(system);
+ case SvcId::CreateSharedMemory:
+ return SvcWrap_CreateSharedMemory64(system);
+ case SvcId::MapTransferMemory:
+ return SvcWrap_MapTransferMemory64(system);
+ case SvcId::UnmapTransferMemory:
+ return SvcWrap_UnmapTransferMemory64(system);
+ case SvcId::CreateInterruptEvent:
+ return SvcWrap_CreateInterruptEvent64(system);
+ case SvcId::QueryPhysicalAddress:
+ return SvcWrap_QueryPhysicalAddress64(system);
+ case SvcId::QueryIoMapping:
+ return SvcWrap_QueryIoMapping64(system);
+ case SvcId::CreateDeviceAddressSpace:
+ return SvcWrap_CreateDeviceAddressSpace64(system);
+ case SvcId::AttachDeviceAddressSpace:
+ return SvcWrap_AttachDeviceAddressSpace64(system);
+ case SvcId::DetachDeviceAddressSpace:
+ return SvcWrap_DetachDeviceAddressSpace64(system);
+ case SvcId::MapDeviceAddressSpaceByForce:
+ return SvcWrap_MapDeviceAddressSpaceByForce64(system);
+ case SvcId::MapDeviceAddressSpaceAligned:
+ return SvcWrap_MapDeviceAddressSpaceAligned64(system);
+ case SvcId::UnmapDeviceAddressSpace:
+ return SvcWrap_UnmapDeviceAddressSpace64(system);
+ case SvcId::InvalidateProcessDataCache:
+ return SvcWrap_InvalidateProcessDataCache64(system);
+ case SvcId::StoreProcessDataCache:
+ return SvcWrap_StoreProcessDataCache64(system);
+ case SvcId::FlushProcessDataCache:
+ return SvcWrap_FlushProcessDataCache64(system);
+ case SvcId::DebugActiveProcess:
+ return SvcWrap_DebugActiveProcess64(system);
+ case SvcId::BreakDebugProcess:
+ return SvcWrap_BreakDebugProcess64(system);
+ case SvcId::TerminateDebugProcess:
+ return SvcWrap_TerminateDebugProcess64(system);
+ case SvcId::GetDebugEvent:
+ return SvcWrap_GetDebugEvent64(system);
+ case SvcId::ContinueDebugEvent:
+ return SvcWrap_ContinueDebugEvent64(system);
+ case SvcId::GetProcessList:
+ return SvcWrap_GetProcessList64(system);
+ case SvcId::GetThreadList:
+ return SvcWrap_GetThreadList64(system);
+ case SvcId::GetDebugThreadContext:
+ return SvcWrap_GetDebugThreadContext64(system);
+ case SvcId::SetDebugThreadContext:
+ return SvcWrap_SetDebugThreadContext64(system);
+ case SvcId::QueryDebugProcessMemory:
+ return SvcWrap_QueryDebugProcessMemory64(system);
+ case SvcId::ReadDebugProcessMemory:
+ return SvcWrap_ReadDebugProcessMemory64(system);
+ case SvcId::WriteDebugProcessMemory:
+ return SvcWrap_WriteDebugProcessMemory64(system);
+ case SvcId::SetHardwareBreakPoint:
+ return SvcWrap_SetHardwareBreakPoint64(system);
+ case SvcId::GetDebugThreadParam:
+ return SvcWrap_GetDebugThreadParam64(system);
+ case SvcId::GetSystemInfo:
+ return SvcWrap_GetSystemInfo64(system);
+ case SvcId::CreatePort:
+ return SvcWrap_CreatePort64(system);
+ case SvcId::ManageNamedPort:
+ return SvcWrap_ManageNamedPort64(system);
+ case SvcId::ConnectToPort:
+ return SvcWrap_ConnectToPort64(system);
+ case SvcId::SetProcessMemoryPermission:
+ return SvcWrap_SetProcessMemoryPermission64(system);
+ case SvcId::MapProcessMemory:
+ return SvcWrap_MapProcessMemory64(system);
+ case SvcId::UnmapProcessMemory:
+ return SvcWrap_UnmapProcessMemory64(system);
+ case SvcId::QueryProcessMemory:
+ return SvcWrap_QueryProcessMemory64(system);
+ case SvcId::MapProcessCodeMemory:
+ return SvcWrap_MapProcessCodeMemory64(system);
+ case SvcId::UnmapProcessCodeMemory:
+ return SvcWrap_UnmapProcessCodeMemory64(system);
+ case SvcId::CreateProcess:
+ return SvcWrap_CreateProcess64(system);
+ case SvcId::StartProcess:
+ return SvcWrap_StartProcess64(system);
+ case SvcId::TerminateProcess:
+ return SvcWrap_TerminateProcess64(system);
+ case SvcId::GetProcessInfo:
+ return SvcWrap_GetProcessInfo64(system);
+ case SvcId::CreateResourceLimit:
+ return SvcWrap_CreateResourceLimit64(system);
+ case SvcId::SetResourceLimitLimitValue:
+ return SvcWrap_SetResourceLimitLimitValue64(system);
+ case SvcId::CallSecureMonitor:
+ return SvcWrap_CallSecureMonitor64(system);
+ case SvcId::MapInsecureMemory:
+ return SvcWrap_MapInsecureMemory64(system);
+ case SvcId::UnmapInsecureMemory:
+ return SvcWrap_UnmapInsecureMemory64(system);
+ default:
+ LOG_CRITICAL(Kernel_SVC, "Unknown SVC {:x}!", imm);
+ break;
}
- return &SVC_Table_64[func_num];
}
+// clang-format on
-void Call(Core::System& system, u32 immediate) {
+void Call(Core::System& system, u32 imm) {
auto& kernel = system.Kernel();
kernel.EnterSVCProfile();
- auto* thread = GetCurrentThreadPointer(kernel);
- thread->SetIsCallingSvc();
-
- const FunctionDef* info = system.CurrentProcess()->Is64BitProcess() ? GetSVCInfo64(immediate)
- : GetSVCInfo32(immediate);
- if (info) {
- if (info->func) {
- info->func(system);
- } else {
- LOG_CRITICAL(Kernel_SVC, "Unimplemented SVC function {}(..)", info->name);
- }
+ if (GetCurrentProcess(system.Kernel()).Is64BitProcess()) {
+ Call64(system, imm);
} else {
- LOG_CRITICAL(Kernel_SVC, "Unknown SVC function 0x{:X}", immediate);
+ Call32(system, imm);
}
kernel.ExitSVCProfile();
diff --git a/src/core/hle/kernel/svc.h b/src/core/hle/kernel/svc.h
index 13f061b83..ac4696008 100644
--- a/src/core/hle/kernel/svc.h
+++ b/src/core/hle/kernel/svc.h
@@ -1,16 +1,536 @@
-// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
-#pragma once
+// This file is automatically generated using svc_generator.py.
-#include "common/common_types.h"
+#pragma once
namespace Core {
class System;
}
+#include "common/common_types.h"
+#include "core/hle/kernel/svc_types.h"
+#include "core/hle/result.h"
+
namespace Kernel::Svc {
-void Call(Core::System& system, u32 immediate);
+// clang-format off
+Result SetHeapSize(Core::System& system, uint64_t* out_address, uint64_t size);
+Result SetMemoryPermission(Core::System& system, uint64_t address, uint64_t size, MemoryPermission perm);
+Result SetMemoryAttribute(Core::System& system, uint64_t address, uint64_t size, uint32_t mask, uint32_t attr);
+Result MapMemory(Core::System& system, uint64_t dst_address, uint64_t src_address, uint64_t size);
+Result UnmapMemory(Core::System& system, uint64_t dst_address, uint64_t src_address, uint64_t size);
+Result QueryMemory(Core::System& system, uint64_t out_memory_info, PageInfo* out_page_info, uint64_t address);
+void ExitProcess(Core::System& system);
+Result CreateThread(Core::System& system, Handle* out_handle, uint64_t func, uint64_t arg, uint64_t stack_bottom, int32_t priority, int32_t core_id);
+Result StartThread(Core::System& system, Handle thread_handle);
+void ExitThread(Core::System& system);
+void SleepThread(Core::System& system, int64_t ns);
+Result GetThreadPriority(Core::System& system, int32_t* out_priority, Handle thread_handle);
+Result SetThreadPriority(Core::System& system, Handle thread_handle, int32_t priority);
+Result GetThreadCoreMask(Core::System& system, int32_t* out_core_id, uint64_t* out_affinity_mask, Handle thread_handle);
+Result SetThreadCoreMask(Core::System& system, Handle thread_handle, int32_t core_id, uint64_t affinity_mask);
+int32_t GetCurrentProcessorNumber(Core::System& system);
+Result SignalEvent(Core::System& system, Handle event_handle);
+Result ClearEvent(Core::System& system, Handle event_handle);
+Result MapSharedMemory(Core::System& system, Handle shmem_handle, uint64_t address, uint64_t size, MemoryPermission map_perm);
+Result UnmapSharedMemory(Core::System& system, Handle shmem_handle, uint64_t address, uint64_t size);
+Result CreateTransferMemory(Core::System& system, Handle* out_handle, uint64_t address, uint64_t size, MemoryPermission map_perm);
+Result CloseHandle(Core::System& system, Handle handle);
+Result ResetSignal(Core::System& system, Handle handle);
+Result WaitSynchronization(Core::System& system, int32_t* out_index, uint64_t handles, int32_t num_handles, int64_t timeout_ns);
+Result CancelSynchronization(Core::System& system, Handle handle);
+Result ArbitrateLock(Core::System& system, Handle thread_handle, uint64_t address, uint32_t tag);
+Result ArbitrateUnlock(Core::System& system, uint64_t address);
+Result WaitProcessWideKeyAtomic(Core::System& system, uint64_t address, uint64_t cv_key, uint32_t tag, int64_t timeout_ns);
+void SignalProcessWideKey(Core::System& system, uint64_t cv_key, int32_t count);
+int64_t GetSystemTick(Core::System& system);
+Result ConnectToNamedPort(Core::System& system, Handle* out_handle, uint64_t name);
+Result SendSyncRequest(Core::System& system, Handle session_handle);
+Result SendSyncRequestWithUserBuffer(Core::System& system, uint64_t message_buffer, uint64_t message_buffer_size, Handle session_handle);
+Result SendAsyncRequestWithUserBuffer(Core::System& system, Handle* out_event_handle, uint64_t message_buffer, uint64_t message_buffer_size, Handle session_handle);
+Result GetProcessId(Core::System& system, uint64_t* out_process_id, Handle process_handle);
+Result GetThreadId(Core::System& system, uint64_t* out_thread_id, Handle thread_handle);
+void Break(Core::System& system, BreakReason break_reason, uint64_t arg, uint64_t size);
+Result OutputDebugString(Core::System& system, uint64_t debug_str, uint64_t len);
+void ReturnFromException(Core::System& system, Result result);
+Result GetInfo(Core::System& system, uint64_t* out, InfoType info_type, Handle handle, uint64_t info_subtype);
+void FlushEntireDataCache(Core::System& system);
+Result FlushDataCache(Core::System& system, uint64_t address, uint64_t size);
+Result MapPhysicalMemory(Core::System& system, uint64_t address, uint64_t size);
+Result UnmapPhysicalMemory(Core::System& system, uint64_t address, uint64_t size);
+Result GetDebugFutureThreadInfo(Core::System& system, lp64::LastThreadContext* out_context, uint64_t* out_thread_id, Handle debug_handle, int64_t ns);
+Result GetLastThreadInfo(Core::System& system, lp64::LastThreadContext* out_context, uint64_t* out_tls_address, uint32_t* out_flags);
+Result GetResourceLimitLimitValue(Core::System& system, int64_t* out_limit_value, Handle resource_limit_handle, LimitableResource which);
+Result GetResourceLimitCurrentValue(Core::System& system, int64_t* out_current_value, Handle resource_limit_handle, LimitableResource which);
+Result SetThreadActivity(Core::System& system, Handle thread_handle, ThreadActivity thread_activity);
+Result GetThreadContext3(Core::System& system, uint64_t out_context, Handle thread_handle);
+Result WaitForAddress(Core::System& system, uint64_t address, ArbitrationType arb_type, int32_t value, int64_t timeout_ns);
+Result SignalToAddress(Core::System& system, uint64_t address, SignalType signal_type, int32_t value, int32_t count);
+void SynchronizePreemptionState(Core::System& system);
+Result GetResourceLimitPeakValue(Core::System& system, int64_t* out_peak_value, Handle resource_limit_handle, LimitableResource which);
+Result CreateIoPool(Core::System& system, Handle* out_handle, IoPoolType which);
+Result CreateIoRegion(Core::System& system, Handle* out_handle, Handle io_pool, uint64_t physical_address, uint64_t size, MemoryMapping mapping, MemoryPermission perm);
+void KernelDebug(Core::System& system, KernelDebugType kern_debug_type, uint64_t arg0, uint64_t arg1, uint64_t arg2);
+void ChangeKernelTraceState(Core::System& system, KernelTraceState kern_trace_state);
+Result CreateSession(Core::System& system, Handle* out_server_session_handle, Handle* out_client_session_handle, bool is_light, uint64_t name);
+Result AcceptSession(Core::System& system, Handle* out_handle, Handle port);
+Result ReplyAndReceive(Core::System& system, int32_t* out_index, uint64_t handles, int32_t num_handles, Handle reply_target, int64_t timeout_ns);
+Result ReplyAndReceiveWithUserBuffer(Core::System& system, int32_t* out_index, uint64_t message_buffer, uint64_t message_buffer_size, uint64_t handles, int32_t num_handles, Handle reply_target, int64_t timeout_ns);
+Result CreateEvent(Core::System& system, Handle* out_write_handle, Handle* out_read_handle);
+Result MapIoRegion(Core::System& system, Handle io_region, uint64_t address, uint64_t size, MemoryPermission perm);
+Result UnmapIoRegion(Core::System& system, Handle io_region, uint64_t address, uint64_t size);
+Result MapPhysicalMemoryUnsafe(Core::System& system, uint64_t address, uint64_t size);
+Result UnmapPhysicalMemoryUnsafe(Core::System& system, uint64_t address, uint64_t size);
+Result SetUnsafeLimit(Core::System& system, uint64_t limit);
+Result CreateCodeMemory(Core::System& system, Handle* out_handle, uint64_t address, uint64_t size);
+Result ControlCodeMemory(Core::System& system, Handle code_memory_handle, CodeMemoryOperation operation, uint64_t address, uint64_t size, MemoryPermission perm);
+void SleepSystem(Core::System& system);
+Result ReadWriteRegister(Core::System& system, uint32_t* out_value, uint64_t address, uint32_t mask, uint32_t value);
+Result SetProcessActivity(Core::System& system, Handle process_handle, ProcessActivity process_activity);
+Result CreateSharedMemory(Core::System& system, Handle* out_handle, uint64_t size, MemoryPermission owner_perm, MemoryPermission remote_perm);
+Result MapTransferMemory(Core::System& system, Handle trmem_handle, uint64_t address, uint64_t size, MemoryPermission owner_perm);
+Result UnmapTransferMemory(Core::System& system, Handle trmem_handle, uint64_t address, uint64_t size);
+Result CreateInterruptEvent(Core::System& system, Handle* out_read_handle, int32_t interrupt_id, InterruptType interrupt_type);
+Result QueryPhysicalAddress(Core::System& system, lp64::PhysicalMemoryInfo* out_info, uint64_t address);
+Result QueryIoMapping(Core::System& system, uint64_t* out_address, uint64_t* out_size, uint64_t physical_address, uint64_t size);
+Result CreateDeviceAddressSpace(Core::System& system, Handle* out_handle, uint64_t das_address, uint64_t das_size);
+Result AttachDeviceAddressSpace(Core::System& system, DeviceName device_name, Handle das_handle);
+Result DetachDeviceAddressSpace(Core::System& system, DeviceName device_name, Handle das_handle);
+Result MapDeviceAddressSpaceByForce(Core::System& system, Handle das_handle, Handle process_handle, uint64_t process_address, uint64_t size, uint64_t device_address, uint32_t option);
+Result MapDeviceAddressSpaceAligned(Core::System& system, Handle das_handle, Handle process_handle, uint64_t process_address, uint64_t size, uint64_t device_address, uint32_t option);
+Result UnmapDeviceAddressSpace(Core::System& system, Handle das_handle, Handle process_handle, uint64_t process_address, uint64_t size, uint64_t device_address);
+Result InvalidateProcessDataCache(Core::System& system, Handle process_handle, uint64_t address, uint64_t size);
+Result StoreProcessDataCache(Core::System& system, Handle process_handle, uint64_t address, uint64_t size);
+Result FlushProcessDataCache(Core::System& system, Handle process_handle, uint64_t address, uint64_t size);
+Result DebugActiveProcess(Core::System& system, Handle* out_handle, uint64_t process_id);
+Result BreakDebugProcess(Core::System& system, Handle debug_handle);
+Result TerminateDebugProcess(Core::System& system, Handle debug_handle);
+Result GetDebugEvent(Core::System& system, uint64_t out_info, Handle debug_handle);
+Result ContinueDebugEvent(Core::System& system, Handle debug_handle, uint32_t flags, uint64_t thread_ids, int32_t num_thread_ids);
+Result GetProcessList(Core::System& system, int32_t* out_num_processes, uint64_t out_process_ids, int32_t max_out_count);
+Result GetThreadList(Core::System& system, int32_t* out_num_threads, uint64_t out_thread_ids, int32_t max_out_count, Handle debug_handle);
+Result GetDebugThreadContext(Core::System& system, uint64_t out_context, Handle debug_handle, uint64_t thread_id, uint32_t context_flags);
+Result SetDebugThreadContext(Core::System& system, Handle debug_handle, uint64_t thread_id, uint64_t context, uint32_t context_flags);
+Result QueryDebugProcessMemory(Core::System& system, uint64_t out_memory_info, PageInfo* out_page_info, Handle process_handle, uint64_t address);
+Result ReadDebugProcessMemory(Core::System& system, uint64_t buffer, Handle debug_handle, uint64_t address, uint64_t size);
+Result WriteDebugProcessMemory(Core::System& system, Handle debug_handle, uint64_t buffer, uint64_t address, uint64_t size);
+Result SetHardwareBreakPoint(Core::System& system, HardwareBreakPointRegisterName name, uint64_t flags, uint64_t value);
+Result GetDebugThreadParam(Core::System& system, uint64_t* out_64, uint32_t* out_32, Handle debug_handle, uint64_t thread_id, DebugThreadParam param);
+Result GetSystemInfo(Core::System& system, uint64_t* out, SystemInfoType info_type, Handle handle, uint64_t info_subtype);
+Result CreatePort(Core::System& system, Handle* out_server_handle, Handle* out_client_handle, int32_t max_sessions, bool is_light, uint64_t name);
+Result ManageNamedPort(Core::System& system, Handle* out_server_handle, uint64_t name, int32_t max_sessions);
+Result ConnectToPort(Core::System& system, Handle* out_handle, Handle port);
+Result SetProcessMemoryPermission(Core::System& system, Handle process_handle, uint64_t address, uint64_t size, MemoryPermission perm);
+Result MapProcessMemory(Core::System& system, uint64_t dst_address, Handle process_handle, uint64_t src_address, uint64_t size);
+Result UnmapProcessMemory(Core::System& system, uint64_t dst_address, Handle process_handle, uint64_t src_address, uint64_t size);
+Result QueryProcessMemory(Core::System& system, uint64_t out_memory_info, PageInfo* out_page_info, Handle process_handle, uint64_t address);
+Result MapProcessCodeMemory(Core::System& system, Handle process_handle, uint64_t dst_address, uint64_t src_address, uint64_t size);
+Result UnmapProcessCodeMemory(Core::System& system, Handle process_handle, uint64_t dst_address, uint64_t src_address, uint64_t size);
+Result CreateProcess(Core::System& system, Handle* out_handle, uint64_t parameters, uint64_t caps, int32_t num_caps);
+Result StartProcess(Core::System& system, Handle process_handle, int32_t priority, int32_t core_id, uint64_t main_thread_stack_size);
+Result TerminateProcess(Core::System& system, Handle process_handle);
+Result GetProcessInfo(Core::System& system, int64_t* out_info, Handle process_handle, ProcessInfoType info_type);
+Result CreateResourceLimit(Core::System& system, Handle* out_handle);
+Result SetResourceLimitLimitValue(Core::System& system, Handle resource_limit_handle, LimitableResource which, int64_t limit_value);
+Result MapInsecureMemory(Core::System& system, uint64_t address, uint64_t size);
+Result UnmapInsecureMemory(Core::System& system, uint64_t address, uint64_t size);
+
+Result SetHeapSize64From32(Core::System& system, uint64_t* out_address, uint32_t size);
+Result SetMemoryPermission64From32(Core::System& system, uint32_t address, uint32_t size, MemoryPermission perm);
+Result SetMemoryAttribute64From32(Core::System& system, uint32_t address, uint32_t size, uint32_t mask, uint32_t attr);
+Result MapMemory64From32(Core::System& system, uint32_t dst_address, uint32_t src_address, uint32_t size);
+Result UnmapMemory64From32(Core::System& system, uint32_t dst_address, uint32_t src_address, uint32_t size);
+Result QueryMemory64From32(Core::System& system, uint32_t out_memory_info, PageInfo* out_page_info, uint32_t address);
+void ExitProcess64From32(Core::System& system);
+Result CreateThread64From32(Core::System& system, Handle* out_handle, uint32_t func, uint32_t arg, uint32_t stack_bottom, int32_t priority, int32_t core_id);
+Result StartThread64From32(Core::System& system, Handle thread_handle);
+void ExitThread64From32(Core::System& system);
+void SleepThread64From32(Core::System& system, int64_t ns);
+Result GetThreadPriority64From32(Core::System& system, int32_t* out_priority, Handle thread_handle);
+Result SetThreadPriority64From32(Core::System& system, Handle thread_handle, int32_t priority);
+Result GetThreadCoreMask64From32(Core::System& system, int32_t* out_core_id, uint64_t* out_affinity_mask, Handle thread_handle);
+Result SetThreadCoreMask64From32(Core::System& system, Handle thread_handle, int32_t core_id, uint64_t affinity_mask);
+int32_t GetCurrentProcessorNumber64From32(Core::System& system);
+Result SignalEvent64From32(Core::System& system, Handle event_handle);
+Result ClearEvent64From32(Core::System& system, Handle event_handle);
+Result MapSharedMemory64From32(Core::System& system, Handle shmem_handle, uint32_t address, uint32_t size, MemoryPermission map_perm);
+Result UnmapSharedMemory64From32(Core::System& system, Handle shmem_handle, uint32_t address, uint32_t size);
+Result CreateTransferMemory64From32(Core::System& system, Handle* out_handle, uint32_t address, uint32_t size, MemoryPermission map_perm);
+Result CloseHandle64From32(Core::System& system, Handle handle);
+Result ResetSignal64From32(Core::System& system, Handle handle);
+Result WaitSynchronization64From32(Core::System& system, int32_t* out_index, uint32_t handles, int32_t num_handles, int64_t timeout_ns);
+Result CancelSynchronization64From32(Core::System& system, Handle handle);
+Result ArbitrateLock64From32(Core::System& system, Handle thread_handle, uint32_t address, uint32_t tag);
+Result ArbitrateUnlock64From32(Core::System& system, uint32_t address);
+Result WaitProcessWideKeyAtomic64From32(Core::System& system, uint32_t address, uint32_t cv_key, uint32_t tag, int64_t timeout_ns);
+void SignalProcessWideKey64From32(Core::System& system, uint32_t cv_key, int32_t count);
+int64_t GetSystemTick64From32(Core::System& system);
+Result ConnectToNamedPort64From32(Core::System& system, Handle* out_handle, uint32_t name);
+Result SendSyncRequest64From32(Core::System& system, Handle session_handle);
+Result SendSyncRequestWithUserBuffer64From32(Core::System& system, uint32_t message_buffer, uint32_t message_buffer_size, Handle session_handle);
+Result SendAsyncRequestWithUserBuffer64From32(Core::System& system, Handle* out_event_handle, uint32_t message_buffer, uint32_t message_buffer_size, Handle session_handle);
+Result GetProcessId64From32(Core::System& system, uint64_t* out_process_id, Handle process_handle);
+Result GetThreadId64From32(Core::System& system, uint64_t* out_thread_id, Handle thread_handle);
+void Break64From32(Core::System& system, BreakReason break_reason, uint32_t arg, uint32_t size);
+Result OutputDebugString64From32(Core::System& system, uint32_t debug_str, uint32_t len);
+void ReturnFromException64From32(Core::System& system, Result result);
+Result GetInfo64From32(Core::System& system, uint64_t* out, InfoType info_type, Handle handle, uint64_t info_subtype);
+void FlushEntireDataCache64From32(Core::System& system);
+Result FlushDataCache64From32(Core::System& system, uint32_t address, uint32_t size);
+Result MapPhysicalMemory64From32(Core::System& system, uint32_t address, uint32_t size);
+Result UnmapPhysicalMemory64From32(Core::System& system, uint32_t address, uint32_t size);
+Result GetDebugFutureThreadInfo64From32(Core::System& system, ilp32::LastThreadContext* out_context, uint64_t* out_thread_id, Handle debug_handle, int64_t ns);
+Result GetLastThreadInfo64From32(Core::System& system, ilp32::LastThreadContext* out_context, uint64_t* out_tls_address, uint32_t* out_flags);
+Result GetResourceLimitLimitValue64From32(Core::System& system, int64_t* out_limit_value, Handle resource_limit_handle, LimitableResource which);
+Result GetResourceLimitCurrentValue64From32(Core::System& system, int64_t* out_current_value, Handle resource_limit_handle, LimitableResource which);
+Result SetThreadActivity64From32(Core::System& system, Handle thread_handle, ThreadActivity thread_activity);
+Result GetThreadContext364From32(Core::System& system, uint32_t out_context, Handle thread_handle);
+Result WaitForAddress64From32(Core::System& system, uint32_t address, ArbitrationType arb_type, int32_t value, int64_t timeout_ns);
+Result SignalToAddress64From32(Core::System& system, uint32_t address, SignalType signal_type, int32_t value, int32_t count);
+void SynchronizePreemptionState64From32(Core::System& system);
+Result GetResourceLimitPeakValue64From32(Core::System& system, int64_t* out_peak_value, Handle resource_limit_handle, LimitableResource which);
+Result CreateIoPool64From32(Core::System& system, Handle* out_handle, IoPoolType which);
+Result CreateIoRegion64From32(Core::System& system, Handle* out_handle, Handle io_pool, uint64_t physical_address, uint32_t size, MemoryMapping mapping, MemoryPermission perm);
+void KernelDebug64From32(Core::System& system, KernelDebugType kern_debug_type, uint64_t arg0, uint64_t arg1, uint64_t arg2);
+void ChangeKernelTraceState64From32(Core::System& system, KernelTraceState kern_trace_state);
+Result CreateSession64From32(Core::System& system, Handle* out_server_session_handle, Handle* out_client_session_handle, bool is_light, uint32_t name);
+Result AcceptSession64From32(Core::System& system, Handle* out_handle, Handle port);
+Result ReplyAndReceive64From32(Core::System& system, int32_t* out_index, uint32_t handles, int32_t num_handles, Handle reply_target, int64_t timeout_ns);
+Result ReplyAndReceiveWithUserBuffer64From32(Core::System& system, int32_t* out_index, uint32_t message_buffer, uint32_t message_buffer_size, uint32_t handles, int32_t num_handles, Handle reply_target, int64_t timeout_ns);
+Result CreateEvent64From32(Core::System& system, Handle* out_write_handle, Handle* out_read_handle);
+Result MapIoRegion64From32(Core::System& system, Handle io_region, uint32_t address, uint32_t size, MemoryPermission perm);
+Result UnmapIoRegion64From32(Core::System& system, Handle io_region, uint32_t address, uint32_t size);
+Result MapPhysicalMemoryUnsafe64From32(Core::System& system, uint32_t address, uint32_t size);
+Result UnmapPhysicalMemoryUnsafe64From32(Core::System& system, uint32_t address, uint32_t size);
+Result SetUnsafeLimit64From32(Core::System& system, uint32_t limit);
+Result CreateCodeMemory64From32(Core::System& system, Handle* out_handle, uint32_t address, uint32_t size);
+Result ControlCodeMemory64From32(Core::System& system, Handle code_memory_handle, CodeMemoryOperation operation, uint64_t address, uint64_t size, MemoryPermission perm);
+void SleepSystem64From32(Core::System& system);
+Result ReadWriteRegister64From32(Core::System& system, uint32_t* out_value, uint64_t address, uint32_t mask, uint32_t value);
+Result SetProcessActivity64From32(Core::System& system, Handle process_handle, ProcessActivity process_activity);
+Result CreateSharedMemory64From32(Core::System& system, Handle* out_handle, uint32_t size, MemoryPermission owner_perm, MemoryPermission remote_perm);
+Result MapTransferMemory64From32(Core::System& system, Handle trmem_handle, uint32_t address, uint32_t size, MemoryPermission owner_perm);
+Result UnmapTransferMemory64From32(Core::System& system, Handle trmem_handle, uint32_t address, uint32_t size);
+Result CreateInterruptEvent64From32(Core::System& system, Handle* out_read_handle, int32_t interrupt_id, InterruptType interrupt_type);
+Result QueryPhysicalAddress64From32(Core::System& system, ilp32::PhysicalMemoryInfo* out_info, uint32_t address);
+Result QueryIoMapping64From32(Core::System& system, uint64_t* out_address, uint64_t* out_size, uint64_t physical_address, uint32_t size);
+Result CreateDeviceAddressSpace64From32(Core::System& system, Handle* out_handle, uint64_t das_address, uint64_t das_size);
+Result AttachDeviceAddressSpace64From32(Core::System& system, DeviceName device_name, Handle das_handle);
+Result DetachDeviceAddressSpace64From32(Core::System& system, DeviceName device_name, Handle das_handle);
+Result MapDeviceAddressSpaceByForce64From32(Core::System& system, Handle das_handle, Handle process_handle, uint64_t process_address, uint32_t size, uint64_t device_address, uint32_t option);
+Result MapDeviceAddressSpaceAligned64From32(Core::System& system, Handle das_handle, Handle process_handle, uint64_t process_address, uint32_t size, uint64_t device_address, uint32_t option);
+Result UnmapDeviceAddressSpace64From32(Core::System& system, Handle das_handle, Handle process_handle, uint64_t process_address, uint32_t size, uint64_t device_address);
+Result InvalidateProcessDataCache64From32(Core::System& system, Handle process_handle, uint64_t address, uint64_t size);
+Result StoreProcessDataCache64From32(Core::System& system, Handle process_handle, uint64_t address, uint64_t size);
+Result FlushProcessDataCache64From32(Core::System& system, Handle process_handle, uint64_t address, uint64_t size);
+Result DebugActiveProcess64From32(Core::System& system, Handle* out_handle, uint64_t process_id);
+Result BreakDebugProcess64From32(Core::System& system, Handle debug_handle);
+Result TerminateDebugProcess64From32(Core::System& system, Handle debug_handle);
+Result GetDebugEvent64From32(Core::System& system, uint32_t out_info, Handle debug_handle);
+Result ContinueDebugEvent64From32(Core::System& system, Handle debug_handle, uint32_t flags, uint32_t thread_ids, int32_t num_thread_ids);
+Result GetProcessList64From32(Core::System& system, int32_t* out_num_processes, uint32_t out_process_ids, int32_t max_out_count);
+Result GetThreadList64From32(Core::System& system, int32_t* out_num_threads, uint32_t out_thread_ids, int32_t max_out_count, Handle debug_handle);
+Result GetDebugThreadContext64From32(Core::System& system, uint32_t out_context, Handle debug_handle, uint64_t thread_id, uint32_t context_flags);
+Result SetDebugThreadContext64From32(Core::System& system, Handle debug_handle, uint64_t thread_id, uint32_t context, uint32_t context_flags);
+Result QueryDebugProcessMemory64From32(Core::System& system, uint32_t out_memory_info, PageInfo* out_page_info, Handle process_handle, uint32_t address);
+Result ReadDebugProcessMemory64From32(Core::System& system, uint32_t buffer, Handle debug_handle, uint32_t address, uint32_t size);
+Result WriteDebugProcessMemory64From32(Core::System& system, Handle debug_handle, uint32_t buffer, uint32_t address, uint32_t size);
+Result SetHardwareBreakPoint64From32(Core::System& system, HardwareBreakPointRegisterName name, uint64_t flags, uint64_t value);
+Result GetDebugThreadParam64From32(Core::System& system, uint64_t* out_64, uint32_t* out_32, Handle debug_handle, uint64_t thread_id, DebugThreadParam param);
+Result GetSystemInfo64From32(Core::System& system, uint64_t* out, SystemInfoType info_type, Handle handle, uint64_t info_subtype);
+Result CreatePort64From32(Core::System& system, Handle* out_server_handle, Handle* out_client_handle, int32_t max_sessions, bool is_light, uint32_t name);
+Result ManageNamedPort64From32(Core::System& system, Handle* out_server_handle, uint32_t name, int32_t max_sessions);
+Result ConnectToPort64From32(Core::System& system, Handle* out_handle, Handle port);
+Result SetProcessMemoryPermission64From32(Core::System& system, Handle process_handle, uint64_t address, uint64_t size, MemoryPermission perm);
+Result MapProcessMemory64From32(Core::System& system, uint32_t dst_address, Handle process_handle, uint64_t src_address, uint32_t size);
+Result UnmapProcessMemory64From32(Core::System& system, uint32_t dst_address, Handle process_handle, uint64_t src_address, uint32_t size);
+Result QueryProcessMemory64From32(Core::System& system, uint32_t out_memory_info, PageInfo* out_page_info, Handle process_handle, uint64_t address);
+Result MapProcessCodeMemory64From32(Core::System& system, Handle process_handle, uint64_t dst_address, uint64_t src_address, uint64_t size);
+Result UnmapProcessCodeMemory64From32(Core::System& system, Handle process_handle, uint64_t dst_address, uint64_t src_address, uint64_t size);
+Result CreateProcess64From32(Core::System& system, Handle* out_handle, uint32_t parameters, uint32_t caps, int32_t num_caps);
+Result StartProcess64From32(Core::System& system, Handle process_handle, int32_t priority, int32_t core_id, uint64_t main_thread_stack_size);
+Result TerminateProcess64From32(Core::System& system, Handle process_handle);
+Result GetProcessInfo64From32(Core::System& system, int64_t* out_info, Handle process_handle, ProcessInfoType info_type);
+Result CreateResourceLimit64From32(Core::System& system, Handle* out_handle);
+Result SetResourceLimitLimitValue64From32(Core::System& system, Handle resource_limit_handle, LimitableResource which, int64_t limit_value);
+Result MapInsecureMemory64From32(Core::System& system, uint32_t address, uint32_t size);
+Result UnmapInsecureMemory64From32(Core::System& system, uint32_t address, uint32_t size);
+
+Result SetHeapSize64(Core::System& system, uint64_t* out_address, uint64_t size);
+Result SetMemoryPermission64(Core::System& system, uint64_t address, uint64_t size, MemoryPermission perm);
+Result SetMemoryAttribute64(Core::System& system, uint64_t address, uint64_t size, uint32_t mask, uint32_t attr);
+Result MapMemory64(Core::System& system, uint64_t dst_address, uint64_t src_address, uint64_t size);
+Result UnmapMemory64(Core::System& system, uint64_t dst_address, uint64_t src_address, uint64_t size);
+Result QueryMemory64(Core::System& system, uint64_t out_memory_info, PageInfo* out_page_info, uint64_t address);
+void ExitProcess64(Core::System& system);
+Result CreateThread64(Core::System& system, Handle* out_handle, uint64_t func, uint64_t arg, uint64_t stack_bottom, int32_t priority, int32_t core_id);
+Result StartThread64(Core::System& system, Handle thread_handle);
+void ExitThread64(Core::System& system);
+void SleepThread64(Core::System& system, int64_t ns);
+Result GetThreadPriority64(Core::System& system, int32_t* out_priority, Handle thread_handle);
+Result SetThreadPriority64(Core::System& system, Handle thread_handle, int32_t priority);
+Result GetThreadCoreMask64(Core::System& system, int32_t* out_core_id, uint64_t* out_affinity_mask, Handle thread_handle);
+Result SetThreadCoreMask64(Core::System& system, Handle thread_handle, int32_t core_id, uint64_t affinity_mask);
+int32_t GetCurrentProcessorNumber64(Core::System& system);
+Result SignalEvent64(Core::System& system, Handle event_handle);
+Result ClearEvent64(Core::System& system, Handle event_handle);
+Result MapSharedMemory64(Core::System& system, Handle shmem_handle, uint64_t address, uint64_t size, MemoryPermission map_perm);
+Result UnmapSharedMemory64(Core::System& system, Handle shmem_handle, uint64_t address, uint64_t size);
+Result CreateTransferMemory64(Core::System& system, Handle* out_handle, uint64_t address, uint64_t size, MemoryPermission map_perm);
+Result CloseHandle64(Core::System& system, Handle handle);
+Result ResetSignal64(Core::System& system, Handle handle);
+Result WaitSynchronization64(Core::System& system, int32_t* out_index, uint64_t handles, int32_t num_handles, int64_t timeout_ns);
+Result CancelSynchronization64(Core::System& system, Handle handle);
+Result ArbitrateLock64(Core::System& system, Handle thread_handle, uint64_t address, uint32_t tag);
+Result ArbitrateUnlock64(Core::System& system, uint64_t address);
+Result WaitProcessWideKeyAtomic64(Core::System& system, uint64_t address, uint64_t cv_key, uint32_t tag, int64_t timeout_ns);
+void SignalProcessWideKey64(Core::System& system, uint64_t cv_key, int32_t count);
+int64_t GetSystemTick64(Core::System& system);
+Result ConnectToNamedPort64(Core::System& system, Handle* out_handle, uint64_t name);
+Result SendSyncRequest64(Core::System& system, Handle session_handle);
+Result SendSyncRequestWithUserBuffer64(Core::System& system, uint64_t message_buffer, uint64_t message_buffer_size, Handle session_handle);
+Result SendAsyncRequestWithUserBuffer64(Core::System& system, Handle* out_event_handle, uint64_t message_buffer, uint64_t message_buffer_size, Handle session_handle);
+Result GetProcessId64(Core::System& system, uint64_t* out_process_id, Handle process_handle);
+Result GetThreadId64(Core::System& system, uint64_t* out_thread_id, Handle thread_handle);
+void Break64(Core::System& system, BreakReason break_reason, uint64_t arg, uint64_t size);
+Result OutputDebugString64(Core::System& system, uint64_t debug_str, uint64_t len);
+void ReturnFromException64(Core::System& system, Result result);
+Result GetInfo64(Core::System& system, uint64_t* out, InfoType info_type, Handle handle, uint64_t info_subtype);
+void FlushEntireDataCache64(Core::System& system);
+Result FlushDataCache64(Core::System& system, uint64_t address, uint64_t size);
+Result MapPhysicalMemory64(Core::System& system, uint64_t address, uint64_t size);
+Result UnmapPhysicalMemory64(Core::System& system, uint64_t address, uint64_t size);
+Result GetDebugFutureThreadInfo64(Core::System& system, lp64::LastThreadContext* out_context, uint64_t* out_thread_id, Handle debug_handle, int64_t ns);
+Result GetLastThreadInfo64(Core::System& system, lp64::LastThreadContext* out_context, uint64_t* out_tls_address, uint32_t* out_flags);
+Result GetResourceLimitLimitValue64(Core::System& system, int64_t* out_limit_value, Handle resource_limit_handle, LimitableResource which);
+Result GetResourceLimitCurrentValue64(Core::System& system, int64_t* out_current_value, Handle resource_limit_handle, LimitableResource which);
+Result SetThreadActivity64(Core::System& system, Handle thread_handle, ThreadActivity thread_activity);
+Result GetThreadContext364(Core::System& system, uint64_t out_context, Handle thread_handle);
+Result WaitForAddress64(Core::System& system, uint64_t address, ArbitrationType arb_type, int32_t value, int64_t timeout_ns);
+Result SignalToAddress64(Core::System& system, uint64_t address, SignalType signal_type, int32_t value, int32_t count);
+void SynchronizePreemptionState64(Core::System& system);
+Result GetResourceLimitPeakValue64(Core::System& system, int64_t* out_peak_value, Handle resource_limit_handle, LimitableResource which);
+Result CreateIoPool64(Core::System& system, Handle* out_handle, IoPoolType which);
+Result CreateIoRegion64(Core::System& system, Handle* out_handle, Handle io_pool, uint64_t physical_address, uint64_t size, MemoryMapping mapping, MemoryPermission perm);
+void KernelDebug64(Core::System& system, KernelDebugType kern_debug_type, uint64_t arg0, uint64_t arg1, uint64_t arg2);
+void ChangeKernelTraceState64(Core::System& system, KernelTraceState kern_trace_state);
+Result CreateSession64(Core::System& system, Handle* out_server_session_handle, Handle* out_client_session_handle, bool is_light, uint64_t name);
+Result AcceptSession64(Core::System& system, Handle* out_handle, Handle port);
+Result ReplyAndReceive64(Core::System& system, int32_t* out_index, uint64_t handles, int32_t num_handles, Handle reply_target, int64_t timeout_ns);
+Result ReplyAndReceiveWithUserBuffer64(Core::System& system, int32_t* out_index, uint64_t message_buffer, uint64_t message_buffer_size, uint64_t handles, int32_t num_handles, Handle reply_target, int64_t timeout_ns);
+Result CreateEvent64(Core::System& system, Handle* out_write_handle, Handle* out_read_handle);
+Result MapIoRegion64(Core::System& system, Handle io_region, uint64_t address, uint64_t size, MemoryPermission perm);
+Result UnmapIoRegion64(Core::System& system, Handle io_region, uint64_t address, uint64_t size);
+Result MapPhysicalMemoryUnsafe64(Core::System& system, uint64_t address, uint64_t size);
+Result UnmapPhysicalMemoryUnsafe64(Core::System& system, uint64_t address, uint64_t size);
+Result SetUnsafeLimit64(Core::System& system, uint64_t limit);
+Result CreateCodeMemory64(Core::System& system, Handle* out_handle, uint64_t address, uint64_t size);
+Result ControlCodeMemory64(Core::System& system, Handle code_memory_handle, CodeMemoryOperation operation, uint64_t address, uint64_t size, MemoryPermission perm);
+void SleepSystem64(Core::System& system);
+Result ReadWriteRegister64(Core::System& system, uint32_t* out_value, uint64_t address, uint32_t mask, uint32_t value);
+Result SetProcessActivity64(Core::System& system, Handle process_handle, ProcessActivity process_activity);
+Result CreateSharedMemory64(Core::System& system, Handle* out_handle, uint64_t size, MemoryPermission owner_perm, MemoryPermission remote_perm);
+Result MapTransferMemory64(Core::System& system, Handle trmem_handle, uint64_t address, uint64_t size, MemoryPermission owner_perm);
+Result UnmapTransferMemory64(Core::System& system, Handle trmem_handle, uint64_t address, uint64_t size);
+Result CreateInterruptEvent64(Core::System& system, Handle* out_read_handle, int32_t interrupt_id, InterruptType interrupt_type);
+Result QueryPhysicalAddress64(Core::System& system, lp64::PhysicalMemoryInfo* out_info, uint64_t address);
+Result QueryIoMapping64(Core::System& system, uint64_t* out_address, uint64_t* out_size, uint64_t physical_address, uint64_t size);
+Result CreateDeviceAddressSpace64(Core::System& system, Handle* out_handle, uint64_t das_address, uint64_t das_size);
+Result AttachDeviceAddressSpace64(Core::System& system, DeviceName device_name, Handle das_handle);
+Result DetachDeviceAddressSpace64(Core::System& system, DeviceName device_name, Handle das_handle);
+Result MapDeviceAddressSpaceByForce64(Core::System& system, Handle das_handle, Handle process_handle, uint64_t process_address, uint64_t size, uint64_t device_address, uint32_t option);
+Result MapDeviceAddressSpaceAligned64(Core::System& system, Handle das_handle, Handle process_handle, uint64_t process_address, uint64_t size, uint64_t device_address, uint32_t option);
+Result UnmapDeviceAddressSpace64(Core::System& system, Handle das_handle, Handle process_handle, uint64_t process_address, uint64_t size, uint64_t device_address);
+Result InvalidateProcessDataCache64(Core::System& system, Handle process_handle, uint64_t address, uint64_t size);
+Result StoreProcessDataCache64(Core::System& system, Handle process_handle, uint64_t address, uint64_t size);
+Result FlushProcessDataCache64(Core::System& system, Handle process_handle, uint64_t address, uint64_t size);
+Result DebugActiveProcess64(Core::System& system, Handle* out_handle, uint64_t process_id);
+Result BreakDebugProcess64(Core::System& system, Handle debug_handle);
+Result TerminateDebugProcess64(Core::System& system, Handle debug_handle);
+Result GetDebugEvent64(Core::System& system, uint64_t out_info, Handle debug_handle);
+Result ContinueDebugEvent64(Core::System& system, Handle debug_handle, uint32_t flags, uint64_t thread_ids, int32_t num_thread_ids);
+Result GetProcessList64(Core::System& system, int32_t* out_num_processes, uint64_t out_process_ids, int32_t max_out_count);
+Result GetThreadList64(Core::System& system, int32_t* out_num_threads, uint64_t out_thread_ids, int32_t max_out_count, Handle debug_handle);
+Result GetDebugThreadContext64(Core::System& system, uint64_t out_context, Handle debug_handle, uint64_t thread_id, uint32_t context_flags);
+Result SetDebugThreadContext64(Core::System& system, Handle debug_handle, uint64_t thread_id, uint64_t context, uint32_t context_flags);
+Result QueryDebugProcessMemory64(Core::System& system, uint64_t out_memory_info, PageInfo* out_page_info, Handle process_handle, uint64_t address);
+Result ReadDebugProcessMemory64(Core::System& system, uint64_t buffer, Handle debug_handle, uint64_t address, uint64_t size);
+Result WriteDebugProcessMemory64(Core::System& system, Handle debug_handle, uint64_t buffer, uint64_t address, uint64_t size);
+Result SetHardwareBreakPoint64(Core::System& system, HardwareBreakPointRegisterName name, uint64_t flags, uint64_t value);
+Result GetDebugThreadParam64(Core::System& system, uint64_t* out_64, uint32_t* out_32, Handle debug_handle, uint64_t thread_id, DebugThreadParam param);
+Result GetSystemInfo64(Core::System& system, uint64_t* out, SystemInfoType info_type, Handle handle, uint64_t info_subtype);
+Result CreatePort64(Core::System& system, Handle* out_server_handle, Handle* out_client_handle, int32_t max_sessions, bool is_light, uint64_t name);
+Result ManageNamedPort64(Core::System& system, Handle* out_server_handle, uint64_t name, int32_t max_sessions);
+Result ConnectToPort64(Core::System& system, Handle* out_handle, Handle port);
+Result SetProcessMemoryPermission64(Core::System& system, Handle process_handle, uint64_t address, uint64_t size, MemoryPermission perm);
+Result MapProcessMemory64(Core::System& system, uint64_t dst_address, Handle process_handle, uint64_t src_address, uint64_t size);
+Result UnmapProcessMemory64(Core::System& system, uint64_t dst_address, Handle process_handle, uint64_t src_address, uint64_t size);
+Result QueryProcessMemory64(Core::System& system, uint64_t out_memory_info, PageInfo* out_page_info, Handle process_handle, uint64_t address);
+Result MapProcessCodeMemory64(Core::System& system, Handle process_handle, uint64_t dst_address, uint64_t src_address, uint64_t size);
+Result UnmapProcessCodeMemory64(Core::System& system, Handle process_handle, uint64_t dst_address, uint64_t src_address, uint64_t size);
+Result CreateProcess64(Core::System& system, Handle* out_handle, uint64_t parameters, uint64_t caps, int32_t num_caps);
+Result StartProcess64(Core::System& system, Handle process_handle, int32_t priority, int32_t core_id, uint64_t main_thread_stack_size);
+Result TerminateProcess64(Core::System& system, Handle process_handle);
+Result GetProcessInfo64(Core::System& system, int64_t* out_info, Handle process_handle, ProcessInfoType info_type);
+Result CreateResourceLimit64(Core::System& system, Handle* out_handle);
+Result SetResourceLimitLimitValue64(Core::System& system, Handle resource_limit_handle, LimitableResource which, int64_t limit_value);
+Result MapInsecureMemory64(Core::System& system, uint64_t address, uint64_t size);
+Result UnmapInsecureMemory64(Core::System& system, uint64_t address, uint64_t size);
+
+enum class SvcId : u32 {
+ SetHeapSize = 0x1,
+ SetMemoryPermission = 0x2,
+ SetMemoryAttribute = 0x3,
+ MapMemory = 0x4,
+ UnmapMemory = 0x5,
+ QueryMemory = 0x6,
+ ExitProcess = 0x7,
+ CreateThread = 0x8,
+ StartThread = 0x9,
+ ExitThread = 0xa,
+ SleepThread = 0xb,
+ GetThreadPriority = 0xc,
+ SetThreadPriority = 0xd,
+ GetThreadCoreMask = 0xe,
+ SetThreadCoreMask = 0xf,
+ GetCurrentProcessorNumber = 0x10,
+ SignalEvent = 0x11,
+ ClearEvent = 0x12,
+ MapSharedMemory = 0x13,
+ UnmapSharedMemory = 0x14,
+ CreateTransferMemory = 0x15,
+ CloseHandle = 0x16,
+ ResetSignal = 0x17,
+ WaitSynchronization = 0x18,
+ CancelSynchronization = 0x19,
+ ArbitrateLock = 0x1a,
+ ArbitrateUnlock = 0x1b,
+ WaitProcessWideKeyAtomic = 0x1c,
+ SignalProcessWideKey = 0x1d,
+ GetSystemTick = 0x1e,
+ ConnectToNamedPort = 0x1f,
+ SendSyncRequestLight = 0x20,
+ SendSyncRequest = 0x21,
+ SendSyncRequestWithUserBuffer = 0x22,
+ SendAsyncRequestWithUserBuffer = 0x23,
+ GetProcessId = 0x24,
+ GetThreadId = 0x25,
+ Break = 0x26,
+ OutputDebugString = 0x27,
+ ReturnFromException = 0x28,
+ GetInfo = 0x29,
+ FlushEntireDataCache = 0x2a,
+ FlushDataCache = 0x2b,
+ MapPhysicalMemory = 0x2c,
+ UnmapPhysicalMemory = 0x2d,
+ GetDebugFutureThreadInfo = 0x2e,
+ GetLastThreadInfo = 0x2f,
+ GetResourceLimitLimitValue = 0x30,
+ GetResourceLimitCurrentValue = 0x31,
+ SetThreadActivity = 0x32,
+ GetThreadContext3 = 0x33,
+ WaitForAddress = 0x34,
+ SignalToAddress = 0x35,
+ SynchronizePreemptionState = 0x36,
+ GetResourceLimitPeakValue = 0x37,
+ CreateIoPool = 0x39,
+ CreateIoRegion = 0x3a,
+ KernelDebug = 0x3c,
+ ChangeKernelTraceState = 0x3d,
+ CreateSession = 0x40,
+ AcceptSession = 0x41,
+ ReplyAndReceiveLight = 0x42,
+ ReplyAndReceive = 0x43,
+ ReplyAndReceiveWithUserBuffer = 0x44,
+ CreateEvent = 0x45,
+ MapIoRegion = 0x46,
+ UnmapIoRegion = 0x47,
+ MapPhysicalMemoryUnsafe = 0x48,
+ UnmapPhysicalMemoryUnsafe = 0x49,
+ SetUnsafeLimit = 0x4a,
+ CreateCodeMemory = 0x4b,
+ ControlCodeMemory = 0x4c,
+ SleepSystem = 0x4d,
+ ReadWriteRegister = 0x4e,
+ SetProcessActivity = 0x4f,
+ CreateSharedMemory = 0x50,
+ MapTransferMemory = 0x51,
+ UnmapTransferMemory = 0x52,
+ CreateInterruptEvent = 0x53,
+ QueryPhysicalAddress = 0x54,
+ QueryIoMapping = 0x55,
+ CreateDeviceAddressSpace = 0x56,
+ AttachDeviceAddressSpace = 0x57,
+ DetachDeviceAddressSpace = 0x58,
+ MapDeviceAddressSpaceByForce = 0x59,
+ MapDeviceAddressSpaceAligned = 0x5a,
+ UnmapDeviceAddressSpace = 0x5c,
+ InvalidateProcessDataCache = 0x5d,
+ StoreProcessDataCache = 0x5e,
+ FlushProcessDataCache = 0x5f,
+ DebugActiveProcess = 0x60,
+ BreakDebugProcess = 0x61,
+ TerminateDebugProcess = 0x62,
+ GetDebugEvent = 0x63,
+ ContinueDebugEvent = 0x64,
+ GetProcessList = 0x65,
+ GetThreadList = 0x66,
+ GetDebugThreadContext = 0x67,
+ SetDebugThreadContext = 0x68,
+ QueryDebugProcessMemory = 0x69,
+ ReadDebugProcessMemory = 0x6a,
+ WriteDebugProcessMemory = 0x6b,
+ SetHardwareBreakPoint = 0x6c,
+ GetDebugThreadParam = 0x6d,
+ GetSystemInfo = 0x6f,
+ CreatePort = 0x70,
+ ManageNamedPort = 0x71,
+ ConnectToPort = 0x72,
+ SetProcessMemoryPermission = 0x73,
+ MapProcessMemory = 0x74,
+ UnmapProcessMemory = 0x75,
+ QueryProcessMemory = 0x76,
+ MapProcessCodeMemory = 0x77,
+ UnmapProcessCodeMemory = 0x78,
+ CreateProcess = 0x79,
+ StartProcess = 0x7a,
+ TerminateProcess = 0x7b,
+ GetProcessInfo = 0x7c,
+ CreateResourceLimit = 0x7d,
+ SetResourceLimitLimitValue = 0x7e,
+ CallSecureMonitor = 0x7f,
+ MapInsecureMemory = 0x90,
+ UnmapInsecureMemory = 0x91,
+};
+// clang-format on
+
+// Custom ABI.
+Result ReplyAndReceiveLight(Core::System& system, Handle handle, uint32_t* args);
+Result ReplyAndReceiveLight64From32(Core::System& system, Handle handle, uint32_t* args);
+Result ReplyAndReceiveLight64(Core::System& system, Handle handle, uint32_t* args);
+
+Result SendSyncRequestLight(Core::System& system, Handle session_handle, uint32_t* args);
+Result SendSyncRequestLight64From32(Core::System& system, Handle session_handle, uint32_t* args);
+Result SendSyncRequestLight64(Core::System& system, Handle session_handle, uint32_t* args);
+
+void CallSecureMonitor(Core::System& system, lp64::SecureMonitorArguments* args);
+void CallSecureMonitor64From32(Core::System& system, ilp32::SecureMonitorArguments* args);
+void CallSecureMonitor64(Core::System& system, lp64::SecureMonitorArguments* args);
+
+// Defined in svc_light_ipc.cpp.
+void SvcWrap_ReplyAndReceiveLight64From32(Core::System& system);
+void SvcWrap_ReplyAndReceiveLight64(Core::System& system);
+
+void SvcWrap_SendSyncRequestLight64From32(Core::System& system);
+void SvcWrap_SendSyncRequestLight64(Core::System& system);
+
+// Defined in svc_secure_monitor_call.cpp.
+void SvcWrap_CallSecureMonitor64From32(Core::System& system);
+void SvcWrap_CallSecureMonitor64(Core::System& system);
+
+// Perform a supervisor call by index.
+void Call(Core::System& system, u32 imm);
} // namespace Kernel::Svc
diff --git a/src/core/hle/kernel/svc/svc_activity.cpp b/src/core/hle/kernel/svc/svc_activity.cpp
new file mode 100644
index 000000000..63bc08555
--- /dev/null
+++ b/src/core/hle/kernel/svc/svc_activity.cpp
@@ -0,0 +1,66 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/core.h"
+#include "core/hle/kernel/k_process.h"
+#include "core/hle/kernel/k_thread.h"
+#include "core/hle/kernel/svc.h"
+#include "core/hle/kernel/svc_results.h"
+
+namespace Kernel::Svc {
+
+/// Sets the thread activity
+Result SetThreadActivity(Core::System& system, Handle thread_handle,
+ ThreadActivity thread_activity) {
+ LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, activity=0x{:08X}", thread_handle,
+ thread_activity);
+
+ // Validate the activity.
+ static constexpr auto IsValidThreadActivity = [](ThreadActivity activity) {
+ return activity == ThreadActivity::Runnable || activity == ThreadActivity::Paused;
+ };
+ R_UNLESS(IsValidThreadActivity(thread_activity), ResultInvalidEnumValue);
+
+ // Get the thread from its handle.
+ KScopedAutoObject thread =
+ GetCurrentProcess(system.Kernel()).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.
+ R_UNLESS(thread->GetOwnerProcess() == GetCurrentProcessPointer(system.Kernel()),
+ ResultInvalidHandle);
+ R_UNLESS(thread.GetPointerUnsafe() != GetCurrentThreadPointer(system.Kernel()), ResultBusy);
+
+ // Set the activity.
+ R_TRY(thread->SetActivity(thread_activity));
+
+ return ResultSuccess;
+}
+
+Result SetProcessActivity(Core::System& system, Handle process_handle,
+ ProcessActivity process_activity) {
+ UNIMPLEMENTED();
+ R_THROW(ResultNotImplemented);
+}
+
+Result SetThreadActivity64(Core::System& system, Handle thread_handle,
+ ThreadActivity thread_activity) {
+ return SetThreadActivity(system, thread_handle, thread_activity);
+}
+
+Result SetProcessActivity64(Core::System& system, Handle process_handle,
+ ProcessActivity process_activity) {
+ return SetProcessActivity(system, process_handle, process_activity);
+}
+
+Result SetThreadActivity64From32(Core::System& system, Handle thread_handle,
+ ThreadActivity thread_activity) {
+ return SetThreadActivity(system, thread_handle, thread_activity);
+}
+
+Result SetProcessActivity64From32(Core::System& system, Handle process_handle,
+ ProcessActivity process_activity) {
+ return SetProcessActivity(system, process_handle, process_activity);
+}
+
+} // namespace Kernel::Svc
diff --git a/src/core/hle/kernel/svc/svc_address_arbiter.cpp b/src/core/hle/kernel/svc/svc_address_arbiter.cpp
new file mode 100644
index 000000000..04cc5ea64
--- /dev/null
+++ b/src/core/hle/kernel/svc/svc_address_arbiter.cpp
@@ -0,0 +1,105 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/core.h"
+#include "core/hle/kernel/k_memory_layout.h"
+#include "core/hle/kernel/k_process.h"
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/svc.h"
+#include "core/hle/kernel/svc_results.h"
+#include "core/hle/kernel/svc_types.h"
+
+namespace Kernel::Svc {
+namespace {
+
+constexpr bool IsValidSignalType(Svc::SignalType type) {
+ switch (type) {
+ case Svc::SignalType::Signal:
+ case Svc::SignalType::SignalAndIncrementIfEqual:
+ case Svc::SignalType::SignalAndModifyByWaitingCountIfEqual:
+ return true;
+ default:
+ return false;
+ }
+}
+
+constexpr bool IsValidArbitrationType(Svc::ArbitrationType type) {
+ switch (type) {
+ case Svc::ArbitrationType::WaitIfLessThan:
+ case Svc::ArbitrationType::DecrementAndWaitIfLessThan:
+ case Svc::ArbitrationType::WaitIfEqual:
+ return true;
+ default:
+ return false;
+ }
+}
+
+} // namespace
+
+// Wait for an address (via Address Arbiter)
+Result WaitForAddress(Core::System& system, u64 address, ArbitrationType arb_type, s32 value,
+ s64 timeout_ns) {
+ LOG_TRACE(Kernel_SVC, "called, address=0x{:X}, arb_type=0x{:X}, value=0x{:X}, timeout_ns={}",
+ address, arb_type, value, timeout_ns);
+
+ // Validate input.
+ R_UNLESS(!IsKernelAddress(address), ResultInvalidCurrentMemory);
+ R_UNLESS(Common::IsAligned(address, sizeof(s32)), ResultInvalidAddress);
+ R_UNLESS(IsValidArbitrationType(arb_type), ResultInvalidEnumValue);
+
+ // Convert timeout from nanoseconds to ticks.
+ s64 timeout{};
+ if (timeout_ns > 0) {
+ const s64 offset_tick(timeout_ns);
+ if (offset_tick > 0) {
+ timeout = offset_tick + 2;
+ if (timeout <= 0) {
+ timeout = std::numeric_limits<s64>::max();
+ }
+ } else {
+ timeout = std::numeric_limits<s64>::max();
+ }
+ } else {
+ timeout = timeout_ns;
+ }
+
+ R_RETURN(
+ GetCurrentProcess(system.Kernel()).WaitAddressArbiter(address, arb_type, value, timeout));
+}
+
+// Signals to an address (via Address Arbiter)
+Result SignalToAddress(Core::System& system, u64 address, SignalType signal_type, s32 value,
+ s32 count) {
+ LOG_TRACE(Kernel_SVC, "called, address=0x{:X}, signal_type=0x{:X}, value=0x{:X}, count=0x{:X}",
+ address, signal_type, value, count);
+
+ // Validate input.
+ R_UNLESS(!IsKernelAddress(address), ResultInvalidCurrentMemory);
+ R_UNLESS(Common::IsAligned(address, sizeof(s32)), ResultInvalidAddress);
+ R_UNLESS(IsValidSignalType(signal_type), ResultInvalidEnumValue);
+
+ R_RETURN(GetCurrentProcess(system.Kernel())
+ .SignalAddressArbiter(address, signal_type, value, count));
+}
+
+Result WaitForAddress64(Core::System& system, u64 address, ArbitrationType arb_type, s32 value,
+ s64 timeout_ns) {
+ R_RETURN(WaitForAddress(system, address, arb_type, value, timeout_ns));
+}
+
+Result SignalToAddress64(Core::System& system, u64 address, SignalType signal_type, s32 value,
+ s32 count) {
+ R_RETURN(SignalToAddress(system, address, signal_type, value, count));
+}
+
+Result WaitForAddress64From32(Core::System& system, u32 address, ArbitrationType arb_type,
+ s32 value, s64 timeout_ns) {
+ R_RETURN(WaitForAddress(system, address, arb_type, value, timeout_ns));
+}
+
+Result SignalToAddress64From32(Core::System& system, u32 address, SignalType signal_type, s32 value,
+ s32 count) {
+ R_RETURN(SignalToAddress(system, address, signal_type, value, count));
+}
+
+} // namespace Kernel::Svc
diff --git a/src/core/hle/kernel/svc/svc_address_translation.cpp b/src/core/hle/kernel/svc/svc_address_translation.cpp
new file mode 100644
index 000000000..e65a11cda
--- /dev/null
+++ b/src/core/hle/kernel/svc/svc_address_translation.cpp
@@ -0,0 +1,50 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/kernel/svc.h"
+#include "core/hle/kernel/svc_results.h"
+
+namespace Kernel::Svc {
+
+Result QueryPhysicalAddress(Core::System& system, lp64::PhysicalMemoryInfo* out_info,
+ uint64_t address) {
+ UNIMPLEMENTED();
+ R_THROW(ResultNotImplemented);
+}
+
+Result QueryIoMapping(Core::System& system, uint64_t* out_address, uint64_t* out_size,
+ uint64_t physical_address, uint64_t size) {
+ UNIMPLEMENTED();
+ R_THROW(ResultNotImplemented);
+}
+
+Result QueryPhysicalAddress64(Core::System& system, lp64::PhysicalMemoryInfo* out_info,
+ uint64_t address) {
+ R_RETURN(QueryPhysicalAddress(system, out_info, address));
+}
+
+Result QueryIoMapping64(Core::System& system, uint64_t* out_address, uint64_t* out_size,
+ uint64_t physical_address, uint64_t size) {
+ R_RETURN(QueryIoMapping(system, out_address, out_size, physical_address, size));
+}
+
+Result QueryPhysicalAddress64From32(Core::System& system, ilp32::PhysicalMemoryInfo* out_info,
+ uint32_t address) {
+ lp64::PhysicalMemoryInfo info{};
+ R_TRY(QueryPhysicalAddress(system, std::addressof(info), address));
+
+ *out_info = {
+ .physical_address = info.physical_address,
+ .virtual_address = static_cast<u32>(info.virtual_address),
+ .size = static_cast<u32>(info.size),
+ };
+ R_SUCCEED();
+}
+
+Result QueryIoMapping64From32(Core::System& system, uint64_t* out_address, uint64_t* out_size,
+ uint64_t physical_address, uint32_t size) {
+ R_RETURN(QueryIoMapping(system, reinterpret_cast<uint64_t*>(out_address),
+ reinterpret_cast<uint64_t*>(out_size), physical_address, size));
+}
+
+} // namespace Kernel::Svc
diff --git a/src/core/hle/kernel/svc/svc_cache.cpp b/src/core/hle/kernel/svc/svc_cache.cpp
new file mode 100644
index 000000000..082942dab
--- /dev/null
+++ b/src/core/hle/kernel/svc/svc_cache.cpp
@@ -0,0 +1,98 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/core.h"
+#include "core/hle/kernel/k_process.h"
+#include "core/hle/kernel/svc.h"
+#include "core/hle/kernel/svc_results.h"
+#include "core/hle/kernel/svc_types.h"
+
+namespace Kernel::Svc {
+
+void FlushEntireDataCache(Core::System& system) {
+ UNIMPLEMENTED();
+}
+
+Result FlushDataCache(Core::System& system, uint64_t address, uint64_t size) {
+ UNIMPLEMENTED();
+ R_THROW(ResultNotImplemented);
+}
+
+Result InvalidateProcessDataCache(Core::System& system, Handle process_handle, uint64_t address,
+ uint64_t size) {
+ UNIMPLEMENTED();
+ R_THROW(ResultNotImplemented);
+}
+
+Result StoreProcessDataCache(Core::System& system, Handle process_handle, uint64_t address,
+ uint64_t size) {
+ UNIMPLEMENTED();
+ R_THROW(ResultNotImplemented);
+}
+
+Result FlushProcessDataCache(Core::System& system, Handle process_handle, u64 address, u64 size) {
+ // Validate address/size.
+ R_UNLESS(size > 0, ResultInvalidSize);
+ R_UNLESS(address == static_cast<uint64_t>(address), ResultInvalidCurrentMemory);
+ R_UNLESS(size == static_cast<uint64_t>(size), ResultInvalidCurrentMemory);
+
+ // Get the process from its handle.
+ KScopedAutoObject process =
+ GetCurrentProcess(system.Kernel()).GetHandleTable().GetObject<KProcess>(process_handle);
+ R_UNLESS(process.IsNotNull(), ResultInvalidHandle);
+
+ // Verify the region is within range.
+ auto& page_table = process->PageTable();
+ R_UNLESS(page_table.Contains(address, size), ResultInvalidCurrentMemory);
+
+ // Perform the operation.
+ R_RETURN(GetCurrentMemory(system.Kernel()).FlushDataCache(address, size));
+}
+
+void FlushEntireDataCache64(Core::System& system) {
+ FlushEntireDataCache(system);
+}
+
+Result FlushDataCache64(Core::System& system, uint64_t address, uint64_t size) {
+ R_RETURN(FlushDataCache(system, address, size));
+}
+
+Result InvalidateProcessDataCache64(Core::System& system, Handle process_handle, uint64_t address,
+ uint64_t size) {
+ R_RETURN(InvalidateProcessDataCache(system, process_handle, address, size));
+}
+
+Result StoreProcessDataCache64(Core::System& system, Handle process_handle, uint64_t address,
+ uint64_t size) {
+ R_RETURN(StoreProcessDataCache(system, process_handle, address, size));
+}
+
+Result FlushProcessDataCache64(Core::System& system, Handle process_handle, uint64_t address,
+ uint64_t size) {
+ R_RETURN(FlushProcessDataCache(system, process_handle, address, size));
+}
+
+void FlushEntireDataCache64From32(Core::System& system) {
+ return FlushEntireDataCache(system);
+}
+
+Result FlushDataCache64From32(Core::System& system, uint32_t address, uint32_t size) {
+ R_RETURN(FlushDataCache(system, address, size));
+}
+
+Result InvalidateProcessDataCache64From32(Core::System& system, Handle process_handle,
+ uint64_t address, uint64_t size) {
+ R_RETURN(InvalidateProcessDataCache(system, process_handle, address, size));
+}
+
+Result StoreProcessDataCache64From32(Core::System& system, Handle process_handle, uint64_t address,
+ uint64_t size) {
+ R_RETURN(StoreProcessDataCache(system, process_handle, address, size));
+}
+
+Result FlushProcessDataCache64From32(Core::System& system, Handle process_handle, uint64_t address,
+ uint64_t size) {
+ R_RETURN(FlushProcessDataCache(system, process_handle, address, size));
+}
+
+} // namespace Kernel::Svc
diff --git a/src/core/hle/kernel/svc/svc_code_memory.cpp b/src/core/hle/kernel/svc/svc_code_memory.cpp
new file mode 100644
index 000000000..687baff82
--- /dev/null
+++ b/src/core/hle/kernel/svc/svc_code_memory.cpp
@@ -0,0 +1,171 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "common/scope_exit.h"
+#include "core/core.h"
+#include "core/hle/kernel/k_code_memory.h"
+#include "core/hle/kernel/k_process.h"
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/svc.h"
+
+namespace Kernel::Svc {
+namespace {
+
+constexpr bool IsValidMapCodeMemoryPermission(MemoryPermission perm) {
+ return perm == MemoryPermission::ReadWrite;
+}
+
+constexpr bool IsValidMapToOwnerCodeMemoryPermission(MemoryPermission perm) {
+ return perm == MemoryPermission::Read || perm == MemoryPermission::ReadExecute;
+}
+
+constexpr bool IsValidUnmapCodeMemoryPermission(MemoryPermission perm) {
+ return perm == MemoryPermission::None;
+}
+
+constexpr bool IsValidUnmapFromOwnerCodeMemoryPermission(MemoryPermission perm) {
+ return perm == MemoryPermission::None;
+}
+
+} // namespace
+
+Result CreateCodeMemory(Core::System& system, Handle* out, u64 address, uint64_t size) {
+ LOG_TRACE(Kernel_SVC, "called, address=0x{:X}, size=0x{:X}", address, size);
+
+ // Get kernel instance.
+ auto& kernel = system.Kernel();
+
+ // Validate 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);
+
+ // Create the code memory.
+
+ KCodeMemory* code_mem = KCodeMemory::Create(kernel);
+ R_UNLESS(code_mem != nullptr, ResultOutOfResource);
+ SCOPE_EXIT({ code_mem->Close(); });
+
+ // Verify that the region is in range.
+ R_UNLESS(GetCurrentProcess(system.Kernel()).PageTable().Contains(address, size),
+ ResultInvalidCurrentMemory);
+
+ // Initialize the code memory.
+ R_TRY(code_mem->Initialize(system.DeviceMemory(), address, size));
+
+ // Register the code memory.
+ KCodeMemory::Register(kernel, code_mem);
+
+ // Add the code memory to the handle table.
+ R_TRY(GetCurrentProcess(system.Kernel()).GetHandleTable().Add(out, code_mem));
+
+ R_SUCCEED();
+}
+
+Result ControlCodeMemory(Core::System& system, Handle code_memory_handle,
+ CodeMemoryOperation operation, u64 address, uint64_t size,
+ MemoryPermission perm) {
+
+ LOG_TRACE(Kernel_SVC,
+ "called, code_memory_handle=0x{:X}, operation=0x{:X}, address=0x{:X}, size=0x{:X}, "
+ "permission=0x{:X}",
+ code_memory_handle, operation, address, size, perm);
+
+ // 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 code memory from its handle.
+ KScopedAutoObject code_mem = GetCurrentProcess(system.Kernel())
+ .GetHandleTable()
+ .GetObject<KCodeMemory>(code_memory_handle);
+ R_UNLESS(code_mem.IsNotNull(), ResultInvalidHandle);
+
+ // NOTE: Here, Atmosphere extends the SVC to allow code memory operations on one's own process.
+ // This enables homebrew usage of these SVCs for JIT.
+
+ // Perform the operation.
+ switch (operation) {
+ case CodeMemoryOperation::Map: {
+ // Check that the region is in range.
+ R_UNLESS(GetCurrentProcess(system.Kernel())
+ .PageTable()
+ .CanContain(address, size, KMemoryState::CodeOut),
+ ResultInvalidMemoryRegion);
+
+ // Check the memory permission.
+ R_UNLESS(IsValidMapCodeMemoryPermission(perm), ResultInvalidNewMemoryPermission);
+
+ // Map the memory.
+ R_TRY(code_mem->Map(address, size));
+ } break;
+ case CodeMemoryOperation::Unmap: {
+ // Check that the region is in range.
+ R_UNLESS(GetCurrentProcess(system.Kernel())
+ .PageTable()
+ .CanContain(address, size, KMemoryState::CodeOut),
+ ResultInvalidMemoryRegion);
+
+ // Check the memory permission.
+ R_UNLESS(IsValidUnmapCodeMemoryPermission(perm), ResultInvalidNewMemoryPermission);
+
+ // Unmap the memory.
+ R_TRY(code_mem->Unmap(address, size));
+ } break;
+ case CodeMemoryOperation::MapToOwner: {
+ // Check that the region is in range.
+ R_UNLESS(code_mem->GetOwner()->PageTable().CanContain(address, size,
+ KMemoryState::GeneratedCode),
+ ResultInvalidMemoryRegion);
+
+ // Check the memory permission.
+ R_UNLESS(IsValidMapToOwnerCodeMemoryPermission(perm), ResultInvalidNewMemoryPermission);
+
+ // Map the memory to its owner.
+ R_TRY(code_mem->MapToOwner(address, size, perm));
+ } break;
+ case CodeMemoryOperation::UnmapFromOwner: {
+ // Check that the region is in range.
+ R_UNLESS(code_mem->GetOwner()->PageTable().CanContain(address, size,
+ KMemoryState::GeneratedCode),
+ ResultInvalidMemoryRegion);
+
+ // Check the memory permission.
+ R_UNLESS(IsValidUnmapFromOwnerCodeMemoryPermission(perm), ResultInvalidNewMemoryPermission);
+
+ // Unmap the memory from its owner.
+ R_TRY(code_mem->UnmapFromOwner(address, size));
+ } break;
+ default:
+ R_THROW(ResultInvalidEnumValue);
+ }
+
+ R_SUCCEED();
+}
+
+Result CreateCodeMemory64(Core::System& system, Handle* out_handle, uint64_t address,
+ uint64_t size) {
+ R_RETURN(CreateCodeMemory(system, out_handle, address, size));
+}
+
+Result ControlCodeMemory64(Core::System& system, Handle code_memory_handle,
+ CodeMemoryOperation operation, uint64_t address, uint64_t size,
+ MemoryPermission perm) {
+ R_RETURN(ControlCodeMemory(system, code_memory_handle, operation, address, size, perm));
+}
+
+Result CreateCodeMemory64From32(Core::System& system, Handle* out_handle, uint32_t address,
+ uint32_t size) {
+ R_RETURN(CreateCodeMemory(system, out_handle, address, size));
+}
+
+Result ControlCodeMemory64From32(Core::System& system, Handle code_memory_handle,
+ CodeMemoryOperation operation, uint64_t address, uint64_t size,
+ MemoryPermission perm) {
+ R_RETURN(ControlCodeMemory(system, code_memory_handle, operation, address, size, perm));
+}
+
+} // namespace Kernel::Svc
diff --git a/src/core/hle/kernel/svc/svc_condition_variable.cpp b/src/core/hle/kernel/svc/svc_condition_variable.cpp
new file mode 100644
index 000000000..ca120d67e
--- /dev/null
+++ b/src/core/hle/kernel/svc/svc_condition_variable.cpp
@@ -0,0 +1,72 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/core.h"
+#include "core/hle/kernel/k_memory_layout.h"
+#include "core/hle/kernel/k_process.h"
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/svc.h"
+#include "core/hle/kernel/svc_results.h"
+
+namespace Kernel::Svc {
+
+/// Wait process wide key atomic
+Result WaitProcessWideKeyAtomic(Core::System& system, u64 address, u64 cv_key, u32 tag,
+ s64 timeout_ns) {
+ LOG_TRACE(Kernel_SVC, "called address={:X}, cv_key={:X}, tag=0x{:08X}, timeout_ns={}", address,
+ cv_key, tag, timeout_ns);
+
+ // Validate input.
+ R_UNLESS(!IsKernelAddress(address), ResultInvalidCurrentMemory);
+ R_UNLESS(Common::IsAligned(address, sizeof(s32)), ResultInvalidAddress);
+
+ // Convert timeout from nanoseconds to ticks.
+ s64 timeout{};
+ if (timeout_ns > 0) {
+ const s64 offset_tick(timeout_ns);
+ if (offset_tick > 0) {
+ timeout = offset_tick + 2;
+ if (timeout <= 0) {
+ timeout = std::numeric_limits<s64>::max();
+ }
+ } else {
+ timeout = std::numeric_limits<s64>::max();
+ }
+ } else {
+ timeout = timeout_ns;
+ }
+
+ // Wait on the condition variable.
+ R_RETURN(
+ GetCurrentProcess(system.Kernel())
+ .WaitConditionVariable(address, Common::AlignDown(cv_key, sizeof(u32)), tag, timeout));
+}
+
+/// Signal process wide key
+void SignalProcessWideKey(Core::System& system, u64 cv_key, s32 count) {
+ LOG_TRACE(Kernel_SVC, "called, cv_key=0x{:X}, count=0x{:08X}", cv_key, count);
+
+ // Signal the condition variable.
+ return GetCurrentProcess(system.Kernel())
+ .SignalConditionVariable(Common::AlignDown(cv_key, sizeof(u32)), count);
+}
+
+Result WaitProcessWideKeyAtomic64(Core::System& system, uint64_t address, uint64_t cv_key,
+ uint32_t tag, int64_t timeout_ns) {
+ R_RETURN(WaitProcessWideKeyAtomic(system, address, cv_key, tag, timeout_ns));
+}
+
+void SignalProcessWideKey64(Core::System& system, uint64_t cv_key, int32_t count) {
+ SignalProcessWideKey(system, cv_key, count);
+}
+
+Result WaitProcessWideKeyAtomic64From32(Core::System& system, uint32_t address, uint32_t cv_key,
+ uint32_t tag, int64_t timeout_ns) {
+ R_RETURN(WaitProcessWideKeyAtomic(system, address, cv_key, tag, timeout_ns));
+}
+
+void SignalProcessWideKey64From32(Core::System& system, uint32_t cv_key, int32_t count) {
+ SignalProcessWideKey(system, cv_key, count);
+}
+
+} // namespace Kernel::Svc
diff --git a/src/core/hle/kernel/svc/svc_debug.cpp b/src/core/hle/kernel/svc/svc_debug.cpp
new file mode 100644
index 000000000..a4d1f700e
--- /dev/null
+++ b/src/core/hle/kernel/svc/svc_debug.cpp
@@ -0,0 +1,194 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/kernel/svc.h"
+#include "core/hle/kernel/svc_results.h"
+
+namespace Kernel::Svc {
+
+Result DebugActiveProcess(Core::System& system, Handle* out_handle, uint64_t process_id) {
+ UNIMPLEMENTED();
+ R_THROW(ResultNotImplemented);
+}
+
+Result BreakDebugProcess(Core::System& system, Handle debug_handle) {
+ UNIMPLEMENTED();
+ R_THROW(ResultNotImplemented);
+}
+
+Result TerminateDebugProcess(Core::System& system, Handle debug_handle) {
+ UNIMPLEMENTED();
+ R_THROW(ResultNotImplemented);
+}
+
+Result GetDebugEvent(Core::System& system, uint64_t out_info, Handle debug_handle) {
+ UNIMPLEMENTED();
+ R_THROW(ResultNotImplemented);
+}
+
+Result ContinueDebugEvent(Core::System& system, Handle debug_handle, uint32_t flags,
+ uint64_t user_thread_ids, int32_t num_thread_ids) {
+ UNIMPLEMENTED();
+ R_THROW(ResultNotImplemented);
+}
+
+Result GetDebugThreadContext(Core::System& system, uint64_t out_context, Handle debug_handle,
+ uint64_t thread_id, uint32_t context_flags) {
+ UNIMPLEMENTED();
+ R_THROW(ResultNotImplemented);
+}
+
+Result SetDebugThreadContext(Core::System& system, Handle debug_handle, uint64_t thread_id,
+ uint64_t user_context, uint32_t context_flags) {
+ UNIMPLEMENTED();
+ R_THROW(ResultNotImplemented);
+}
+
+Result QueryDebugProcessMemory(Core::System& system, uint64_t out_memory_info,
+ PageInfo* out_page_info, Handle process_handle, uint64_t address) {
+ UNIMPLEMENTED();
+ R_THROW(ResultNotImplemented);
+}
+
+Result ReadDebugProcessMemory(Core::System& system, uint64_t buffer, Handle debug_handle,
+ uint64_t address, uint64_t size) {
+ UNIMPLEMENTED();
+ R_THROW(ResultNotImplemented);
+}
+
+Result WriteDebugProcessMemory(Core::System& system, Handle debug_handle, uint64_t buffer,
+ uint64_t address, uint64_t size) {
+ UNIMPLEMENTED();
+ R_THROW(ResultNotImplemented);
+}
+
+Result SetHardwareBreakPoint(Core::System& system, HardwareBreakPointRegisterName name,
+ uint64_t flags, uint64_t value) {
+ UNIMPLEMENTED();
+ R_THROW(ResultNotImplemented);
+}
+
+Result GetDebugThreadParam(Core::System& system, uint64_t* out_64, uint32_t* out_32,
+ Handle debug_handle, uint64_t thread_id, DebugThreadParam param) {
+ UNIMPLEMENTED();
+ R_THROW(ResultNotImplemented);
+}
+
+Result DebugActiveProcess64(Core::System& system, Handle* out_handle, uint64_t process_id) {
+ R_RETURN(DebugActiveProcess(system, out_handle, process_id));
+}
+
+Result BreakDebugProcess64(Core::System& system, Handle debug_handle) {
+ R_RETURN(BreakDebugProcess(system, debug_handle));
+}
+
+Result TerminateDebugProcess64(Core::System& system, Handle debug_handle) {
+ R_RETURN(TerminateDebugProcess(system, debug_handle));
+}
+
+Result GetDebugEvent64(Core::System& system, uint64_t out_info, Handle debug_handle) {
+ R_RETURN(GetDebugEvent(system, out_info, debug_handle));
+}
+
+Result ContinueDebugEvent64(Core::System& system, Handle debug_handle, uint32_t flags,
+ uint64_t thread_ids, int32_t num_thread_ids) {
+ R_RETURN(ContinueDebugEvent(system, debug_handle, flags, thread_ids, num_thread_ids));
+}
+
+Result GetDebugThreadContext64(Core::System& system, uint64_t out_context, Handle debug_handle,
+ uint64_t thread_id, uint32_t context_flags) {
+ R_RETURN(GetDebugThreadContext(system, out_context, debug_handle, thread_id, context_flags));
+}
+
+Result SetDebugThreadContext64(Core::System& system, Handle debug_handle, uint64_t thread_id,
+ uint64_t context, uint32_t context_flags) {
+ R_RETURN(SetDebugThreadContext(system, debug_handle, thread_id, context, context_flags));
+}
+
+Result QueryDebugProcessMemory64(Core::System& system, uint64_t out_memory_info,
+ PageInfo* out_page_info, Handle debug_handle, uint64_t address) {
+ R_RETURN(
+ QueryDebugProcessMemory(system, out_memory_info, out_page_info, debug_handle, address));
+}
+
+Result ReadDebugProcessMemory64(Core::System& system, uint64_t buffer, Handle debug_handle,
+ uint64_t address, uint64_t size) {
+ R_RETURN(ReadDebugProcessMemory(system, buffer, debug_handle, address, size));
+}
+
+Result WriteDebugProcessMemory64(Core::System& system, Handle debug_handle, uint64_t buffer,
+ uint64_t address, uint64_t size) {
+ R_RETURN(WriteDebugProcessMemory(system, debug_handle, buffer, address, size));
+}
+
+Result SetHardwareBreakPoint64(Core::System& system, HardwareBreakPointRegisterName name,
+ uint64_t flags, uint64_t value) {
+ R_RETURN(SetHardwareBreakPoint(system, name, flags, value));
+}
+
+Result GetDebugThreadParam64(Core::System& system, uint64_t* out_64, uint32_t* out_32,
+ Handle debug_handle, uint64_t thread_id, DebugThreadParam param) {
+ R_RETURN(GetDebugThreadParam(system, out_64, out_32, debug_handle, thread_id, param));
+}
+
+Result DebugActiveProcess64From32(Core::System& system, Handle* out_handle, uint64_t process_id) {
+ R_RETURN(DebugActiveProcess(system, out_handle, process_id));
+}
+
+Result BreakDebugProcess64From32(Core::System& system, Handle debug_handle) {
+ R_RETURN(BreakDebugProcess(system, debug_handle));
+}
+
+Result TerminateDebugProcess64From32(Core::System& system, Handle debug_handle) {
+ R_RETURN(TerminateDebugProcess(system, debug_handle));
+}
+
+Result GetDebugEvent64From32(Core::System& system, uint32_t out_info, Handle debug_handle) {
+ R_RETURN(GetDebugEvent(system, out_info, debug_handle));
+}
+
+Result ContinueDebugEvent64From32(Core::System& system, Handle debug_handle, uint32_t flags,
+ uint32_t thread_ids, int32_t num_thread_ids) {
+ R_RETURN(ContinueDebugEvent(system, debug_handle, flags, thread_ids, num_thread_ids));
+}
+
+Result GetDebugThreadContext64From32(Core::System& system, uint32_t out_context,
+ Handle debug_handle, uint64_t thread_id,
+ uint32_t context_flags) {
+ R_RETURN(GetDebugThreadContext(system, out_context, debug_handle, thread_id, context_flags));
+}
+
+Result SetDebugThreadContext64From32(Core::System& system, Handle debug_handle, uint64_t thread_id,
+ uint32_t context, uint32_t context_flags) {
+ R_RETURN(SetDebugThreadContext(system, debug_handle, thread_id, context, context_flags));
+}
+
+Result QueryDebugProcessMemory64From32(Core::System& system, uint32_t out_memory_info,
+ PageInfo* out_page_info, Handle debug_handle,
+ uint32_t address) {
+ R_RETURN(
+ QueryDebugProcessMemory(system, out_memory_info, out_page_info, debug_handle, address));
+}
+
+Result ReadDebugProcessMemory64From32(Core::System& system, uint32_t buffer, Handle debug_handle,
+ uint32_t address, uint32_t size) {
+ R_RETURN(ReadDebugProcessMemory(system, buffer, debug_handle, address, size));
+}
+
+Result WriteDebugProcessMemory64From32(Core::System& system, Handle debug_handle, uint32_t buffer,
+ uint32_t address, uint32_t size) {
+ R_RETURN(WriteDebugProcessMemory(system, debug_handle, buffer, address, size));
+}
+
+Result SetHardwareBreakPoint64From32(Core::System& system, HardwareBreakPointRegisterName name,
+ uint64_t flags, uint64_t value) {
+ R_RETURN(SetHardwareBreakPoint(system, name, flags, value));
+}
+
+Result GetDebugThreadParam64From32(Core::System& system, uint64_t* out_64, uint32_t* out_32,
+ Handle debug_handle, uint64_t thread_id,
+ DebugThreadParam param) {
+ R_RETURN(GetDebugThreadParam(system, out_64, out_32, debug_handle, thread_id, param));
+}
+
+} // namespace Kernel::Svc
diff --git a/src/core/hle/kernel/svc/svc_debug_string.cpp b/src/core/hle/kernel/svc/svc_debug_string.cpp
new file mode 100644
index 000000000..4c14ce668
--- /dev/null
+++ b/src/core/hle/kernel/svc/svc_debug_string.cpp
@@ -0,0 +1,30 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/core.h"
+#include "core/hle/kernel/k_thread.h"
+#include "core/hle/kernel/svc.h"
+#include "core/memory.h"
+
+namespace Kernel::Svc {
+
+/// Used to output a message on a debug hardware unit - does nothing on a retail unit
+Result OutputDebugString(Core::System& system, u64 address, u64 len) {
+ R_SUCCEED_IF(len == 0);
+
+ std::string str(len, '\0');
+ GetCurrentMemory(system.Kernel()).ReadBlock(address, str.data(), str.size());
+ LOG_DEBUG(Debug_Emulated, "{}", str);
+
+ R_SUCCEED();
+}
+
+Result OutputDebugString64(Core::System& system, uint64_t debug_str, uint64_t len) {
+ R_RETURN(OutputDebugString(system, debug_str, len));
+}
+
+Result OutputDebugString64From32(Core::System& system, uint32_t debug_str, uint32_t len) {
+ R_RETURN(OutputDebugString(system, debug_str, len));
+}
+
+} // namespace Kernel::Svc
diff --git a/src/core/hle/kernel/svc/svc_device_address_space.cpp b/src/core/hle/kernel/svc/svc_device_address_space.cpp
new file mode 100644
index 000000000..ec3143e67
--- /dev/null
+++ b/src/core/hle/kernel/svc/svc_device_address_space.cpp
@@ -0,0 +1,258 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "common/alignment.h"
+#include "common/scope_exit.h"
+#include "core/core.h"
+#include "core/hle/kernel/k_device_address_space.h"
+#include "core/hle/kernel/k_process.h"
+#include "core/hle/kernel/svc.h"
+
+namespace Kernel::Svc {
+
+constexpr inline u64 DeviceAddressSpaceAlignMask = (1ULL << 22) - 1;
+
+constexpr bool IsProcessAndDeviceAligned(uint64_t process_address, uint64_t device_address) {
+ return (process_address & DeviceAddressSpaceAlignMask) ==
+ (device_address & DeviceAddressSpaceAlignMask);
+}
+
+Result CreateDeviceAddressSpace(Core::System& system, Handle* out, uint64_t das_address,
+ uint64_t das_size) {
+ // Validate input.
+ R_UNLESS(Common::IsAligned(das_address, PageSize), ResultInvalidMemoryRegion);
+ R_UNLESS(Common::IsAligned(das_size, PageSize), ResultInvalidMemoryRegion);
+ R_UNLESS(das_size > 0, ResultInvalidMemoryRegion);
+ R_UNLESS((das_address < das_address + das_size), ResultInvalidMemoryRegion);
+
+ // Create the device address space.
+ KDeviceAddressSpace* das = KDeviceAddressSpace::Create(system.Kernel());
+ R_UNLESS(das != nullptr, ResultOutOfResource);
+ SCOPE_EXIT({ das->Close(); });
+
+ // Initialize the device address space.
+ R_TRY(das->Initialize(das_address, das_size));
+
+ // Register the device address space.
+ KDeviceAddressSpace::Register(system.Kernel(), das);
+
+ // Add to the handle table.
+ R_TRY(GetCurrentProcess(system.Kernel()).GetHandleTable().Add(out, das));
+
+ R_SUCCEED();
+}
+
+Result AttachDeviceAddressSpace(Core::System& system, DeviceName device_name, Handle das_handle) {
+ // Get the device address space.
+ KScopedAutoObject das = GetCurrentProcess(system.Kernel())
+ .GetHandleTable()
+ .GetObject<KDeviceAddressSpace>(das_handle);
+ R_UNLESS(das.IsNotNull(), ResultInvalidHandle);
+
+ // Attach.
+ R_RETURN(das->Attach(device_name));
+}
+
+Result DetachDeviceAddressSpace(Core::System& system, DeviceName device_name, Handle das_handle) {
+ // Get the device address space.
+ KScopedAutoObject das = GetCurrentProcess(system.Kernel())
+ .GetHandleTable()
+ .GetObject<KDeviceAddressSpace>(das_handle);
+ R_UNLESS(das.IsNotNull(), ResultInvalidHandle);
+
+ // Detach.
+ R_RETURN(das->Detach(device_name));
+}
+
+constexpr bool IsValidDeviceMemoryPermission(MemoryPermission device_perm) {
+ switch (device_perm) {
+ case MemoryPermission::Read:
+ case MemoryPermission::Write:
+ case MemoryPermission::ReadWrite:
+ return true;
+ default:
+ return false;
+ }
+}
+
+Result MapDeviceAddressSpaceByForce(Core::System& system, Handle das_handle, Handle process_handle,
+ uint64_t process_address, uint64_t size,
+ uint64_t device_address, u32 option) {
+ // Decode the option.
+ const MapDeviceAddressSpaceOption option_pack{option};
+ const auto device_perm = option_pack.permission;
+ const auto reserved = option_pack.reserved;
+
+ // Validate input.
+ R_UNLESS(Common::IsAligned(process_address, PageSize), ResultInvalidAddress);
+ R_UNLESS(Common::IsAligned(device_address, PageSize), ResultInvalidAddress);
+ R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize);
+ R_UNLESS(size > 0, ResultInvalidSize);
+ R_UNLESS((process_address < process_address + size), ResultInvalidCurrentMemory);
+ R_UNLESS((device_address < device_address + size), ResultInvalidMemoryRegion);
+ R_UNLESS((process_address == static_cast<uint64_t>(process_address)),
+ ResultInvalidCurrentMemory);
+ R_UNLESS(IsValidDeviceMemoryPermission(device_perm), ResultInvalidNewMemoryPermission);
+ R_UNLESS(reserved == 0, ResultInvalidEnumValue);
+
+ // Get the device address space.
+ KScopedAutoObject das = GetCurrentProcess(system.Kernel())
+ .GetHandleTable()
+ .GetObject<KDeviceAddressSpace>(das_handle);
+ R_UNLESS(das.IsNotNull(), ResultInvalidHandle);
+
+ // Get the process.
+ KScopedAutoObject process =
+ GetCurrentProcess(system.Kernel()).GetHandleTable().GetObject<KProcess>(process_handle);
+ R_UNLESS(process.IsNotNull(), ResultInvalidHandle);
+
+ // Validate that the process address is within range.
+ auto& page_table = process->PageTable();
+ R_UNLESS(page_table.Contains(process_address, size), ResultInvalidCurrentMemory);
+
+ // Map.
+ R_RETURN(
+ das->MapByForce(std::addressof(page_table), process_address, size, device_address, option));
+}
+
+Result MapDeviceAddressSpaceAligned(Core::System& system, Handle das_handle, Handle process_handle,
+ uint64_t process_address, uint64_t size,
+ uint64_t device_address, u32 option) {
+ // Decode the option.
+ const MapDeviceAddressSpaceOption option_pack{option};
+ const auto device_perm = option_pack.permission;
+ const auto reserved = option_pack.reserved;
+
+ // Validate input.
+ R_UNLESS(Common::IsAligned(process_address, PageSize), ResultInvalidAddress);
+ R_UNLESS(Common::IsAligned(device_address, PageSize), ResultInvalidAddress);
+ R_UNLESS(IsProcessAndDeviceAligned(process_address, device_address), ResultInvalidAddress);
+ R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize);
+ R_UNLESS(size > 0, ResultInvalidSize);
+ R_UNLESS((process_address < process_address + size), ResultInvalidCurrentMemory);
+ R_UNLESS((device_address < device_address + size), ResultInvalidMemoryRegion);
+ R_UNLESS((process_address == static_cast<uint64_t>(process_address)),
+ ResultInvalidCurrentMemory);
+ R_UNLESS(IsValidDeviceMemoryPermission(device_perm), ResultInvalidNewMemoryPermission);
+ R_UNLESS(reserved == 0, ResultInvalidEnumValue);
+
+ // Get the device address space.
+ KScopedAutoObject das = GetCurrentProcess(system.Kernel())
+ .GetHandleTable()
+ .GetObject<KDeviceAddressSpace>(das_handle);
+ R_UNLESS(das.IsNotNull(), ResultInvalidHandle);
+
+ // Get the process.
+ KScopedAutoObject process =
+ GetCurrentProcess(system.Kernel()).GetHandleTable().GetObject<KProcess>(process_handle);
+ R_UNLESS(process.IsNotNull(), ResultInvalidHandle);
+
+ // Validate that the process address is within range.
+ auto& page_table = process->PageTable();
+ R_UNLESS(page_table.Contains(process_address, size), ResultInvalidCurrentMemory);
+
+ // Map.
+ R_RETURN(
+ das->MapAligned(std::addressof(page_table), process_address, size, device_address, option));
+}
+
+Result UnmapDeviceAddressSpace(Core::System& system, Handle das_handle, Handle process_handle,
+ uint64_t process_address, uint64_t size, uint64_t device_address) {
+ // Validate input.
+ R_UNLESS(Common::IsAligned(process_address, PageSize), ResultInvalidAddress);
+ R_UNLESS(Common::IsAligned(device_address, PageSize), ResultInvalidAddress);
+ R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize);
+ R_UNLESS(size > 0, ResultInvalidSize);
+ R_UNLESS((process_address < process_address + size), ResultInvalidCurrentMemory);
+ R_UNLESS((device_address < device_address + size), ResultInvalidMemoryRegion);
+ R_UNLESS((process_address == static_cast<uint64_t>(process_address)),
+ ResultInvalidCurrentMemory);
+
+ // Get the device address space.
+ KScopedAutoObject das = GetCurrentProcess(system.Kernel())
+ .GetHandleTable()
+ .GetObject<KDeviceAddressSpace>(das_handle);
+ R_UNLESS(das.IsNotNull(), ResultInvalidHandle);
+
+ // Get the process.
+ KScopedAutoObject process =
+ GetCurrentProcess(system.Kernel()).GetHandleTable().GetObject<KProcess>(process_handle);
+ R_UNLESS(process.IsNotNull(), ResultInvalidHandle);
+
+ // Validate that the process address is within range.
+ auto& page_table = process->PageTable();
+ R_UNLESS(page_table.Contains(process_address, size), ResultInvalidCurrentMemory);
+
+ R_RETURN(das->Unmap(std::addressof(page_table), process_address, size, device_address));
+}
+
+Result CreateDeviceAddressSpace64(Core::System& system, Handle* out_handle, uint64_t das_address,
+ uint64_t das_size) {
+ R_RETURN(CreateDeviceAddressSpace(system, out_handle, das_address, das_size));
+}
+
+Result AttachDeviceAddressSpace64(Core::System& system, DeviceName device_name, Handle das_handle) {
+ R_RETURN(AttachDeviceAddressSpace(system, device_name, das_handle));
+}
+
+Result DetachDeviceAddressSpace64(Core::System& system, DeviceName device_name, Handle das_handle) {
+ R_RETURN(DetachDeviceAddressSpace(system, device_name, das_handle));
+}
+
+Result MapDeviceAddressSpaceByForce64(Core::System& system, Handle das_handle,
+ Handle process_handle, uint64_t process_address,
+ uint64_t size, uint64_t device_address, u32 option) {
+ R_RETURN(MapDeviceAddressSpaceByForce(system, das_handle, process_handle, process_address, size,
+ device_address, option));
+}
+
+Result MapDeviceAddressSpaceAligned64(Core::System& system, Handle das_handle,
+ Handle process_handle, uint64_t process_address,
+ uint64_t size, uint64_t device_address, u32 option) {
+ R_RETURN(MapDeviceAddressSpaceAligned(system, das_handle, process_handle, process_address, size,
+ device_address, option));
+}
+
+Result UnmapDeviceAddressSpace64(Core::System& system, Handle das_handle, Handle process_handle,
+ uint64_t process_address, uint64_t size, uint64_t device_address) {
+ R_RETURN(UnmapDeviceAddressSpace(system, das_handle, process_handle, process_address, size,
+ device_address));
+}
+
+Result CreateDeviceAddressSpace64From32(Core::System& system, Handle* out_handle,
+ uint64_t das_address, uint64_t das_size) {
+ R_RETURN(CreateDeviceAddressSpace(system, out_handle, das_address, das_size));
+}
+
+Result AttachDeviceAddressSpace64From32(Core::System& system, DeviceName device_name,
+ Handle das_handle) {
+ R_RETURN(AttachDeviceAddressSpace(system, device_name, das_handle));
+}
+
+Result DetachDeviceAddressSpace64From32(Core::System& system, DeviceName device_name,
+ Handle das_handle) {
+ R_RETURN(DetachDeviceAddressSpace(system, device_name, das_handle));
+}
+
+Result MapDeviceAddressSpaceByForce64From32(Core::System& system, Handle das_handle,
+ Handle process_handle, uint64_t process_address,
+ uint32_t size, uint64_t device_address, u32 option) {
+ R_RETURN(MapDeviceAddressSpaceByForce(system, das_handle, process_handle, process_address, size,
+ device_address, option));
+}
+
+Result MapDeviceAddressSpaceAligned64From32(Core::System& system, Handle das_handle,
+ Handle process_handle, uint64_t process_address,
+ uint32_t size, uint64_t device_address, u32 option) {
+ R_RETURN(MapDeviceAddressSpaceAligned(system, das_handle, process_handle, process_address, size,
+ device_address, option));
+}
+
+Result UnmapDeviceAddressSpace64From32(Core::System& system, Handle das_handle,
+ Handle process_handle, uint64_t process_address,
+ uint32_t size, uint64_t device_address) {
+ R_RETURN(UnmapDeviceAddressSpace(system, das_handle, process_handle, process_address, size,
+ device_address));
+}
+
+} // namespace Kernel::Svc
diff --git a/src/core/hle/kernel/svc/svc_event.cpp b/src/core/hle/kernel/svc/svc_event.cpp
new file mode 100644
index 000000000..901202e6a
--- /dev/null
+++ b/src/core/hle/kernel/svc/svc_event.cpp
@@ -0,0 +1,120 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "common/scope_exit.h"
+#include "core/core.h"
+#include "core/hle/kernel/k_event.h"
+#include "core/hle/kernel/k_process.h"
+#include "core/hle/kernel/k_scoped_resource_reservation.h"
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/svc.h"
+
+namespace Kernel::Svc {
+
+Result SignalEvent(Core::System& system, Handle event_handle) {
+ LOG_DEBUG(Kernel_SVC, "called, event_handle=0x{:08X}", event_handle);
+
+ // Get the current handle table.
+ const KHandleTable& handle_table = GetCurrentProcess(system.Kernel()).GetHandleTable();
+
+ // Get the event.
+ KScopedAutoObject event = handle_table.GetObject<KEvent>(event_handle);
+ R_UNLESS(event.IsNotNull(), ResultInvalidHandle);
+
+ R_RETURN(event->Signal());
+}
+
+Result ClearEvent(Core::System& system, Handle event_handle) {
+ LOG_TRACE(Kernel_SVC, "called, event_handle=0x{:08X}", event_handle);
+
+ // Get the current handle table.
+ const auto& handle_table = GetCurrentProcess(system.Kernel()).GetHandleTable();
+
+ // Try to clear the writable event.
+ {
+ KScopedAutoObject event = handle_table.GetObject<KEvent>(event_handle);
+ if (event.IsNotNull()) {
+ R_RETURN(event->Clear());
+ }
+ }
+
+ // Try to clear the readable event.
+ {
+ KScopedAutoObject readable_event = handle_table.GetObject<KReadableEvent>(event_handle);
+ if (readable_event.IsNotNull()) {
+ R_RETURN(readable_event->Clear());
+ }
+ }
+
+ R_THROW(ResultInvalidHandle);
+}
+
+Result CreateEvent(Core::System& system, Handle* out_write, Handle* out_read) {
+ LOG_DEBUG(Kernel_SVC, "called");
+
+ // Get the kernel reference and handle table.
+ auto& kernel = system.Kernel();
+ auto& handle_table = GetCurrentProcess(kernel).GetHandleTable();
+
+ // Reserve a new event from the process resource limit
+ KScopedResourceReservation event_reservation(GetCurrentProcessPointer(kernel),
+ LimitableResource::EventCountMax);
+ R_UNLESS(event_reservation.Succeeded(), ResultLimitReached);
+
+ // Create a new event.
+ KEvent* event = KEvent::Create(kernel);
+ R_UNLESS(event != nullptr, ResultOutOfResource);
+
+ // Initialize the event.
+ event->Initialize(GetCurrentProcessPointer(kernel));
+
+ // 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->GetReadableEvent().Close();
+ event->Close();
+ });
+
+ // Register the event.
+ KEvent::Register(kernel, event);
+
+ // Add the event to the handle table.
+ R_TRY(handle_table.Add(out_write, event));
+
+ // Ensure that we maintain a clean handle state on exit.
+ ON_RESULT_FAILURE {
+ handle_table.Remove(*out_write);
+ };
+
+ // Add the readable event to the handle table.
+ R_RETURN(handle_table.Add(out_read, std::addressof(event->GetReadableEvent())));
+}
+
+Result SignalEvent64(Core::System& system, Handle event_handle) {
+ R_RETURN(SignalEvent(system, event_handle));
+}
+
+Result ClearEvent64(Core::System& system, Handle event_handle) {
+ R_RETURN(ClearEvent(system, event_handle));
+}
+
+Result CreateEvent64(Core::System& system, Handle* out_write_handle, Handle* out_read_handle) {
+ R_RETURN(CreateEvent(system, out_write_handle, out_read_handle));
+}
+
+Result SignalEvent64From32(Core::System& system, Handle event_handle) {
+ R_RETURN(SignalEvent(system, event_handle));
+}
+
+Result ClearEvent64From32(Core::System& system, Handle event_handle) {
+ R_RETURN(ClearEvent(system, event_handle));
+}
+
+Result CreateEvent64From32(Core::System& system, Handle* out_write_handle,
+ Handle* out_read_handle) {
+ R_RETURN(CreateEvent(system, out_write_handle, out_read_handle));
+}
+
+} // namespace Kernel::Svc
diff --git a/src/core/hle/kernel/svc/svc_exception.cpp b/src/core/hle/kernel/svc/svc_exception.cpp
new file mode 100644
index 000000000..580cf2f75
--- /dev/null
+++ b/src/core/hle/kernel/svc/svc_exception.cpp
@@ -0,0 +1,137 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/core.h"
+#include "core/debugger/debugger.h"
+#include "core/hle/kernel/k_thread.h"
+#include "core/hle/kernel/svc.h"
+#include "core/hle/kernel/svc_types.h"
+#include "core/memory.h"
+#include "core/reporter.h"
+
+namespace Kernel::Svc {
+
+/// Break program execution
+void Break(Core::System& system, BreakReason reason, u64 info1, u64 info2) {
+ BreakReason break_reason =
+ reason & static_cast<BreakReason>(~BreakReason::NotificationOnlyFlag);
+ bool notification_only = True(reason & BreakReason::NotificationOnlyFlag);
+
+ bool has_dumped_buffer{};
+ std::vector<u8> debug_buffer;
+
+ const auto handle_debug_buffer = [&](u64 addr, u64 sz) {
+ if (sz == 0 || addr == 0 || has_dumped_buffer) {
+ return;
+ }
+
+ auto& memory = GetCurrentMemory(system.Kernel());
+
+ // This typically is an error code so we're going to assume this is the case
+ if (sz == sizeof(u32)) {
+ LOG_CRITICAL(Debug_Emulated, "debug_buffer_err_code={:X}", memory.Read32(addr));
+ } else {
+ // We don't know what's in here so we'll hexdump it
+ debug_buffer.resize(sz);
+ memory.ReadBlock(addr, debug_buffer.data(), sz);
+ std::string hexdump;
+ for (std::size_t i = 0; i < debug_buffer.size(); i++) {
+ hexdump += fmt::format("{:02X} ", debug_buffer[i]);
+ if (i != 0 && i % 16 == 0) {
+ hexdump += '\n';
+ }
+ }
+ LOG_CRITICAL(Debug_Emulated, "debug_buffer=\n{}", hexdump);
+ }
+ has_dumped_buffer = true;
+ };
+ switch (break_reason) {
+ case BreakReason::Panic:
+ LOG_CRITICAL(Debug_Emulated, "Userspace PANIC! info1=0x{:016X}, info2=0x{:016X}", info1,
+ info2);
+ handle_debug_buffer(info1, info2);
+ break;
+ case BreakReason::Assert:
+ LOG_CRITICAL(Debug_Emulated, "Userspace Assertion failed! info1=0x{:016X}, info2=0x{:016X}",
+ info1, info2);
+ handle_debug_buffer(info1, info2);
+ break;
+ case BreakReason::User:
+ LOG_WARNING(Debug_Emulated, "Userspace Break! 0x{:016X} with size 0x{:016X}", info1, info2);
+ handle_debug_buffer(info1, info2);
+ break;
+ case BreakReason::PreLoadDll:
+ LOG_INFO(Debug_Emulated,
+ "Userspace Attempting to load an NRO at 0x{:016X} with size 0x{:016X}", info1,
+ info2);
+ break;
+ case BreakReason::PostLoadDll:
+ LOG_INFO(Debug_Emulated, "Userspace Loaded an NRO at 0x{:016X} with size 0x{:016X}", info1,
+ info2);
+ break;
+ case BreakReason::PreUnloadDll:
+ LOG_INFO(Debug_Emulated,
+ "Userspace Attempting to unload an NRO at 0x{:016X} with size 0x{:016X}", info1,
+ info2);
+ break;
+ case BreakReason::PostUnloadDll:
+ LOG_INFO(Debug_Emulated, "Userspace Unloaded an NRO at 0x{:016X} with size 0x{:016X}",
+ info1, info2);
+ break;
+ case BreakReason::CppException:
+ LOG_CRITICAL(Debug_Emulated, "Signalling debugger. Uncaught C++ exception encountered.");
+ break;
+ default:
+ LOG_WARNING(
+ Debug_Emulated,
+ "Signalling debugger, Unknown break reason {:#X}, info1=0x{:016X}, info2=0x{:016X}",
+ reason, info1, info2);
+ handle_debug_buffer(info1, info2);
+ break;
+ }
+
+ system.GetReporter().SaveSvcBreakReport(
+ static_cast<u32>(reason), notification_only, info1, info2,
+ has_dumped_buffer ? std::make_optional(debug_buffer) : std::nullopt);
+
+ if (!notification_only) {
+ LOG_CRITICAL(
+ Debug_Emulated,
+ "Emulated program broke execution! reason=0x{:016X}, info1=0x{:016X}, info2=0x{:016X}",
+ reason, info1, info2);
+
+ handle_debug_buffer(info1, info2);
+
+ auto* const current_thread = GetCurrentThreadPointer(system.Kernel());
+ const auto thread_processor_id = current_thread->GetActiveCore();
+ system.ArmInterface(static_cast<std::size_t>(thread_processor_id)).LogBacktrace();
+ }
+
+ if (system.DebuggerEnabled()) {
+ auto* thread = system.Kernel().GetCurrentEmuThread();
+ system.GetDebugger().NotifyThreadStopped(thread);
+ thread->RequestSuspend(Kernel::SuspendType::Debug);
+ }
+}
+
+void ReturnFromException(Core::System& system, Result result) {
+ UNIMPLEMENTED();
+}
+
+void Break64(Core::System& system, BreakReason break_reason, uint64_t arg, uint64_t size) {
+ Break(system, break_reason, arg, size);
+}
+
+void Break64From32(Core::System& system, BreakReason break_reason, uint32_t arg, uint32_t size) {
+ Break(system, break_reason, arg, size);
+}
+
+void ReturnFromException64(Core::System& system, Result result) {
+ ReturnFromException(system, result);
+}
+
+void ReturnFromException64From32(Core::System& system, Result result) {
+ ReturnFromException(system, result);
+}
+
+} // namespace Kernel::Svc
diff --git a/src/core/hle/kernel/svc/svc_info.cpp b/src/core/hle/kernel/svc/svc_info.cpp
new file mode 100644
index 000000000..445cdd87b
--- /dev/null
+++ b/src/core/hle/kernel/svc/svc_info.cpp
@@ -0,0 +1,277 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/core.h"
+#include "core/core_timing.h"
+#include "core/hle/kernel/k_process.h"
+#include "core/hle/kernel/k_resource_limit.h"
+#include "core/hle/kernel/svc.h"
+
+namespace Kernel::Svc {
+
+/// Gets system/memory information for the current process
+Result GetInfo(Core::System& system, u64* result, InfoType info_id_type, Handle handle,
+ u64 info_sub_id) {
+ LOG_TRACE(Kernel_SVC, "called info_id=0x{:X}, info_sub_id=0x{:X}, handle=0x{:08X}",
+ info_id_type, info_sub_id, handle);
+
+ u32 info_id = static_cast<u32>(info_id_type);
+
+ switch (info_id_type) {
+ case InfoType::CoreMask:
+ case InfoType::PriorityMask:
+ case InfoType::AliasRegionAddress:
+ case InfoType::AliasRegionSize:
+ case InfoType::HeapRegionAddress:
+ case InfoType::HeapRegionSize:
+ case InfoType::AslrRegionAddress:
+ case InfoType::AslrRegionSize:
+ case InfoType::StackRegionAddress:
+ case InfoType::StackRegionSize:
+ case InfoType::TotalMemorySize:
+ case InfoType::UsedMemorySize:
+ case InfoType::SystemResourceSizeTotal:
+ case InfoType::SystemResourceSizeUsed:
+ case InfoType::ProgramId:
+ case InfoType::UserExceptionContextAddress:
+ case InfoType::TotalNonSystemMemorySize:
+ case InfoType::UsedNonSystemMemorySize:
+ case InfoType::IsApplication:
+ case InfoType::FreeThreadCount: {
+ R_UNLESS(info_sub_id == 0, ResultInvalidEnumValue);
+
+ const auto& handle_table = GetCurrentProcess(system.Kernel()).GetHandleTable();
+ KScopedAutoObject process = handle_table.GetObject<KProcess>(handle);
+ R_UNLESS(process.IsNotNull(), ResultInvalidHandle);
+
+ switch (info_id_type) {
+ case InfoType::CoreMask:
+ *result = process->GetCoreMask();
+ R_SUCCEED();
+
+ case InfoType::PriorityMask:
+ *result = process->GetPriorityMask();
+ R_SUCCEED();
+
+ case InfoType::AliasRegionAddress:
+ *result = GetInteger(process->PageTable().GetAliasRegionStart());
+ R_SUCCEED();
+
+ case InfoType::AliasRegionSize:
+ *result = process->PageTable().GetAliasRegionSize();
+ R_SUCCEED();
+
+ case InfoType::HeapRegionAddress:
+ *result = GetInteger(process->PageTable().GetHeapRegionStart());
+ R_SUCCEED();
+
+ case InfoType::HeapRegionSize:
+ *result = process->PageTable().GetHeapRegionSize();
+ R_SUCCEED();
+
+ case InfoType::AslrRegionAddress:
+ *result = GetInteger(process->PageTable().GetAliasCodeRegionStart());
+ R_SUCCEED();
+
+ case InfoType::AslrRegionSize:
+ *result = process->PageTable().GetAliasCodeRegionSize();
+ R_SUCCEED();
+
+ case InfoType::StackRegionAddress:
+ *result = GetInteger(process->PageTable().GetStackRegionStart());
+ R_SUCCEED();
+
+ case InfoType::StackRegionSize:
+ *result = process->PageTable().GetStackRegionSize();
+ R_SUCCEED();
+
+ case InfoType::TotalMemorySize:
+ *result = process->GetTotalPhysicalMemoryAvailable();
+ R_SUCCEED();
+
+ case InfoType::UsedMemorySize:
+ *result = process->GetTotalPhysicalMemoryUsed();
+ R_SUCCEED();
+
+ case InfoType::SystemResourceSizeTotal:
+ *result = process->GetSystemResourceSize();
+ R_SUCCEED();
+
+ case InfoType::SystemResourceSizeUsed:
+ LOG_WARNING(Kernel_SVC, "(STUBBED) Attempted to query system resource usage");
+ *result = process->GetSystemResourceUsage();
+ R_SUCCEED();
+
+ case InfoType::ProgramId:
+ *result = process->GetProgramId();
+ R_SUCCEED();
+
+ case InfoType::UserExceptionContextAddress:
+ *result = GetInteger(process->GetProcessLocalRegionAddress());
+ R_SUCCEED();
+
+ case InfoType::TotalNonSystemMemorySize:
+ *result = process->GetTotalPhysicalMemoryAvailableWithoutSystemResource();
+ R_SUCCEED();
+
+ case InfoType::UsedNonSystemMemorySize:
+ *result = process->GetTotalPhysicalMemoryUsedWithoutSystemResource();
+ R_SUCCEED();
+
+ case InfoType::IsApplication:
+ LOG_WARNING(Kernel_SVC, "(STUBBED) Assuming process is application");
+ *result = true;
+ R_SUCCEED();
+
+ case InfoType::FreeThreadCount:
+ *result = process->GetFreeThreadCount();
+ R_SUCCEED();
+
+ default:
+ break;
+ }
+
+ LOG_ERROR(Kernel_SVC, "Unimplemented svcGetInfo id=0x{:016X}", info_id);
+ R_THROW(ResultInvalidEnumValue);
+ }
+
+ case InfoType::DebuggerAttached:
+ *result = 0;
+ R_SUCCEED();
+
+ case InfoType::ResourceLimit: {
+ R_UNLESS(handle == 0, ResultInvalidHandle);
+ R_UNLESS(info_sub_id == 0, ResultInvalidCombination);
+
+ KProcess* const current_process = GetCurrentProcessPointer(system.Kernel());
+ KHandleTable& handle_table = current_process->GetHandleTable();
+ const auto resource_limit = current_process->GetResourceLimit();
+ if (!resource_limit) {
+ *result = Svc::InvalidHandle;
+ // Yes, the kernel considers this a successful operation.
+ R_SUCCEED();
+ }
+
+ Handle resource_handle{};
+ R_TRY(handle_table.Add(std::addressof(resource_handle), resource_limit));
+
+ *result = resource_handle;
+ R_SUCCEED();
+ }
+
+ case InfoType::RandomEntropy:
+ R_UNLESS(handle == 0, ResultInvalidHandle);
+ R_UNLESS(info_sub_id < KProcess::RANDOM_ENTROPY_SIZE, ResultInvalidCombination);
+
+ *result = GetCurrentProcess(system.Kernel()).GetRandomEntropy(info_sub_id);
+ R_SUCCEED();
+
+ case InfoType::InitialProcessIdRange:
+ LOG_WARNING(Kernel_SVC,
+ "(STUBBED) Attempted to query privileged process id bounds, returned 0");
+ *result = 0;
+ R_SUCCEED();
+
+ case InfoType::ThreadTickCount: {
+ constexpr u64 num_cpus = 4;
+ if (info_sub_id != 0xFFFFFFFFFFFFFFFF && info_sub_id >= num_cpus) {
+ LOG_ERROR(Kernel_SVC, "Core count is out of range, expected {} but got {}", num_cpus,
+ info_sub_id);
+ R_THROW(ResultInvalidCombination);
+ }
+
+ KScopedAutoObject thread = GetCurrentProcess(system.Kernel())
+ .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));
+ R_THROW(ResultInvalidHandle);
+ }
+
+ const auto& core_timing = system.CoreTiming();
+ const auto& scheduler = *system.Kernel().CurrentScheduler();
+ const auto* const current_thread = GetCurrentThreadPointer(system.Kernel());
+ const bool same_thread = current_thread == thread.GetPointerUnsafe();
+
+ const u64 prev_ctx_ticks = scheduler.GetLastContextSwitchTime();
+ u64 out_ticks = 0;
+ if (same_thread && info_sub_id == 0xFFFFFFFFFFFFFFFF) {
+ const u64 thread_ticks = current_thread->GetCpuTime();
+
+ out_ticks = thread_ticks + (core_timing.GetClockTicks() - prev_ctx_ticks);
+ } else if (same_thread && info_sub_id == system.Kernel().CurrentPhysicalCoreIndex()) {
+ out_ticks = core_timing.GetClockTicks() - prev_ctx_ticks;
+ }
+
+ *result = out_ticks;
+ R_SUCCEED();
+ }
+ case InfoType::IdleTickCount: {
+ // Verify the input handle is invalid.
+ R_UNLESS(handle == InvalidHandle, ResultInvalidHandle);
+
+ // Verify the requested core is valid.
+ const bool core_valid =
+ (info_sub_id == 0xFFFFFFFFFFFFFFFF) ||
+ (info_sub_id == static_cast<u64>(system.Kernel().CurrentPhysicalCoreIndex()));
+ R_UNLESS(core_valid, ResultInvalidCombination);
+
+ // Get the idle tick count.
+ *result = system.Kernel().CurrentScheduler()->GetIdleThread()->GetCpuTime();
+ R_SUCCEED();
+ }
+ case InfoType::MesosphereCurrentProcess: {
+ // Verify the input handle is invalid.
+ R_UNLESS(handle == InvalidHandle, ResultInvalidHandle);
+
+ // Verify the sub-type is valid.
+ R_UNLESS(info_sub_id == 0, ResultInvalidCombination);
+
+ // Get the handle table.
+ KProcess* current_process = GetCurrentProcessPointer(system.Kernel());
+ KHandleTable& handle_table = current_process->GetHandleTable();
+
+ // Get a new handle for the current process.
+ Handle tmp;
+ R_TRY(handle_table.Add(std::addressof(tmp), current_process));
+
+ // Set the output.
+ *result = tmp;
+
+ // We succeeded.
+ R_SUCCEED();
+ }
+ default:
+ LOG_ERROR(Kernel_SVC, "Unimplemented svcGetInfo id=0x{:016X}", info_id);
+ R_THROW(ResultInvalidEnumValue);
+ }
+}
+
+Result GetSystemInfo(Core::System& system, uint64_t* out, SystemInfoType info_type, Handle handle,
+ uint64_t info_subtype) {
+ UNIMPLEMENTED();
+ R_THROW(ResultNotImplemented);
+}
+
+Result GetInfo64(Core::System& system, uint64_t* out, InfoType info_type, Handle handle,
+ uint64_t info_subtype) {
+ R_RETURN(GetInfo(system, out, info_type, handle, info_subtype));
+}
+
+Result GetSystemInfo64(Core::System& system, uint64_t* out, SystemInfoType info_type, Handle handle,
+ uint64_t info_subtype) {
+ R_RETURN(GetSystemInfo(system, out, info_type, handle, info_subtype));
+}
+
+Result GetInfo64From32(Core::System& system, uint64_t* out, InfoType info_type, Handle handle,
+ uint64_t info_subtype) {
+ R_RETURN(GetInfo(system, out, info_type, handle, info_subtype));
+}
+
+Result GetSystemInfo64From32(Core::System& system, uint64_t* out, SystemInfoType info_type,
+ Handle handle, uint64_t info_subtype) {
+ R_RETURN(GetSystemInfo(system, out, info_type, handle, info_subtype));
+}
+
+} // namespace Kernel::Svc
diff --git a/src/core/hle/kernel/svc/svc_insecure_memory.cpp b/src/core/hle/kernel/svc/svc_insecure_memory.cpp
new file mode 100644
index 000000000..00457c6bf
--- /dev/null
+++ b/src/core/hle/kernel/svc/svc_insecure_memory.cpp
@@ -0,0 +1,35 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/kernel/svc.h"
+#include "core/hle/kernel/svc_results.h"
+
+namespace Kernel::Svc {
+
+Result MapInsecureMemory(Core::System& system, uint64_t address, uint64_t size) {
+ UNIMPLEMENTED();
+ R_THROW(ResultNotImplemented);
+}
+
+Result UnmapInsecureMemory(Core::System& system, uint64_t address, uint64_t size) {
+ UNIMPLEMENTED();
+ R_THROW(ResultNotImplemented);
+}
+
+Result MapInsecureMemory64(Core::System& system, uint64_t address, uint64_t size) {
+ R_RETURN(MapInsecureMemory(system, address, size));
+}
+
+Result UnmapInsecureMemory64(Core::System& system, uint64_t address, uint64_t size) {
+ R_RETURN(UnmapInsecureMemory(system, address, size));
+}
+
+Result MapInsecureMemory64From32(Core::System& system, uint32_t address, uint32_t size) {
+ R_RETURN(MapInsecureMemory(system, address, size));
+}
+
+Result UnmapInsecureMemory64From32(Core::System& system, uint32_t address, uint32_t size) {
+ R_RETURN(UnmapInsecureMemory(system, address, size));
+}
+
+} // namespace Kernel::Svc
diff --git a/src/core/hle/kernel/svc/svc_interrupt_event.cpp b/src/core/hle/kernel/svc/svc_interrupt_event.cpp
new file mode 100644
index 000000000..768b30a1f
--- /dev/null
+++ b/src/core/hle/kernel/svc/svc_interrupt_event.cpp
@@ -0,0 +1,25 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/kernel/svc.h"
+#include "core/hle/kernel/svc_results.h"
+
+namespace Kernel::Svc {
+
+Result CreateInterruptEvent(Core::System& system, Handle* out, int32_t interrupt_id,
+ InterruptType type) {
+ UNIMPLEMENTED();
+ R_THROW(ResultNotImplemented);
+}
+
+Result CreateInterruptEvent64(Core::System& system, Handle* out_read_handle, int32_t interrupt_id,
+ InterruptType interrupt_type) {
+ R_RETURN(CreateInterruptEvent(system, out_read_handle, interrupt_id, interrupt_type));
+}
+
+Result CreateInterruptEvent64From32(Core::System& system, Handle* out_read_handle,
+ int32_t interrupt_id, InterruptType interrupt_type) {
+ R_RETURN(CreateInterruptEvent(system, out_read_handle, interrupt_id, interrupt_type));
+}
+
+} // namespace Kernel::Svc
diff --git a/src/core/hle/kernel/svc/svc_io_pool.cpp b/src/core/hle/kernel/svc/svc_io_pool.cpp
new file mode 100644
index 000000000..f01817e24
--- /dev/null
+++ b/src/core/hle/kernel/svc/svc_io_pool.cpp
@@ -0,0 +1,71 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/kernel/svc.h"
+#include "core/hle/kernel/svc_results.h"
+
+namespace Kernel::Svc {
+
+Result CreateIoPool(Core::System& system, Handle* out, IoPoolType pool_type) {
+ UNIMPLEMENTED();
+ R_THROW(ResultNotImplemented);
+}
+
+Result CreateIoRegion(Core::System& system, Handle* out, Handle io_pool_handle, uint64_t phys_addr,
+ uint64_t size, MemoryMapping mapping, MemoryPermission perm) {
+ UNIMPLEMENTED();
+ R_THROW(ResultNotImplemented);
+}
+
+Result MapIoRegion(Core::System& system, Handle io_region_handle, uint64_t address, uint64_t size,
+ MemoryPermission map_perm) {
+ UNIMPLEMENTED();
+ R_THROW(ResultNotImplemented);
+}
+
+Result UnmapIoRegion(Core::System& system, Handle io_region_handle, uint64_t address,
+ uint64_t size) {
+ UNIMPLEMENTED();
+ R_THROW(ResultNotImplemented);
+}
+
+Result CreateIoPool64(Core::System& system, Handle* out_handle, IoPoolType pool_type) {
+ R_RETURN(CreateIoPool(system, out_handle, pool_type));
+}
+
+Result CreateIoRegion64(Core::System& system, Handle* out_handle, Handle io_pool,
+ uint64_t physical_address, uint64_t size, MemoryMapping mapping,
+ MemoryPermission perm) {
+ R_RETURN(CreateIoRegion(system, out_handle, io_pool, physical_address, size, mapping, perm));
+}
+
+Result MapIoRegion64(Core::System& system, Handle io_region, uint64_t address, uint64_t size,
+ MemoryPermission perm) {
+ R_RETURN(MapIoRegion(system, io_region, address, size, perm));
+}
+
+Result UnmapIoRegion64(Core::System& system, Handle io_region, uint64_t address, uint64_t size) {
+ R_RETURN(UnmapIoRegion(system, io_region, address, size));
+}
+
+Result CreateIoPool64From32(Core::System& system, Handle* out_handle, IoPoolType pool_type) {
+ R_RETURN(CreateIoPool(system, out_handle, pool_type));
+}
+
+Result CreateIoRegion64From32(Core::System& system, Handle* out_handle, Handle io_pool,
+ uint64_t physical_address, uint32_t size, MemoryMapping mapping,
+ MemoryPermission perm) {
+ R_RETURN(CreateIoRegion(system, out_handle, io_pool, physical_address, size, mapping, perm));
+}
+
+Result MapIoRegion64From32(Core::System& system, Handle io_region, uint32_t address, uint32_t size,
+ MemoryPermission perm) {
+ R_RETURN(MapIoRegion(system, io_region, address, size, perm));
+}
+
+Result UnmapIoRegion64From32(Core::System& system, Handle io_region, uint32_t address,
+ uint32_t size) {
+ R_RETURN(UnmapIoRegion(system, io_region, address, size));
+}
+
+} // namespace Kernel::Svc
diff --git a/src/core/hle/kernel/svc/svc_ipc.cpp b/src/core/hle/kernel/svc/svc_ipc.cpp
new file mode 100644
index 000000000..60247df2e
--- /dev/null
+++ b/src/core/hle/kernel/svc/svc_ipc.cpp
@@ -0,0 +1,173 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "common/scope_exit.h"
+#include "common/scratch_buffer.h"
+#include "core/core.h"
+#include "core/hle/kernel/k_client_session.h"
+#include "core/hle/kernel/k_process.h"
+#include "core/hle/kernel/k_server_session.h"
+#include "core/hle/kernel/svc.h"
+
+namespace Kernel::Svc {
+
+/// Makes a blocking IPC call to a service.
+Result SendSyncRequest(Core::System& system, Handle handle) {
+ // Get the client session from its handle.
+ KScopedAutoObject session =
+ GetCurrentProcess(system.Kernel()).GetHandleTable().GetObject<KClientSession>(handle);
+ R_UNLESS(session.IsNotNull(), ResultInvalidHandle);
+
+ LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}", handle);
+
+ R_RETURN(session->SendSyncRequest());
+}
+
+Result SendSyncRequestWithUserBuffer(Core::System& system, uint64_t message_buffer,
+ uint64_t message_buffer_size, Handle session_handle) {
+ UNIMPLEMENTED();
+ R_THROW(ResultNotImplemented);
+}
+
+Result SendAsyncRequestWithUserBuffer(Core::System& system, Handle* out_event_handle,
+ uint64_t message_buffer, uint64_t message_buffer_size,
+ Handle session_handle) {
+ UNIMPLEMENTED();
+ R_THROW(ResultNotImplemented);
+}
+
+Result ReplyAndReceive(Core::System& system, s32* out_index, uint64_t handles_addr, s32 num_handles,
+ Handle reply_target, s64 timeout_ns) {
+ auto& kernel = system.Kernel();
+ auto& handle_table = GetCurrentProcess(kernel).GetHandleTable();
+
+ R_UNLESS(0 <= num_handles && num_handles <= ArgumentHandleCountMax, ResultOutOfRange);
+ R_UNLESS(GetCurrentMemory(kernel).IsValidVirtualAddressRange(
+ handles_addr, static_cast<u64>(sizeof(Handle) * num_handles)),
+ ResultInvalidPointer);
+
+ std::array<Handle, Svc::ArgumentHandleCountMax> handles;
+ GetCurrentMemory(kernel).ReadBlock(handles_addr, handles.data(), sizeof(Handle) * num_handles);
+
+ // Convert handle list to object table.
+ std::array<KSynchronizationObject*, Svc::ArgumentHandleCountMax> objs;
+ R_UNLESS(handle_table.GetMultipleObjects<KSynchronizationObject>(objs.data(), handles.data(),
+ num_handles),
+ ResultInvalidHandle);
+
+ // Ensure handles are closed when we're done.
+ SCOPE_EXIT({
+ for (auto i = 0; i < num_handles; ++i) {
+ objs[i]->Close();
+ }
+ });
+
+ // Reply to the target, if one is specified.
+ if (reply_target != InvalidHandle) {
+ KScopedAutoObject session = handle_table.GetObject<KServerSession>(reply_target);
+ R_UNLESS(session.IsNotNull(), ResultInvalidHandle);
+
+ // If we fail to reply, we want to set the output index to -1.
+ ON_RESULT_FAILURE {
+ *out_index = -1;
+ };
+
+ // Send the reply.
+ R_TRY(session->SendReply());
+ }
+
+ // Wait for a message.
+ while (true) {
+ // Wait for an object.
+ s32 index;
+ Result result = KSynchronizationObject::Wait(kernel, std::addressof(index), objs.data(),
+ num_handles, timeout_ns);
+ if (result == ResultTimedOut) {
+ R_RETURN(result);
+ }
+
+ // Receive the request.
+ if (R_SUCCEEDED(result)) {
+ KServerSession* session = objs[index]->DynamicCast<KServerSession*>();
+ if (session != nullptr) {
+ result = session->ReceiveRequest();
+ if (result == ResultNotFound) {
+ continue;
+ }
+ }
+ }
+
+ *out_index = index;
+ R_RETURN(result);
+ }
+}
+
+Result ReplyAndReceiveWithUserBuffer(Core::System& system, int32_t* out_index,
+ uint64_t message_buffer, uint64_t message_buffer_size,
+ uint64_t handles, int32_t num_handles, Handle reply_target,
+ int64_t timeout_ns) {
+ UNIMPLEMENTED();
+ R_THROW(ResultNotImplemented);
+}
+
+Result SendSyncRequest64(Core::System& system, Handle session_handle) {
+ R_RETURN(SendSyncRequest(system, session_handle));
+}
+
+Result SendSyncRequestWithUserBuffer64(Core::System& system, uint64_t message_buffer,
+ uint64_t message_buffer_size, Handle session_handle) {
+ R_RETURN(
+ SendSyncRequestWithUserBuffer(system, message_buffer, message_buffer_size, session_handle));
+}
+
+Result SendAsyncRequestWithUserBuffer64(Core::System& system, Handle* out_event_handle,
+ uint64_t message_buffer, uint64_t message_buffer_size,
+ Handle session_handle) {
+ R_RETURN(SendAsyncRequestWithUserBuffer(system, out_event_handle, message_buffer,
+ message_buffer_size, session_handle));
+}
+
+Result ReplyAndReceive64(Core::System& system, int32_t* out_index, uint64_t handles,
+ int32_t num_handles, Handle reply_target, int64_t timeout_ns) {
+ R_RETURN(ReplyAndReceive(system, out_index, handles, num_handles, reply_target, timeout_ns));
+}
+
+Result ReplyAndReceiveWithUserBuffer64(Core::System& system, int32_t* out_index,
+ uint64_t message_buffer, uint64_t message_buffer_size,
+ uint64_t handles, int32_t num_handles, Handle reply_target,
+ int64_t timeout_ns) {
+ R_RETURN(ReplyAndReceiveWithUserBuffer(system, out_index, message_buffer, message_buffer_size,
+ handles, num_handles, reply_target, timeout_ns));
+}
+
+Result SendSyncRequest64From32(Core::System& system, Handle session_handle) {
+ R_RETURN(SendSyncRequest(system, session_handle));
+}
+
+Result SendSyncRequestWithUserBuffer64From32(Core::System& system, uint32_t message_buffer,
+ uint32_t message_buffer_size, Handle session_handle) {
+ R_RETURN(
+ SendSyncRequestWithUserBuffer(system, message_buffer, message_buffer_size, session_handle));
+}
+
+Result SendAsyncRequestWithUserBuffer64From32(Core::System& system, Handle* out_event_handle,
+ uint32_t message_buffer, uint32_t message_buffer_size,
+ Handle session_handle) {
+ R_RETURN(SendAsyncRequestWithUserBuffer(system, out_event_handle, message_buffer,
+ message_buffer_size, session_handle));
+}
+
+Result ReplyAndReceive64From32(Core::System& system, int32_t* out_index, uint32_t handles,
+ int32_t num_handles, Handle reply_target, int64_t timeout_ns) {
+ R_RETURN(ReplyAndReceive(system, out_index, handles, num_handles, reply_target, timeout_ns));
+}
+
+Result ReplyAndReceiveWithUserBuffer64From32(Core::System& system, int32_t* out_index,
+ uint32_t message_buffer, uint32_t message_buffer_size,
+ uint32_t handles, int32_t num_handles,
+ Handle reply_target, int64_t timeout_ns) {
+ R_RETURN(ReplyAndReceiveWithUserBuffer(system, out_index, message_buffer, message_buffer_size,
+ handles, num_handles, reply_target, timeout_ns));
+}
+
+} // namespace Kernel::Svc
diff --git a/src/core/hle/kernel/svc/svc_kernel_debug.cpp b/src/core/hle/kernel/svc/svc_kernel_debug.cpp
new file mode 100644
index 000000000..cee048279
--- /dev/null
+++ b/src/core/hle/kernel/svc/svc_kernel_debug.cpp
@@ -0,0 +1,35 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/kernel/svc.h"
+
+namespace Kernel::Svc {
+
+void KernelDebug(Core::System& system, KernelDebugType kernel_debug_type, u64 arg0, u64 arg1,
+ u64 arg2) {
+ // Intentionally do nothing, as this does nothing in released kernel binaries.
+}
+
+void ChangeKernelTraceState(Core::System& system, KernelTraceState trace_state) {
+ // Intentionally do nothing, as this does nothing in released kernel binaries.
+}
+
+void KernelDebug64(Core::System& system, KernelDebugType kern_debug_type, uint64_t arg0,
+ uint64_t arg1, uint64_t arg2) {
+ KernelDebug(system, kern_debug_type, arg0, arg1, arg2);
+}
+
+void ChangeKernelTraceState64(Core::System& system, KernelTraceState kern_trace_state) {
+ ChangeKernelTraceState(system, kern_trace_state);
+}
+
+void KernelDebug64From32(Core::System& system, KernelDebugType kern_debug_type, uint64_t arg0,
+ uint64_t arg1, uint64_t arg2) {
+ KernelDebug(system, kern_debug_type, arg0, arg1, arg2);
+}
+
+void ChangeKernelTraceState64From32(Core::System& system, KernelTraceState kern_trace_state) {
+ ChangeKernelTraceState(system, kern_trace_state);
+}
+
+} // namespace Kernel::Svc
diff --git a/src/core/hle/kernel/svc/svc_light_ipc.cpp b/src/core/hle/kernel/svc/svc_light_ipc.cpp
new file mode 100644
index 000000000..b76ce984c
--- /dev/null
+++ b/src/core/hle/kernel/svc/svc_light_ipc.cpp
@@ -0,0 +1,73 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/arm/arm_interface.h"
+#include "core/core.h"
+#include "core/hle/kernel/svc.h"
+#include "core/hle/kernel/svc_results.h"
+
+namespace Kernel::Svc {
+
+Result SendSyncRequestLight(Core::System& system, Handle session_handle, u32* args) {
+ UNIMPLEMENTED();
+ R_THROW(ResultNotImplemented);
+}
+
+Result ReplyAndReceiveLight(Core::System& system, Handle session_handle, u32* args) {
+ UNIMPLEMENTED();
+ R_THROW(ResultNotImplemented);
+}
+
+Result SendSyncRequestLight64(Core::System& system, Handle session_handle, u32* args) {
+ R_RETURN(SendSyncRequestLight(system, session_handle, args));
+}
+
+Result ReplyAndReceiveLight64(Core::System& system, Handle session_handle, u32* args) {
+ R_RETURN(ReplyAndReceiveLight(system, session_handle, args));
+}
+
+Result SendSyncRequestLight64From32(Core::System& system, Handle session_handle, u32* args) {
+ R_RETURN(SendSyncRequestLight(system, session_handle, args));
+}
+
+Result ReplyAndReceiveLight64From32(Core::System& system, Handle session_handle, u32* args) {
+ R_RETURN(ReplyAndReceiveLight(system, session_handle, args));
+}
+
+// Custom ABI implementation for light IPC.
+
+template <typename F>
+static void SvcWrap_LightIpc(Core::System& system, F&& cb) {
+ auto& core = system.CurrentArmInterface();
+ std::array<u32, 7> arguments{};
+
+ Handle session_handle = static_cast<Handle>(core.GetReg(0));
+ for (int i = 0; i < 7; i++) {
+ arguments[i] = static_cast<u32>(core.GetReg(i + 1));
+ }
+
+ Result ret = cb(system, session_handle, arguments.data());
+
+ core.SetReg(0, ret.raw);
+ for (int i = 0; i < 7; i++) {
+ core.SetReg(i + 1, arguments[i]);
+ }
+}
+
+void SvcWrap_SendSyncRequestLight64(Core::System& system) {
+ SvcWrap_LightIpc(system, SendSyncRequestLight64);
+}
+
+void SvcWrap_ReplyAndReceiveLight64(Core::System& system) {
+ SvcWrap_LightIpc(system, ReplyAndReceiveLight64);
+}
+
+void SvcWrap_SendSyncRequestLight64From32(Core::System& system) {
+ SvcWrap_LightIpc(system, SendSyncRequestLight64From32);
+}
+
+void SvcWrap_ReplyAndReceiveLight64From32(Core::System& system) {
+ SvcWrap_LightIpc(system, ReplyAndReceiveLight64From32);
+}
+
+} // namespace Kernel::Svc
diff --git a/src/core/hle/kernel/svc/svc_lock.cpp b/src/core/hle/kernel/svc/svc_lock.cpp
new file mode 100644
index 000000000..1d7bc4246
--- /dev/null
+++ b/src/core/hle/kernel/svc/svc_lock.cpp
@@ -0,0 +1,51 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/core.h"
+#include "core/hle/kernel/k_memory_layout.h"
+#include "core/hle/kernel/k_process.h"
+#include "core/hle/kernel/svc.h"
+
+namespace Kernel::Svc {
+
+/// Attempts to locks a mutex
+Result ArbitrateLock(Core::System& system, Handle thread_handle, u64 address, u32 tag) {
+ LOG_TRACE(Kernel_SVC, "called thread_handle=0x{:08X}, address=0x{:X}, tag=0x{:08X}",
+ thread_handle, address, tag);
+
+ // Validate the input address.
+ R_UNLESS(!IsKernelAddress(address), ResultInvalidCurrentMemory);
+ R_UNLESS(Common::IsAligned(address, sizeof(u32)), ResultInvalidAddress);
+
+ R_RETURN(GetCurrentProcess(system.Kernel()).WaitForAddress(thread_handle, address, tag));
+}
+
+/// Unlock a mutex
+Result ArbitrateUnlock(Core::System& system, u64 address) {
+ LOG_TRACE(Kernel_SVC, "called address=0x{:X}", address);
+
+ // Validate the input address.
+ R_UNLESS(!IsKernelAddress(address), ResultInvalidCurrentMemory);
+ R_UNLESS(Common::IsAligned(address, sizeof(u32)), ResultInvalidAddress);
+
+ R_RETURN(GetCurrentProcess(system.Kernel()).SignalToAddress(address));
+}
+
+Result ArbitrateLock64(Core::System& system, Handle thread_handle, uint64_t address, uint32_t tag) {
+ R_RETURN(ArbitrateLock(system, thread_handle, address, tag));
+}
+
+Result ArbitrateUnlock64(Core::System& system, uint64_t address) {
+ R_RETURN(ArbitrateUnlock(system, address));
+}
+
+Result ArbitrateLock64From32(Core::System& system, Handle thread_handle, uint32_t address,
+ uint32_t tag) {
+ R_RETURN(ArbitrateLock(system, thread_handle, address, tag));
+}
+
+Result ArbitrateUnlock64From32(Core::System& system, uint32_t address) {
+ R_RETURN(ArbitrateUnlock(system, address));
+}
+
+} // namespace Kernel::Svc
diff --git a/src/core/hle/kernel/svc/svc_memory.cpp b/src/core/hle/kernel/svc/svc_memory.cpp
new file mode 100644
index 000000000..5dcb7f045
--- /dev/null
+++ b/src/core/hle/kernel/svc/svc_memory.cpp
@@ -0,0 +1,216 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/core.h"
+#include "core/hle/kernel/k_process.h"
+#include "core/hle/kernel/svc.h"
+
+namespace Kernel::Svc {
+namespace {
+
+constexpr bool IsValidSetMemoryPermission(MemoryPermission perm) {
+ switch (perm) {
+ case MemoryPermission::None:
+ case MemoryPermission::Read:
+ case MemoryPermission::ReadWrite:
+ return true;
+ default:
+ return false;
+ }
+}
+
+// Checks if address + size is greater than the given address
+// This can return false if the size causes an overflow of a 64-bit type
+// or if the given size is zero.
+constexpr bool IsValidAddressRange(u64 address, u64 size) {
+ return address + size > address;
+}
+
+// Helper function that performs the common sanity checks for svcMapMemory
+// and svcUnmapMemory. This is doable, as both functions perform their sanitizing
+// in the same order.
+Result MapUnmapMemorySanityChecks(const KPageTable& manager, u64 dst_addr, u64 src_addr, u64 size) {
+ if (!Common::Is4KBAligned(dst_addr)) {
+ LOG_ERROR(Kernel_SVC, "Destination address is not aligned to 4KB, 0x{:016X}", dst_addr);
+ R_THROW(ResultInvalidAddress);
+ }
+
+ if (!Common::Is4KBAligned(src_addr)) {
+ LOG_ERROR(Kernel_SVC, "Source address is not aligned to 4KB, 0x{:016X}", src_addr);
+ R_THROW(ResultInvalidSize);
+ }
+
+ if (size == 0) {
+ LOG_ERROR(Kernel_SVC, "Size is 0");
+ R_THROW(ResultInvalidSize);
+ }
+
+ if (!Common::Is4KBAligned(size)) {
+ LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, 0x{:016X}", size);
+ R_THROW(ResultInvalidSize);
+ }
+
+ if (!IsValidAddressRange(dst_addr, size)) {
+ LOG_ERROR(Kernel_SVC,
+ "Destination is not a valid address range, addr=0x{:016X}, size=0x{:016X}",
+ dst_addr, size);
+ R_THROW(ResultInvalidCurrentMemory);
+ }
+
+ if (!IsValidAddressRange(src_addr, size)) {
+ LOG_ERROR(Kernel_SVC, "Source is not a valid address range, addr=0x{:016X}, size=0x{:016X}",
+ src_addr, size);
+ R_THROW(ResultInvalidCurrentMemory);
+ }
+
+ if (!manager.IsInsideAddressSpace(src_addr, size)) {
+ LOG_ERROR(Kernel_SVC,
+ "Source is not within the address space, addr=0x{:016X}, size=0x{:016X}",
+ src_addr, size);
+ R_THROW(ResultInvalidCurrentMemory);
+ }
+
+ if (manager.IsOutsideStackRegion(dst_addr, size)) {
+ LOG_ERROR(Kernel_SVC,
+ "Destination is not within the stack region, addr=0x{:016X}, size=0x{:016X}",
+ dst_addr, size);
+ R_THROW(ResultInvalidMemoryRegion);
+ }
+
+ if (manager.IsInsideHeapRegion(dst_addr, size)) {
+ LOG_ERROR(Kernel_SVC,
+ "Destination does not fit within the heap region, addr=0x{:016X}, "
+ "size=0x{:016X}",
+ dst_addr, size);
+ R_THROW(ResultInvalidMemoryRegion);
+ }
+
+ if (manager.IsInsideAliasRegion(dst_addr, size)) {
+ LOG_ERROR(Kernel_SVC,
+ "Destination does not fit within the map region, addr=0x{:016X}, "
+ "size=0x{:016X}",
+ dst_addr, size);
+ R_THROW(ResultInvalidMemoryRegion);
+ }
+
+ R_SUCCEED();
+}
+
+} // namespace
+
+Result SetMemoryPermission(Core::System& system, u64 address, u64 size, MemoryPermission perm) {
+ LOG_DEBUG(Kernel_SVC, "called, address=0x{:016X}, size=0x{:X}, perm=0x{:08X", address, size,
+ perm);
+
+ // Validate 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);
+
+ // Validate the permission.
+ R_UNLESS(IsValidSetMemoryPermission(perm), ResultInvalidNewMemoryPermission);
+
+ // Validate that the region is in range for the current process.
+ auto& page_table = GetCurrentProcess(system.Kernel()).PageTable();
+ R_UNLESS(page_table.Contains(address, size), ResultInvalidCurrentMemory);
+
+ // Set the memory attribute.
+ R_RETURN(page_table.SetMemoryPermission(address, size, perm));
+}
+
+Result SetMemoryAttribute(Core::System& system, u64 address, u64 size, u32 mask, u32 attr) {
+ LOG_DEBUG(Kernel_SVC,
+ "called, address=0x{:016X}, size=0x{:X}, mask=0x{:08X}, attribute=0x{:08X}", address,
+ size, mask, attr);
+
+ // Validate 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);
+
+ // Validate the attribute and mask.
+ constexpr u32 SupportedMask = static_cast<u32>(MemoryAttribute::Uncached);
+ R_UNLESS((mask | attr) == mask, ResultInvalidCombination);
+ R_UNLESS((mask | attr | SupportedMask) == SupportedMask, ResultInvalidCombination);
+
+ // Validate that the region is in range for the current process.
+ auto& page_table{GetCurrentProcess(system.Kernel()).PageTable()};
+ R_UNLESS(page_table.Contains(address, size), ResultInvalidCurrentMemory);
+
+ // Set the memory attribute.
+ R_RETURN(page_table.SetMemoryAttribute(address, size, mask, attr));
+}
+
+/// Maps a memory range into a different range.
+Result MapMemory(Core::System& system, u64 dst_addr, u64 src_addr, u64 size) {
+ LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr,
+ src_addr, size);
+
+ auto& page_table{GetCurrentProcess(system.Kernel()).PageTable()};
+
+ if (const Result result{MapUnmapMemorySanityChecks(page_table, dst_addr, src_addr, size)};
+ result.IsError()) {
+ return result;
+ }
+
+ R_RETURN(page_table.MapMemory(dst_addr, src_addr, size));
+}
+
+/// Unmaps a region that was previously mapped with svcMapMemory
+Result UnmapMemory(Core::System& system, u64 dst_addr, u64 src_addr, u64 size) {
+ LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr,
+ src_addr, size);
+
+ auto& page_table{GetCurrentProcess(system.Kernel()).PageTable()};
+
+ if (const Result result{MapUnmapMemorySanityChecks(page_table, dst_addr, src_addr, size)};
+ result.IsError()) {
+ return result;
+ }
+
+ R_RETURN(page_table.UnmapMemory(dst_addr, src_addr, size));
+}
+
+Result SetMemoryPermission64(Core::System& system, uint64_t address, uint64_t size,
+ MemoryPermission perm) {
+ R_RETURN(SetMemoryPermission(system, address, size, perm));
+}
+
+Result SetMemoryAttribute64(Core::System& system, uint64_t address, uint64_t size, uint32_t mask,
+ uint32_t attr) {
+ R_RETURN(SetMemoryAttribute(system, address, size, mask, attr));
+}
+
+Result MapMemory64(Core::System& system, uint64_t dst_address, uint64_t src_address,
+ uint64_t size) {
+ R_RETURN(MapMemory(system, dst_address, src_address, size));
+}
+
+Result UnmapMemory64(Core::System& system, uint64_t dst_address, uint64_t src_address,
+ uint64_t size) {
+ R_RETURN(UnmapMemory(system, dst_address, src_address, size));
+}
+
+Result SetMemoryPermission64From32(Core::System& system, uint32_t address, uint32_t size,
+ MemoryPermission perm) {
+ R_RETURN(SetMemoryPermission(system, address, size, perm));
+}
+
+Result SetMemoryAttribute64From32(Core::System& system, uint32_t address, uint32_t size,
+ uint32_t mask, uint32_t attr) {
+ R_RETURN(SetMemoryAttribute(system, address, size, mask, attr));
+}
+
+Result MapMemory64From32(Core::System& system, uint32_t dst_address, uint32_t src_address,
+ uint32_t size) {
+ R_RETURN(MapMemory(system, dst_address, src_address, size));
+}
+
+Result UnmapMemory64From32(Core::System& system, uint32_t dst_address, uint32_t src_address,
+ uint32_t size) {
+ R_RETURN(UnmapMemory(system, dst_address, src_address, size));
+}
+
+} // namespace Kernel::Svc
diff --git a/src/core/hle/kernel/svc/svc_physical_memory.cpp b/src/core/hle/kernel/svc/svc_physical_memory.cpp
new file mode 100644
index 000000000..c2fbfb59a
--- /dev/null
+++ b/src/core/hle/kernel/svc/svc_physical_memory.cpp
@@ -0,0 +1,183 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/core.h"
+#include "core/hle/kernel/k_process.h"
+#include "core/hle/kernel/svc.h"
+
+namespace Kernel::Svc {
+
+/// Set the process heap to a given Size. It can both extend and shrink the heap.
+Result SetHeapSize(Core::System& system, u64* out_address, u64 size) {
+ LOG_TRACE(Kernel_SVC, "called, heap_size=0x{:X}", size);
+
+ // Validate size.
+ R_UNLESS(Common::IsAligned(size, HeapSizeAlignment), ResultInvalidSize);
+ R_UNLESS(size < MainMemorySizeMax, ResultInvalidSize);
+
+ // Set the heap size.
+ R_RETURN(GetCurrentProcess(system.Kernel()).PageTable().SetHeapSize(out_address, size));
+}
+
+/// Maps memory at a desired address
+Result MapPhysicalMemory(Core::System& system, u64 addr, u64 size) {
+ LOG_DEBUG(Kernel_SVC, "called, addr=0x{:016X}, size=0x{:X}", addr, size);
+
+ if (!Common::Is4KBAligned(addr)) {
+ LOG_ERROR(Kernel_SVC, "Address is not aligned to 4KB, 0x{:016X}", addr);
+ R_THROW(ResultInvalidAddress);
+ }
+
+ if (!Common::Is4KBAligned(size)) {
+ LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, 0x{:X}", size);
+ R_THROW(ResultInvalidSize);
+ }
+
+ if (size == 0) {
+ LOG_ERROR(Kernel_SVC, "Size is zero");
+ R_THROW(ResultInvalidSize);
+ }
+
+ if (!(addr < addr + size)) {
+ LOG_ERROR(Kernel_SVC, "Size causes 64-bit overflow of address");
+ R_THROW(ResultInvalidMemoryRegion);
+ }
+
+ KProcess* const current_process{GetCurrentProcessPointer(system.Kernel())};
+ auto& page_table{current_process->PageTable()};
+
+ if (current_process->GetSystemResourceSize() == 0) {
+ LOG_ERROR(Kernel_SVC, "System Resource Size is zero");
+ R_THROW(ResultInvalidState);
+ }
+
+ if (!page_table.IsInsideAddressSpace(addr, size)) {
+ LOG_ERROR(Kernel_SVC,
+ "Address is not within the address space, addr=0x{:016X}, size=0x{:016X}", addr,
+ size);
+ R_THROW(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);
+ R_THROW(ResultInvalidMemoryRegion);
+ }
+
+ R_RETURN(page_table.MapPhysicalMemory(addr, size));
+}
+
+/// Unmaps memory previously mapped via MapPhysicalMemory
+Result UnmapPhysicalMemory(Core::System& system, u64 addr, u64 size) {
+ LOG_DEBUG(Kernel_SVC, "called, addr=0x{:016X}, size=0x{:X}", addr, size);
+
+ if (!Common::Is4KBAligned(addr)) {
+ LOG_ERROR(Kernel_SVC, "Address is not aligned to 4KB, 0x{:016X}", addr);
+ R_THROW(ResultInvalidAddress);
+ }
+
+ if (!Common::Is4KBAligned(size)) {
+ LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, 0x{:X}", size);
+ R_THROW(ResultInvalidSize);
+ }
+
+ if (size == 0) {
+ LOG_ERROR(Kernel_SVC, "Size is zero");
+ R_THROW(ResultInvalidSize);
+ }
+
+ if (!(addr < addr + size)) {
+ LOG_ERROR(Kernel_SVC, "Size causes 64-bit overflow of address");
+ R_THROW(ResultInvalidMemoryRegion);
+ }
+
+ KProcess* const current_process{GetCurrentProcessPointer(system.Kernel())};
+ auto& page_table{current_process->PageTable()};
+
+ if (current_process->GetSystemResourceSize() == 0) {
+ LOG_ERROR(Kernel_SVC, "System Resource Size is zero");
+ R_THROW(ResultInvalidState);
+ }
+
+ if (!page_table.IsInsideAddressSpace(addr, size)) {
+ LOG_ERROR(Kernel_SVC,
+ "Address is not within the address space, addr=0x{:016X}, size=0x{:016X}", addr,
+ size);
+ R_THROW(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);
+ R_THROW(ResultInvalidMemoryRegion);
+ }
+
+ R_RETURN(page_table.UnmapPhysicalMemory(addr, size));
+}
+
+Result MapPhysicalMemoryUnsafe(Core::System& system, uint64_t address, uint64_t size) {
+ UNIMPLEMENTED();
+ R_THROW(ResultNotImplemented);
+}
+
+Result UnmapPhysicalMemoryUnsafe(Core::System& system, uint64_t address, uint64_t size) {
+ UNIMPLEMENTED();
+ R_THROW(ResultNotImplemented);
+}
+
+Result SetUnsafeLimit(Core::System& system, uint64_t limit) {
+ UNIMPLEMENTED();
+ R_THROW(ResultNotImplemented);
+}
+
+Result SetHeapSize64(Core::System& system, uint64_t* out_address, uint64_t size) {
+ R_RETURN(SetHeapSize(system, out_address, size));
+}
+
+Result MapPhysicalMemory64(Core::System& system, uint64_t address, uint64_t size) {
+ R_RETURN(MapPhysicalMemory(system, address, size));
+}
+
+Result UnmapPhysicalMemory64(Core::System& system, uint64_t address, uint64_t size) {
+ R_RETURN(UnmapPhysicalMemory(system, address, size));
+}
+
+Result MapPhysicalMemoryUnsafe64(Core::System& system, uint64_t address, uint64_t size) {
+ R_RETURN(MapPhysicalMemoryUnsafe(system, address, size));
+}
+
+Result UnmapPhysicalMemoryUnsafe64(Core::System& system, uint64_t address, uint64_t size) {
+ R_RETURN(UnmapPhysicalMemoryUnsafe(system, address, size));
+}
+
+Result SetUnsafeLimit64(Core::System& system, uint64_t limit) {
+ R_RETURN(SetUnsafeLimit(system, limit));
+}
+
+Result SetHeapSize64From32(Core::System& system, uint64_t* out_address, uint32_t size) {
+ R_RETURN(SetHeapSize(system, out_address, size));
+}
+
+Result MapPhysicalMemory64From32(Core::System& system, uint32_t address, uint32_t size) {
+ R_RETURN(MapPhysicalMemory(system, address, size));
+}
+
+Result UnmapPhysicalMemory64From32(Core::System& system, uint32_t address, uint32_t size) {
+ R_RETURN(UnmapPhysicalMemory(system, address, size));
+}
+
+Result MapPhysicalMemoryUnsafe64From32(Core::System& system, uint32_t address, uint32_t size) {
+ R_RETURN(MapPhysicalMemoryUnsafe(system, address, size));
+}
+
+Result UnmapPhysicalMemoryUnsafe64From32(Core::System& system, uint32_t address, uint32_t size) {
+ R_RETURN(UnmapPhysicalMemoryUnsafe(system, address, size));
+}
+
+Result SetUnsafeLimit64From32(Core::System& system, uint32_t limit) {
+ R_RETURN(SetUnsafeLimit(system, limit));
+}
+
+} // namespace Kernel::Svc
diff --git a/src/core/hle/kernel/svc/svc_port.cpp b/src/core/hle/kernel/svc/svc_port.cpp
new file mode 100644
index 000000000..abba757c7
--- /dev/null
+++ b/src/core/hle/kernel/svc/svc_port.cpp
@@ -0,0 +1,159 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "common/scope_exit.h"
+#include "core/core.h"
+#include "core/hle/kernel/k_client_port.h"
+#include "core/hle/kernel/k_client_session.h"
+#include "core/hle/kernel/k_object_name.h"
+#include "core/hle/kernel/k_port.h"
+#include "core/hle/kernel/k_process.h"
+#include "core/hle/kernel/svc.h"
+
+namespace Kernel::Svc {
+
+Result ConnectToNamedPort(Core::System& system, Handle* out, u64 user_name) {
+ // Copy the provided name from user memory to kernel memory.
+ auto string_name =
+ GetCurrentMemory(system.Kernel()).ReadCString(user_name, KObjectName::NameLengthMax);
+
+ std::array<char, KObjectName::NameLengthMax> name{};
+ std::strncpy(name.data(), string_name.c_str(), KObjectName::NameLengthMax - 1);
+
+ // Validate that the name is valid.
+ R_UNLESS(name[sizeof(name) - 1] == '\x00', ResultOutOfRange);
+
+ // Get the current handle table.
+ auto& handle_table = GetCurrentProcess(system.Kernel()).GetHandleTable();
+
+ // Find the client port.
+ auto port = KObjectName::Find<KClientPort>(system.Kernel(), name.data());
+ R_UNLESS(port.IsNotNull(), ResultNotFound);
+
+ // Reserve a handle for the port.
+ // NOTE: Nintendo really does write directly to the output handle here.
+ R_TRY(handle_table.Reserve(out));
+ ON_RESULT_FAILURE {
+ handle_table.Unreserve(*out);
+ };
+
+ // Create a session.
+ KClientSession* session;
+ R_TRY(port->CreateSession(std::addressof(session)));
+
+ // Register the session in the table, close the extra reference.
+ handle_table.Register(*out, session);
+ session->Close();
+
+ // We succeeded.
+ R_SUCCEED();
+}
+
+Result CreatePort(Core::System& system, Handle* out_server, Handle* out_client,
+ int32_t max_sessions, bool is_light, uint64_t name) {
+ UNIMPLEMENTED();
+ R_THROW(ResultNotImplemented);
+}
+
+Result ConnectToPort(Core::System& system, Handle* out_handle, Handle port) {
+ UNIMPLEMENTED();
+ R_THROW(ResultNotImplemented);
+}
+
+Result ManageNamedPort(Core::System& system, Handle* out_server_handle, uint64_t user_name,
+ int32_t max_sessions) {
+ // Copy the provided name from user memory to kernel memory.
+ auto string_name =
+ GetCurrentMemory(system.Kernel()).ReadCString(user_name, KObjectName::NameLengthMax);
+
+ // Copy the provided name from user memory to kernel memory.
+ std::array<char, KObjectName::NameLengthMax> name{};
+ std::strncpy(name.data(), string_name.c_str(), KObjectName::NameLengthMax - 1);
+
+ // Validate that sessions and name are valid.
+ R_UNLESS(max_sessions >= 0, ResultOutOfRange);
+ R_UNLESS(name[sizeof(name) - 1] == '\x00', ResultOutOfRange);
+
+ if (max_sessions > 0) {
+ // Get the current handle table.
+ auto& handle_table = GetCurrentProcess(system.Kernel()).GetHandleTable();
+
+ // Create a new port.
+ KPort* port = KPort::Create(system.Kernel());
+ R_UNLESS(port != nullptr, ResultOutOfResource);
+
+ // Initialize the new port.
+ port->Initialize(max_sessions, false, 0);
+
+ // Register the port.
+ KPort::Register(system.Kernel(), port);
+
+ // Ensure that our only reference to the port is in the handle table when we're done.
+ SCOPE_EXIT({
+ port->GetClientPort().Close();
+ port->GetServerPort().Close();
+ });
+
+ // Register the handle in the table.
+ R_TRY(handle_table.Add(out_server_handle, std::addressof(port->GetServerPort())));
+ ON_RESULT_FAILURE {
+ handle_table.Remove(*out_server_handle);
+ };
+
+ // Create a new object name.
+ R_TRY(KObjectName::NewFromName(system.Kernel(), std::addressof(port->GetClientPort()),
+ name.data()));
+ } else /* if (max_sessions == 0) */ {
+ // Ensure that this else case is correct.
+ ASSERT(max_sessions == 0);
+
+ // If we're closing, there's no server handle.
+ *out_server_handle = InvalidHandle;
+
+ // Delete the object.
+ R_TRY(KObjectName::Delete<KClientPort>(system.Kernel(), name.data()));
+ }
+
+ R_SUCCEED();
+}
+
+Result ConnectToNamedPort64(Core::System& system, Handle* out_handle, uint64_t name) {
+ R_RETURN(ConnectToNamedPort(system, out_handle, name));
+}
+
+Result CreatePort64(Core::System& system, Handle* out_server_handle, Handle* out_client_handle,
+ int32_t max_sessions, bool is_light, uint64_t name) {
+ R_RETURN(
+ CreatePort(system, out_server_handle, out_client_handle, max_sessions, is_light, name));
+}
+
+Result ManageNamedPort64(Core::System& system, Handle* out_server_handle, uint64_t name,
+ int32_t max_sessions) {
+ R_RETURN(ManageNamedPort(system, out_server_handle, name, max_sessions));
+}
+
+Result ConnectToPort64(Core::System& system, Handle* out_handle, Handle port) {
+ R_RETURN(ConnectToPort(system, out_handle, port));
+}
+
+Result ConnectToNamedPort64From32(Core::System& system, Handle* out_handle, uint32_t name) {
+ R_RETURN(ConnectToNamedPort(system, out_handle, name));
+}
+
+Result CreatePort64From32(Core::System& system, Handle* out_server_handle,
+ Handle* out_client_handle, int32_t max_sessions, bool is_light,
+ uint32_t name) {
+ R_RETURN(
+ CreatePort(system, out_server_handle, out_client_handle, max_sessions, is_light, name));
+}
+
+Result ManageNamedPort64From32(Core::System& system, Handle* out_server_handle, uint32_t name,
+ int32_t max_sessions) {
+ R_RETURN(ManageNamedPort(system, out_server_handle, name, max_sessions));
+}
+
+Result ConnectToPort64From32(Core::System& system, Handle* out_handle, Handle port) {
+ R_RETURN(ConnectToPort(system, out_handle, port));
+}
+
+} // namespace Kernel::Svc
diff --git a/src/core/hle/kernel/svc/svc_power_management.cpp b/src/core/hle/kernel/svc/svc_power_management.cpp
new file mode 100644
index 000000000..f605a0317
--- /dev/null
+++ b/src/core/hle/kernel/svc/svc_power_management.cpp
@@ -0,0 +1,21 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/kernel/svc.h"
+#include "core/hle/kernel/svc_results.h"
+
+namespace Kernel::Svc {
+
+void SleepSystem(Core::System& system) {
+ UNIMPLEMENTED();
+}
+
+void SleepSystem64(Core::System& system) {
+ return SleepSystem(system);
+}
+
+void SleepSystem64From32(Core::System& system) {
+ return SleepSystem(system);
+}
+
+} // namespace Kernel::Svc
diff --git a/src/core/hle/kernel/svc/svc_process.cpp b/src/core/hle/kernel/svc/svc_process.cpp
new file mode 100644
index 000000000..619ed16a3
--- /dev/null
+++ b/src/core/hle/kernel/svc/svc_process.cpp
@@ -0,0 +1,194 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/core.h"
+#include "core/hle/kernel/k_process.h"
+#include "core/hle/kernel/svc.h"
+
+namespace Kernel::Svc {
+
+/// Exits the current process
+void ExitProcess(Core::System& system) {
+ auto* current_process = GetCurrentProcessPointer(system.Kernel());
+
+ LOG_INFO(Kernel_SVC, "Process {} exiting", current_process->GetProcessId());
+ ASSERT_MSG(current_process->GetState() == KProcess::State::Running,
+ "Process has already exited");
+
+ system.Exit();
+}
+
+/// Gets the ID of the specified process or a specified thread's owning process.
+Result GetProcessId(Core::System& system, u64* out_process_id, Handle handle) {
+ LOG_DEBUG(Kernel_SVC, "called handle=0x{:08X}", handle);
+
+ // Get the object from the handle table.
+ KScopedAutoObject obj = GetCurrentProcess(system.Kernel())
+ .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");
+ }
+
+ // Make sure the target process exists.
+ R_UNLESS(process != nullptr, ResultInvalidHandle);
+
+ // Get the process id.
+ *out_process_id = process->GetId();
+
+ R_SUCCEED();
+}
+
+Result GetProcessList(Core::System& system, s32* out_num_processes, u64 out_process_ids,
+ int32_t out_process_ids_size) {
+ LOG_DEBUG(Kernel_SVC, "called. out_process_ids=0x{:016X}, out_process_ids_size={}",
+ out_process_ids, out_process_ids_size);
+
+ // If the supplied size is negative or greater than INT32_MAX / sizeof(u64), bail.
+ if ((out_process_ids_size & 0xF0000000) != 0) {
+ LOG_ERROR(Kernel_SVC,
+ "Supplied size outside [0, 0x0FFFFFFF] range. out_process_ids_size={}",
+ out_process_ids_size);
+ R_THROW(ResultOutOfRange);
+ }
+
+ auto& kernel = system.Kernel();
+ const auto total_copy_size = out_process_ids_size * sizeof(u64);
+
+ if (out_process_ids_size > 0 && !GetCurrentProcess(kernel).PageTable().IsInsideAddressSpace(
+ out_process_ids, total_copy_size)) {
+ LOG_ERROR(Kernel_SVC, "Address range outside address space. begin=0x{:016X}, end=0x{:016X}",
+ out_process_ids, out_process_ids + total_copy_size);
+ R_THROW(ResultInvalidCurrentMemory);
+ }
+
+ auto& memory = GetCurrentMemory(kernel);
+ const auto& process_list = kernel.GetProcessList();
+ const auto num_processes = process_list.size();
+ const auto copy_amount =
+ std::min(static_cast<std::size_t>(out_process_ids_size), num_processes);
+
+ for (std::size_t i = 0; i < copy_amount; ++i) {
+ memory.Write64(out_process_ids, process_list[i]->GetProcessId());
+ out_process_ids += sizeof(u64);
+ }
+
+ *out_num_processes = static_cast<u32>(num_processes);
+ R_SUCCEED();
+}
+
+Result GetProcessInfo(Core::System& system, s64* out, Handle process_handle,
+ ProcessInfoType info_type) {
+ LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, type=0x{:X}", process_handle, info_type);
+
+ const auto& handle_table = GetCurrentProcess(system.Kernel()).GetHandleTable();
+ 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);
+ R_THROW(ResultInvalidHandle);
+ }
+
+ if (info_type != ProcessInfoType::ProcessState) {
+ LOG_ERROR(Kernel_SVC, "Expected info_type to be ProcessState but got {} instead",
+ info_type);
+ R_THROW(ResultInvalidEnumValue);
+ }
+
+ *out = static_cast<s64>(process->GetState());
+ R_SUCCEED();
+}
+
+Result CreateProcess(Core::System& system, Handle* out_handle, uint64_t parameters, uint64_t caps,
+ int32_t num_caps) {
+ UNIMPLEMENTED();
+ R_THROW(ResultNotImplemented);
+}
+
+Result StartProcess(Core::System& system, Handle process_handle, int32_t priority, int32_t core_id,
+ uint64_t main_thread_stack_size) {
+ UNIMPLEMENTED();
+ R_THROW(ResultNotImplemented);
+}
+
+Result TerminateProcess(Core::System& system, Handle process_handle) {
+ UNIMPLEMENTED();
+ R_THROW(ResultNotImplemented);
+}
+
+void ExitProcess64(Core::System& system) {
+ ExitProcess(system);
+}
+
+Result GetProcessId64(Core::System& system, uint64_t* out_process_id, Handle process_handle) {
+ R_RETURN(GetProcessId(system, out_process_id, process_handle));
+}
+
+Result GetProcessList64(Core::System& system, int32_t* out_num_processes, uint64_t out_process_ids,
+ int32_t max_out_count) {
+ R_RETURN(GetProcessList(system, out_num_processes, out_process_ids, max_out_count));
+}
+
+Result CreateProcess64(Core::System& system, Handle* out_handle, uint64_t parameters, uint64_t caps,
+ int32_t num_caps) {
+ R_RETURN(CreateProcess(system, out_handle, parameters, caps, num_caps));
+}
+
+Result StartProcess64(Core::System& system, Handle process_handle, int32_t priority,
+ int32_t core_id, uint64_t main_thread_stack_size) {
+ R_RETURN(StartProcess(system, process_handle, priority, core_id, main_thread_stack_size));
+}
+
+Result TerminateProcess64(Core::System& system, Handle process_handle) {
+ R_RETURN(TerminateProcess(system, process_handle));
+}
+
+Result GetProcessInfo64(Core::System& system, int64_t* out_info, Handle process_handle,
+ ProcessInfoType info_type) {
+ R_RETURN(GetProcessInfo(system, out_info, process_handle, info_type));
+}
+
+void ExitProcess64From32(Core::System& system) {
+ ExitProcess(system);
+}
+
+Result GetProcessId64From32(Core::System& system, uint64_t* out_process_id, Handle process_handle) {
+ R_RETURN(GetProcessId(system, out_process_id, process_handle));
+}
+
+Result GetProcessList64From32(Core::System& system, int32_t* out_num_processes,
+ uint32_t out_process_ids, int32_t max_out_count) {
+ R_RETURN(GetProcessList(system, out_num_processes, out_process_ids, max_out_count));
+}
+
+Result CreateProcess64From32(Core::System& system, Handle* out_handle, uint32_t parameters,
+ uint32_t caps, int32_t num_caps) {
+ R_RETURN(CreateProcess(system, out_handle, parameters, caps, num_caps));
+}
+
+Result StartProcess64From32(Core::System& system, Handle process_handle, int32_t priority,
+ int32_t core_id, uint64_t main_thread_stack_size) {
+ R_RETURN(StartProcess(system, process_handle, priority, core_id, main_thread_stack_size));
+}
+
+Result TerminateProcess64From32(Core::System& system, Handle process_handle) {
+ R_RETURN(TerminateProcess(system, process_handle));
+}
+
+Result GetProcessInfo64From32(Core::System& system, int64_t* out_info, Handle process_handle,
+ ProcessInfoType info_type) {
+ R_RETURN(GetProcessInfo(system, out_info, process_handle, info_type));
+}
+
+} // namespace Kernel::Svc
diff --git a/src/core/hle/kernel/svc/svc_process_memory.cpp b/src/core/hle/kernel/svc/svc_process_memory.cpp
new file mode 100644
index 000000000..aee0f2f36
--- /dev/null
+++ b/src/core/hle/kernel/svc/svc_process_memory.cpp
@@ -0,0 +1,320 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/core.h"
+#include "core/hle/kernel/k_process.h"
+#include "core/hle/kernel/svc.h"
+
+namespace Kernel::Svc {
+namespace {
+
+constexpr bool IsValidAddressRange(u64 address, u64 size) {
+ return address + size > address;
+}
+
+constexpr bool IsValidProcessMemoryPermission(Svc::MemoryPermission perm) {
+ switch (perm) {
+ case Svc::MemoryPermission::None:
+ case Svc::MemoryPermission::Read:
+ case Svc::MemoryPermission::ReadWrite:
+ case Svc::MemoryPermission::ReadExecute:
+ return true;
+ default:
+ return false;
+ }
+}
+
+} // namespace
+
+Result SetProcessMemoryPermission(Core::System& system, Handle process_handle, u64 address,
+ u64 size, Svc::MemoryPermission perm) {
+ LOG_TRACE(Kernel_SVC,
+ "called, process_handle=0x{:X}, addr=0x{:X}, size=0x{:X}, permissions=0x{:08X}",
+ process_handle, address, size, perm);
+
+ // 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);
+ R_UNLESS(address == static_cast<uint64_t>(address), ResultInvalidCurrentMemory);
+ R_UNLESS(size == static_cast<uint64_t>(size), ResultInvalidCurrentMemory);
+
+ // Validate the memory permission.
+ R_UNLESS(IsValidProcessMemoryPermission(perm), ResultInvalidNewMemoryPermission);
+
+ // Get the process from its handle.
+ KScopedAutoObject process =
+ GetCurrentProcess(system.Kernel()).GetHandleTable().GetObject<KProcess>(process_handle);
+ R_UNLESS(process.IsNotNull(), ResultInvalidHandle);
+
+ // Validate that the address is in range.
+ auto& page_table = process->PageTable();
+ R_UNLESS(page_table.Contains(address, size), ResultInvalidCurrentMemory);
+
+ // Set the memory permission.
+ R_RETURN(page_table.SetProcessMemoryPermission(address, size, perm));
+}
+
+Result MapProcessMemory(Core::System& system, u64 dst_address, Handle process_handle,
+ u64 src_address, u64 size) {
+ LOG_TRACE(Kernel_SVC,
+ "called, dst_address=0x{:X}, process_handle=0x{:X}, src_address=0x{:X}, size=0x{:X}",
+ dst_address, process_handle, src_address, size);
+
+ // Validate the address/size.
+ R_UNLESS(Common::IsAligned(dst_address, PageSize), ResultInvalidAddress);
+ R_UNLESS(Common::IsAligned(src_address, PageSize), ResultInvalidAddress);
+ R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize);
+ R_UNLESS(size > 0, ResultInvalidSize);
+ R_UNLESS((dst_address < dst_address + size), ResultInvalidCurrentMemory);
+ R_UNLESS((src_address < src_address + size), ResultInvalidCurrentMemory);
+
+ // Get the processes.
+ KProcess* dst_process = GetCurrentProcessPointer(system.Kernel());
+ KScopedAutoObject src_process =
+ dst_process->GetHandleTable().GetObjectWithoutPseudoHandle<KProcess>(process_handle);
+ R_UNLESS(src_process.IsNotNull(), ResultInvalidHandle);
+
+ // Get the page tables.
+ auto& dst_pt = dst_process->PageTable();
+ auto& src_pt = src_process->PageTable();
+
+ // Validate that the mapping is in range.
+ R_UNLESS(src_pt.Contains(src_address, size), ResultInvalidCurrentMemory);
+ R_UNLESS(dst_pt.CanContain(dst_address, size, KMemoryState::SharedCode),
+ ResultInvalidMemoryRegion);
+
+ // Create a new page group.
+ KPageGroup pg{system.Kernel(), dst_pt.GetBlockInfoManager()};
+ R_TRY(src_pt.MakeAndOpenPageGroup(
+ std::addressof(pg), src_address, size / PageSize, KMemoryState::FlagCanMapProcess,
+ KMemoryState::FlagCanMapProcess, KMemoryPermission::None, KMemoryPermission::None,
+ KMemoryAttribute::All, KMemoryAttribute::None));
+
+ // Map the group.
+ R_RETURN(dst_pt.MapPageGroup(dst_address, pg, KMemoryState::SharedCode,
+ KMemoryPermission::UserReadWrite));
+}
+
+Result UnmapProcessMemory(Core::System& system, u64 dst_address, Handle process_handle,
+ u64 src_address, u64 size) {
+ LOG_TRACE(Kernel_SVC,
+ "called, dst_address=0x{:X}, process_handle=0x{:X}, src_address=0x{:X}, size=0x{:X}",
+ dst_address, process_handle, src_address, size);
+
+ // Validate the address/size.
+ R_UNLESS(Common::IsAligned(dst_address, PageSize), ResultInvalidAddress);
+ R_UNLESS(Common::IsAligned(src_address, PageSize), ResultInvalidAddress);
+ R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize);
+ R_UNLESS(size > 0, ResultInvalidSize);
+ R_UNLESS((dst_address < dst_address + size), ResultInvalidCurrentMemory);
+ R_UNLESS((src_address < src_address + size), ResultInvalidCurrentMemory);
+
+ // Get the processes.
+ KProcess* dst_process = GetCurrentProcessPointer(system.Kernel());
+ KScopedAutoObject src_process =
+ dst_process->GetHandleTable().GetObjectWithoutPseudoHandle<KProcess>(process_handle);
+ R_UNLESS(src_process.IsNotNull(), ResultInvalidHandle);
+
+ // Get the page tables.
+ auto& dst_pt = dst_process->PageTable();
+ auto& src_pt = src_process->PageTable();
+
+ // Validate that the mapping is in range.
+ R_UNLESS(src_pt.Contains(src_address, size), ResultInvalidCurrentMemory);
+ R_UNLESS(dst_pt.CanContain(dst_address, size, KMemoryState::SharedCode),
+ ResultInvalidMemoryRegion);
+
+ // Unmap the memory.
+ R_RETURN(dst_pt.UnmapProcessMemory(dst_address, size, src_pt, src_address));
+}
+
+Result MapProcessCodeMemory(Core::System& system, Handle process_handle, u64 dst_address,
+ u64 src_address, u64 size) {
+ LOG_DEBUG(Kernel_SVC,
+ "called. process_handle=0x{:08X}, dst_address=0x{:016X}, "
+ "src_address=0x{:016X}, size=0x{:016X}",
+ process_handle, dst_address, src_address, size);
+
+ if (!Common::Is4KBAligned(src_address)) {
+ LOG_ERROR(Kernel_SVC, "src_address is not page-aligned (src_address=0x{:016X}).",
+ src_address);
+ R_THROW(ResultInvalidAddress);
+ }
+
+ if (!Common::Is4KBAligned(dst_address)) {
+ LOG_ERROR(Kernel_SVC, "dst_address is not page-aligned (dst_address=0x{:016X}).",
+ dst_address);
+ R_THROW(ResultInvalidAddress);
+ }
+
+ if (size == 0 || !Common::Is4KBAligned(size)) {
+ LOG_ERROR(Kernel_SVC, "Size is zero or not page-aligned (size=0x{:016X})", size);
+ R_THROW(ResultInvalidSize);
+ }
+
+ if (!IsValidAddressRange(dst_address, size)) {
+ LOG_ERROR(Kernel_SVC,
+ "Destination address range overflows the address space (dst_address=0x{:016X}, "
+ "size=0x{:016X}).",
+ dst_address, size);
+ R_THROW(ResultInvalidCurrentMemory);
+ }
+
+ if (!IsValidAddressRange(src_address, size)) {
+ LOG_ERROR(Kernel_SVC,
+ "Source address range overflows the address space (src_address=0x{:016X}, "
+ "size=0x{:016X}).",
+ src_address, size);
+ R_THROW(ResultInvalidCurrentMemory);
+ }
+
+ const auto& handle_table = GetCurrentProcess(system.Kernel()).GetHandleTable();
+ KScopedAutoObject process = handle_table.GetObject<KProcess>(process_handle);
+ if (process.IsNull()) {
+ LOG_ERROR(Kernel_SVC, "Invalid process handle specified (handle=0x{:08X}).",
+ process_handle);
+ R_THROW(ResultInvalidHandle);
+ }
+
+ auto& page_table = process->PageTable();
+ if (!page_table.IsInsideAddressSpace(src_address, size)) {
+ LOG_ERROR(Kernel_SVC,
+ "Source address range is not within the address space (src_address=0x{:016X}, "
+ "size=0x{:016X}).",
+ src_address, size);
+ R_THROW(ResultInvalidCurrentMemory);
+ }
+
+ if (!page_table.IsInsideASLRRegion(dst_address, size)) {
+ LOG_ERROR(Kernel_SVC,
+ "Destination address range is not within the ASLR region (dst_address=0x{:016X}, "
+ "size=0x{:016X}).",
+ dst_address, size);
+ R_THROW(ResultInvalidMemoryRegion);
+ }
+
+ R_RETURN(page_table.MapCodeMemory(dst_address, src_address, size));
+}
+
+Result UnmapProcessCodeMemory(Core::System& system, Handle process_handle, u64 dst_address,
+ u64 src_address, u64 size) {
+ LOG_DEBUG(Kernel_SVC,
+ "called. process_handle=0x{:08X}, dst_address=0x{:016X}, src_address=0x{:016X}, "
+ "size=0x{:016X}",
+ process_handle, dst_address, src_address, size);
+
+ if (!Common::Is4KBAligned(dst_address)) {
+ LOG_ERROR(Kernel_SVC, "dst_address is not page-aligned (dst_address=0x{:016X}).",
+ dst_address);
+ R_THROW(ResultInvalidAddress);
+ }
+
+ if (!Common::Is4KBAligned(src_address)) {
+ LOG_ERROR(Kernel_SVC, "src_address is not page-aligned (src_address=0x{:016X}).",
+ src_address);
+ R_THROW(ResultInvalidAddress);
+ }
+
+ if (size == 0 || !Common::Is4KBAligned(size)) {
+ LOG_ERROR(Kernel_SVC, "Size is zero or not page-aligned (size=0x{:016X}).", size);
+ R_THROW(ResultInvalidSize);
+ }
+
+ if (!IsValidAddressRange(dst_address, size)) {
+ LOG_ERROR(Kernel_SVC,
+ "Destination address range overflows the address space (dst_address=0x{:016X}, "
+ "size=0x{:016X}).",
+ dst_address, size);
+ R_THROW(ResultInvalidCurrentMemory);
+ }
+
+ if (!IsValidAddressRange(src_address, size)) {
+ LOG_ERROR(Kernel_SVC,
+ "Source address range overflows the address space (src_address=0x{:016X}, "
+ "size=0x{:016X}).",
+ src_address, size);
+ R_THROW(ResultInvalidCurrentMemory);
+ }
+
+ const auto& handle_table = GetCurrentProcess(system.Kernel()).GetHandleTable();
+ KScopedAutoObject process = handle_table.GetObject<KProcess>(process_handle);
+ if (process.IsNull()) {
+ LOG_ERROR(Kernel_SVC, "Invalid process handle specified (handle=0x{:08X}).",
+ process_handle);
+ R_THROW(ResultInvalidHandle);
+ }
+
+ auto& page_table = process->PageTable();
+ if (!page_table.IsInsideAddressSpace(src_address, size)) {
+ LOG_ERROR(Kernel_SVC,
+ "Source address range is not within the address space (src_address=0x{:016X}, "
+ "size=0x{:016X}).",
+ src_address, size);
+ R_THROW(ResultInvalidCurrentMemory);
+ }
+
+ if (!page_table.IsInsideASLRRegion(dst_address, size)) {
+ LOG_ERROR(Kernel_SVC,
+ "Destination address range is not within the ASLR region (dst_address=0x{:016X}, "
+ "size=0x{:016X}).",
+ dst_address, size);
+ R_THROW(ResultInvalidMemoryRegion);
+ }
+
+ R_RETURN(page_table.UnmapCodeMemory(dst_address, src_address, size,
+ KPageTable::ICacheInvalidationStrategy::InvalidateAll));
+}
+
+Result SetProcessMemoryPermission64(Core::System& system, Handle process_handle, uint64_t address,
+ uint64_t size, MemoryPermission perm) {
+ R_RETURN(SetProcessMemoryPermission(system, process_handle, address, size, perm));
+}
+
+Result MapProcessMemory64(Core::System& system, uint64_t dst_address, Handle process_handle,
+ uint64_t src_address, uint64_t size) {
+ R_RETURN(MapProcessMemory(system, dst_address, process_handle, src_address, size));
+}
+
+Result UnmapProcessMemory64(Core::System& system, uint64_t dst_address, Handle process_handle,
+ uint64_t src_address, uint64_t size) {
+ R_RETURN(UnmapProcessMemory(system, dst_address, process_handle, src_address, size));
+}
+
+Result MapProcessCodeMemory64(Core::System& system, Handle process_handle, uint64_t dst_address,
+ uint64_t src_address, uint64_t size) {
+ R_RETURN(MapProcessCodeMemory(system, process_handle, dst_address, src_address, size));
+}
+
+Result UnmapProcessCodeMemory64(Core::System& system, Handle process_handle, uint64_t dst_address,
+ uint64_t src_address, uint64_t size) {
+ R_RETURN(UnmapProcessCodeMemory(system, process_handle, dst_address, src_address, size));
+}
+
+Result SetProcessMemoryPermission64From32(Core::System& system, Handle process_handle,
+ uint64_t address, uint64_t size, MemoryPermission perm) {
+ R_RETURN(SetProcessMemoryPermission(system, process_handle, address, size, perm));
+}
+
+Result MapProcessMemory64From32(Core::System& system, uint32_t dst_address, Handle process_handle,
+ uint64_t src_address, uint32_t size) {
+ R_RETURN(MapProcessMemory(system, dst_address, process_handle, src_address, size));
+}
+
+Result UnmapProcessMemory64From32(Core::System& system, uint32_t dst_address, Handle process_handle,
+ uint64_t src_address, uint32_t size) {
+ R_RETURN(UnmapProcessMemory(system, dst_address, process_handle, src_address, size));
+}
+
+Result MapProcessCodeMemory64From32(Core::System& system, Handle process_handle,
+ uint64_t dst_address, uint64_t src_address, uint64_t size) {
+ R_RETURN(MapProcessCodeMemory(system, process_handle, dst_address, src_address, size));
+}
+
+Result UnmapProcessCodeMemory64From32(Core::System& system, Handle process_handle,
+ uint64_t dst_address, uint64_t src_address, uint64_t size) {
+ R_RETURN(UnmapProcessCodeMemory(system, process_handle, dst_address, src_address, size));
+}
+
+} // namespace Kernel::Svc
diff --git a/src/core/hle/kernel/svc/svc_processor.cpp b/src/core/hle/kernel/svc/svc_processor.cpp
new file mode 100644
index 000000000..7602ce6c0
--- /dev/null
+++ b/src/core/hle/kernel/svc/svc_processor.cpp
@@ -0,0 +1,25 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "common/logging/log.h"
+#include "core/core.h"
+#include "core/hle/kernel/physical_core.h"
+#include "core/hle/kernel/svc.h"
+
+namespace Kernel::Svc {
+
+/// Get which CPU core is executing the current thread
+int32_t GetCurrentProcessorNumber(Core::System& system) {
+ LOG_TRACE(Kernel_SVC, "called");
+ return static_cast<int32_t>(system.CurrentPhysicalCore().CoreIndex());
+}
+
+int32_t GetCurrentProcessorNumber64(Core::System& system) {
+ return GetCurrentProcessorNumber(system);
+}
+
+int32_t GetCurrentProcessorNumber64From32(Core::System& system) {
+ return GetCurrentProcessorNumber(system);
+}
+
+} // namespace Kernel::Svc
diff --git a/src/core/hle/kernel/svc/svc_query_memory.cpp b/src/core/hle/kernel/svc/svc_query_memory.cpp
new file mode 100644
index 000000000..4d9fcd25f
--- /dev/null
+++ b/src/core/hle/kernel/svc/svc_query_memory.cpp
@@ -0,0 +1,65 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/core.h"
+#include "core/hle/kernel/k_process.h"
+#include "core/hle/kernel/svc.h"
+
+namespace Kernel::Svc {
+
+Result QueryMemory(Core::System& system, uint64_t out_memory_info, PageInfo* out_page_info,
+ u64 query_address) {
+ LOG_TRACE(Kernel_SVC,
+ "called, out_memory_info=0x{:016X}, "
+ "query_address=0x{:016X}",
+ out_memory_info, query_address);
+
+ // Query memory is just QueryProcessMemory on the current process.
+ R_RETURN(
+ QueryProcessMemory(system, out_memory_info, out_page_info, CurrentProcess, query_address));
+}
+
+Result QueryProcessMemory(Core::System& system, uint64_t out_memory_info, PageInfo* out_page_info,
+ Handle process_handle, uint64_t address) {
+ LOG_TRACE(Kernel_SVC, "called process=0x{:08X} address={:X}", process_handle, address);
+ const auto& handle_table = GetCurrentProcess(system.Kernel()).GetHandleTable();
+ 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);
+ R_THROW(ResultInvalidHandle);
+ }
+
+ auto& current_memory{GetCurrentMemory(system.Kernel())};
+ const auto memory_info{process->PageTable().QueryInfo(address).GetSvcMemoryInfo()};
+
+ current_memory.WriteBlock(out_memory_info, std::addressof(memory_info), sizeof(memory_info));
+
+ //! This is supposed to be part of the QueryInfo call.
+ *out_page_info = {};
+
+ R_SUCCEED();
+}
+
+Result QueryMemory64(Core::System& system, uint64_t out_memory_info, PageInfo* out_page_info,
+ uint64_t address) {
+ R_RETURN(QueryMemory(system, out_memory_info, out_page_info, address));
+}
+
+Result QueryProcessMemory64(Core::System& system, uint64_t out_memory_info, PageInfo* out_page_info,
+ Handle process_handle, uint64_t address) {
+ R_RETURN(QueryProcessMemory(system, out_memory_info, out_page_info, process_handle, address));
+}
+
+Result QueryMemory64From32(Core::System& system, uint32_t out_memory_info, PageInfo* out_page_info,
+ uint32_t address) {
+ R_RETURN(QueryMemory(system, out_memory_info, out_page_info, address));
+}
+
+Result QueryProcessMemory64From32(Core::System& system, uint32_t out_memory_info,
+ PageInfo* out_page_info, Handle process_handle,
+ uint64_t address) {
+ R_RETURN(QueryProcessMemory(system, out_memory_info, out_page_info, process_handle, address));
+}
+
+} // namespace Kernel::Svc
diff --git a/src/core/hle/kernel/svc/svc_register.cpp b/src/core/hle/kernel/svc/svc_register.cpp
new file mode 100644
index 000000000..b883e6618
--- /dev/null
+++ b/src/core/hle/kernel/svc/svc_register.cpp
@@ -0,0 +1,27 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/kernel/svc.h"
+#include "core/hle/kernel/svc_results.h"
+
+namespace Kernel::Svc {
+
+Result ReadWriteRegister(Core::System& system, uint32_t* out, uint64_t address, uint32_t mask,
+ uint32_t value) {
+ *out = 0;
+
+ UNIMPLEMENTED();
+ R_THROW(ResultNotImplemented);
+}
+
+Result ReadWriteRegister64(Core::System& system, uint32_t* out_value, uint64_t address,
+ uint32_t mask, uint32_t value) {
+ R_RETURN(ReadWriteRegister(system, out_value, address, mask, value));
+}
+
+Result ReadWriteRegister64From32(Core::System& system, uint32_t* out_value, uint64_t address,
+ uint32_t mask, uint32_t value) {
+ R_RETURN(ReadWriteRegister(system, out_value, address, mask, value));
+}
+
+} // namespace Kernel::Svc
diff --git a/src/core/hle/kernel/svc/svc_resource_limit.cpp b/src/core/hle/kernel/svc/svc_resource_limit.cpp
new file mode 100644
index 000000000..732bc017e
--- /dev/null
+++ b/src/core/hle/kernel/svc/svc_resource_limit.cpp
@@ -0,0 +1,145 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "common/scope_exit.h"
+#include "core/core.h"
+#include "core/hle/kernel/k_process.h"
+#include "core/hle/kernel/k_resource_limit.h"
+#include "core/hle/kernel/svc.h"
+
+namespace Kernel::Svc {
+
+Result CreateResourceLimit(Core::System& system, Handle* out_handle) {
+ LOG_DEBUG(Kernel_SVC, "called");
+
+ // Create a new resource limit.
+ auto& kernel = system.Kernel();
+ KResourceLimit* resource_limit = KResourceLimit::Create(kernel);
+ R_UNLESS(resource_limit != nullptr, ResultOutOfResource);
+
+ // Ensure we don't leak a reference to the limit.
+ SCOPE_EXIT({ resource_limit->Close(); });
+
+ // Initialize the resource limit.
+ resource_limit->Initialize(std::addressof(system.CoreTiming()));
+
+ // Register the limit.
+ KResourceLimit::Register(kernel, resource_limit);
+
+ // Add the limit to the handle table.
+ R_RETURN(GetCurrentProcess(kernel).GetHandleTable().Add(out_handle, resource_limit));
+}
+
+Result GetResourceLimitLimitValue(Core::System& system, s64* out_limit_value,
+ Handle resource_limit_handle, LimitableResource which) {
+ LOG_DEBUG(Kernel_SVC, "called, resource_limit_handle={:08X}, which={}", resource_limit_handle,
+ which);
+
+ // Validate the resource.
+ R_UNLESS(IsValidResourceType(which), ResultInvalidEnumValue);
+
+ // Get the resource limit.
+ KScopedAutoObject resource_limit = GetCurrentProcess(system.Kernel())
+ .GetHandleTable()
+ .GetObject<KResourceLimit>(resource_limit_handle);
+ R_UNLESS(resource_limit.IsNotNull(), ResultInvalidHandle);
+
+ // Get the limit value.
+ *out_limit_value = resource_limit->GetLimitValue(which);
+
+ R_SUCCEED();
+}
+
+Result GetResourceLimitCurrentValue(Core::System& system, s64* out_current_value,
+ Handle resource_limit_handle, LimitableResource which) {
+ LOG_DEBUG(Kernel_SVC, "called, resource_limit_handle={:08X}, which={}", resource_limit_handle,
+ which);
+
+ // Validate the resource.
+ R_UNLESS(IsValidResourceType(which), ResultInvalidEnumValue);
+
+ // Get the resource limit.
+ KScopedAutoObject resource_limit = GetCurrentProcess(system.Kernel())
+ .GetHandleTable()
+ .GetObject<KResourceLimit>(resource_limit_handle);
+ R_UNLESS(resource_limit.IsNotNull(), ResultInvalidHandle);
+
+ // Get the current value.
+ *out_current_value = resource_limit->GetCurrentValue(which);
+
+ R_SUCCEED();
+}
+
+Result SetResourceLimitLimitValue(Core::System& system, Handle resource_limit_handle,
+ LimitableResource which, s64 limit_value) {
+ LOG_DEBUG(Kernel_SVC, "called, resource_limit_handle={:08X}, which={}, limit_value={}",
+ resource_limit_handle, which, limit_value);
+
+ // Validate the resource.
+ R_UNLESS(IsValidResourceType(which), ResultInvalidEnumValue);
+
+ // Get the resource limit.
+ KScopedAutoObject resource_limit = GetCurrentProcess(system.Kernel())
+ .GetHandleTable()
+ .GetObject<KResourceLimit>(resource_limit_handle);
+ R_UNLESS(resource_limit.IsNotNull(), ResultInvalidHandle);
+
+ // Set the limit value.
+ R_RETURN(resource_limit->SetLimitValue(which, limit_value));
+}
+
+Result GetResourceLimitPeakValue(Core::System& system, int64_t* out_peak_value,
+ Handle resource_limit_handle, LimitableResource which) {
+ UNIMPLEMENTED();
+ R_THROW(ResultNotImplemented);
+}
+
+Result GetResourceLimitLimitValue64(Core::System& system, int64_t* out_limit_value,
+ Handle resource_limit_handle, LimitableResource which) {
+ R_RETURN(GetResourceLimitLimitValue(system, out_limit_value, resource_limit_handle, which));
+}
+
+Result GetResourceLimitCurrentValue64(Core::System& system, int64_t* out_current_value,
+ Handle resource_limit_handle, LimitableResource which) {
+ R_RETURN(GetResourceLimitCurrentValue(system, out_current_value, resource_limit_handle, which));
+}
+
+Result GetResourceLimitPeakValue64(Core::System& system, int64_t* out_peak_value,
+ Handle resource_limit_handle, LimitableResource which) {
+ R_RETURN(GetResourceLimitPeakValue(system, out_peak_value, resource_limit_handle, which));
+}
+
+Result CreateResourceLimit64(Core::System& system, Handle* out_handle) {
+ R_RETURN(CreateResourceLimit(system, out_handle));
+}
+
+Result SetResourceLimitLimitValue64(Core::System& system, Handle resource_limit_handle,
+ LimitableResource which, int64_t limit_value) {
+ R_RETURN(SetResourceLimitLimitValue(system, resource_limit_handle, which, limit_value));
+}
+
+Result GetResourceLimitLimitValue64From32(Core::System& system, int64_t* out_limit_value,
+ Handle resource_limit_handle, LimitableResource which) {
+ R_RETURN(GetResourceLimitLimitValue(system, out_limit_value, resource_limit_handle, which));
+}
+
+Result GetResourceLimitCurrentValue64From32(Core::System& system, int64_t* out_current_value,
+ Handle resource_limit_handle, LimitableResource which) {
+ R_RETURN(GetResourceLimitCurrentValue(system, out_current_value, resource_limit_handle, which));
+}
+
+Result GetResourceLimitPeakValue64From32(Core::System& system, int64_t* out_peak_value,
+ Handle resource_limit_handle, LimitableResource which) {
+ R_RETURN(GetResourceLimitPeakValue(system, out_peak_value, resource_limit_handle, which));
+}
+
+Result CreateResourceLimit64From32(Core::System& system, Handle* out_handle) {
+ R_RETURN(CreateResourceLimit(system, out_handle));
+}
+
+Result SetResourceLimitLimitValue64From32(Core::System& system, Handle resource_limit_handle,
+ LimitableResource which, int64_t limit_value) {
+ R_RETURN(SetResourceLimitLimitValue(system, resource_limit_handle, which, limit_value));
+}
+
+} // namespace Kernel::Svc
diff --git a/src/core/hle/kernel/svc/svc_secure_monitor_call.cpp b/src/core/hle/kernel/svc/svc_secure_monitor_call.cpp
new file mode 100644
index 000000000..62c781551
--- /dev/null
+++ b/src/core/hle/kernel/svc/svc_secure_monitor_call.cpp
@@ -0,0 +1,53 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/core.h"
+#include "core/hle/kernel/physical_core.h"
+#include "core/hle/kernel/svc.h"
+
+namespace Kernel::Svc {
+
+void CallSecureMonitor(Core::System& system, lp64::SecureMonitorArguments* args) {
+ UNIMPLEMENTED();
+}
+
+void CallSecureMonitor64(Core::System& system, lp64::SecureMonitorArguments* args) {
+ CallSecureMonitor(system, args);
+}
+
+void CallSecureMonitor64From32(Core::System& system, ilp32::SecureMonitorArguments* args) {
+ // CallSecureMonitor64From32 is not supported.
+ UNIMPLEMENTED_MSG("CallSecureMonitor64From32");
+}
+
+// Custom ABI for CallSecureMonitor.
+
+void SvcWrap_CallSecureMonitor64(Core::System& system) {
+ auto& core = system.CurrentPhysicalCore().ArmInterface();
+ lp64::SecureMonitorArguments args{};
+ for (int i = 0; i < 8; i++) {
+ args.r[i] = core.GetReg(i);
+ }
+
+ CallSecureMonitor64(system, std::addressof(args));
+
+ for (int i = 0; i < 8; i++) {
+ core.SetReg(i, args.r[i]);
+ }
+}
+
+void SvcWrap_CallSecureMonitor64From32(Core::System& system) {
+ auto& core = system.CurrentPhysicalCore().ArmInterface();
+ ilp32::SecureMonitorArguments args{};
+ for (int i = 0; i < 8; i++) {
+ args.r[i] = static_cast<u32>(core.GetReg(i));
+ }
+
+ CallSecureMonitor64From32(system, std::addressof(args));
+
+ for (int i = 0; i < 8; i++) {
+ core.SetReg(i, args.r[i]);
+ }
+}
+
+} // namespace Kernel::Svc
diff --git a/src/core/hle/kernel/svc/svc_session.cpp b/src/core/hle/kernel/svc/svc_session.cpp
new file mode 100644
index 000000000..01b8a52ad
--- /dev/null
+++ b/src/core/hle/kernel/svc/svc_session.cpp
@@ -0,0 +1,127 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "common/scope_exit.h"
+#include "core/core.h"
+#include "core/hle/kernel/k_process.h"
+#include "core/hle/kernel/k_scoped_resource_reservation.h"
+#include "core/hle/kernel/k_session.h"
+#include "core/hle/kernel/svc.h"
+
+namespace Kernel::Svc {
+namespace {
+
+template <typename T>
+Result CreateSession(Core::System& system, Handle* out_server, Handle* out_client, uint64_t name) {
+ auto& process = GetCurrentProcess(system.Kernel());
+ auto& handle_table = process.GetHandleTable();
+
+ // Declare the session we're going to allocate.
+ T* session;
+
+ // Reserve a new session from the process resource limit.
+ // FIXME: LimitableResource_SessionCountMax
+ KScopedResourceReservation session_reservation(std::addressof(process),
+ LimitableResource::SessionCountMax);
+ if (session_reservation.Succeeded()) {
+ session = T::Create(system.Kernel());
+ } else {
+ R_THROW(ResultLimitReached);
+
+ // // We couldn't reserve a session. Check that we support dynamically expanding the
+ // // resource limit.
+ // R_UNLESS(process.GetResourceLimit() ==
+ // std::addressof(system.Kernel().GetSystemResourceLimit()), ResultLimitReached);
+ // R_UNLESS(KTargetSystem::IsDynamicResourceLimitsEnabled(), ResultLimitReached());
+
+ // // Try to allocate a session from unused slab memory.
+ // session = T::CreateFromUnusedSlabMemory();
+ // R_UNLESS(session != nullptr, ResultLimitReached);
+ // ON_RESULT_FAILURE { session->Close(); };
+
+ // // If we're creating a KSession, we want to add two KSessionRequests to the heap, to
+ // // prevent request exhaustion.
+ // // NOTE: Nintendo checks if session->DynamicCast<KSession *>() != nullptr, but there's
+ // // no reason to not do this statically.
+ // if constexpr (std::same_as<T, KSession>) {
+ // for (size_t i = 0; i < 2; i++) {
+ // KSessionRequest* request = KSessionRequest::CreateFromUnusedSlabMemory();
+ // R_UNLESS(request != nullptr, ResultLimitReached);
+ // request->Close();
+ // }
+ // }
+
+ // We successfully allocated a session, so add the object we allocated to the resource
+ // limit.
+ // system.Kernel().GetSystemResourceLimit().Reserve(LimitableResource::SessionCountMax, 1);
+ }
+
+ // Check that we successfully created a session.
+ R_UNLESS(session != nullptr, ResultOutOfResource);
+
+ // Initialize the session.
+ session->Initialize(nullptr, name);
+
+ // Commit the session reservation.
+ session_reservation.Commit();
+
+ // Ensure that we clean up the session (and its only references are handle table) on function
+ // end.
+ SCOPE_EXIT({
+ session->GetClientSession().Close();
+ session->GetServerSession().Close();
+ });
+
+ // Register the session.
+ T::Register(system.Kernel(), session);
+
+ // Add the server session to the handle table.
+ R_TRY(handle_table.Add(out_server, std::addressof(session->GetServerSession())));
+
+ // Ensure that we maintain a clean handle state on exit.
+ ON_RESULT_FAILURE {
+ handle_table.Remove(*out_server);
+ };
+
+ // Add the client session to the handle table.
+ R_RETURN(handle_table.Add(out_client, std::addressof(session->GetClientSession())));
+}
+
+} // namespace
+
+Result CreateSession(Core::System& system, Handle* out_server, Handle* out_client, bool is_light,
+ u64 name) {
+ if (is_light) {
+ // return CreateSession<KLightSession>(system, out_server, out_client, name);
+ R_THROW(ResultNotImplemented);
+ } else {
+ R_RETURN(CreateSession<KSession>(system, out_server, out_client, name));
+ }
+}
+
+Result AcceptSession(Core::System& system, Handle* out_handle, Handle port_handle) {
+ UNIMPLEMENTED();
+ R_THROW(ResultNotImplemented);
+}
+
+Result CreateSession64(Core::System& system, Handle* out_server_session_handle,
+ Handle* out_client_session_handle, bool is_light, uint64_t name) {
+ R_RETURN(CreateSession(system, out_server_session_handle, out_client_session_handle, is_light,
+ name));
+}
+
+Result AcceptSession64(Core::System& system, Handle* out_handle, Handle port) {
+ R_RETURN(AcceptSession(system, out_handle, port));
+}
+
+Result CreateSession64From32(Core::System& system, Handle* out_server_session_handle,
+ Handle* out_client_session_handle, bool is_light, uint32_t name) {
+ R_RETURN(CreateSession(system, out_server_session_handle, out_client_session_handle, is_light,
+ name));
+}
+
+Result AcceptSession64From32(Core::System& system, Handle* out_handle, Handle port) {
+ R_RETURN(AcceptSession(system, out_handle, port));
+}
+
+} // namespace Kernel::Svc
diff --git a/src/core/hle/kernel/svc/svc_shared_memory.cpp b/src/core/hle/kernel/svc/svc_shared_memory.cpp
new file mode 100644
index 000000000..a698596aa
--- /dev/null
+++ b/src/core/hle/kernel/svc/svc_shared_memory.cpp
@@ -0,0 +1,130 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "common/scope_exit.h"
+#include "core/core.h"
+#include "core/hle/kernel/k_process.h"
+#include "core/hle/kernel/k_shared_memory.h"
+#include "core/hle/kernel/svc.h"
+
+namespace Kernel::Svc {
+namespace {
+
+constexpr bool IsValidSharedMemoryPermission(MemoryPermission perm) {
+ switch (perm) {
+ case MemoryPermission::Read:
+ case MemoryPermission::ReadWrite:
+ return true;
+ default:
+ return false;
+ }
+}
+
+[[maybe_unused]] constexpr bool IsValidRemoteSharedMemoryPermission(MemoryPermission perm) {
+ return IsValidSharedMemoryPermission(perm) || perm == MemoryPermission::DontCare;
+}
+
+} // namespace
+
+Result MapSharedMemory(Core::System& system, Handle shmem_handle, u64 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}",
+ shmem_handle, address, size, map_perm);
+
+ // 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);
+
+ // Validate the permission.
+ R_UNLESS(IsValidSharedMemoryPermission(map_perm), ResultInvalidNewMemoryPermission);
+
+ // Get the current process.
+ auto& process = GetCurrentProcess(system.Kernel());
+ auto& page_table = process.PageTable();
+
+ // Get the shared memory.
+ KScopedAutoObject shmem = process.GetHandleTable().GetObject<KSharedMemory>(shmem_handle);
+ R_UNLESS(shmem.IsNotNull(), ResultInvalidHandle);
+
+ // Verify that the mapping is in range.
+ R_UNLESS(page_table.CanContain(address, size, KMemoryState::Shared), ResultInvalidMemoryRegion);
+
+ // Add the shared memory to the process.
+ R_TRY(process.AddSharedMemory(shmem.GetPointerUnsafe(), address, size));
+
+ // Ensure that we clean up the shared memory if we fail to map it.
+ ON_RESULT_FAILURE {
+ process.RemoveSharedMemory(shmem.GetPointerUnsafe(), address, size);
+ };
+
+ // Map the shared memory.
+ R_RETURN(shmem->Map(process, address, size, map_perm));
+}
+
+Result UnmapSharedMemory(Core::System& system, Handle shmem_handle, u64 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 = GetCurrentProcess(system.Kernel());
+ auto& page_table = process.PageTable();
+
+ // Get the shared memory.
+ KScopedAutoObject shmem = process.GetHandleTable().GetObject<KSharedMemory>(shmem_handle);
+ R_UNLESS(shmem.IsNotNull(), ResultInvalidHandle);
+
+ // 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);
+
+ R_SUCCEED();
+}
+
+Result CreateSharedMemory(Core::System& system, Handle* out_handle, uint64_t size,
+ MemoryPermission owner_perm, MemoryPermission remote_perm) {
+ UNIMPLEMENTED();
+ R_THROW(ResultNotImplemented);
+}
+
+Result MapSharedMemory64(Core::System& system, Handle shmem_handle, uint64_t address, uint64_t size,
+ MemoryPermission map_perm) {
+ R_RETURN(MapSharedMemory(system, shmem_handle, address, size, map_perm));
+}
+
+Result UnmapSharedMemory64(Core::System& system, Handle shmem_handle, uint64_t address,
+ uint64_t size) {
+ R_RETURN(UnmapSharedMemory(system, shmem_handle, address, size));
+}
+
+Result CreateSharedMemory64(Core::System& system, Handle* out_handle, uint64_t size,
+ MemoryPermission owner_perm, MemoryPermission remote_perm) {
+ R_RETURN(CreateSharedMemory(system, out_handle, size, owner_perm, remote_perm));
+}
+
+Result MapSharedMemory64From32(Core::System& system, Handle shmem_handle, uint32_t address,
+ uint32_t size, MemoryPermission map_perm) {
+ R_RETURN(MapSharedMemory(system, shmem_handle, address, size, map_perm));
+}
+
+Result UnmapSharedMemory64From32(Core::System& system, Handle shmem_handle, uint32_t address,
+ uint32_t size) {
+ R_RETURN(UnmapSharedMemory(system, shmem_handle, address, size));
+}
+
+Result CreateSharedMemory64From32(Core::System& system, Handle* out_handle, uint32_t size,
+ MemoryPermission owner_perm, MemoryPermission remote_perm) {
+ R_RETURN(CreateSharedMemory(system, out_handle, size, owner_perm, remote_perm));
+}
+
+} // namespace Kernel::Svc
diff --git a/src/core/hle/kernel/svc/svc_synchronization.cpp b/src/core/hle/kernel/svc/svc_synchronization.cpp
new file mode 100644
index 000000000..53df5bcd8
--- /dev/null
+++ b/src/core/hle/kernel/svc/svc_synchronization.cpp
@@ -0,0 +1,175 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "common/scope_exit.h"
+#include "common/scratch_buffer.h"
+#include "core/core.h"
+#include "core/hle/kernel/k_process.h"
+#include "core/hle/kernel/k_readable_event.h"
+#include "core/hle/kernel/svc.h"
+
+namespace Kernel::Svc {
+
+/// Close a handle
+Result CloseHandle(Core::System& system, Handle handle) {
+ LOG_TRACE(Kernel_SVC, "Closing handle 0x{:08X}", handle);
+
+ // Remove the handle.
+ R_UNLESS(GetCurrentProcess(system.Kernel()).GetHandleTable().Remove(handle),
+ ResultInvalidHandle);
+
+ R_SUCCEED();
+}
+
+/// Clears the signaled state of an event or process.
+Result ResetSignal(Core::System& system, Handle handle) {
+ LOG_DEBUG(Kernel_SVC, "called handle 0x{:08X}", handle);
+
+ // Get the current handle table.
+ const auto& handle_table = GetCurrentProcess(system.Kernel()).GetHandleTable();
+
+ // Try to reset as readable event.
+ {
+ KScopedAutoObject readable_event = handle_table.GetObject<KReadableEvent>(handle);
+ if (readable_event.IsNotNull()) {
+ R_RETURN(readable_event->Reset());
+ }
+ }
+
+ // Try to reset as process.
+ {
+ KScopedAutoObject process = handle_table.GetObject<KProcess>(handle);
+ if (process.IsNotNull()) {
+ R_RETURN(process->Reset());
+ }
+ }
+
+ R_THROW(ResultInvalidHandle);
+}
+
+static Result WaitSynchronization(Core::System& system, int32_t* out_index, const Handle* handles,
+ int32_t num_handles, int64_t timeout_ns) {
+ // Ensure number of handles is valid.
+ R_UNLESS(0 <= num_handles && num_handles <= Svc::ArgumentHandleCountMax, ResultOutOfRange);
+
+ // Get the synchronization context.
+ auto& kernel = system.Kernel();
+ auto& handle_table = GetCurrentProcess(kernel).GetHandleTable();
+ std::array<KSynchronizationObject*, Svc::ArgumentHandleCountMax> objs;
+
+ // Copy user handles.
+ if (num_handles > 0) {
+ // Convert the handles to objects.
+ R_UNLESS(handle_table.GetMultipleObjects<KSynchronizationObject>(objs.data(), handles,
+ num_handles),
+ ResultInvalidHandle);
+ }
+
+ // Ensure handles are closed when we're done.
+ SCOPE_EXIT({
+ for (auto i = 0; i < num_handles; ++i) {
+ objs[i]->Close();
+ }
+ });
+
+ // Wait on the objects.
+ Result res =
+ KSynchronizationObject::Wait(kernel, out_index, objs.data(), num_handles, timeout_ns);
+
+ R_SUCCEED_IF(res == ResultSessionClosed);
+ R_RETURN(res);
+}
+
+/// Wait for the given handles to synchronize, timeout after the specified nanoseconds
+Result WaitSynchronization(Core::System& system, int32_t* out_index, u64 user_handles,
+ int32_t num_handles, int64_t timeout_ns) {
+ LOG_TRACE(Kernel_SVC, "called user_handles={:#x}, num_handles={}, timeout_ns={}", user_handles,
+ num_handles, timeout_ns);
+
+ // Ensure number of handles is valid.
+ R_UNLESS(0 <= num_handles && num_handles <= Svc::ArgumentHandleCountMax, ResultOutOfRange);
+ std::array<Handle, Svc::ArgumentHandleCountMax> handles;
+ if (num_handles > 0) {
+ GetCurrentMemory(system.Kernel())
+ .ReadBlock(user_handles, handles.data(), num_handles * sizeof(Handle));
+ }
+
+ R_RETURN(WaitSynchronization(system, out_index, handles.data(), num_handles, timeout_ns));
+}
+
+/// Resumes a thread waiting on WaitSynchronization
+Result CancelSynchronization(Core::System& system, Handle handle) {
+ LOG_TRACE(Kernel_SVC, "called handle=0x{:X}", handle);
+
+ // Get the thread from its handle.
+ KScopedAutoObject thread =
+ GetCurrentProcess(system.Kernel()).GetHandleTable().GetObject<KThread>(handle);
+ R_UNLESS(thread.IsNotNull(), ResultInvalidHandle);
+
+ // Cancel the thread's wait.
+ thread->WaitCancel();
+ R_SUCCEED();
+}
+
+void SynchronizePreemptionState(Core::System& system) {
+ auto& kernel = system.Kernel();
+
+ // Lock the scheduler.
+ KScopedSchedulerLock sl{kernel};
+
+ // If the current thread is pinned, unpin it.
+ KProcess* cur_process = GetCurrentProcessPointer(kernel);
+ const auto core_id = GetCurrentCoreId(kernel);
+
+ if (cur_process->GetPinnedThread(core_id) == GetCurrentThreadPointer(kernel)) {
+ // Clear the current thread's interrupt flag.
+ GetCurrentThread(kernel).ClearInterruptFlag();
+
+ // Unpin the current thread.
+ cur_process->UnpinCurrentThread(core_id);
+ }
+}
+
+Result CloseHandle64(Core::System& system, Handle handle) {
+ R_RETURN(CloseHandle(system, handle));
+}
+
+Result ResetSignal64(Core::System& system, Handle handle) {
+ R_RETURN(ResetSignal(system, handle));
+}
+
+Result WaitSynchronization64(Core::System& system, int32_t* out_index, uint64_t handles,
+ int32_t num_handles, int64_t timeout_ns) {
+ R_RETURN(WaitSynchronization(system, out_index, handles, num_handles, timeout_ns));
+}
+
+Result CancelSynchronization64(Core::System& system, Handle handle) {
+ R_RETURN(CancelSynchronization(system, handle));
+}
+
+void SynchronizePreemptionState64(Core::System& system) {
+ SynchronizePreemptionState(system);
+}
+
+Result CloseHandle64From32(Core::System& system, Handle handle) {
+ R_RETURN(CloseHandle(system, handle));
+}
+
+Result ResetSignal64From32(Core::System& system, Handle handle) {
+ R_RETURN(ResetSignal(system, handle));
+}
+
+Result WaitSynchronization64From32(Core::System& system, int32_t* out_index, uint32_t handles,
+ int32_t num_handles, int64_t timeout_ns) {
+ R_RETURN(WaitSynchronization(system, out_index, handles, num_handles, timeout_ns));
+}
+
+Result CancelSynchronization64From32(Core::System& system, Handle handle) {
+ R_RETURN(CancelSynchronization(system, handle));
+}
+
+void SynchronizePreemptionState64From32(Core::System& system) {
+ SynchronizePreemptionState(system);
+}
+
+} // namespace Kernel::Svc
diff --git a/src/core/hle/kernel/svc/svc_thread.cpp b/src/core/hle/kernel/svc/svc_thread.cpp
new file mode 100644
index 000000000..36b94e6bf
--- /dev/null
+++ b/src/core/hle/kernel/svc/svc_thread.cpp
@@ -0,0 +1,412 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "common/scope_exit.h"
+#include "core/core.h"
+#include "core/core_timing.h"
+#include "core/hle/kernel/k_process.h"
+#include "core/hle/kernel/k_scoped_resource_reservation.h"
+#include "core/hle/kernel/k_thread.h"
+#include "core/hle/kernel/svc.h"
+
+namespace Kernel::Svc {
+namespace {
+
+constexpr bool IsValidVirtualCoreId(int32_t core_id) {
+ return (0 <= core_id && core_id < static_cast<int32_t>(Core::Hardware::NUM_CPU_CORES));
+}
+
+} // Anonymous namespace
+
+/// Creates a new thread
+Result CreateThread(Core::System& system, Handle* out_handle, u64 entry_point, u64 arg,
+ u64 stack_bottom, s32 priority, s32 core_id) {
+ LOG_DEBUG(Kernel_SVC,
+ "called entry_point=0x{:08X}, arg=0x{:08X}, stack_bottom=0x{:08X}, "
+ "priority=0x{:08X}, core_id=0x{:08X}",
+ entry_point, arg, stack_bottom, priority, core_id);
+
+ // Adjust core id, if it's the default magic.
+ auto& kernel = system.Kernel();
+ auto& process = GetCurrentProcess(kernel);
+ if (core_id == IdealCoreUseProcessValue) {
+ core_id = process.GetIdealCoreId();
+ }
+
+ // Validate arguments.
+ R_UNLESS(IsValidVirtualCoreId(core_id), ResultInvalidCoreId);
+ R_UNLESS(((1ull << core_id) & process.GetCoreMask()) != 0, ResultInvalidCoreId);
+
+ R_UNLESS(HighestThreadPriority <= priority && priority <= LowestThreadPriority,
+ ResultInvalidPriority);
+ R_UNLESS(process.CheckThreadPriority(priority), ResultInvalidPriority);
+
+ // Reserve a new thread from the process resource limit (waiting up to 100ms).
+ KScopedResourceReservation thread_reservation(
+ std::addressof(process), LimitableResource::ThreadCountMax, 1,
+ system.CoreTiming().GetGlobalTimeNs().count() + 100000000);
+ R_UNLESS(thread_reservation.Succeeded(), ResultLimitReached);
+
+ // Create the thread.
+ KThread* thread = KThread::Create(kernel);
+ R_UNLESS(thread != nullptr, ResultOutOfResource)
+ SCOPE_EXIT({ thread->Close(); });
+
+ // Initialize the thread.
+ {
+ KScopedLightLock lk{process.GetStateLock()};
+ R_TRY(KThread::InitializeUserThread(system, thread, entry_point, arg, stack_bottom,
+ priority, core_id, std::addressof(process)));
+ }
+
+ // Commit the thread reservation.
+ thread_reservation.Commit();
+
+ // Clone the current fpu status to the new thread.
+ thread->CloneFpuStatus();
+
+ // Register the new thread.
+ KThread::Register(kernel, thread);
+
+ // Add the thread to the handle table.
+ R_RETURN(process.GetHandleTable().Add(out_handle, thread));
+}
+
+/// Starts the thread for the provided handle
+Result StartThread(Core::System& system, Handle thread_handle) {
+ LOG_DEBUG(Kernel_SVC, "called thread=0x{:08X}", thread_handle);
+
+ // Get the thread from its handle.
+ KScopedAutoObject thread =
+ GetCurrentProcess(system.Kernel()).GetHandleTable().GetObject<KThread>(thread_handle);
+ R_UNLESS(thread.IsNotNull(), ResultInvalidHandle);
+
+ // Try to start the thread.
+ R_TRY(thread->Run());
+
+ // If we succeeded, persist a reference to the thread.
+ thread->Open();
+ system.Kernel().RegisterInUseObject(thread.GetPointerUnsafe());
+
+ R_SUCCEED();
+}
+
+/// Called when a thread exits
+void ExitThread(Core::System& system) {
+ LOG_DEBUG(Kernel_SVC, "called, pc=0x{:08X}", system.CurrentArmInterface().GetPC());
+
+ auto* const current_thread = GetCurrentThreadPointer(system.Kernel());
+ system.GlobalSchedulerContext().RemoveThread(current_thread);
+ current_thread->Exit();
+ system.Kernel().UnregisterInUseObject(current_thread);
+}
+
+/// Sleep the current thread
+void SleepThread(Core::System& system, s64 nanoseconds) {
+ auto& kernel = system.Kernel();
+ const auto yield_type = static_cast<Svc::YieldType>(nanoseconds);
+
+ LOG_TRACE(Kernel_SVC, "called nanoseconds={}", nanoseconds);
+
+ // When the input tick is positive, sleep.
+ if (nanoseconds > 0) {
+ // Convert the timeout from nanoseconds to ticks.
+ // NOTE: Nintendo does not use this conversion logic in WaitSynchronization...
+
+ // Sleep.
+ // NOTE: Nintendo does not check the result of this sleep.
+ static_cast<void>(GetCurrentThread(kernel).Sleep(nanoseconds));
+ } else if (yield_type == Svc::YieldType::WithoutCoreMigration) {
+ KScheduler::YieldWithoutCoreMigration(kernel);
+ } else if (yield_type == Svc::YieldType::WithCoreMigration) {
+ KScheduler::YieldWithCoreMigration(kernel);
+ } else if (yield_type == Svc::YieldType::ToAnyThread) {
+ KScheduler::YieldToAnyThread(kernel);
+ } else {
+ // Nintendo does nothing at all if an otherwise invalid value is passed.
+ ASSERT_MSG(false, "Unimplemented sleep yield type '{:016X}'!", nanoseconds);
+ }
+}
+
+/// Gets the thread context
+Result GetThreadContext3(Core::System& system, u64 out_context, Handle thread_handle) {
+ 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.
+ KScopedAutoObject thread =
+ GetCurrentProcess(kernel).GetHandleTable().GetObject<KThread>(thread_handle);
+ R_UNLESS(thread.IsNotNull(), ResultInvalidHandle);
+
+ // Require the handle be to a non-current thread in the current process.
+ const auto* current_process = GetCurrentProcessPointer(kernel);
+ R_UNLESS(current_process == thread->GetOwnerProcess(), ResultInvalidId);
+
+ // 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};
+
+ // 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).GetSchedulerCurrentThread()) {
+ current = true;
+ break;
+ }
+ }
+
+ // If the thread is current, retry until it isn't.
+ if (current) {
+ continue;
+ }
+ }
+
+ // Get the thread context.
+ static thread_local Common::ScratchBuffer<u8> context;
+ R_TRY(thread->GetThreadContext3(context));
+
+ // Copy the thread context to user space.
+ GetCurrentMemory(kernel).WriteBlock(out_context, context.data(), context.size());
+
+ R_SUCCEED();
+ }
+}
+
+/// Gets the priority for the specified thread
+Result GetThreadPriority(Core::System& system, s32* out_priority, Handle handle) {
+ LOG_TRACE(Kernel_SVC, "called");
+
+ // Get the thread from its handle.
+ KScopedAutoObject thread =
+ GetCurrentProcess(system.Kernel()).GetHandleTable().GetObject<KThread>(handle);
+ R_UNLESS(thread.IsNotNull(), ResultInvalidHandle);
+
+ // Get the thread's priority.
+ *out_priority = thread->GetPriority();
+ R_SUCCEED();
+}
+
+/// Sets the priority for the specified thread
+Result SetThreadPriority(Core::System& system, Handle thread_handle, s32 priority) {
+ // Get the current process.
+ KProcess& process = GetCurrentProcess(system.Kernel());
+
+ // Validate the priority.
+ R_UNLESS(HighestThreadPriority <= priority && priority <= LowestThreadPriority,
+ ResultInvalidPriority);
+ R_UNLESS(process.CheckThreadPriority(priority), ResultInvalidPriority);
+
+ // Get the thread from its handle.
+ KScopedAutoObject thread = process.GetHandleTable().GetObject<KThread>(thread_handle);
+ R_UNLESS(thread.IsNotNull(), ResultInvalidHandle);
+
+ // Set the thread priority.
+ thread->SetBasePriority(priority);
+ R_SUCCEED();
+}
+
+Result GetThreadList(Core::System& system, s32* out_num_threads, u64 out_thread_ids,
+ s32 out_thread_ids_size, Handle debug_handle) {
+ // TODO: Handle this case when debug events are supported.
+ UNIMPLEMENTED_IF(debug_handle != InvalidHandle);
+
+ LOG_DEBUG(Kernel_SVC, "called. out_thread_ids=0x{:016X}, out_thread_ids_size={}",
+ out_thread_ids, out_thread_ids_size);
+
+ // If the size is negative or larger than INT32_MAX / sizeof(u64)
+ if ((out_thread_ids_size & 0xF0000000) != 0) {
+ LOG_ERROR(Kernel_SVC, "Supplied size outside [0, 0x0FFFFFFF] range. size={}",
+ out_thread_ids_size);
+ R_THROW(ResultOutOfRange);
+ }
+
+ auto* const current_process = GetCurrentProcessPointer(system.Kernel());
+ const auto total_copy_size = out_thread_ids_size * sizeof(u64);
+
+ if (out_thread_ids_size > 0 &&
+ !current_process->PageTable().IsInsideAddressSpace(out_thread_ids, total_copy_size)) {
+ LOG_ERROR(Kernel_SVC, "Address range outside address space. begin=0x{:016X}, end=0x{:016X}",
+ out_thread_ids, out_thread_ids + total_copy_size);
+ R_THROW(ResultInvalidCurrentMemory);
+ }
+
+ auto& memory = GetCurrentMemory(system.Kernel());
+ const auto& thread_list = current_process->GetThreadList();
+ const auto num_threads = thread_list.size();
+ const auto copy_amount = std::min(static_cast<std::size_t>(out_thread_ids_size), num_threads);
+
+ auto list_iter = thread_list.cbegin();
+ for (std::size_t i = 0; i < copy_amount; ++i, ++list_iter) {
+ memory.Write64(out_thread_ids, (*list_iter)->GetThreadId());
+ out_thread_ids += sizeof(u64);
+ }
+
+ *out_num_threads = static_cast<u32>(num_threads);
+ R_SUCCEED();
+}
+
+Result GetThreadCoreMask(Core::System& system, s32* out_core_id, u64* out_affinity_mask,
+ Handle thread_handle) {
+ LOG_TRACE(Kernel_SVC, "called, handle=0x{:08X}", thread_handle);
+
+ // Get the thread from its handle.
+ KScopedAutoObject thread =
+ GetCurrentProcess(system.Kernel()).GetHandleTable().GetObject<KThread>(thread_handle);
+ R_UNLESS(thread.IsNotNull(), ResultInvalidHandle);
+
+ // Get the core mask.
+ R_RETURN(thread->GetCoreMask(out_core_id, out_affinity_mask));
+}
+
+Result SetThreadCoreMask(Core::System& system, Handle thread_handle, s32 core_id,
+ u64 affinity_mask) {
+ // Determine the core id/affinity mask.
+ if (core_id == IdealCoreUseProcessValue) {
+ core_id = GetCurrentProcess(system.Kernel()).GetIdealCoreId();
+ affinity_mask = (1ULL << core_id);
+ } else {
+ // Validate the affinity mask.
+ const u64 process_core_mask = GetCurrentProcess(system.Kernel()).GetCoreMask();
+ R_UNLESS((affinity_mask | process_core_mask) == process_core_mask, ResultInvalidCoreId);
+ R_UNLESS(affinity_mask != 0, ResultInvalidCombination);
+
+ // Validate the core id.
+ if (IsValidVirtualCoreId(core_id)) {
+ R_UNLESS(((1ULL << core_id) & affinity_mask) != 0, ResultInvalidCombination);
+ } else {
+ R_UNLESS(core_id == IdealCoreNoUpdate || core_id == IdealCoreDontCare,
+ ResultInvalidCoreId);
+ }
+ }
+
+ // Get the thread from its handle.
+ KScopedAutoObject thread =
+ GetCurrentProcess(system.Kernel()).GetHandleTable().GetObject<KThread>(thread_handle);
+ R_UNLESS(thread.IsNotNull(), ResultInvalidHandle);
+
+ // Set the core mask.
+ R_RETURN(thread->SetCoreMask(core_id, affinity_mask));
+}
+
+/// Get the ID for the specified thread.
+Result GetThreadId(Core::System& system, u64* out_thread_id, Handle thread_handle) {
+ // Get the thread from its handle.
+ KScopedAutoObject thread =
+ GetCurrentProcess(system.Kernel()).GetHandleTable().GetObject<KThread>(thread_handle);
+ R_UNLESS(thread.IsNotNull(), ResultInvalidHandle);
+
+ // Get the thread's id.
+ *out_thread_id = thread->GetId();
+ R_SUCCEED();
+}
+
+Result CreateThread64(Core::System& system, Handle* out_handle, uint64_t func, uint64_t arg,
+ uint64_t stack_bottom, int32_t priority, int32_t core_id) {
+ R_RETURN(CreateThread(system, out_handle, func, arg, stack_bottom, priority, core_id));
+}
+
+Result StartThread64(Core::System& system, Handle thread_handle) {
+ R_RETURN(StartThread(system, thread_handle));
+}
+
+void ExitThread64(Core::System& system) {
+ return ExitThread(system);
+}
+
+void SleepThread64(Core::System& system, int64_t ns) {
+ return SleepThread(system, ns);
+}
+
+Result GetThreadPriority64(Core::System& system, int32_t* out_priority, Handle thread_handle) {
+ R_RETURN(GetThreadPriority(system, out_priority, thread_handle));
+}
+
+Result SetThreadPriority64(Core::System& system, Handle thread_handle, int32_t priority) {
+ R_RETURN(SetThreadPriority(system, thread_handle, priority));
+}
+
+Result GetThreadCoreMask64(Core::System& system, int32_t* out_core_id, uint64_t* out_affinity_mask,
+ Handle thread_handle) {
+ R_RETURN(GetThreadCoreMask(system, out_core_id, out_affinity_mask, thread_handle));
+}
+
+Result SetThreadCoreMask64(Core::System& system, Handle thread_handle, int32_t core_id,
+ uint64_t affinity_mask) {
+ R_RETURN(SetThreadCoreMask(system, thread_handle, core_id, affinity_mask));
+}
+
+Result GetThreadId64(Core::System& system, uint64_t* out_thread_id, Handle thread_handle) {
+ R_RETURN(GetThreadId(system, out_thread_id, thread_handle));
+}
+
+Result GetThreadContext364(Core::System& system, uint64_t out_context, Handle thread_handle) {
+ R_RETURN(GetThreadContext3(system, out_context, thread_handle));
+}
+
+Result GetThreadList64(Core::System& system, int32_t* out_num_threads, uint64_t out_thread_ids,
+ int32_t max_out_count, Handle debug_handle) {
+ R_RETURN(GetThreadList(system, out_num_threads, out_thread_ids, max_out_count, debug_handle));
+}
+
+Result CreateThread64From32(Core::System& system, Handle* out_handle, uint32_t func, uint32_t arg,
+ uint32_t stack_bottom, int32_t priority, int32_t core_id) {
+ R_RETURN(CreateThread(system, out_handle, func, arg, stack_bottom, priority, core_id));
+}
+
+Result StartThread64From32(Core::System& system, Handle thread_handle) {
+ R_RETURN(StartThread(system, thread_handle));
+}
+
+void ExitThread64From32(Core::System& system) {
+ return ExitThread(system);
+}
+
+void SleepThread64From32(Core::System& system, int64_t ns) {
+ return SleepThread(system, ns);
+}
+
+Result GetThreadPriority64From32(Core::System& system, int32_t* out_priority,
+ Handle thread_handle) {
+ R_RETURN(GetThreadPriority(system, out_priority, thread_handle));
+}
+
+Result SetThreadPriority64From32(Core::System& system, Handle thread_handle, int32_t priority) {
+ R_RETURN(SetThreadPriority(system, thread_handle, priority));
+}
+
+Result GetThreadCoreMask64From32(Core::System& system, int32_t* out_core_id,
+ uint64_t* out_affinity_mask, Handle thread_handle) {
+ R_RETURN(GetThreadCoreMask(system, out_core_id, out_affinity_mask, thread_handle));
+}
+
+Result SetThreadCoreMask64From32(Core::System& system, Handle thread_handle, int32_t core_id,
+ uint64_t affinity_mask) {
+ R_RETURN(SetThreadCoreMask(system, thread_handle, core_id, affinity_mask));
+}
+
+Result GetThreadId64From32(Core::System& system, uint64_t* out_thread_id, Handle thread_handle) {
+ R_RETURN(GetThreadId(system, out_thread_id, thread_handle));
+}
+
+Result GetThreadContext364From32(Core::System& system, uint32_t out_context, Handle thread_handle) {
+ R_RETURN(GetThreadContext3(system, out_context, thread_handle));
+}
+
+Result GetThreadList64From32(Core::System& system, int32_t* out_num_threads,
+ uint32_t out_thread_ids, int32_t max_out_count, Handle debug_handle) {
+ R_RETURN(GetThreadList(system, out_num_threads, out_thread_ids, max_out_count, debug_handle));
+}
+
+} // namespace Kernel::Svc
diff --git a/src/core/hle/kernel/svc/svc_thread_profiler.cpp b/src/core/hle/kernel/svc/svc_thread_profiler.cpp
new file mode 100644
index 000000000..40de7708b
--- /dev/null
+++ b/src/core/hle/kernel/svc/svc_thread_profiler.cpp
@@ -0,0 +1,60 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/kernel/svc.h"
+#include "core/hle/kernel/svc_results.h"
+
+namespace Kernel::Svc {
+
+Result GetDebugFutureThreadInfo(Core::System& system, lp64::LastThreadContext* out_context,
+ uint64_t* out_thread_id, Handle debug_handle, int64_t ns) {
+ UNIMPLEMENTED();
+ R_THROW(ResultNotImplemented);
+}
+
+Result GetLastThreadInfo(Core::System& system, lp64::LastThreadContext* out_context,
+ uint64_t* out_tls_address, uint32_t* out_flags) {
+ UNIMPLEMENTED();
+ R_THROW(ResultNotImplemented);
+}
+
+Result GetDebugFutureThreadInfo64(Core::System& system, lp64::LastThreadContext* out_context,
+ uint64_t* out_thread_id, Handle debug_handle, int64_t ns) {
+ R_RETURN(GetDebugFutureThreadInfo(system, out_context, out_thread_id, debug_handle, ns));
+}
+
+Result GetLastThreadInfo64(Core::System& system, lp64::LastThreadContext* out_context,
+ uint64_t* out_tls_address, uint32_t* out_flags) {
+ R_RETURN(GetLastThreadInfo(system, out_context, out_tls_address, out_flags));
+}
+
+Result GetDebugFutureThreadInfo64From32(Core::System& system, ilp32::LastThreadContext* out_context,
+ uint64_t* out_thread_id, Handle debug_handle, int64_t ns) {
+ lp64::LastThreadContext context{};
+ R_TRY(
+ GetDebugFutureThreadInfo(system, std::addressof(context), out_thread_id, debug_handle, ns));
+
+ *out_context = {
+ .fp = static_cast<u32>(context.fp),
+ .sp = static_cast<u32>(context.sp),
+ .lr = static_cast<u32>(context.lr),
+ .pc = static_cast<u32>(context.pc),
+ };
+ R_SUCCEED();
+}
+
+Result GetLastThreadInfo64From32(Core::System& system, ilp32::LastThreadContext* out_context,
+ uint64_t* out_tls_address, uint32_t* out_flags) {
+ lp64::LastThreadContext context{};
+ R_TRY(GetLastThreadInfo(system, std::addressof(context), out_tls_address, out_flags));
+
+ *out_context = {
+ .fp = static_cast<u32>(context.fp),
+ .sp = static_cast<u32>(context.sp),
+ .lr = static_cast<u32>(context.lr),
+ .pc = static_cast<u32>(context.pc),
+ };
+ R_SUCCEED();
+}
+
+} // namespace Kernel::Svc
diff --git a/src/core/hle/kernel/svc/svc_tick.cpp b/src/core/hle/kernel/svc/svc_tick.cpp
new file mode 100644
index 000000000..7dd7c6e51
--- /dev/null
+++ b/src/core/hle/kernel/svc/svc_tick.cpp
@@ -0,0 +1,27 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/core.h"
+#include "core/core_timing.h"
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/svc.h"
+
+namespace Kernel::Svc {
+
+/// This returns the total CPU ticks elapsed since the CPU was powered-on
+int64_t GetSystemTick(Core::System& system) {
+ LOG_TRACE(Kernel_SVC, "called");
+
+ // Returns the value of cntpct_el0 (https://switchbrew.org/wiki/SVC#svcGetSystemTick)
+ return static_cast<int64_t>(system.CoreTiming().GetClockTicks());
+}
+
+int64_t GetSystemTick64(Core::System& system) {
+ return GetSystemTick(system);
+}
+
+int64_t GetSystemTick64From32(Core::System& system) {
+ return GetSystemTick(system);
+}
+
+} // namespace Kernel::Svc
diff --git a/src/core/hle/kernel/svc/svc_transfer_memory.cpp b/src/core/hle/kernel/svc/svc_transfer_memory.cpp
new file mode 100644
index 000000000..82d469a37
--- /dev/null
+++ b/src/core/hle/kernel/svc/svc_transfer_memory.cpp
@@ -0,0 +1,115 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "common/scope_exit.h"
+#include "core/core.h"
+#include "core/hle/kernel/k_process.h"
+#include "core/hle/kernel/k_scoped_resource_reservation.h"
+#include "core/hle/kernel/k_transfer_memory.h"
+#include "core/hle/kernel/svc.h"
+
+namespace Kernel::Svc {
+namespace {
+
+constexpr bool IsValidTransferMemoryPermission(MemoryPermission perm) {
+ switch (perm) {
+ case MemoryPermission::None:
+ case MemoryPermission::Read:
+ case MemoryPermission::ReadWrite:
+ return true;
+ default:
+ return false;
+ }
+}
+
+} // Anonymous namespace
+
+/// Creates a TransferMemory object
+Result CreateTransferMemory(Core::System& system, Handle* out, u64 address, u64 size,
+ MemoryPermission map_perm) {
+ auto& kernel = system.Kernel();
+
+ // 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);
+
+ // Validate the permissions.
+ R_UNLESS(IsValidTransferMemoryPermission(map_perm), ResultInvalidNewMemoryPermission);
+
+ // Get the current process and handle table.
+ auto& process = GetCurrentProcess(kernel);
+ auto& handle_table = process.GetHandleTable();
+
+ // Reserve a new transfer memory from the process resource limit.
+ KScopedResourceReservation trmem_reservation(std::addressof(process),
+ LimitableResource::TransferMemoryCountMax);
+ R_UNLESS(trmem_reservation.Succeeded(), ResultLimitReached);
+
+ // Create the transfer memory.
+ KTransferMemory* trmem = KTransferMemory::Create(kernel);
+ R_UNLESS(trmem != nullptr, ResultOutOfResource);
+
+ // 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();
+
+ // Register the transfer memory.
+ KTransferMemory::Register(kernel, trmem);
+
+ // Add the transfer memory to the handle table.
+ R_RETURN(handle_table.Add(out, trmem));
+}
+
+Result MapTransferMemory(Core::System& system, Handle trmem_handle, uint64_t address, uint64_t size,
+ MemoryPermission owner_perm) {
+ UNIMPLEMENTED();
+ R_THROW(ResultNotImplemented);
+}
+
+Result UnmapTransferMemory(Core::System& system, Handle trmem_handle, uint64_t address,
+ uint64_t size) {
+ UNIMPLEMENTED();
+ R_THROW(ResultNotImplemented);
+}
+
+Result MapTransferMemory64(Core::System& system, Handle trmem_handle, uint64_t address,
+ uint64_t size, MemoryPermission owner_perm) {
+ R_RETURN(MapTransferMemory(system, trmem_handle, address, size, owner_perm));
+}
+
+Result UnmapTransferMemory64(Core::System& system, Handle trmem_handle, uint64_t address,
+ uint64_t size) {
+ R_RETURN(UnmapTransferMemory(system, trmem_handle, address, size));
+}
+
+Result CreateTransferMemory64(Core::System& system, Handle* out_handle, uint64_t address,
+ uint64_t size, MemoryPermission map_perm) {
+ R_RETURN(CreateTransferMemory(system, out_handle, address, size, map_perm));
+}
+
+Result MapTransferMemory64From32(Core::System& system, Handle trmem_handle, uint32_t address,
+ uint32_t size, MemoryPermission owner_perm) {
+ R_RETURN(MapTransferMemory(system, trmem_handle, address, size, owner_perm));
+}
+
+Result UnmapTransferMemory64From32(Core::System& system, Handle trmem_handle, uint32_t address,
+ uint32_t size) {
+ R_RETURN(UnmapTransferMemory(system, trmem_handle, address, size));
+}
+
+Result CreateTransferMemory64From32(Core::System& system, Handle* out_handle, uint32_t address,
+ uint32_t size, MemoryPermission map_perm) {
+ R_RETURN(CreateTransferMemory(system, out_handle, address, size, map_perm));
+}
+
+} // namespace Kernel::Svc
diff --git a/src/core/hle/kernel/svc_generator.py b/src/core/hle/kernel/svc_generator.py
new file mode 100644
index 000000000..7fcbb1ba1
--- /dev/null
+++ b/src/core/hle/kernel/svc_generator.py
@@ -0,0 +1,716 @@
+# SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+# Raw SVC definitions from the kernel.
+#
+# Avoid modifying the prototypes; see below for how to customize generation
+# for a given typename.
+SVCS = [
+ [0x01, "Result SetHeapSize(Address* out_address, Size size);"],
+ [0x02, "Result SetMemoryPermission(Address address, Size size, MemoryPermission perm);"],
+ [0x03, "Result SetMemoryAttribute(Address address, Size size, uint32_t mask, uint32_t attr);"],
+ [0x04, "Result MapMemory(Address dst_address, Address src_address, Size size);"],
+ [0x05, "Result UnmapMemory(Address dst_address, Address src_address, Size size);"],
+ [0x06, "Result QueryMemory(Address out_memory_info, PageInfo* out_page_info, Address address);"],
+ [0x07, "void ExitProcess();"],
+ [0x08, "Result CreateThread(Handle* out_handle, ThreadFunc func, Address arg, Address stack_bottom, int32_t priority, int32_t core_id);"],
+ [0x09, "Result StartThread(Handle thread_handle);"],
+ [0x0A, "void ExitThread();"],
+ [0x0B, "void SleepThread(int64_t ns);"],
+ [0x0C, "Result GetThreadPriority(int32_t* out_priority, Handle thread_handle);"],
+ [0x0D, "Result SetThreadPriority(Handle thread_handle, int32_t priority);"],
+ [0x0E, "Result GetThreadCoreMask(int32_t* out_core_id, uint64_t* out_affinity_mask, Handle thread_handle);"],
+ [0x0F, "Result SetThreadCoreMask(Handle thread_handle, int32_t core_id, uint64_t affinity_mask);"],
+ [0x10, "int32_t GetCurrentProcessorNumber();"],
+ [0x11, "Result SignalEvent(Handle event_handle);"],
+ [0x12, "Result ClearEvent(Handle event_handle);"],
+ [0x13, "Result MapSharedMemory(Handle shmem_handle, Address address, Size size, MemoryPermission map_perm);"],
+ [0x14, "Result UnmapSharedMemory(Handle shmem_handle, Address address, Size size);"],
+ [0x15, "Result CreateTransferMemory(Handle* out_handle, Address address, Size size, MemoryPermission map_perm);"],
+ [0x16, "Result CloseHandle(Handle handle);"],
+ [0x17, "Result ResetSignal(Handle handle);"],
+ [0x18, "Result WaitSynchronization(int32_t* out_index, Address handles, int32_t num_handles, int64_t timeout_ns);"],
+ [0x19, "Result CancelSynchronization(Handle handle);"],
+ [0x1A, "Result ArbitrateLock(Handle thread_handle, Address address, uint32_t tag);"],
+ [0x1B, "Result ArbitrateUnlock(Address address);"],
+ [0x1C, "Result WaitProcessWideKeyAtomic(Address address, Address cv_key, uint32_t tag, int64_t timeout_ns);"],
+ [0x1D, "void SignalProcessWideKey(Address cv_key, int32_t count);"],
+ [0x1E, "int64_t GetSystemTick();"],
+ [0x1F, "Result ConnectToNamedPort(Handle* out_handle, Address name);"],
+ [0x20, "Result SendSyncRequestLight(Handle session_handle);"],
+ [0x21, "Result SendSyncRequest(Handle session_handle);"],
+ [0x22, "Result SendSyncRequestWithUserBuffer(Address message_buffer, Size message_buffer_size, Handle session_handle);"],
+ [0x23, "Result SendAsyncRequestWithUserBuffer(Handle* out_event_handle, Address message_buffer, Size message_buffer_size, Handle session_handle);"],
+ [0x24, "Result GetProcessId(uint64_t* out_process_id, Handle process_handle);"],
+ [0x25, "Result GetThreadId(uint64_t* out_thread_id, Handle thread_handle);"],
+ [0x26, "void Break(BreakReason break_reason, Address arg, Size size);"],
+ [0x27, "Result OutputDebugString(Address debug_str, Size len);"],
+ [0x28, "void ReturnFromException(Result result);"],
+ [0x29, "Result GetInfo(uint64_t* out, InfoType info_type, Handle handle, uint64_t info_subtype);"],
+ [0x2A, "void FlushEntireDataCache();"],
+ [0x2B, "Result FlushDataCache(Address address, Size size);"],
+ [0x2C, "Result MapPhysicalMemory(Address address, Size size);"],
+ [0x2D, "Result UnmapPhysicalMemory(Address address, Size size);"],
+ [0x2E, "Result GetDebugFutureThreadInfo(LastThreadContext* out_context, uint64_t* out_thread_id, Handle debug_handle, int64_t ns);"],
+ [0x2F, "Result GetLastThreadInfo(LastThreadContext* out_context, Address* out_tls_address, uint32_t* out_flags);"],
+ [0x30, "Result GetResourceLimitLimitValue(int64_t* out_limit_value, Handle resource_limit_handle, LimitableResource which);"],
+ [0x31, "Result GetResourceLimitCurrentValue(int64_t* out_current_value, Handle resource_limit_handle, LimitableResource which);"],
+ [0x32, "Result SetThreadActivity(Handle thread_handle, ThreadActivity thread_activity);"],
+ [0x33, "Result GetThreadContext3(Address out_context, Handle thread_handle);"],
+ [0x34, "Result WaitForAddress(Address address, ArbitrationType arb_type, int32_t value, int64_t timeout_ns);"],
+ [0x35, "Result SignalToAddress(Address address, SignalType signal_type, int32_t value, int32_t count);"],
+ [0x36, "void SynchronizePreemptionState();"],
+ [0x37, "Result GetResourceLimitPeakValue(int64_t* out_peak_value, Handle resource_limit_handle, LimitableResource which);"],
+
+ [0x39, "Result CreateIoPool(Handle* out_handle, IoPoolType which);"],
+ [0x3A, "Result CreateIoRegion(Handle* out_handle, Handle io_pool, PhysicalAddress physical_address, Size size, MemoryMapping mapping, MemoryPermission perm);"],
+
+ [0x3C, "void KernelDebug(KernelDebugType kern_debug_type, uint64_t arg0, uint64_t arg1, uint64_t arg2);"],
+ [0x3D, "void ChangeKernelTraceState(KernelTraceState kern_trace_state);"],
+
+ [0x40, "Result CreateSession(Handle* out_server_session_handle, Handle* out_client_session_handle, bool is_light, Address name);"],
+ [0x41, "Result AcceptSession(Handle* out_handle, Handle port);"],
+ [0x42, "Result ReplyAndReceiveLight(Handle handle);"],
+ [0x43, "Result ReplyAndReceive(int32_t* out_index, Address handles, int32_t num_handles, Handle reply_target, int64_t timeout_ns);"],
+ [0x44, "Result ReplyAndReceiveWithUserBuffer(int32_t* out_index, Address message_buffer, Size message_buffer_size, Address handles, int32_t num_handles, Handle reply_target, int64_t timeout_ns);"],
+ [0x45, "Result CreateEvent(Handle* out_write_handle, Handle* out_read_handle);"],
+ [0x46, "Result MapIoRegion(Handle io_region, Address address, Size size, MemoryPermission perm);"],
+ [0x47, "Result UnmapIoRegion(Handle io_region, Address address, Size size);"],
+ [0x48, "Result MapPhysicalMemoryUnsafe(Address address, Size size);"],
+ [0x49, "Result UnmapPhysicalMemoryUnsafe(Address address, Size size);"],
+ [0x4A, "Result SetUnsafeLimit(Size limit);"],
+ [0x4B, "Result CreateCodeMemory(Handle* out_handle, Address address, Size size);"],
+ [0x4C, "Result ControlCodeMemory(Handle code_memory_handle, CodeMemoryOperation operation, uint64_t address, uint64_t size, MemoryPermission perm);"],
+ [0x4D, "void SleepSystem();"],
+ [0x4E, "Result ReadWriteRegister(uint32_t* out_value, PhysicalAddress address, uint32_t mask, uint32_t value);"],
+ [0x4F, "Result SetProcessActivity(Handle process_handle, ProcessActivity process_activity);"],
+ [0x50, "Result CreateSharedMemory(Handle* out_handle, Size size, MemoryPermission owner_perm, MemoryPermission remote_perm);"],
+ [0x51, "Result MapTransferMemory(Handle trmem_handle, Address address, Size size, MemoryPermission owner_perm);"],
+ [0x52, "Result UnmapTransferMemory(Handle trmem_handle, Address address, Size size);"],
+ [0x53, "Result CreateInterruptEvent(Handle* out_read_handle, int32_t interrupt_id, InterruptType interrupt_type);"],
+ [0x54, "Result QueryPhysicalAddress(PhysicalMemoryInfo* out_info, Address address);"],
+ [0x55, "Result QueryIoMapping(Address* out_address, Size* out_size, PhysicalAddress physical_address, Size size);"],
+ [0x56, "Result CreateDeviceAddressSpace(Handle* out_handle, uint64_t das_address, uint64_t das_size);"],
+ [0x57, "Result AttachDeviceAddressSpace(DeviceName device_name, Handle das_handle);"],
+ [0x58, "Result DetachDeviceAddressSpace(DeviceName device_name, Handle das_handle);"],
+ [0x59, "Result MapDeviceAddressSpaceByForce(Handle das_handle, Handle process_handle, uint64_t process_address, Size size, uint64_t device_address, uint32_t option);"],
+ [0x5A, "Result MapDeviceAddressSpaceAligned(Handle das_handle, Handle process_handle, uint64_t process_address, Size size, uint64_t device_address, uint32_t option);"],
+ [0x5C, "Result UnmapDeviceAddressSpace(Handle das_handle, Handle process_handle, uint64_t process_address, Size size, uint64_t device_address);"],
+ [0x5D, "Result InvalidateProcessDataCache(Handle process_handle, uint64_t address, uint64_t size);"],
+ [0x5E, "Result StoreProcessDataCache(Handle process_handle, uint64_t address, uint64_t size);"],
+ [0x5F, "Result FlushProcessDataCache(Handle process_handle, uint64_t address, uint64_t size);"],
+ [0x60, "Result DebugActiveProcess(Handle* out_handle, uint64_t process_id);"],
+ [0x61, "Result BreakDebugProcess(Handle debug_handle);"],
+ [0x62, "Result TerminateDebugProcess(Handle debug_handle);"],
+ [0x63, "Result GetDebugEvent(Address out_info, Handle debug_handle);"],
+ [0x64, "Result ContinueDebugEvent(Handle debug_handle, uint32_t flags, Address thread_ids, int32_t num_thread_ids);"],
+ [0x65, "Result GetProcessList(int32_t* out_num_processes, Address out_process_ids, int32_t max_out_count);"],
+ [0x66, "Result GetThreadList(int32_t* out_num_threads, Address out_thread_ids, int32_t max_out_count, Handle debug_handle);"],
+ [0x67, "Result GetDebugThreadContext(Address out_context, Handle debug_handle, uint64_t thread_id, uint32_t context_flags);"],
+ [0x68, "Result SetDebugThreadContext(Handle debug_handle, uint64_t thread_id, Address context, uint32_t context_flags);"],
+ [0x69, "Result QueryDebugProcessMemory(Address out_memory_info, PageInfo* out_page_info, Handle process_handle, Address address);"],
+ [0x6A, "Result ReadDebugProcessMemory(Address buffer, Handle debug_handle, Address address, Size size);"],
+ [0x6B, "Result WriteDebugProcessMemory(Handle debug_handle, Address buffer, Address address, Size size);"],
+ [0x6C, "Result SetHardwareBreakPoint(HardwareBreakPointRegisterName name, uint64_t flags, uint64_t value);"],
+ [0x6D, "Result GetDebugThreadParam(uint64_t* out_64, uint32_t* out_32, Handle debug_handle, uint64_t thread_id, DebugThreadParam param);"],
+
+ [0x6F, "Result GetSystemInfo(uint64_t* out, SystemInfoType info_type, Handle handle, uint64_t info_subtype);"],
+ [0x70, "Result CreatePort(Handle* out_server_handle, Handle* out_client_handle, int32_t max_sessions, bool is_light, Address name);"],
+ [0x71, "Result ManageNamedPort(Handle* out_server_handle, Address name, int32_t max_sessions);"],
+ [0x72, "Result ConnectToPort(Handle* out_handle, Handle port);"],
+ [0x73, "Result SetProcessMemoryPermission(Handle process_handle, uint64_t address, uint64_t size, MemoryPermission perm);"],
+ [0x74, "Result MapProcessMemory(Address dst_address, Handle process_handle, uint64_t src_address, Size size);"],
+ [0x75, "Result UnmapProcessMemory(Address dst_address, Handle process_handle, uint64_t src_address, Size size);"],
+ [0x76, "Result QueryProcessMemory(Address out_memory_info, PageInfo* out_page_info, Handle process_handle, uint64_t address);"],
+ [0x77, "Result MapProcessCodeMemory(Handle process_handle, uint64_t dst_address, uint64_t src_address, uint64_t size);"],
+ [0x78, "Result UnmapProcessCodeMemory(Handle process_handle, uint64_t dst_address, uint64_t src_address, uint64_t size);"],
+ [0x79, "Result CreateProcess(Handle* out_handle, Address parameters, Address caps, int32_t num_caps);"],
+ [0x7A, "Result StartProcess(Handle process_handle, int32_t priority, int32_t core_id, uint64_t main_thread_stack_size);"],
+ [0x7B, "Result TerminateProcess(Handle process_handle);"],
+ [0x7C, "Result GetProcessInfo(int64_t* out_info, Handle process_handle, ProcessInfoType info_type);"],
+ [0x7D, "Result CreateResourceLimit(Handle* out_handle);"],
+ [0x7E, "Result SetResourceLimitLimitValue(Handle resource_limit_handle, LimitableResource which, int64_t limit_value);"],
+ [0x7F, "void CallSecureMonitor(SecureMonitorArguments args);"],
+
+ [0x90, "Result MapInsecureMemory(Address address, Size size);"],
+ [0x91, "Result UnmapInsecureMemory(Address address, Size size);"],
+]
+
+# These use a custom ABI, and therefore require custom wrappers
+SKIP_WRAPPERS = {
+ 0x20: "SendSyncRequestLight",
+ 0x42: "ReplyAndReceiveLight",
+ 0x7F: "CallSecureMonitor",
+}
+
+BIT_32 = 0
+BIT_64 = 1
+
+REG_SIZES = [4, 8]
+SUFFIX_NAMES = ["64From32", "64"]
+TYPE_SIZES = {
+ # SVC types
+ "ArbitrationType": 4,
+ "BreakReason": 4,
+ "CodeMemoryOperation": 4,
+ "DebugThreadParam": 4,
+ "DeviceName": 4,
+ "HardwareBreakPointRegisterName": 4,
+ "Handle": 4,
+ "InfoType": 4,
+ "InterruptType": 4,
+ "IoPoolType": 4,
+ "KernelDebugType": 4,
+ "KernelTraceState": 4,
+ "LimitableResource": 4,
+ "MemoryMapping": 4,
+ "MemoryPermission": 4,
+ "PageInfo": 4,
+ "ProcessActivity": 4,
+ "ProcessInfoType": 4,
+ "Result": 4,
+ "SignalType": 4,
+ "SystemInfoType": 4,
+ "ThreadActivity": 4,
+
+ # Arch-specific types
+ "ilp32::LastThreadContext": 16,
+ "ilp32::PhysicalMemoryInfo": 16,
+ "ilp32::SecureMonitorArguments": 32,
+ "lp64::LastThreadContext": 32,
+ "lp64::PhysicalMemoryInfo": 24,
+ "lp64::SecureMonitorArguments": 64,
+
+ # Generic types
+ "bool": 1,
+ "int32_t": 4,
+ "int64_t": 8,
+ "uint32_t": 4,
+ "uint64_t": 8,
+ "void": 0,
+}
+
+TYPE_REPLACEMENTS = {
+ "Address": ["uint32_t", "uint64_t"],
+ "LastThreadContext": ["ilp32::LastThreadContext", "lp64::LastThreadContext"],
+ "PhysicalAddress": ["uint64_t", "uint64_t"],
+ "PhysicalMemoryInfo": ["ilp32::PhysicalMemoryInfo", "lp64::PhysicalMemoryInfo"],
+ "SecureMonitorArguments": ["ilp32::SecureMonitorArguments", "lp64::SecureMonitorArguments"],
+ "Size": ["uint32_t", "uint64_t"],
+ "ThreadFunc": ["uint32_t", "uint64_t"],
+}
+
+# Statically verify that the hardcoded sizes match the intended
+# sizes in C++.
+def emit_size_check():
+ lines = []
+
+ for type, size in TYPE_SIZES.items():
+ if type != "void":
+ lines.append(f"static_assert(sizeof({type}) == {size});")
+
+ return "\n".join(lines)
+
+
+# Replaces a type with an arch-specific one, if it exists.
+def substitute_type(name, bitness):
+ if name in TYPE_REPLACEMENTS:
+ return TYPE_REPLACEMENTS[name][bitness]
+ else:
+ return name
+
+
+class Argument:
+ def __init__(self, type_name, var_name, is_output, is_outptr, is_address):
+ self.type_name = type_name
+ self.var_name = var_name
+ self.is_output = is_output
+ self.is_outptr = is_outptr
+ self.is_address = is_address
+
+
+# Parses C-style string declarations for SVCs.
+def parse_declaration(declaration, bitness):
+ return_type, rest = declaration.split(" ", 1)
+ func_name, rest = rest.split("(", 1)
+ arg_names, rest = rest.split(")", 1)
+ argument_types = []
+
+ return_type = substitute_type(return_type, bitness)
+ assert return_type in TYPE_SIZES, f"Unknown type '{return_type}'"
+
+ if arg_names:
+ for arg_name in arg_names.split(", "):
+ type_name, var_name = arg_name.replace("*", "").split(" ", 1)
+
+ # All outputs must contain out_ in the name.
+ is_output = var_name == "out" or var_name.find("out_") != -1
+
+ # User-pointer outputs are not written to registers.
+ is_outptr = is_output and arg_name.find("*") == -1
+
+ # Special handling is performed for output addresses to avoid awkwardness
+ # in conversion for the 32-bit equivalents.
+ is_address = is_output and not is_outptr and \
+ type_name in ["Address", "Size"]
+ type_name = substitute_type(type_name, bitness)
+
+ assert type_name in TYPE_SIZES, f"Unknown type '{type_name}'"
+
+ argument_types.append(
+ Argument(type_name, var_name, is_output, is_outptr, is_address))
+
+ return (return_type, func_name, argument_types)
+
+
+class RegisterAllocator:
+ def __init__(self, num_regs, byte_size, parameter_count):
+ self.registers = {}
+ self.num_regs = num_regs
+ self.byte_size = byte_size
+ self.parameter_count = parameter_count
+
+ # Mark the given register as allocated, for use in layout
+ # calculation if the NGRN exceeds the ABI parameter count.
+ def allocate(self, i):
+ assert i not in self.registers, f"Register R{i} already allocated"
+ self.registers[i] = True
+ return i
+
+ # Calculate the next available location for a register;
+ # the NGRN has exceeded the ABI parameter count.
+ def allocate_first_free(self):
+ for i in range(0, self.num_regs):
+ if i in self.registers:
+ continue
+
+ self.allocate(i)
+ return i
+
+ assert False, "No registers available"
+
+ # Add a single register at the given NGRN.
+ # If the index exceeds the ABI parameter count, try to find a
+ # location to add it. Returns the output location and increment.
+ def add_single(self, ngrn):
+ if ngrn >= self.parameter_count:
+ return (self.allocate_first_free(), 0)
+ else:
+ return (self.allocate(ngrn), 1)
+
+ # Add registers at the given NGRN for a data type of
+ # the given size. Returns the output locations and increment.
+ def add(self, ngrn, data_size, align=True):
+ if data_size <= self.byte_size:
+ r, i = self.add_single(ngrn)
+ return ([r], i)
+
+ regs = []
+ inc = ngrn % 2 if align else 0
+ remaining_size = data_size
+ while remaining_size > 0:
+ r, i = self.add_single(ngrn + inc)
+ regs.append(r)
+ inc += i
+ remaining_size -= self.byte_size
+
+ return (regs, inc)
+
+
+def reg_alloc(bitness):
+ if bitness == 0:
+ # aapcs32: 4 4-byte registers
+ return RegisterAllocator(8, 4, 4)
+ elif bitness == 1:
+ # aapcs64: 8 8-byte registers
+ return RegisterAllocator(8, 8, 8)
+
+
+# Converts a parsed SVC declaration into register lists for
+# the return value, outputs, and inputs.
+def get_registers(parse_result, bitness):
+ output_alloc = reg_alloc(bitness)
+ input_alloc = reg_alloc(bitness)
+ return_type, _, arguments = parse_result
+
+ return_write = []
+ output_writes = []
+ input_reads = []
+
+ input_ngrn = 0
+ output_ngrn = 0
+
+ # Run the input calculation.
+ for arg in arguments:
+ if arg.is_output and not arg.is_outptr:
+ input_ngrn += 1
+ continue
+
+ regs, increment = input_alloc.add(
+ input_ngrn, TYPE_SIZES[arg.type_name], align=True)
+ input_reads.append([arg.type_name, arg.var_name, regs])
+ input_ngrn += increment
+
+ # Include the return value if this SVC returns a value.
+ if return_type != "void":
+ regs, increment = output_alloc.add(
+ output_ngrn, TYPE_SIZES[return_type], align=False)
+ return_write.append([return_type, regs])
+ output_ngrn += increment
+
+ # Run the output calculation.
+ for arg in arguments:
+ if not arg.is_output or arg.is_outptr:
+ continue
+
+ regs, increment = output_alloc.add(
+ output_ngrn, TYPE_SIZES[arg.type_name], align=False)
+ output_writes.append(
+ [arg.type_name, arg.var_name, regs, arg.is_address])
+ output_ngrn += increment
+
+ return (return_write, output_writes, input_reads)
+
+
+# Collects possibly multiple source registers into the named C++ value.
+def emit_gather(sources, name, type_name, reg_size):
+ get_fn = f"GetReg{reg_size*8}"
+
+ if len(sources) == 1:
+ s, = sources
+ line = f"{name} = Convert<{type_name}>({get_fn}(system, {s}));"
+ return [line]
+
+ var_type = f"std::array<uint{reg_size*8}_t, {len(sources)}>"
+ lines = [
+ f"{var_type} {name}_gather{{}};"
+ ]
+ for i in range(0, len(sources)):
+ lines.append(
+ f"{name}_gather[{i}] = {get_fn}(system, {sources[i]});")
+
+ lines.append(f"{name} = Convert<{type_name}>({name}_gather);")
+ return lines
+
+
+# Produces one or more statements which assign the named C++ value
+# into possibly multiple registers.
+def emit_scatter(destinations, name, reg_size):
+ set_fn = f"SetReg{reg_size*8}"
+ reg_type = f"uint{reg_size*8}_t"
+
+ if len(destinations) == 1:
+ d, = destinations
+ line = f"{set_fn}(system, {d}, Convert<{reg_type}>({name}));"
+ return [line]
+
+ var_type = f"std::array<{reg_type}, {len(destinations)}>"
+ lines = [
+ f"auto {name}_scatter = Convert<{var_type}>({name});"
+ ]
+
+ for i in range(0, len(destinations)):
+ lines.append(
+ f"{set_fn}(system, {destinations[i]}, {name}_scatter[{i}]);")
+
+ return lines
+
+
+def emit_lines(lines, indent=' '):
+ output_lines = []
+ first = True
+ for line in lines:
+ if line and not first:
+ output_lines.append(indent + line)
+ else:
+ output_lines.append(line)
+ first = False
+
+ return "\n".join(output_lines)
+
+
+# Emit a C++ function to wrap a guest SVC.
+def emit_wrapper(wrapped_fn, suffix, register_info, arguments, byte_size):
+ return_write, output_writes, input_reads = register_info
+ lines = [
+ f"static void SvcWrap_{wrapped_fn}{suffix}(Core::System& system) {{"
+ ]
+
+ # Get everything ready.
+ for return_type, _ in return_write:
+ lines.append(f"{return_type} ret{{}};")
+ if return_write:
+ lines.append("")
+
+ for output_type, var_name, _, is_address in output_writes:
+ output_type = "uint64_t" if is_address else output_type
+ lines.append(f"{output_type} {var_name}{{}};")
+ for input_type, var_name, _ in input_reads:
+ lines.append(f"{input_type} {var_name}{{}};")
+
+ if output_writes or input_reads:
+ lines.append("")
+
+ for input_type, var_name, sources in input_reads:
+ lines += emit_gather(sources, var_name, input_type, byte_size)
+ if input_reads:
+ lines.append("")
+
+ # Build the call.
+ call_arguments = ["system"]
+ for arg in arguments:
+ if arg.is_output and not arg.is_outptr:
+ call_arguments.append(f"std::addressof({arg.var_name})")
+ else:
+ call_arguments.append(arg.var_name)
+
+ line = ""
+ if return_write:
+ line += "ret = "
+
+ line += f"{wrapped_fn}{suffix}({', '.join(call_arguments)});"
+ lines.append(line)
+
+ if return_write or output_writes:
+ lines.append("")
+
+ # Write back the return value and outputs.
+ for _, destinations in return_write:
+ lines += emit_scatter(destinations, "ret", byte_size)
+ for _, var_name, destinations, _ in output_writes:
+ lines += emit_scatter(destinations, var_name, byte_size)
+
+ # Finish.
+ return emit_lines(lines) + "\n}"
+
+
+COPYRIGHT = """\
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+// This file is automatically generated using svc_generator.py.
+"""
+
+PROLOGUE_H = """
+#pragma once
+
+namespace Core {
+class System;
+}
+
+#include "common/common_types.h"
+#include "core/hle/kernel/svc_types.h"
+#include "core/hle/result.h"
+
+namespace Kernel::Svc {
+
+// clang-format off
+"""
+
+EPILOGUE_H = """
+// clang-format on
+
+// Custom ABI.
+Result ReplyAndReceiveLight(Core::System& system, Handle handle, uint32_t* args);
+Result ReplyAndReceiveLight64From32(Core::System& system, Handle handle, uint32_t* args);
+Result ReplyAndReceiveLight64(Core::System& system, Handle handle, uint32_t* args);
+
+Result SendSyncRequestLight(Core::System& system, Handle session_handle, uint32_t* args);
+Result SendSyncRequestLight64From32(Core::System& system, Handle session_handle, uint32_t* args);
+Result SendSyncRequestLight64(Core::System& system, Handle session_handle, uint32_t* args);
+
+void CallSecureMonitor(Core::System& system, lp64::SecureMonitorArguments* args);
+void CallSecureMonitor64From32(Core::System& system, ilp32::SecureMonitorArguments* args);
+void CallSecureMonitor64(Core::System& system, lp64::SecureMonitorArguments* args);
+
+// Defined in svc_light_ipc.cpp.
+void SvcWrap_ReplyAndReceiveLight64From32(Core::System& system);
+void SvcWrap_ReplyAndReceiveLight64(Core::System& system);
+
+void SvcWrap_SendSyncRequestLight64From32(Core::System& system);
+void SvcWrap_SendSyncRequestLight64(Core::System& system);
+
+// Defined in svc_secure_monitor_call.cpp.
+void SvcWrap_CallSecureMonitor64From32(Core::System& system);
+void SvcWrap_CallSecureMonitor64(Core::System& system);
+
+// Perform a supervisor call by index.
+void Call(Core::System& system, u32 imm);
+
+} // namespace Kernel::Svc
+"""
+
+PROLOGUE_CPP = """
+#include <type_traits>
+
+#include "core/arm/arm_interface.h"
+#include "core/core.h"
+#include "core/hle/kernel/k_process.h"
+#include "core/hle/kernel/svc.h"
+
+namespace Kernel::Svc {
+
+static uint32_t GetReg32(Core::System& system, int n) {
+ return static_cast<uint32_t>(system.CurrentArmInterface().GetReg(n));
+}
+
+static void SetReg32(Core::System& system, int n, uint32_t result) {
+ system.CurrentArmInterface().SetReg(n, static_cast<uint64_t>(result));
+}
+
+static uint64_t GetReg64(Core::System& system, int n) {
+ return system.CurrentArmInterface().GetReg(n);
+}
+
+static void SetReg64(Core::System& system, int n, uint64_t result) {
+ system.CurrentArmInterface().SetReg(n, result);
+}
+
+// Like bit_cast, but handles the case when the source and dest
+// are differently-sized.
+template <typename To, typename From>
+ requires(std::is_trivial_v<To> && std::is_trivially_copyable_v<From>)
+static To Convert(const From& from) {
+ To to{};
+
+ if constexpr (sizeof(To) >= sizeof(From)) {
+ std::memcpy(std::addressof(to), std::addressof(from), sizeof(From));
+ } else {
+ std::memcpy(std::addressof(to), std::addressof(from), sizeof(To));
+ }
+
+ return to;
+}
+
+// clang-format off
+"""
+
+EPILOGUE_CPP = """
+// clang-format on
+
+void Call(Core::System& system, u32 imm) {
+ auto& kernel = system.Kernel();
+ kernel.EnterSVCProfile();
+
+ if (GetCurrentProcess(system.Kernel()).Is64BitProcess()) {
+ Call64(system, imm);
+ } else {
+ Call32(system, imm);
+ }
+
+ kernel.ExitSVCProfile();
+}
+
+} // namespace Kernel::Svc
+"""
+
+
+def emit_call(bitness, names, suffix):
+ bit_size = REG_SIZES[bitness]*8
+ indent = " "
+ lines = [
+ f"static void Call{bit_size}(Core::System& system, u32 imm) {{",
+ f"{indent}switch (static_cast<SvcId>(imm)) {{"
+ ]
+
+ for _, name in names:
+ lines.append(f"{indent}case SvcId::{name}:")
+ lines.append(f"{indent*2}return SvcWrap_{name}{suffix}(system);")
+
+ lines.append(f"{indent}default:")
+ lines.append(
+ f"{indent*2}LOG_CRITICAL(Kernel_SVC, \"Unknown SVC {{:x}}!\", imm);")
+ lines.append(f"{indent*2}break;")
+ lines.append(f"{indent}}}")
+ lines.append("}")
+
+ return "\n".join(lines)
+
+
+def build_fn_declaration(return_type, name, arguments):
+ arg_list = ["Core::System& system"]
+ for arg in arguments:
+ type_name = "uint64_t" if arg.is_address else arg.type_name
+ pointer = "*" if arg.is_output and not arg.is_outptr else ""
+ arg_list.append(f"{type_name}{pointer} {arg.var_name}")
+
+ return f"{return_type} {name}({', '.join(arg_list)});"
+
+
+def build_enum_declarations():
+ lines = ["enum class SvcId : u32 {"]
+ indent = " "
+
+ for imm, decl in SVCS:
+ _, name, _ = parse_declaration(decl, BIT_64)
+ lines.append(f"{indent}{name} = {hex(imm)},")
+
+ lines.append("};")
+ return "\n".join(lines)
+
+
+def main():
+ arch_fw_declarations = [[], []]
+ svc_fw_declarations = []
+ wrapper_fns = []
+ names = []
+
+ for imm, decl in SVCS:
+ return_type, name, arguments = parse_declaration(decl, BIT_64)
+
+ if imm not in SKIP_WRAPPERS:
+ svc_fw_declarations.append(
+ build_fn_declaration(return_type, name, arguments))
+
+ names.append([imm, name])
+
+ for bitness in range(2):
+ byte_size = REG_SIZES[bitness]
+ suffix = SUFFIX_NAMES[bitness]
+
+ for imm, decl in SVCS:
+ if imm in SKIP_WRAPPERS:
+ continue
+
+ parse_result = parse_declaration(decl, bitness)
+ return_type, name, arguments = parse_result
+
+ register_info = get_registers(parse_result, bitness)
+ wrapper_fns.append(
+ emit_wrapper(name, suffix, register_info, arguments, byte_size))
+ arch_fw_declarations[bitness].append(
+ build_fn_declaration(return_type, name + suffix, arguments))
+
+ call_32 = emit_call(BIT_32, names, SUFFIX_NAMES[BIT_32])
+ call_64 = emit_call(BIT_64, names, SUFFIX_NAMES[BIT_64])
+ enum_decls = build_enum_declarations()
+
+ with open("svc.h", "w") as f:
+ f.write(COPYRIGHT)
+ f.write(PROLOGUE_H)
+ f.write("\n".join(svc_fw_declarations))
+ f.write("\n\n")
+ f.write("\n".join(arch_fw_declarations[BIT_32]))
+ f.write("\n\n")
+ f.write("\n".join(arch_fw_declarations[BIT_64]))
+ f.write("\n\n")
+ f.write(enum_decls)
+ f.write(EPILOGUE_H)
+
+ with open("svc.cpp", "w") as f:
+ f.write(COPYRIGHT)
+ f.write(PROLOGUE_CPP)
+ f.write(emit_size_check())
+ f.write("\n\n")
+ f.write("\n\n".join(wrapper_fns))
+ f.write("\n\n")
+ f.write(call_32)
+ f.write("\n\n")
+ f.write(call_64)
+ f.write(EPILOGUE_CPP)
+
+ print(f"Done (emitted {len(names)} definitions)")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/src/core/hle/kernel/svc_results.h b/src/core/hle/kernel/svc_results.h
index b7ca53085..e1ad78607 100644
--- a/src/core/hle/kernel/svc_results.h
+++ b/src/core/hle/kernel/svc_results.h
@@ -11,6 +11,7 @@ namespace Kernel {
constexpr Result ResultOutOfSessions{ErrorModule::Kernel, 7};
constexpr Result ResultInvalidArgument{ErrorModule::Kernel, 14};
+constexpr Result ResultNotImplemented{ErrorModule::Kernel, 33};
constexpr Result ResultNoSynchronizationObject{ErrorModule::Kernel, 57};
constexpr Result ResultTerminationRequested{ErrorModule::Kernel, 59};
constexpr Result ResultInvalidSize{ErrorModule::Kernel, 101};
diff --git a/src/core/hle/kernel/svc_types.h b/src/core/hle/kernel/svc_types.h
index 33eebcef6..7f380ca4f 100644
--- a/src/core/hle/kernel/svc_types.h
+++ b/src/core/hle/kernel/svc_types.h
@@ -3,6 +3,9 @@
#pragma once
+#include <bitset>
+
+#include "common/bit_field.h"
#include "common/common_funcs.h"
#include "common/common_types.h"
@@ -148,6 +151,7 @@ enum class InfoType : u32 {
FreeThreadCount = 24,
ThreadTickCount = 25,
IsSvcPermitted = 26,
+ IoRegionHint = 27,
MesosphereMeta = 65000,
MesosphereCurrentProcess = 65001,
@@ -165,6 +169,7 @@ enum class BreakReason : u32 {
NotificationOnlyFlag = 0x80000000,
};
+DECLARE_ENUM_FLAG_OPERATORS(BreakReason);
enum class DebugEvent : u32 {
CreateProcess = 0,
@@ -248,7 +253,7 @@ struct LastThreadContext {
};
struct PhysicalMemoryInfo {
- PAddr physical_address;
+ u64 physical_address;
u64 virtual_address;
u64 size;
};
@@ -354,7 +359,7 @@ struct LastThreadContext {
};
struct PhysicalMemoryInfo {
- PAddr physical_address;
+ u64 physical_address;
u32 virtual_address;
u32 size;
};
@@ -496,6 +501,19 @@ enum class MemoryMapping : u32 {
Memory = 2,
};
+enum class MapDeviceAddressSpaceFlag : u32 {
+ None = (0U << 0),
+ NotIoRegister = (1U << 0),
+};
+DECLARE_ENUM_FLAG_OPERATORS(MapDeviceAddressSpaceFlag);
+
+union MapDeviceAddressSpaceOption {
+ u32 raw;
+ BitField<0, 16, MemoryPermission> permission;
+ BitField<16, 1, MapDeviceAddressSpaceFlag> flags;
+ BitField<17, 15, u32> reserved;
+};
+
enum class KernelDebugType : u32 {
Thread = 0,
ThreadCallStack = 1,
@@ -580,6 +598,11 @@ enum class ProcessInfoType : u32 {
ProcessState = 0,
};
+enum class ProcessActivity : u32 {
+ Runnable,
+ Paused,
+};
+
struct CreateProcessParameter {
std::array<char, 12> name;
u32 version;
@@ -592,4 +615,12 @@ struct CreateProcessParameter {
};
static_assert(sizeof(CreateProcessParameter) == 0x30);
+constexpr size_t NumSupervisorCalls = 0xC0;
+using SvcAccessFlagSet = std::bitset<NumSupervisorCalls>;
+
+enum class InitialProcessIdRangeInfo : u64 {
+ Minimum = 0,
+ Maximum = 1,
+};
+
} // namespace Kernel::Svc
diff --git a/src/core/hle/kernel/svc_version.h b/src/core/hle/kernel/svc_version.h
new file mode 100644
index 000000000..3eb95aa7b
--- /dev/null
+++ b/src/core/hle/kernel/svc_version.h
@@ -0,0 +1,58 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "common/bit_field.h"
+#include "common/common_types.h"
+#include "common/literals.h"
+
+namespace Kernel::Svc {
+
+constexpr inline u32 ConvertToSvcMajorVersion(u32 sdk) {
+ return sdk + 4;
+}
+constexpr inline u32 ConvertToSdkMajorVersion(u32 svc) {
+ return svc - 4;
+}
+
+constexpr inline u32 ConvertToSvcMinorVersion(u32 sdk) {
+ return sdk;
+}
+constexpr inline u32 ConvertToSdkMinorVersion(u32 svc) {
+ return svc;
+}
+
+union KernelVersion {
+ u32 value;
+ BitField<0, 4, u32> minor_version;
+ BitField<4, 13, u32> major_version;
+};
+
+constexpr inline u32 EncodeKernelVersion(u32 major, u32 minor) {
+ return decltype(KernelVersion::minor_version)::FormatValue(minor) |
+ decltype(KernelVersion::major_version)::FormatValue(major);
+}
+
+constexpr inline u32 GetKernelMajorVersion(u32 encoded) {
+ return decltype(KernelVersion::major_version)::ExtractValue(encoded);
+}
+
+constexpr inline u32 GetKernelMinorVersion(u32 encoded) {
+ return decltype(KernelVersion::minor_version)::ExtractValue(encoded);
+}
+
+// Nintendo doesn't support programs targeting SVC versions < 3.0.
+constexpr inline u32 RequiredKernelMajorVersion = 3;
+constexpr inline u32 RequiredKernelMinorVersion = 0;
+constexpr inline u32 RequiredKernelVersion =
+ EncodeKernelVersion(RequiredKernelMajorVersion, RequiredKernelMinorVersion);
+
+// This is the highest SVC version supported, to be updated on new kernel releases.
+// NOTE: Official kernel versions have SVC major = SDK major + 4, SVC minor = SDK minor.
+constexpr inline u32 SupportedKernelMajorVersion = ConvertToSvcMajorVersion(15);
+constexpr inline u32 SupportedKernelMinorVersion = ConvertToSvcMinorVersion(3);
+constexpr inline u32 SupportedKernelVersion =
+ EncodeKernelVersion(SupportedKernelMajorVersion, SupportedKernelMinorVersion);
+
+} // namespace Kernel::Svc
diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h
deleted file mode 100644
index 1ea8c7fbc..000000000
--- a/src/core/hle/kernel/svc_wrap.h
+++ /dev/null
@@ -1,733 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#pragma once
-
-#include "common/common_types.h"
-#include "core/arm/arm_interface.h"
-#include "core/core.h"
-#include "core/hle/kernel/svc_types.h"
-#include "core/hle/result.h"
-#include "core/memory.h"
-
-namespace Kernel {
-
-static inline u64 Param(const Core::System& system, int n) {
- return system.CurrentArmInterface().GetReg(n);
-}
-
-static inline u32 Param32(const Core::System& system, int n) {
- return static_cast<u32>(system.CurrentArmInterface().GetReg(n));
-}
-
-/**
- * HLE a function return from the current ARM userland process
- * @param system System context
- * @param result Result to return
- */
-static inline void FuncReturn(Core::System& system, u64 result) {
- system.CurrentArmInterface().SetReg(0, result);
-}
-
-static inline void FuncReturn32(Core::System& system, u32 result) {
- system.CurrentArmInterface().SetReg(0, (u64)result);
-}
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Function wrappers that return type Result
-
-template <Result func(Core::System&, u64)>
-void SvcWrap64(Core::System& system) {
- FuncReturn(system, func(system, Param(system, 0)).raw);
-}
-
-template <Result func(Core::System&, u64, u64)>
-void SvcWrap64(Core::System& system) {
- FuncReturn(system, func(system, Param(system, 0), Param(system, 1)).raw);
-}
-
-template <Result func(Core::System&, u32)>
-void SvcWrap64(Core::System& system) {
- FuncReturn(system, func(system, static_cast<u32>(Param(system, 0))).raw);
-}
-
-template <Result func(Core::System&, u32, u32)>
-void SvcWrap64(Core::System& system) {
- FuncReturn(
- system,
- func(system, static_cast<u32>(Param(system, 0)), static_cast<u32>(Param(system, 1))).raw);
-}
-
-// Used by SetThreadActivity
-template <Result func(Core::System&, Handle, Svc::ThreadActivity)>
-void SvcWrap64(Core::System& system) {
- FuncReturn(system, func(system, static_cast<u32>(Param(system, 0)),
- static_cast<Svc::ThreadActivity>(Param(system, 1)))
- .raw);
-}
-
-template <Result func(Core::System&, u32, u64, u64, u64)>
-void SvcWrap64(Core::System& system) {
- FuncReturn(system, func(system, static_cast<u32>(Param(system, 0)), Param(system, 1),
- Param(system, 2), Param(system, 3))
- .raw);
-}
-
-// Used by MapProcessMemory and UnmapProcessMemory
-template <Result func(Core::System&, u64, u32, u64, u64)>
-void SvcWrap64(Core::System& system) {
- FuncReturn(system, func(system, Param(system, 0), static_cast<u32>(Param(system, 1)),
- Param(system, 2), Param(system, 3))
- .raw);
-}
-
-// Used by ControlCodeMemory
-template <Result func(Core::System&, Handle, u32, VAddr, size_t, Svc::MemoryPermission)>
-void SvcWrap64(Core::System& system) {
- FuncReturn(system, func(system, static_cast<Handle>(Param(system, 0)),
- static_cast<u32>(Param(system, 1)), Param(system, 2), Param(system, 3),
- static_cast<Svc::MemoryPermission>(Param(system, 4)))
- .raw);
-}
-
-template <Result func(Core::System&, u32*)>
-void SvcWrap64(Core::System& system) {
- u32 param = 0;
- const u32 retval = func(system, &param).raw;
- system.CurrentArmInterface().SetReg(1, param);
- FuncReturn(system, retval);
-}
-
-template <Result func(Core::System&, u32*, u32)>
-void SvcWrap64(Core::System& system) {
- u32 param_1 = 0;
- const u32 retval = func(system, &param_1, static_cast<u32>(Param(system, 1))).raw;
- system.CurrentArmInterface().SetReg(1, param_1);
- FuncReturn(system, retval);
-}
-
-template <Result func(Core::System&, u32*, u32*)>
-void SvcWrap64(Core::System& system) {
- u32 param_1 = 0;
- u32 param_2 = 0;
- const u32 retval = func(system, &param_1, &param_2).raw;
-
- auto& arm_interface = system.CurrentArmInterface();
- arm_interface.SetReg(1, param_1);
- arm_interface.SetReg(2, param_2);
-
- FuncReturn(system, retval);
-}
-
-template <Result func(Core::System&, u32*, u64)>
-void SvcWrap64(Core::System& system) {
- u32 param_1 = 0;
- const u32 retval = func(system, &param_1, Param(system, 1)).raw;
- system.CurrentArmInterface().SetReg(1, param_1);
- FuncReturn(system, retval);
-}
-
-template <Result func(Core::System&, u32*, u64, u32)>
-void SvcWrap64(Core::System& system) {
- u32 param_1 = 0;
- const u32 retval =
- func(system, &param_1, Param(system, 1), static_cast<u32>(Param(system, 2))).raw;
-
- system.CurrentArmInterface().SetReg(1, param_1);
- FuncReturn(system, retval);
-}
-
-template <Result func(Core::System&, u64*, u32)>
-void SvcWrap64(Core::System& system) {
- u64 param_1 = 0;
- const u32 retval = func(system, &param_1, static_cast<u32>(Param(system, 1))).raw;
-
- system.CurrentArmInterface().SetReg(1, param_1);
- FuncReturn(system, retval);
-}
-
-template <Result func(Core::System&, u64, u32)>
-void SvcWrap64(Core::System& system) {
- FuncReturn(system, func(system, Param(system, 0), static_cast<u32>(Param(system, 1))).raw);
-}
-
-template <Result func(Core::System&, u64*, u64)>
-void SvcWrap64(Core::System& system) {
- u64 param_1 = 0;
- const u32 retval = func(system, &param_1, Param(system, 1)).raw;
-
- system.CurrentArmInterface().SetReg(1, param_1);
- FuncReturn(system, retval);
-}
-
-template <Result func(Core::System&, u64*, u32, u32)>
-void SvcWrap64(Core::System& system) {
- u64 param_1 = 0;
- const u32 retval = func(system, &param_1, static_cast<u32>(Param(system, 1)),
- static_cast<u32>(Param(system, 2)))
- .raw;
-
- system.CurrentArmInterface().SetReg(1, param_1);
- FuncReturn(system, retval);
-}
-
-// Used by GetResourceLimitLimitValue.
-template <Result 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 <Result func(Core::System&, u32, u64)>
-void SvcWrap64(Core::System& system) {
- FuncReturn(system, func(system, static_cast<u32>(Param(system, 0)), Param(system, 1)).raw);
-}
-
-// Used by SetResourceLimitLimitValue
-template <Result func(Core::System&, Handle, LimitableResource, u64)>
-void SvcWrap64(Core::System& system) {
- FuncReturn(system, func(system, static_cast<Handle>(Param(system, 0)),
- static_cast<LimitableResource>(Param(system, 1)), Param(system, 2))
- .raw);
-}
-
-// Used by SetThreadCoreMask
-template <Result func(Core::System&, Handle, s32, u64)>
-void SvcWrap64(Core::System& system) {
- FuncReturn(system, func(system, static_cast<u32>(Param(system, 0)),
- static_cast<s32>(Param(system, 1)), Param(system, 2))
- .raw);
-}
-
-// Used by GetThreadCoreMask
-template <Result func(Core::System&, Handle, s32*, u64*)>
-void SvcWrap64(Core::System& system) {
- s32 param_1 = 0;
- u64 param_2 = 0;
- const Result retval = func(system, static_cast<u32>(Param(system, 2)), &param_1, &param_2);
-
- system.CurrentArmInterface().SetReg(1, param_1);
- system.CurrentArmInterface().SetReg(2, param_2);
- FuncReturn(system, retval.raw);
-}
-
-template <Result func(Core::System&, u64, u64, u32, u32)>
-void SvcWrap64(Core::System& system) {
- FuncReturn(system, func(system, Param(system, 0), Param(system, 1),
- static_cast<u32>(Param(system, 2)), static_cast<u32>(Param(system, 3)))
- .raw);
-}
-
-template <Result func(Core::System&, u64, u64, u32, u64)>
-void SvcWrap64(Core::System& system) {
- FuncReturn(system, func(system, Param(system, 0), Param(system, 1),
- static_cast<u32>(Param(system, 2)), Param(system, 3))
- .raw);
-}
-
-template <Result func(Core::System&, u32, u64, u32)>
-void SvcWrap64(Core::System& system) {
- FuncReturn(system, func(system, static_cast<u32>(Param(system, 0)), Param(system, 1),
- static_cast<u32>(Param(system, 2)))
- .raw);
-}
-
-template <Result func(Core::System&, u64, u64, u64)>
-void SvcWrap64(Core::System& system) {
- FuncReturn(system, func(system, Param(system, 0), Param(system, 1), Param(system, 2)).raw);
-}
-
-template <Result func(Core::System&, u64, u64, u32)>
-void SvcWrap64(Core::System& system) {
- FuncReturn(
- system,
- func(system, Param(system, 0), Param(system, 1), static_cast<u32>(Param(system, 2))).raw);
-}
-
-// Used by SetMemoryPermission
-template <Result func(Core::System&, u64, u64, Svc::MemoryPermission)>
-void SvcWrap64(Core::System& system) {
- FuncReturn(system, func(system, Param(system, 0), Param(system, 1),
- static_cast<Svc::MemoryPermission>(Param(system, 2)))
- .raw);
-}
-
-// Used by MapSharedMemory
-template <Result func(Core::System&, Handle, u64, u64, Svc::MemoryPermission)>
-void SvcWrap64(Core::System& system) {
- FuncReturn(system, func(system, static_cast<Handle>(Param(system, 0)), Param(system, 1),
- Param(system, 2), static_cast<Svc::MemoryPermission>(Param(system, 3)))
- .raw);
-}
-
-template <Result func(Core::System&, u32, u64, u64)>
-void SvcWrap64(Core::System& system) {
- FuncReturn(
- system,
- func(system, static_cast<u32>(Param(system, 0)), Param(system, 1), Param(system, 2)).raw);
-}
-
-// Used by WaitSynchronization
-template <Result func(Core::System&, s32*, u64, s32, s64)>
-void SvcWrap64(Core::System& system) {
- s32 param_1 = 0;
- const u32 retval = func(system, &param_1, Param(system, 1), static_cast<s32>(Param(system, 2)),
- static_cast<s64>(Param(system, 3)))
- .raw;
-
- system.CurrentArmInterface().SetReg(1, param_1);
- FuncReturn(system, retval);
-}
-
-template <Result func(Core::System&, u64, u64, u32, s64)>
-void SvcWrap64(Core::System& system) {
- FuncReturn(system, func(system, Param(system, 0), Param(system, 1),
- static_cast<u32>(Param(system, 2)), static_cast<s64>(Param(system, 3)))
- .raw);
-}
-
-// Used by GetInfo
-template <Result 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),
- static_cast<Handle>(Param(system, 2)), Param(system, 3))
- .raw;
-
- system.CurrentArmInterface().SetReg(1, param_1);
- FuncReturn(system, retval);
-}
-
-template <Result func(Core::System&, u32*, u64, u64, u64, u32, s32)>
-void SvcWrap64(Core::System& system) {
- u32 param_1 = 0;
- const u32 retval = func(system, &param_1, Param(system, 1), Param(system, 2), Param(system, 3),
- static_cast<u32>(Param(system, 4)), static_cast<s32>(Param(system, 5)))
- .raw;
-
- system.CurrentArmInterface().SetReg(1, param_1);
- FuncReturn(system, retval);
-}
-
-// Used by CreateTransferMemory
-template <Result 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<Svc::MemoryPermission>(Param(system, 3)))
- .raw;
-
- system.CurrentArmInterface().SetReg(1, param_1);
- FuncReturn(system, retval);
-}
-
-// Used by CreateCodeMemory
-template <Result func(Core::System&, Handle*, VAddr, size_t)>
-void SvcWrap64(Core::System& system) {
- u32 param_1 = 0;
- const u32 retval = func(system, &param_1, Param(system, 1), Param(system, 2)).raw;
-
- system.CurrentArmInterface().SetReg(1, param_1);
- FuncReturn(system, retval);
-}
-
-template <Result func(Core::System&, Handle*, u64, u32, u32)>
-void SvcWrap64(Core::System& system) {
- u32 param_1 = 0;
- const u32 retval = func(system, &param_1, Param(system, 1), static_cast<u32>(Param(system, 2)),
- static_cast<u32>(Param(system, 3)))
- .raw;
-
- system.CurrentArmInterface().SetReg(1, param_1);
- FuncReturn(system, retval);
-}
-
-// Used by CreateSession
-template <Result func(Core::System&, Handle*, Handle*, u32, u64)>
-void SvcWrap64(Core::System& system) {
- Handle param_1 = 0;
- Handle param_2 = 0;
- const u32 retval = func(system, &param_1, &param_2, static_cast<u32>(Param(system, 2)),
- static_cast<u32>(Param(system, 3)))
- .raw;
-
- system.CurrentArmInterface().SetReg(1, param_1);
- system.CurrentArmInterface().SetReg(2, param_2);
- FuncReturn(system, retval);
-}
-
-// Used by ReplyAndReceive
-template <Result func(Core::System&, s32*, Handle*, s32, Handle, s64)>
-void SvcWrap64(Core::System& system) {
- s32 param_1 = 0;
- s32 num_handles = static_cast<s32>(Param(system, 2));
-
- std::vector<Handle> handles(num_handles);
- system.Memory().ReadBlock(Param(system, 1), handles.data(), num_handles * sizeof(Handle));
-
- const u32 retval = func(system, &param_1, handles.data(), num_handles,
- static_cast<s32>(Param(system, 3)), static_cast<s64>(Param(system, 4)))
- .raw;
-
- system.CurrentArmInterface().SetReg(1, param_1);
- FuncReturn(system, retval);
-}
-
-// Used by WaitForAddress
-template <Result func(Core::System&, u64, Svc::ArbitrationType, s32, s64)>
-void SvcWrap64(Core::System& system) {
- FuncReturn(system,
- func(system, Param(system, 0), static_cast<Svc::ArbitrationType>(Param(system, 1)),
- static_cast<s32>(Param(system, 2)), static_cast<s64>(Param(system, 3)))
- .raw);
-}
-
-// Used by SignalToAddress
-template <Result func(Core::System&, u64, Svc::SignalType, s32, s32)>
-void SvcWrap64(Core::System& system) {
- FuncReturn(system,
- func(system, Param(system, 0), static_cast<Svc::SignalType>(Param(system, 1)),
- static_cast<s32>(Param(system, 2)), static_cast<s32>(Param(system, 3)))
- .raw);
-}
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Function wrappers that return type u32
-
-template <u32 func(Core::System&)>
-void SvcWrap64(Core::System& system) {
- FuncReturn(system, func(system));
-}
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Function wrappers that return type u64
-
-template <u64 func(Core::System&)>
-void SvcWrap64(Core::System& system) {
- FuncReturn(system, func(system));
-}
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-/// Function wrappers that return type void
-
-template <void func(Core::System&)>
-void SvcWrap64(Core::System& system) {
- func(system);
-}
-
-template <void func(Core::System&, u32)>
-void SvcWrap64(Core::System& system) {
- func(system, static_cast<u32>(Param(system, 0)));
-}
-
-template <void func(Core::System&, u32, u64, u64, u64)>
-void SvcWrap64(Core::System& system) {
- func(system, static_cast<u32>(Param(system, 0)), Param(system, 1), Param(system, 2),
- Param(system, 3));
-}
-
-template <void func(Core::System&, s64)>
-void SvcWrap64(Core::System& system) {
- func(system, static_cast<s64>(Param(system, 0)));
-}
-
-template <void func(Core::System&, u64, s32)>
-void SvcWrap64(Core::System& system) {
- func(system, Param(system, 0), static_cast<s32>(Param(system, 1)));
-}
-
-template <void func(Core::System&, u64, u64)>
-void SvcWrap64(Core::System& system) {
- func(system, Param(system, 0), Param(system, 1));
-}
-
-template <void func(Core::System&, u64, u64, u64)>
-void SvcWrap64(Core::System& system) {
- func(system, Param(system, 0), Param(system, 1), Param(system, 2));
-}
-
-template <void func(Core::System&, u32, u64, u64)>
-void SvcWrap64(Core::System& system) {
- func(system, static_cast<u32>(Param(system, 0)), Param(system, 1), Param(system, 2));
-}
-
-// Used by QueryMemory32, ArbitrateLock32
-template <Result func(Core::System&, u32, u32, u32)>
-void SvcWrap32(Core::System& system) {
- FuncReturn32(system,
- func(system, Param32(system, 0), Param32(system, 1), Param32(system, 2)).raw);
-}
-
-// Used by Break32
-template <void func(Core::System&, u32, u32, u32)>
-void SvcWrap32(Core::System& system) {
- func(system, Param32(system, 0), Param32(system, 1), Param32(system, 2));
-}
-
-// Used by ExitProcess32, ExitThread32
-template <void func(Core::System&)>
-void SvcWrap32(Core::System& system) {
- func(system);
-}
-
-// Used by GetCurrentProcessorNumber32
-template <u32 func(Core::System&)>
-void SvcWrap32(Core::System& system) {
- FuncReturn32(system, func(system));
-}
-
-// Used by SleepThread32
-template <void func(Core::System&, u32, u32)>
-void SvcWrap32(Core::System& system) {
- func(system, Param32(system, 0), Param32(system, 1));
-}
-
-// Used by CreateThread32
-template <Result func(Core::System&, Handle*, u32, u32, u32, u32, s32)>
-void SvcWrap32(Core::System& system) {
- Handle param_1 = 0;
-
- const u32 retval = func(system, &param_1, Param32(system, 0), Param32(system, 1),
- Param32(system, 2), Param32(system, 3), Param32(system, 4))
- .raw;
-
- system.CurrentArmInterface().SetReg(1, param_1);
- FuncReturn(system, retval);
-}
-
-// Used by GetInfo32
-template <Result func(Core::System&, u32*, u32*, u32, u32, u32, u32)>
-void SvcWrap32(Core::System& system) {
- u32 param_1 = 0;
- u32 param_2 = 0;
-
- const u32 retval = func(system, &param_1, &param_2, Param32(system, 0), Param32(system, 1),
- Param32(system, 2), Param32(system, 3))
- .raw;
-
- system.CurrentArmInterface().SetReg(1, param_1);
- system.CurrentArmInterface().SetReg(2, param_2);
- FuncReturn(system, retval);
-}
-
-// Used by GetThreadPriority32, ConnectToNamedPort32
-template <Result func(Core::System&, u32*, u32)>
-void SvcWrap32(Core::System& system) {
- u32 param_1 = 0;
- const u32 retval = func(system, &param_1, Param32(system, 1)).raw;
- system.CurrentArmInterface().SetReg(1, param_1);
- FuncReturn(system, retval);
-}
-
-// Used by GetThreadId32
-template <Result func(Core::System&, u32*, u32*, u32)>
-void SvcWrap32(Core::System& system) {
- u32 param_1 = 0;
- u32 param_2 = 0;
-
- const u32 retval = func(system, &param_1, &param_2, Param32(system, 1)).raw;
- system.CurrentArmInterface().SetReg(1, param_1);
- system.CurrentArmInterface().SetReg(2, param_2);
- FuncReturn(system, retval);
-}
-
-// Used by GetSystemTick32
-template <void func(Core::System&, u32*, u32*)>
-void SvcWrap32(Core::System& system) {
- u32 param_1 = 0;
- u32 param_2 = 0;
-
- func(system, &param_1, &param_2);
- system.CurrentArmInterface().SetReg(0, param_1);
- system.CurrentArmInterface().SetReg(1, param_2);
-}
-
-// Used by CreateEvent32
-template <Result func(Core::System&, Handle*, Handle*)>
-void SvcWrap32(Core::System& system) {
- Handle param_1 = 0;
- Handle param_2 = 0;
-
- const u32 retval = func(system, &param_1, &param_2).raw;
- system.CurrentArmInterface().SetReg(1, param_1);
- system.CurrentArmInterface().SetReg(2, param_2);
- FuncReturn(system, retval);
-}
-
-// Used by GetThreadId32
-template <Result func(Core::System&, Handle, u32*, u32*, u32*)>
-void SvcWrap32(Core::System& system) {
- u32 param_1 = 0;
- u32 param_2 = 0;
- u32 param_3 = 0;
-
- const u32 retval = func(system, Param32(system, 2), &param_1, &param_2, &param_3).raw;
- system.CurrentArmInterface().SetReg(1, param_1);
- system.CurrentArmInterface().SetReg(2, param_2);
- system.CurrentArmInterface().SetReg(3, param_3);
- FuncReturn(system, retval);
-}
-
-// Used by GetThreadCoreMask32
-template <Result func(Core::System&, Handle, s32*, u32*, u32*)>
-void SvcWrap32(Core::System& system) {
- s32 param_1 = 0;
- u32 param_2 = 0;
- u32 param_3 = 0;
-
- const u32 retval = func(system, Param32(system, 2), &param_1, &param_2, &param_3).raw;
- system.CurrentArmInterface().SetReg(1, param_1);
- system.CurrentArmInterface().SetReg(2, param_2);
- system.CurrentArmInterface().SetReg(3, param_3);
- FuncReturn(system, retval);
-}
-
-// Used by SignalProcessWideKey32
-template <void func(Core::System&, u32, s32)>
-void SvcWrap32(Core::System& system) {
- func(system, static_cast<u32>(Param(system, 0)), static_cast<s32>(Param(system, 1)));
-}
-
-// Used by SetThreadActivity32
-template <Result func(Core::System&, Handle, Svc::ThreadActivity)>
-void SvcWrap32(Core::System& system) {
- const u32 retval = func(system, static_cast<Handle>(Param(system, 0)),
- static_cast<Svc::ThreadActivity>(Param(system, 1)))
- .raw;
- FuncReturn(system, retval);
-}
-
-// Used by SetThreadPriority32
-template <Result func(Core::System&, Handle, u32)>
-void SvcWrap32(Core::System& system) {
- const u32 retval =
- func(system, static_cast<Handle>(Param(system, 0)), static_cast<u32>(Param(system, 1))).raw;
- FuncReturn(system, retval);
-}
-
-// Used by SetMemoryAttribute32
-template <Result func(Core::System&, Handle, u32, u32, u32)>
-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<u32>(Param(system, 3)))
- .raw;
- FuncReturn(system, retval);
-}
-
-// Used by MapSharedMemory32
-template <Result 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 <Result func(Core::System&, Handle, s32, u32, u32)>
-void SvcWrap32(Core::System& system) {
- const u32 retval =
- func(system, static_cast<Handle>(Param(system, 0)), static_cast<s32>(Param(system, 1)),
- static_cast<u32>(Param(system, 2)), static_cast<u32>(Param(system, 3)))
- .raw;
- FuncReturn(system, retval);
-}
-
-// Used by WaitProcessWideKeyAtomic32
-template <Result func(Core::System&, u32, u32, Handle, u32, u32)>
-void SvcWrap32(Core::System& system) {
- const u32 retval =
- func(system, static_cast<u32>(Param(system, 0)), static_cast<u32>(Param(system, 1)),
- static_cast<Handle>(Param(system, 2)), static_cast<u32>(Param(system, 3)),
- static_cast<u32>(Param(system, 4)))
- .raw;
- FuncReturn(system, retval);
-}
-
-// Used by WaitForAddress32
-template <Result func(Core::System&, u32, Svc::ArbitrationType, s32, u32, u32)>
-void SvcWrap32(Core::System& system) {
- const u32 retval = func(system, static_cast<u32>(Param(system, 0)),
- static_cast<Svc::ArbitrationType>(Param(system, 1)),
- static_cast<s32>(Param(system, 2)), static_cast<u32>(Param(system, 3)),
- static_cast<u32>(Param(system, 4)))
- .raw;
- FuncReturn(system, retval);
-}
-
-// Used by SignalToAddress32
-template <Result func(Core::System&, u32, Svc::SignalType, s32, s32)>
-void SvcWrap32(Core::System& system) {
- const u32 retval = func(system, static_cast<u32>(Param(system, 0)),
- static_cast<Svc::SignalType>(Param(system, 1)),
- static_cast<s32>(Param(system, 2)), static_cast<s32>(Param(system, 3)))
- .raw;
- FuncReturn(system, retval);
-}
-
-// Used by SendSyncRequest32, ArbitrateUnlock32
-template <Result func(Core::System&, u32)>
-void SvcWrap32(Core::System& system) {
- FuncReturn(system, func(system, static_cast<u32>(Param(system, 0))).raw);
-}
-
-// Used by CreateTransferMemory32
-template <Result 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),
- static_cast<Svc::MemoryPermission>(Param32(system, 3)))
- .raw;
- system.CurrentArmInterface().SetReg(1, handle);
- FuncReturn(system, retval);
-}
-
-// Used by WaitSynchronization32
-template <Result func(Core::System&, u32, u32, s32, u32, s32*)>
-void SvcWrap32(Core::System& system) {
- s32 param_1 = 0;
- const u32 retval = func(system, Param32(system, 0), Param32(system, 1), Param32(system, 2),
- Param32(system, 3), &param_1)
- .raw;
- system.CurrentArmInterface().SetReg(1, param_1);
- FuncReturn(system, retval);
-}
-
-// Used by CreateCodeMemory32
-template <Result func(Core::System&, Handle*, u32, u32)>
-void SvcWrap32(Core::System& system) {
- Handle handle = 0;
-
- const u32 retval = func(system, &handle, Param32(system, 1), Param32(system, 2)).raw;
-
- system.CurrentArmInterface().SetReg(1, handle);
- FuncReturn(system, retval);
-}
-
-// Used by ControlCodeMemory32
-template <Result func(Core::System&, Handle, u32, u64, u64, Svc::MemoryPermission)>
-void SvcWrap32(Core::System& system) {
- const u32 retval =
- func(system, Param32(system, 0), Param32(system, 1), Param(system, 2), Param(system, 4),
- static_cast<Svc::MemoryPermission>(Param32(system, 6)))
- .raw;
-
- FuncReturn(system, retval);
-}
-
-// Used by Invalidate/Store/FlushProcessDataCache32
-template <Result func(Core::System&, Handle, u64, u64)>
-void SvcWrap32(Core::System& system) {
- const u64 address = (Param(system, 3) << 32) | Param(system, 2);
- const u64 size = (Param(system, 4) << 32) | Param(system, 1);
- FuncReturn32(system, func(system, Param32(system, 0), address, size).raw);
-}
-
-} // namespace Kernel
diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp
index 6d1084fd1..6c29cb613 100644
--- a/src/core/hle/service/acc/acc.cpp
+++ b/src/core/hle/service/acc/acc.cpp
@@ -15,7 +15,6 @@
#include "core/core_timing.h"
#include "core/file_sys/control_metadata.h"
#include "core/file_sys/patch_manager.h"
-#include "core/hle/ipc_helpers.h"
#include "core/hle/service/acc/acc.h"
#include "core/hle/service/acc/acc_aa.h"
#include "core/hle/service/acc/acc_su.h"
@@ -25,16 +24,12 @@
#include "core/hle/service/acc/errors.h"
#include "core/hle/service/acc/profile_manager.h"
#include "core/hle/service/glue/glue_manager.h"
+#include "core/hle/service/ipc_helpers.h"
+#include "core/hle/service/server_manager.h"
#include "core/loader/loader.h"
namespace Service::Account {
-constexpr Result ERR_INVALID_USER_ID{ErrorModule::Account, 20};
-constexpr Result ERR_INVALID_APPLICATION_ID{ErrorModule::Account, 22};
-constexpr Result ERR_INVALID_BUFFER{ErrorModule::Account, 30};
-constexpr Result ERR_INVALID_BUFFER_SIZE{ErrorModule::Account, 31};
-constexpr Result ERR_FAILED_SAVE_DATA{ErrorModule::Account, 100};
-
// Thumbnails are hard coded to be at least this size
constexpr std::size_t THUMBNAIL_SIZE = 0x24000;
@@ -76,6 +71,8 @@ public:
{141, nullptr, "RefreshNetworkServiceLicenseCacheAsync"}, // 5.0.0+
{142, nullptr, "RefreshNetworkServiceLicenseCacheAsyncIfSecondsElapsed"}, // 5.0.0+
{150, nullptr, "CreateAuthorizationRequest"},
+ {160, nullptr, "RequiresUpdateNetworkServiceAccountIdTokenCache"},
+ {161, nullptr, "RequireReauthenticationOfNetworkServiceAccount"},
};
// clang-format on
@@ -136,7 +133,10 @@ public:
{140, nullptr, "GetNetworkServiceLicenseCache"}, // 5.0.0+
{141, nullptr, "RefreshNetworkServiceLicenseCacheAsync"}, // 5.0.0+
{142, nullptr, "RefreshNetworkServiceLicenseCacheAsyncIfSecondsElapsed"}, // 5.0.0+
+ {143, nullptr, "GetNetworkServiceLicenseCacheEx"},
{150, nullptr, "CreateAuthorizationRequest"},
+ {160, nullptr, "RequiresUpdateNetworkServiceAccountIdTokenCache"},
+ {161, nullptr, "RequireReauthenticationOfNetworkServiceAccount"},
{200, nullptr, "IsRegistered"},
{201, nullptr, "RegisterAsync"},
{202, nullptr, "UnregisterAsync"},
@@ -242,6 +242,7 @@ public:
{100, nullptr, "GetRequestWithTheme"},
{101, nullptr, "IsNetworkServiceAccountReplaced"},
{199, nullptr, "GetUrlForIntroductionOfExtraMembership"}, // 2.0.0 - 5.1.0
+ {200, nullptr, "ApplyAsyncWithAuthorizedToken"},
};
// clang-format on
@@ -288,7 +289,7 @@ public:
}
protected:
- void Get(Kernel::HLERequestContext& ctx) {
+ void Get(HLERequestContext& ctx) {
LOG_DEBUG(Service_ACC, "called user_id=0x{}", user_id.RawString());
ProfileBase profile_base{};
UserData data{};
@@ -305,7 +306,7 @@ protected:
}
}
- void GetBase(Kernel::HLERequestContext& ctx) {
+ void GetBase(HLERequestContext& ctx) {
LOG_DEBUG(Service_ACC, "called user_id=0x{}", user_id.RawString());
ProfileBase profile_base{};
if (profile_manager.GetProfileBase(user_id, profile_base)) {
@@ -319,7 +320,7 @@ protected:
}
}
- void LoadImage(Kernel::HLERequestContext& ctx) {
+ void LoadImage(HLERequestContext& ctx) {
LOG_DEBUG(Service_ACC, "called");
IPC::ResponseBuilder rb{ctx, 3};
@@ -346,7 +347,7 @@ protected:
rb.Push<u32>(size);
}
- void GetImageSize(Kernel::HLERequestContext& ctx) {
+ void GetImageSize(HLERequestContext& ctx) {
LOG_DEBUG(Service_ACC, "called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
@@ -363,7 +364,7 @@ protected:
}
}
- void Store(Kernel::HLERequestContext& ctx) {
+ void Store(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto base = rp.PopRaw<ProfileBase>();
@@ -377,7 +378,7 @@ protected:
if (user_data.size() < sizeof(UserData)) {
LOG_ERROR(Service_ACC, "UserData buffer too small!");
IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ERR_INVALID_BUFFER);
+ rb.Push(Account::ResultInvalidArrayLength);
return;
}
@@ -387,7 +388,7 @@ protected:
if (!profile_manager.SetProfileBaseAndData(user_id, base, data)) {
LOG_ERROR(Service_ACC, "Failed to update user data and base!");
IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ERR_FAILED_SAVE_DATA);
+ rb.Push(Account::ResultAccountUpdateFailed);
return;
}
@@ -395,7 +396,7 @@ protected:
rb.Push(ResultSuccess);
}
- void StoreWithImage(Kernel::HLERequestContext& ctx) {
+ void StoreWithImage(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto base = rp.PopRaw<ProfileBase>();
@@ -410,7 +411,7 @@ protected:
if (user_data.size() < sizeof(UserData)) {
LOG_ERROR(Service_ACC, "UserData buffer too small!");
IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ERR_INVALID_BUFFER);
+ rb.Push(Account::ResultInvalidArrayLength);
return;
}
@@ -425,7 +426,7 @@ protected:
!profile_manager.SetProfileBaseAndData(user_id, base, data)) {
LOG_ERROR(Service_ACC, "Failed to update profile data, base, and image!");
IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ERR_FAILED_SAVE_DATA);
+ rb.Push(Account::ResultAccountUpdateFailed);
return;
}
@@ -492,7 +493,7 @@ public:
}
~EnsureTokenIdCacheAsyncInterface() = default;
- void LoadIdTokenCache(Kernel::HLERequestContext& ctx) {
+ void LoadIdTokenCache(HLERequestContext& ctx) {
LOG_WARNING(Service_ACC, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
@@ -535,14 +536,14 @@ public:
}
private:
- void CheckAvailability(Kernel::HLERequestContext& ctx) {
+ void CheckAvailability(HLERequestContext& ctx) {
LOG_DEBUG(Service_ACC, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(false); // TODO: Check when this is supposed to return true and when not
}
- void GetAccountId(Kernel::HLERequestContext& ctx) {
+ void GetAccountId(HLERequestContext& ctx) {
LOG_DEBUG(Service_ACC, "called");
IPC::ResponseBuilder rb{ctx, 4};
@@ -550,7 +551,7 @@ private:
rb.PushRaw<u64>(profile_manager->GetLastOpenedUser().Hash());
}
- void EnsureIdTokenCacheAsync(Kernel::HLERequestContext& ctx) {
+ void EnsureIdTokenCacheAsync(HLERequestContext& ctx) {
LOG_WARNING(Service_ACC, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -558,13 +559,13 @@ private:
rb.PushIpcInterface(ensure_token_id);
}
- void LoadIdTokenCache(Kernel::HLERequestContext& ctx) {
+ void LoadIdTokenCache(HLERequestContext& ctx) {
LOG_WARNING(Service_ACC, "(STUBBED) called");
ensure_token_id->LoadIdTokenCache(ctx);
}
- void GetNintendoAccountUserResourceCacheForApplication(Kernel::HLERequestContext& ctx) {
+ void GetNintendoAccountUserResourceCacheForApplication(HLERequestContext& ctx) {
LOG_WARNING(Service_ACC, "(STUBBED) called");
std::vector<u8> nas_user_base_for_application(0x68);
@@ -580,7 +581,7 @@ private:
rb.PushRaw<u64>(profile_manager->GetLastOpenedUser().Hash());
}
- void StoreOpenContext(Kernel::HLERequestContext& ctx) {
+ void StoreOpenContext(HLERequestContext& ctx) {
LOG_DEBUG(Service_ACC, "called");
profile_manager->StoreOpenedUsers();
@@ -647,9 +648,11 @@ public:
{0, nullptr, "EnsureAuthenticationTokenCacheAsync"},
{1, nullptr, "LoadAuthenticationTokenCache"},
{2, nullptr, "InvalidateAuthenticationTokenCache"},
+ {3, nullptr, "IsDeviceAuthenticationTokenCacheAvailable"},
{10, nullptr, "EnsureEdgeTokenCacheAsync"},
{11, nullptr, "LoadEdgeTokenCache"},
{12, nullptr, "InvalidateEdgeTokenCache"},
+ {13, nullptr, "IsEdgeTokenCacheAvailable"},
{20, nullptr, "EnsureApplicationAuthenticationCacheAsync"},
{21, nullptr, "LoadApplicationAuthenticationTokenCache"},
{22, nullptr, "LoadApplicationNetworkServiceClientConfigCache"},
@@ -680,14 +683,14 @@ public:
}
};
-void Module::Interface::GetUserCount(Kernel::HLERequestContext& ctx) {
+void Module::Interface::GetUserCount(HLERequestContext& ctx) {
LOG_DEBUG(Service_ACC, "called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push<u32>(static_cast<u32>(profile_manager->GetUserCount()));
}
-void Module::Interface::GetUserExistence(Kernel::HLERequestContext& ctx) {
+void Module::Interface::GetUserExistence(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
Common::UUID user_id = rp.PopRaw<Common::UUID>();
LOG_DEBUG(Service_ACC, "called user_id=0x{}", user_id.RawString());
@@ -697,28 +700,28 @@ void Module::Interface::GetUserExistence(Kernel::HLERequestContext& ctx) {
rb.Push(profile_manager->UserExists(user_id));
}
-void Module::Interface::ListAllUsers(Kernel::HLERequestContext& ctx) {
+void Module::Interface::ListAllUsers(HLERequestContext& ctx) {
LOG_DEBUG(Service_ACC, "called");
ctx.WriteBuffer(profile_manager->GetAllUsers());
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
-void Module::Interface::ListOpenUsers(Kernel::HLERequestContext& ctx) {
+void Module::Interface::ListOpenUsers(HLERequestContext& ctx) {
LOG_DEBUG(Service_ACC, "called");
ctx.WriteBuffer(profile_manager->GetOpenUsers());
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
-void Module::Interface::GetLastOpenedUser(Kernel::HLERequestContext& ctx) {
+void Module::Interface::GetLastOpenedUser(HLERequestContext& ctx) {
LOG_DEBUG(Service_ACC, "called");
IPC::ResponseBuilder rb{ctx, 6};
rb.Push(ResultSuccess);
rb.PushRaw<Common::UUID>(profile_manager->GetLastOpenedUser());
}
-void Module::Interface::GetProfile(Kernel::HLERequestContext& ctx) {
+void Module::Interface::GetProfile(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
Common::UUID user_id = rp.PopRaw<Common::UUID>();
LOG_DEBUG(Service_ACC, "called user_id=0x{}", user_id.RawString());
@@ -728,20 +731,20 @@ void Module::Interface::GetProfile(Kernel::HLERequestContext& ctx) {
rb.PushIpcInterface<IProfile>(system, user_id, *profile_manager);
}
-void Module::Interface::IsUserRegistrationRequestPermitted(Kernel::HLERequestContext& ctx) {
+void Module::Interface::IsUserRegistrationRequestPermitted(HLERequestContext& ctx) {
LOG_WARNING(Service_ACC, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(profile_manager->CanSystemRegisterUser());
}
-void Module::Interface::InitializeApplicationInfo(Kernel::HLERequestContext& ctx) {
+void Module::Interface::InitializeApplicationInfo(HLERequestContext& ctx) {
LOG_DEBUG(Service_ACC, "called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(InitializeApplicationInfoBase());
}
-void Module::Interface::InitializeApplicationInfoRestricted(Kernel::HLERequestContext& ctx) {
+void Module::Interface::InitializeApplicationInfoRestricted(HLERequestContext& ctx) {
LOG_WARNING(Service_ACC, "(Partial implementation) called");
// TODO(ogniK): We require checking if the user actually owns the title and what not. As of
@@ -755,18 +758,18 @@ void Module::Interface::InitializeApplicationInfoRestricted(Kernel::HLERequestCo
Result Module::Interface::InitializeApplicationInfoBase() {
if (application_info) {
LOG_ERROR(Service_ACC, "Application already initialized");
- return ERR_ACCOUNTINFO_ALREADY_INITIALIZED;
+ return Account::ResultApplicationInfoAlreadyInitialized;
}
// TODO(ogniK): This should be changed to reflect the target process for when we have multiple
// processes emulated. As we don't actually have pid support we should assume we're just using
// our own process
const auto launch_property =
- system.GetARPManager().GetLaunchProperty(system.GetCurrentProcessProgramID());
+ system.GetARPManager().GetLaunchProperty(system.GetApplicationProcessProgramID());
if (launch_property.Failed()) {
LOG_ERROR(Service_ACC, "Failed to get launch property");
- return ERR_ACCOUNTINFO_BAD_APPLICATION;
+ return Account::ResultInvalidApplication;
}
switch (launch_property->base_game_storage_id) {
@@ -782,23 +785,23 @@ Result Module::Interface::InitializeApplicationInfoBase() {
default:
LOG_ERROR(Service_ACC, "Invalid game storage ID! storage_id={}",
launch_property->base_game_storage_id);
- return ERR_ACCOUNTINFO_BAD_APPLICATION;
+ return Account::ResultInvalidApplication;
}
LOG_WARNING(Service_ACC, "ApplicationInfo init required");
- // TODO(ogniK): Actual initalization here
+ // TODO(ogniK): Actual initialization here
return ResultSuccess;
}
-void Module::Interface::GetBaasAccountManagerForApplication(Kernel::HLERequestContext& ctx) {
+void Module::Interface::GetBaasAccountManagerForApplication(HLERequestContext& ctx) {
LOG_DEBUG(Service_ACC, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IManagerForApplication>(system, profile_manager);
}
-void Module::Interface::IsUserAccountSwitchLocked(Kernel::HLERequestContext& ctx) {
+void Module::Interface::IsUserAccountSwitchLocked(HLERequestContext& ctx) {
LOG_DEBUG(Service_ACC, "called");
FileSys::NACP nacp;
const auto res = system.GetAppLoader().ReadControlData(nacp);
@@ -806,7 +809,7 @@ void Module::Interface::IsUserAccountSwitchLocked(Kernel::HLERequestContext& ctx
bool is_locked = false;
if (res != Loader::ResultStatus::Success) {
- const FileSys::PatchManager pm{system.GetCurrentProcessProgramID(),
+ const FileSys::PatchManager pm{system.GetApplicationProcessProgramID(),
system.GetFileSystemController(),
system.GetContentProvider()};
const auto nacp_unique = pm.GetControlMetadata().first;
@@ -825,14 +828,14 @@ void Module::Interface::IsUserAccountSwitchLocked(Kernel::HLERequestContext& ctx
rb.Push(is_locked);
}
-void Module::Interface::InitializeApplicationInfoV2(Kernel::HLERequestContext& ctx) {
+void Module::Interface::InitializeApplicationInfoV2(HLERequestContext& ctx) {
LOG_WARNING(Service_ACC, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
-void Module::Interface::GetProfileEditor(Kernel::HLERequestContext& ctx) {
+void Module::Interface::GetProfileEditor(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
Common::UUID user_id = rp.PopRaw<Common::UUID>();
@@ -843,7 +846,7 @@ void Module::Interface::GetProfileEditor(Kernel::HLERequestContext& ctx) {
rb.PushIpcInterface<IProfileEditor>(system, user_id, *profile_manager);
}
-void Module::Interface::ListQualifiedUsers(Kernel::HLERequestContext& ctx) {
+void Module::Interface::ListQualifiedUsers(HLERequestContext& ctx) {
LOG_DEBUG(Service_ACC, "called");
// All users should be qualified. We don't actually have parental control or anything to do with
@@ -854,7 +857,7 @@ void Module::Interface::ListQualifiedUsers(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void Module::Interface::ListOpenContextStoredUsers(Kernel::HLERequestContext& ctx) {
+void Module::Interface::ListOpenContextStoredUsers(HLERequestContext& ctx) {
LOG_DEBUG(Service_ACC, "called");
ctx.WriteBuffer(profile_manager->GetStoredOpenedUsers());
@@ -862,7 +865,7 @@ void Module::Interface::ListOpenContextStoredUsers(Kernel::HLERequestContext& ct
rb.Push(ResultSuccess);
}
-void Module::Interface::StoreSaveDataThumbnailApplication(Kernel::HLERequestContext& ctx) {
+void Module::Interface::StoreSaveDataThumbnailApplication(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto uuid = rp.PopRaw<Common::UUID>();
@@ -875,7 +878,7 @@ void Module::Interface::StoreSaveDataThumbnailApplication(Kernel::HLERequestCont
StoreSaveDataThumbnail(ctx, uuid, tid);
}
-void Module::Interface::StoreSaveDataThumbnailSystem(Kernel::HLERequestContext& ctx) {
+void Module::Interface::StoreSaveDataThumbnailSystem(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto uuid = rp.PopRaw<Common::UUID>();
const auto tid = rp.Pop<u64_le>();
@@ -884,26 +887,26 @@ void Module::Interface::StoreSaveDataThumbnailSystem(Kernel::HLERequestContext&
StoreSaveDataThumbnail(ctx, uuid, tid);
}
-void Module::Interface::StoreSaveDataThumbnail(Kernel::HLERequestContext& ctx,
- const Common::UUID& uuid, const u64 tid) {
+void Module::Interface::StoreSaveDataThumbnail(HLERequestContext& ctx, const Common::UUID& uuid,
+ const u64 tid) {
IPC::ResponseBuilder rb{ctx, 2};
if (tid == 0) {
LOG_ERROR(Service_ACC, "TitleID is not valid!");
- rb.Push(ERR_INVALID_APPLICATION_ID);
+ rb.Push(Account::ResultInvalidApplication);
return;
}
if (uuid.IsInvalid()) {
LOG_ERROR(Service_ACC, "User ID is not valid!");
- rb.Push(ERR_INVALID_USER_ID);
+ rb.Push(Account::ResultInvalidUserId);
return;
}
const auto thumbnail_size = ctx.GetReadBufferSize();
if (thumbnail_size != THUMBNAIL_SIZE) {
LOG_ERROR(Service_ACC, "Buffer size is empty! size={:X} expecting {:X}", thumbnail_size,
THUMBNAIL_SIZE);
- rb.Push(ERR_INVALID_BUFFER_SIZE);
+ rb.Push(Account::ResultInvalidArrayLength);
return;
}
@@ -911,7 +914,7 @@ void Module::Interface::StoreSaveDataThumbnail(Kernel::HLERequestContext& ctx,
rb.Push(ResultSuccess);
}
-void Module::Interface::TrySelectUserWithoutInteraction(Kernel::HLERequestContext& ctx) {
+void Module::Interface::TrySelectUserWithoutInteraction(HLERequestContext& ctx) {
LOG_DEBUG(Service_ACC, "called");
// A u8 is passed into this function which we can safely ignore. It's to determine if we have
// access to use the network or not by the looks of it
@@ -942,18 +945,20 @@ Module::Interface::Interface(std::shared_ptr<Module> module_,
Module::Interface::~Interface() = default;
-void InstallInterfaces(Core::System& system) {
+void LoopProcess(Core::System& system) {
auto module = std::make_shared<Module>();
auto profile_manager = std::make_shared<ProfileManager>();
-
- std::make_shared<ACC_AA>(module, profile_manager, system)
- ->InstallAsService(system.ServiceManager());
- std::make_shared<ACC_SU>(module, profile_manager, system)
- ->InstallAsService(system.ServiceManager());
- std::make_shared<ACC_U0>(module, profile_manager, system)
- ->InstallAsService(system.ServiceManager());
- std::make_shared<ACC_U1>(module, profile_manager, system)
- ->InstallAsService(system.ServiceManager());
+ auto server_manager = std::make_unique<ServerManager>(system);
+
+ server_manager->RegisterNamedService("acc:aa",
+ std::make_shared<ACC_AA>(module, profile_manager, system));
+ server_manager->RegisterNamedService("acc:su",
+ std::make_shared<ACC_SU>(module, profile_manager, system));
+ server_manager->RegisterNamedService("acc:u0",
+ std::make_shared<ACC_U0>(module, profile_manager, system));
+ server_manager->RegisterNamedService("acc:u1",
+ std::make_shared<ACC_U1>(module, profile_manager, system));
+ ServerManager::RunServer(std::move(server_manager));
}
} // namespace Service::Account
diff --git a/src/core/hle/service/acc/acc.h b/src/core/hle/service/acc/acc.h
index 9411b0b92..6b4735c2f 100644
--- a/src/core/hle/service/acc/acc.h
+++ b/src/core/hle/service/acc/acc.h
@@ -20,28 +20,28 @@ public:
const char* name);
~Interface() override;
- void GetUserCount(Kernel::HLERequestContext& ctx);
- void GetUserExistence(Kernel::HLERequestContext& ctx);
- void ListAllUsers(Kernel::HLERequestContext& ctx);
- void ListOpenUsers(Kernel::HLERequestContext& ctx);
- void GetLastOpenedUser(Kernel::HLERequestContext& ctx);
- void GetProfile(Kernel::HLERequestContext& ctx);
- void InitializeApplicationInfo(Kernel::HLERequestContext& ctx);
- void InitializeApplicationInfoRestricted(Kernel::HLERequestContext& ctx);
- void GetBaasAccountManagerForApplication(Kernel::HLERequestContext& ctx);
- void IsUserRegistrationRequestPermitted(Kernel::HLERequestContext& ctx);
- void TrySelectUserWithoutInteraction(Kernel::HLERequestContext& ctx);
- void IsUserAccountSwitchLocked(Kernel::HLERequestContext& ctx);
- void InitializeApplicationInfoV2(Kernel::HLERequestContext& ctx);
- void GetProfileEditor(Kernel::HLERequestContext& ctx);
- void ListQualifiedUsers(Kernel::HLERequestContext& ctx);
- void ListOpenContextStoredUsers(Kernel::HLERequestContext& ctx);
- void StoreSaveDataThumbnailApplication(Kernel::HLERequestContext& ctx);
- void StoreSaveDataThumbnailSystem(Kernel::HLERequestContext& ctx);
+ void GetUserCount(HLERequestContext& ctx);
+ void GetUserExistence(HLERequestContext& ctx);
+ void ListAllUsers(HLERequestContext& ctx);
+ void ListOpenUsers(HLERequestContext& ctx);
+ void GetLastOpenedUser(HLERequestContext& ctx);
+ void GetProfile(HLERequestContext& ctx);
+ void InitializeApplicationInfo(HLERequestContext& ctx);
+ void InitializeApplicationInfoRestricted(HLERequestContext& ctx);
+ void GetBaasAccountManagerForApplication(HLERequestContext& ctx);
+ void IsUserRegistrationRequestPermitted(HLERequestContext& ctx);
+ void TrySelectUserWithoutInteraction(HLERequestContext& ctx);
+ void IsUserAccountSwitchLocked(HLERequestContext& ctx);
+ void InitializeApplicationInfoV2(HLERequestContext& ctx);
+ void GetProfileEditor(HLERequestContext& ctx);
+ void ListQualifiedUsers(HLERequestContext& ctx);
+ void ListOpenContextStoredUsers(HLERequestContext& ctx);
+ void StoreSaveDataThumbnailApplication(HLERequestContext& ctx);
+ void StoreSaveDataThumbnailSystem(HLERequestContext& ctx);
private:
Result InitializeApplicationInfoBase();
- void StoreSaveDataThumbnail(Kernel::HLERequestContext& ctx, const Common::UUID& uuid,
+ void StoreSaveDataThumbnail(HLERequestContext& ctx, const Common::UUID& uuid,
const u64 tid);
enum class ApplicationType : u32_le {
@@ -67,7 +67,6 @@ public:
};
};
-/// Registers all ACC services with the specified service manager.
-void InstallInterfaces(Core::System& system);
+void LoopProcess(Core::System& system);
} // namespace Service::Account
diff --git a/src/core/hle/service/acc/acc_su.cpp b/src/core/hle/service/acc/acc_su.cpp
index b6bfd6155..d9882ecd3 100644
--- a/src/core/hle/service/acc/acc_su.cpp
+++ b/src/core/hle/service/acc/acc_su.cpp
@@ -55,6 +55,10 @@ ACC_SU::ACC_SU(std::shared_ptr<Module> module_, std::shared_ptr<ProfileManager>
{290, nullptr, "ProxyProcedureForGuestLoginWithNintendoAccount"},
{291, nullptr, "ProxyProcedureForFloatingRegistrationWithNintendoAccount"},
{299, nullptr, "SuspendBackgroundDaemon"},
+ {900, nullptr, "SetUserUnqualifiedForDebug"},
+ {901, nullptr, "UnsetUserUnqualifiedForDebug"},
+ {902, nullptr, "ListUsersUnqualifiedForDebug"},
+ {910, nullptr, "RefreshFirmwareSettingsForDebug"},
{997, nullptr, "DebugInvalidateTokenCacheForUser"},
{998, nullptr, "DebugSetUserStateClose"},
{999, nullptr, "DebugSetUserStateOpen"},
diff --git a/src/core/hle/service/acc/async_context.cpp b/src/core/hle/service/acc/async_context.cpp
index 713689d8f..c9e0af90c 100644
--- a/src/core/hle/service/acc/async_context.cpp
+++ b/src/core/hle/service/acc/async_context.cpp
@@ -2,9 +2,9 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/core.h"
-#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/k_event.h"
#include "core/hle/service/acc/async_context.h"
+#include "core/hle/service/ipc_helpers.h"
namespace Service::Account {
IAsyncContext::IAsyncContext(Core::System& system_)
@@ -27,7 +27,7 @@ IAsyncContext::~IAsyncContext() {
service_context.CloseEvent(completion_event);
}
-void IAsyncContext::GetSystemEvent(Kernel::HLERequestContext& ctx) {
+void IAsyncContext::GetSystemEvent(HLERequestContext& ctx) {
LOG_DEBUG(Service_ACC, "called");
IPC::ResponseBuilder rb{ctx, 2, 1};
@@ -35,7 +35,7 @@ void IAsyncContext::GetSystemEvent(Kernel::HLERequestContext& ctx) {
rb.PushCopyObjects(completion_event->GetReadableEvent());
}
-void IAsyncContext::Cancel(Kernel::HLERequestContext& ctx) {
+void IAsyncContext::Cancel(HLERequestContext& ctx) {
LOG_DEBUG(Service_ACC, "called");
Cancel();
@@ -45,7 +45,7 @@ void IAsyncContext::Cancel(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void IAsyncContext::HasDone(Kernel::HLERequestContext& ctx) {
+void IAsyncContext::HasDone(HLERequestContext& ctx) {
LOG_DEBUG(Service_ACC, "called");
is_complete.store(IsComplete());
@@ -55,7 +55,7 @@ void IAsyncContext::HasDone(Kernel::HLERequestContext& ctx) {
rb.Push(is_complete.load());
}
-void IAsyncContext::GetResult(Kernel::HLERequestContext& ctx) {
+void IAsyncContext::GetResult(HLERequestContext& ctx) {
LOG_DEBUG(Service_ACC, "called");
IPC::ResponseBuilder rb{ctx, 3};
diff --git a/src/core/hle/service/acc/async_context.h b/src/core/hle/service/acc/async_context.h
index 26332d241..d7bffc055 100644
--- a/src/core/hle/service/acc/async_context.h
+++ b/src/core/hle/service/acc/async_context.h
@@ -18,10 +18,10 @@ public:
explicit IAsyncContext(Core::System& system_);
~IAsyncContext() override;
- void GetSystemEvent(Kernel::HLERequestContext& ctx);
- void Cancel(Kernel::HLERequestContext& ctx);
- void HasDone(Kernel::HLERequestContext& ctx);
- void GetResult(Kernel::HLERequestContext& ctx);
+ void GetSystemEvent(HLERequestContext& ctx);
+ void Cancel(HLERequestContext& ctx);
+ void HasDone(HLERequestContext& ctx);
+ void GetResult(HLERequestContext& ctx);
protected:
virtual bool IsComplete() const = 0;
diff --git a/src/core/hle/service/acc/errors.h b/src/core/hle/service/acc/errors.h
index e9c16b951..433ebfe9d 100644
--- a/src/core/hle/service/acc/errors.h
+++ b/src/core/hle/service/acc/errors.h
@@ -7,7 +7,13 @@
namespace Service::Account {
-constexpr Result ERR_ACCOUNTINFO_BAD_APPLICATION{ErrorModule::Account, 22};
-constexpr Result ERR_ACCOUNTINFO_ALREADY_INITIALIZED{ErrorModule::Account, 41};
+constexpr Result ResultCancelledByUser{ErrorModule::Account, 1};
+constexpr Result ResultNoNotifications{ErrorModule::Account, 15};
+constexpr Result ResultInvalidUserId{ErrorModule::Account, 20};
+constexpr Result ResultInvalidApplication{ErrorModule::Account, 22};
+constexpr Result ResultNullptr{ErrorModule::Account, 30};
+constexpr Result ResultInvalidArrayLength{ErrorModule::Account, 32};
+constexpr Result ResultApplicationInfoAlreadyInitialized{ErrorModule::Account, 41};
+constexpr Result ResultAccountUpdateFailed{ErrorModule::Account, 100};
} // namespace Service::Account
diff --git a/src/core/hle/service/acc/profile_manager.cpp b/src/core/hle/service/acc/profile_manager.cpp
index 97f7c6688..5542d6cbc 100644
--- a/src/core/hle/service/acc/profile_manager.cpp
+++ b/src/core/hle/service/acc/profile_manager.cpp
@@ -46,6 +46,7 @@ ProfileManager::ProfileManager() {
// Create an user if none are present
if (user_count == 0) {
CreateNewUser(UUID::MakeRandom(), "yuzu");
+ WriteUserSaveFile();
}
auto current =
@@ -287,7 +288,7 @@ void ProfileManager::StoreOpenedUsers() {
});
}
-/// Return the users profile base and the unknown arbitary data.
+/// Return the users profile base and the unknown arbitrary data.
bool ProfileManager::GetProfileBaseAndData(std::optional<std::size_t> index, ProfileBase& profile,
UserData& data) const {
if (GetProfileBase(index, profile)) {
@@ -297,13 +298,13 @@ bool ProfileManager::GetProfileBaseAndData(std::optional<std::size_t> index, Pro
return false;
}
-/// Return the users profile base and the unknown arbitary data.
+/// Return the users profile base and the unknown arbitrary data.
bool ProfileManager::GetProfileBaseAndData(UUID uuid, ProfileBase& profile, UserData& data) const {
const auto idx = GetUserIndex(uuid);
return GetProfileBaseAndData(idx, profile, data);
}
-/// Return the users profile base and the unknown arbitary data.
+/// Return the users profile base and the unknown arbitrary data.
bool ProfileManager::GetProfileBaseAndData(const ProfileInfo& user, ProfileBase& profile,
UserData& data) const {
return GetProfileBaseAndData(user.user_uuid, profile, data);
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index 22999c942..a2375508a 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -11,9 +11,9 @@
#include "core/file_sys/patch_manager.h"
#include "core/file_sys/registered_cache.h"
#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_transfer_memory.h"
+#include "core/hle/result.h"
#include "core/hle/service/acc/profile_manager.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/applet_ae.h"
@@ -24,24 +24,25 @@
#include "core/hle/service/am/idle.h"
#include "core/hle/service/am/omm.h"
#include "core/hle/service/am/spsm.h"
-#include "core/hle/service/am/tcap.h"
#include "core/hle/service/apm/apm_controller.h"
#include "core/hle/service/apm/apm_interface.h"
#include "core/hle/service/bcat/backend/backend.h"
#include "core/hle/service/caps/caps.h"
#include "core/hle/service/filesystem/filesystem.h"
+#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/ns/ns.h"
-#include "core/hle/service/nvflinger/nvflinger.h"
+#include "core/hle/service/nvnflinger/nvnflinger.h"
#include "core/hle/service/pm/pm.h"
+#include "core/hle/service/server_manager.h"
#include "core/hle/service/sm/sm.h"
#include "core/hle/service/vi/vi.h"
#include "core/memory.h"
namespace Service::AM {
-constexpr Result ERR_NO_DATA_IN_CHANNEL{ErrorModule::AM, 2};
-constexpr Result ERR_NO_MESSAGES{ErrorModule::AM, 3};
-constexpr Result ERR_SIZE_OUT_OF_BOUNDS{ErrorModule::AM, 503};
+constexpr Result ResultNoDataInChannel{ErrorModule::AM, 2};
+constexpr Result ResultNoMessages{ErrorModule::AM, 3};
+constexpr Result ResultInvalidOffset{ErrorModule::AM, 503};
enum class LaunchParameterKind : u32 {
ApplicationSpecific = 1,
@@ -78,8 +79,8 @@ IWindowController::IWindowController(Core::System& system_)
IWindowController::~IWindowController() = default;
-void IWindowController::GetAppletResourceUserId(Kernel::HLERequestContext& ctx) {
- const u64 process_id = system.CurrentProcess()->GetProcessID();
+void IWindowController::GetAppletResourceUserId(HLERequestContext& ctx) {
+ const u64 process_id = system.ApplicationProcess()->GetProcessId();
LOG_DEBUG(Service_AM, "called. Process ID=0x{:016X}", process_id);
@@ -88,7 +89,7 @@ void IWindowController::GetAppletResourceUserId(Kernel::HLERequestContext& ctx)
rb.Push<u64>(process_id);
}
-void IWindowController::AcquireForegroundRights(Kernel::HLERequestContext& ctx) {
+void IWindowController::AcquireForegroundRights(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
@@ -111,7 +112,7 @@ IAudioController::IAudioController(Core::System& system_)
IAudioController::~IAudioController() = default;
-void IAudioController::SetExpectedMasterVolume(Kernel::HLERequestContext& ctx) {
+void IAudioController::SetExpectedMasterVolume(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const float main_applet_volume_tmp = rp.Pop<float>();
const float library_applet_volume_tmp = rp.Pop<float>();
@@ -128,21 +129,21 @@ void IAudioController::SetExpectedMasterVolume(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void IAudioController::GetMainAppletExpectedMasterVolume(Kernel::HLERequestContext& ctx) {
+void IAudioController::GetMainAppletExpectedMasterVolume(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called. main_applet_volume={}", main_applet_volume);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(main_applet_volume);
}
-void IAudioController::GetLibraryAppletExpectedMasterVolume(Kernel::HLERequestContext& ctx) {
+void IAudioController::GetLibraryAppletExpectedMasterVolume(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called. library_applet_volume={}", library_applet_volume);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(library_applet_volume);
}
-void IAudioController::ChangeMainAppletMasterVolume(Kernel::HLERequestContext& ctx) {
+void IAudioController::ChangeMainAppletMasterVolume(HLERequestContext& ctx) {
struct Parameters {
float volume;
s64 fade_time_ns;
@@ -162,7 +163,7 @@ void IAudioController::ChangeMainAppletMasterVolume(Kernel::HLERequestContext& c
rb.Push(ResultSuccess);
}
-void IAudioController::SetTransparentAudioRate(Kernel::HLERequestContext& ctx) {
+void IAudioController::SetTransparentAudioRate(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const float transparent_volume_rate_tmp = rp.Pop<float>();
@@ -227,6 +228,8 @@ IDebugFunctions::IDebugFunctions(Core::System& system_)
{30, nullptr, "RequestLaunchApplicationWithUserAndArgumentForDebug"},
{31, nullptr, "RequestLaunchApplicationByApplicationLaunchInfoForDebug"},
{40, nullptr, "GetAppletResourceUsageInfo"},
+ {50, nullptr, "AddSystemProgramIdAndAppletIdForDebug"},
+ {51, nullptr, "AddOperationConfirmedLibraryAppletIdForDebug"},
{100, nullptr, "SetCpuBoostModeForApplet"},
{101, nullptr, "CancelCpuBoostModeForApplet"},
{110, nullptr, "PushToAppletBoundChannelForDebug"},
@@ -238,6 +241,8 @@ IDebugFunctions::IDebugFunctions(Core::System& system_)
{131, nullptr, "FriendInvitationClearApplicationParameter"},
{132, nullptr, "FriendInvitationPushApplicationParameter"},
{140, nullptr, "RestrictPowerOperationForSecureLaunchModeForDebug"},
+ {200, nullptr, "CreateFloatingLibraryAppletAccepterForDebug"},
+ {300, nullptr, "TerminateAllRunningApplicationsForDebug"},
{900, nullptr, "GetGrcProcessLaunchedSystemEvent"},
};
// clang-format on
@@ -247,10 +252,9 @@ IDebugFunctions::IDebugFunctions(Core::System& system_)
IDebugFunctions::~IDebugFunctions() = default;
-ISelfController::ISelfController(Core::System& system_, NVFlinger::NVFlinger& nvflinger_)
- : ServiceFramework{system_, "ISelfController"}, nvflinger{nvflinger_}, service_context{
- system,
- "ISelfController"} {
+ISelfController::ISelfController(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger_)
+ : ServiceFramework{system_, "ISelfController"}, nvnflinger{nvnflinger_},
+ service_context{system, "ISelfController"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &ISelfController::Exit, "Exit"},
@@ -324,7 +328,7 @@ ISelfController::~ISelfController() {
service_context.CloseEvent(accumulated_suspended_tick_changed_event);
}
-void ISelfController::Exit(Kernel::HLERequestContext& ctx) {
+void ISelfController::Exit(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2};
@@ -333,7 +337,7 @@ void ISelfController::Exit(Kernel::HLERequestContext& ctx) {
system.Exit();
}
-void ISelfController::LockExit(Kernel::HLERequestContext& ctx) {
+void ISelfController::LockExit(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
system.SetExitLock(true);
@@ -342,7 +346,7 @@ void ISelfController::LockExit(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void ISelfController::UnlockExit(Kernel::HLERequestContext& ctx) {
+void ISelfController::UnlockExit(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
system.SetExitLock(false);
@@ -351,7 +355,7 @@ void ISelfController::UnlockExit(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void ISelfController::EnterFatalSection(Kernel::HLERequestContext& ctx) {
+void ISelfController::EnterFatalSection(HLERequestContext& ctx) {
++num_fatal_sections_entered;
LOG_DEBUG(Service_AM, "called. Num fatal sections entered: {}", num_fatal_sections_entered);
@@ -359,7 +363,7 @@ void ISelfController::EnterFatalSection(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void ISelfController::LeaveFatalSection(Kernel::HLERequestContext& ctx) {
+void ISelfController::LeaveFatalSection(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called.");
// Entry and exit of fatal sections must be balanced.
@@ -375,7 +379,7 @@ void ISelfController::LeaveFatalSection(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void ISelfController::GetLibraryAppletLaunchableEvent(Kernel::HLERequestContext& ctx) {
+void ISelfController::GetLibraryAppletLaunchableEvent(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
launchable_event->Signal();
@@ -385,7 +389,7 @@ void ISelfController::GetLibraryAppletLaunchableEvent(Kernel::HLERequestContext&
rb.PushCopyObjects(launchable_event->GetReadableEvent());
}
-void ISelfController::SetScreenShotPermission(Kernel::HLERequestContext& ctx) {
+void ISelfController::SetScreenShotPermission(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto permission = rp.PopEnum<ScreenshotPermission>();
LOG_DEBUG(Service_AM, "called, permission={}", permission);
@@ -396,7 +400,7 @@ void ISelfController::SetScreenShotPermission(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void ISelfController::SetOperationModeChangedNotification(Kernel::HLERequestContext& ctx) {
+void ISelfController::SetOperationModeChangedNotification(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
bool flag = rp.Pop<bool>();
@@ -406,7 +410,7 @@ void ISelfController::SetOperationModeChangedNotification(Kernel::HLERequestCont
rb.Push(ResultSuccess);
}
-void ISelfController::SetPerformanceModeChangedNotification(Kernel::HLERequestContext& ctx) {
+void ISelfController::SetPerformanceModeChangedNotification(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
bool flag = rp.Pop<bool>();
@@ -416,7 +420,7 @@ void ISelfController::SetPerformanceModeChangedNotification(Kernel::HLERequestCo
rb.Push(ResultSuccess);
}
-void ISelfController::SetFocusHandlingMode(Kernel::HLERequestContext& ctx) {
+void ISelfController::SetFocusHandlingMode(HLERequestContext& ctx) {
// Takes 3 input u8s with each field located immediately after the previous
// u8, these are bool flags. No output.
IPC::RequestParser rp{ctx};
@@ -435,14 +439,14 @@ void ISelfController::SetFocusHandlingMode(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void ISelfController::SetRestartMessageEnabled(Kernel::HLERequestContext& ctx) {
+void ISelfController::SetRestartMessageEnabled(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
-void ISelfController::SetOutOfFocusSuspendingEnabled(Kernel::HLERequestContext& ctx) {
+void ISelfController::SetOutOfFocusSuspendingEnabled(HLERequestContext& ctx) {
// Takes 3 input u8s with each field located immediately after the previous
// u8, these are bool flags. No output.
IPC::RequestParser rp{ctx};
@@ -454,27 +458,27 @@ void ISelfController::SetOutOfFocusSuspendingEnabled(Kernel::HLERequestContext&
rb.Push(ResultSuccess);
}
-void ISelfController::SetAlbumImageOrientation(Kernel::HLERequestContext& ctx) {
+void ISelfController::SetAlbumImageOrientation(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
-void ISelfController::CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx) {
+void ISelfController::CreateManagedDisplayLayer(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
// TODO(Subv): Find out how AM determines the display to use, for now just
// create the layer in the Default display.
- const auto display_id = nvflinger.OpenDisplay("Default");
- const auto layer_id = nvflinger.CreateLayer(*display_id);
+ const auto display_id = nvnflinger.OpenDisplay("Default");
+ const auto layer_id = nvnflinger.CreateLayer(*display_id);
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.Push(*layer_id);
}
-void ISelfController::CreateManagedDisplaySeparableLayer(Kernel::HLERequestContext& ctx) {
+void ISelfController::CreateManagedDisplaySeparableLayer(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
// TODO(Subv): Find out how AM determines the display to use, for now just
@@ -484,22 +488,22 @@ void ISelfController::CreateManagedDisplaySeparableLayer(Kernel::HLERequestConte
// Outputting 1 layer id instead of the expected 2 has not been observed to cause any adverse
// side effects.
// TODO: Support multiple layers
- const auto display_id = nvflinger.OpenDisplay("Default");
- const auto layer_id = nvflinger.CreateLayer(*display_id);
+ const auto display_id = nvnflinger.OpenDisplay("Default");
+ const auto layer_id = nvnflinger.CreateLayer(*display_id);
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.Push(*layer_id);
}
-void ISelfController::SetHandlesRequestToDisplay(Kernel::HLERequestContext& ctx) {
+void ISelfController::SetHandlesRequestToDisplay(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
-void ISelfController::SetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx) {
+void ISelfController::SetIdleTimeDetectionExtension(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
idle_time_detection_extension = rp.Pop<u32>();
LOG_WARNING(Service_AM, "(STUBBED) called idle_time_detection_extension={}",
@@ -509,7 +513,7 @@ void ISelfController::SetIdleTimeDetectionExtension(Kernel::HLERequestContext& c
rb.Push(ResultSuccess);
}
-void ISelfController::GetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx) {
+void ISelfController::GetIdleTimeDetectionExtension(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
@@ -517,14 +521,14 @@ void ISelfController::GetIdleTimeDetectionExtension(Kernel::HLERequestContext& c
rb.Push<u32>(idle_time_detection_extension);
}
-void ISelfController::ReportUserIsActive(Kernel::HLERequestContext& ctx) {
+void ISelfController::ReportUserIsActive(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
-void ISelfController::SetAutoSleepDisabled(Kernel::HLERequestContext& ctx) {
+void ISelfController::SetAutoSleepDisabled(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
is_auto_sleep_disabled = rp.Pop<bool>();
@@ -544,7 +548,7 @@ void ISelfController::SetAutoSleepDisabled(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void ISelfController::IsAutoSleepDisabled(Kernel::HLERequestContext& ctx) {
+void ISelfController::IsAutoSleepDisabled(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called.");
IPC::ResponseBuilder rb{ctx, 3};
@@ -552,7 +556,7 @@ void ISelfController::IsAutoSleepDisabled(Kernel::HLERequestContext& ctx) {
rb.Push(is_auto_sleep_disabled);
}
-void ISelfController::GetAccumulatedSuspendedTickValue(Kernel::HLERequestContext& ctx) {
+void ISelfController::GetAccumulatedSuspendedTickValue(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called.");
// This command returns the total number of system ticks since ISelfController creation
@@ -563,7 +567,7 @@ void ISelfController::GetAccumulatedSuspendedTickValue(Kernel::HLERequestContext
rb.Push<u64>(0);
}
-void ISelfController::GetAccumulatedSuspendedTickChangedEvent(Kernel::HLERequestContext& ctx) {
+void ISelfController::GetAccumulatedSuspendedTickChangedEvent(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called.");
IPC::ResponseBuilder rb{ctx, 2, 1};
@@ -571,7 +575,7 @@ void ISelfController::GetAccumulatedSuspendedTickChangedEvent(Kernel::HLERequest
rb.PushCopyObjects(accumulated_suspended_tick_changed_event->GetReadableEvent());
}
-void ISelfController::SetAlbumImageTakenNotificationEnabled(Kernel::HLERequestContext& ctx) {
+void ISelfController::SetAlbumImageTakenNotificationEnabled(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
// This service call sets an internal flag whether a notification is shown when an image is
@@ -586,7 +590,7 @@ void ISelfController::SetAlbumImageTakenNotificationEnabled(Kernel::HLERequestCo
rb.Push(ResultSuccess);
}
-void ISelfController::SaveCurrentScreenshot(Kernel::HLERequestContext& ctx) {
+void ISelfController::SaveCurrentScreenshot(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto album_report_option = rp.PopEnum<Capture::AlbumReportOption>();
@@ -597,7 +601,7 @@ void ISelfController::SaveCurrentScreenshot(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void ISelfController::SetRecordVolumeMuted(Kernel::HLERequestContext& ctx) {
+void ISelfController::SetRecordVolumeMuted(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto is_record_volume_muted = rp.Pop<bool>();
@@ -731,7 +735,7 @@ ICommonStateGetter::ICommonStateGetter(Core::System& system_,
ICommonStateGetter::~ICommonStateGetter() = default;
-void ICommonStateGetter::GetBootMode(Kernel::HLERequestContext& ctx) {
+void ICommonStateGetter::GetBootMode(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 3};
@@ -739,7 +743,7 @@ void ICommonStateGetter::GetBootMode(Kernel::HLERequestContext& ctx) {
rb.Push<u8>(static_cast<u8>(Service::PM::SystemBootMode::Normal)); // Normal boot mode
}
-void ICommonStateGetter::GetEventHandle(Kernel::HLERequestContext& ctx) {
+void ICommonStateGetter::GetEventHandle(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 1};
@@ -747,7 +751,7 @@ void ICommonStateGetter::GetEventHandle(Kernel::HLERequestContext& ctx) {
rb.PushCopyObjects(msg_queue->GetMessageReceiveEvent());
}
-void ICommonStateGetter::ReceiveMessage(Kernel::HLERequestContext& ctx) {
+void ICommonStateGetter::ReceiveMessage(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
const auto message = msg_queue->PopMessage();
@@ -755,7 +759,7 @@ void ICommonStateGetter::ReceiveMessage(Kernel::HLERequestContext& ctx) {
if (message == AppletMessageQueue::AppletMessage::None) {
LOG_ERROR(Service_AM, "Message queue is empty");
- rb.Push(ERR_NO_MESSAGES);
+ rb.Push(AM::ResultNoMessages);
rb.PushEnum<AppletMessageQueue::AppletMessage>(message);
return;
}
@@ -764,7 +768,7 @@ void ICommonStateGetter::ReceiveMessage(Kernel::HLERequestContext& ctx) {
rb.PushEnum<AppletMessageQueue::AppletMessage>(message);
}
-void ICommonStateGetter::GetCurrentFocusState(Kernel::HLERequestContext& ctx) {
+void ICommonStateGetter::GetCurrentFocusState(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
@@ -772,7 +776,7 @@ void ICommonStateGetter::GetCurrentFocusState(Kernel::HLERequestContext& ctx) {
rb.Push(static_cast<u8>(FocusState::InFocus));
}
-void ICommonStateGetter::IsVrModeEnabled(Kernel::HLERequestContext& ctx) {
+void ICommonStateGetter::IsVrModeEnabled(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 3};
@@ -780,7 +784,7 @@ void ICommonStateGetter::IsVrModeEnabled(Kernel::HLERequestContext& ctx) {
rb.Push(vr_mode_state);
}
-void ICommonStateGetter::SetVrModeEnabled(Kernel::HLERequestContext& ctx) {
+void ICommonStateGetter::SetVrModeEnabled(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
vr_mode_state = rp.Pop<bool>();
@@ -790,7 +794,7 @@ void ICommonStateGetter::SetVrModeEnabled(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void ICommonStateGetter::SetLcdBacklighOffEnabled(Kernel::HLERequestContext& ctx) {
+void ICommonStateGetter::SetLcdBacklighOffEnabled(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto is_lcd_backlight_off_enabled = rp.Pop<bool>();
@@ -801,21 +805,21 @@ void ICommonStateGetter::SetLcdBacklighOffEnabled(Kernel::HLERequestContext& ctx
rb.Push(ResultSuccess);
}
-void ICommonStateGetter::BeginVrModeEx(Kernel::HLERequestContext& ctx) {
+void ICommonStateGetter::BeginVrModeEx(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
-void ICommonStateGetter::EndVrModeEx(Kernel::HLERequestContext& ctx) {
+void ICommonStateGetter::EndVrModeEx(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
-void ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent(Kernel::HLERequestContext& ctx) {
+void ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 1};
@@ -823,7 +827,7 @@ void ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent(Kernel::HLEReque
rb.PushCopyObjects(msg_queue->GetOperationModeChangedEvent());
}
-void ICommonStateGetter::GetDefaultDisplayResolution(Kernel::HLERequestContext& ctx) {
+void ICommonStateGetter::GetDefaultDisplayResolution(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 4};
@@ -838,7 +842,7 @@ void ICommonStateGetter::GetDefaultDisplayResolution(Kernel::HLERequestContext&
}
}
-void ICommonStateGetter::SetCpuBoostMode(Kernel::HLERequestContext& ctx) {
+void ICommonStateGetter::SetCpuBoostMode(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called, forwarding to APM:SYS");
const auto& sm = system.ServiceManager();
@@ -848,7 +852,7 @@ void ICommonStateGetter::SetCpuBoostMode(Kernel::HLERequestContext& ctx) {
apm_sys->SetCpuBoostMode(ctx);
}
-void ICommonStateGetter::PerformSystemButtonPressingIfInFocus(Kernel::HLERequestContext& ctx) {
+void ICommonStateGetter::PerformSystemButtonPressingIfInFocus(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto system_button{rp.PopEnum<SystemButtonType>()};
@@ -859,7 +863,7 @@ void ICommonStateGetter::PerformSystemButtonPressingIfInFocus(Kernel::HLERequest
}
void ICommonStateGetter::SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled(
- Kernel::HLERequestContext& ctx) {
+ HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
@@ -907,7 +911,7 @@ void IStorage::Register() {
IStorage::~IStorage() = default;
-void IStorage::Open(Kernel::HLERequestContext& ctx) {
+void IStorage::Open(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -916,7 +920,7 @@ void IStorage::Open(Kernel::HLERequestContext& ctx) {
rb.PushIpcInterface<IStorageAccessor>(system, *this);
}
-void ICommonStateGetter::GetOperationMode(Kernel::HLERequestContext& ctx) {
+void ICommonStateGetter::GetOperationMode(HLERequestContext& ctx) {
const bool use_docked_mode{Settings::values.use_docked_mode.GetValue()};
LOG_DEBUG(Service_AM, "called, use_docked_mode={}", use_docked_mode);
@@ -925,7 +929,7 @@ void ICommonStateGetter::GetOperationMode(Kernel::HLERequestContext& ctx) {
rb.Push(static_cast<u8>(use_docked_mode ? OperationMode::Docked : OperationMode::Handheld));
}
-void ICommonStateGetter::GetPerformanceMode(Kernel::HLERequestContext& ctx) {
+void ICommonStateGetter::GetPerformanceMode(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 3};
@@ -942,7 +946,7 @@ public:
{0, &ILibraryAppletAccessor::GetAppletStateChangedEvent, "GetAppletStateChangedEvent"},
{1, &ILibraryAppletAccessor::IsCompleted, "IsCompleted"},
{10, &ILibraryAppletAccessor::Start, "Start"},
- {20, nullptr, "RequestExit"},
+ {20, &ILibraryAppletAccessor::RequestExit, "RequestExit"},
{25, nullptr, "Terminate"},
{30, &ILibraryAppletAccessor::GetResult, "GetResult"},
{50, nullptr, "SetOutOfFocusApplicationSuspendingEnabled"},
@@ -965,7 +969,7 @@ public:
}
private:
- void GetAppletStateChangedEvent(Kernel::HLERequestContext& ctx) {
+ void GetAppletStateChangedEvent(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 1};
@@ -973,7 +977,7 @@ private:
rb.PushCopyObjects(applet->GetBroker().GetStateChangedEvent());
}
- void IsCompleted(Kernel::HLERequestContext& ctx) {
+ void IsCompleted(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 3};
@@ -981,21 +985,21 @@ private:
rb.Push<u32>(applet->TransactionComplete());
}
- void GetResult(Kernel::HLERequestContext& ctx) {
+ void GetResult(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(applet->GetStatus());
}
- void PresetLibraryAppletGpuTimeSliceZero(Kernel::HLERequestContext& ctx) {
+ void PresetLibraryAppletGpuTimeSliceZero(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
- void Start(Kernel::HLERequestContext& ctx) {
+ void Start(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
ASSERT(applet != nullptr);
@@ -1007,7 +1011,16 @@ private:
rb.Push(ResultSuccess);
}
- void PushInData(Kernel::HLERequestContext& ctx) {
+ void RequestExit(HLERequestContext& ctx) {
+ LOG_DEBUG(Service_AM, "called");
+
+ ASSERT(applet != nullptr);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(applet->RequestExit());
+ }
+
+ void PushInData(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::RequestParser rp{ctx};
@@ -1017,7 +1030,7 @@ private:
rb.Push(ResultSuccess);
}
- void PopOutData(Kernel::HLERequestContext& ctx) {
+ void PopOutData(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
auto storage = applet->GetBroker().PopNormalDataToGame();
@@ -1025,7 +1038,7 @@ private:
LOG_DEBUG(Service_AM,
"storage is a nullptr. There is no data in the current normal channel");
IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ERR_NO_DATA_IN_CHANNEL);
+ rb.Push(AM::ResultNoDataInChannel);
return;
}
@@ -1034,7 +1047,7 @@ private:
rb.PushIpcInterface<IStorage>(std::move(storage));
}
- void PushInteractiveInData(Kernel::HLERequestContext& ctx) {
+ void PushInteractiveInData(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::RequestParser rp{ctx};
@@ -1048,7 +1061,7 @@ private:
rb.Push(ResultSuccess);
}
- void PopInteractiveOutData(Kernel::HLERequestContext& ctx) {
+ void PopInteractiveOutData(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
auto storage = applet->GetBroker().PopInteractiveDataToGame();
@@ -1056,7 +1069,7 @@ private:
LOG_DEBUG(Service_AM,
"storage is a nullptr. There is no data in the current interactive channel");
IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ERR_NO_DATA_IN_CHANNEL);
+ rb.Push(AM::ResultNoDataInChannel);
return;
}
@@ -1065,7 +1078,7 @@ private:
rb.PushIpcInterface<IStorage>(std::move(storage));
}
- void GetPopOutDataEvent(Kernel::HLERequestContext& ctx) {
+ void GetPopOutDataEvent(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 1};
@@ -1073,7 +1086,7 @@ private:
rb.PushCopyObjects(applet->GetBroker().GetNormalDataEvent());
}
- void GetPopInteractiveOutDataEvent(Kernel::HLERequestContext& ctx) {
+ void GetPopInteractiveOutDataEvent(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 1};
@@ -1081,7 +1094,7 @@ private:
rb.PushCopyObjects(applet->GetBroker().GetInteractiveDataEvent());
}
- void GetIndirectLayerConsumerHandle(Kernel::HLERequestContext& ctx) {
+ void GetIndirectLayerConsumerHandle(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
// We require a non-zero handle to be valid. Using 0xdeadbeef allows us to trace if this is
@@ -1111,7 +1124,7 @@ IStorageAccessor::IStorageAccessor(Core::System& system_, IStorage& backing_)
IStorageAccessor::~IStorageAccessor() = default;
-void IStorageAccessor::GetSize(Kernel::HLERequestContext& ctx) {
+void IStorageAccessor::GetSize(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 4};
@@ -1120,11 +1133,11 @@ void IStorageAccessor::GetSize(Kernel::HLERequestContext& ctx) {
rb.Push(static_cast<u64>(backing.GetSize()));
}
-void IStorageAccessor::Write(Kernel::HLERequestContext& ctx) {
+void IStorageAccessor::Write(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u64 offset{rp.Pop<u64>()};
- const std::vector<u8> data{ctx.ReadBuffer()};
+ const auto data{ctx.ReadBuffer()};
const std::size_t size{std::min<u64>(data.size(), backing.GetSize() - offset)};
LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, size);
@@ -1135,7 +1148,7 @@ void IStorageAccessor::Write(Kernel::HLERequestContext& ctx) {
backing.GetSize(), size, offset);
IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ERR_SIZE_OUT_OF_BOUNDS);
+ rb.Push(AM::ResultInvalidOffset);
return;
}
@@ -1145,7 +1158,7 @@ void IStorageAccessor::Write(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void IStorageAccessor::Read(Kernel::HLERequestContext& ctx) {
+void IStorageAccessor::Read(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u64 offset{rp.Pop<u64>()};
@@ -1158,7 +1171,7 @@ void IStorageAccessor::Read(Kernel::HLERequestContext& ctx) {
backing.GetSize(), size, offset);
IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ERR_SIZE_OUT_OF_BOUNDS);
+ rb.Push(AM::ResultInvalidOffset);
return;
}
@@ -1183,7 +1196,7 @@ ILibraryAppletCreator::ILibraryAppletCreator(Core::System& system_)
ILibraryAppletCreator::~ILibraryAppletCreator() = default;
-void ILibraryAppletCreator::CreateLibraryApplet(Kernel::HLERequestContext& ctx) {
+void ILibraryAppletCreator::CreateLibraryApplet(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto applet_id = rp.PopRaw<Applets::AppletId>();
@@ -1209,7 +1222,7 @@ void ILibraryAppletCreator::CreateLibraryApplet(Kernel::HLERequestContext& ctx)
rb.PushIpcInterface<ILibraryAppletAccessor>(system, applet);
}
-void ILibraryAppletCreator::CreateStorage(Kernel::HLERequestContext& ctx) {
+void ILibraryAppletCreator::CreateStorage(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const s64 size{rp.Pop<s64>()};
@@ -1230,7 +1243,7 @@ void ILibraryAppletCreator::CreateStorage(Kernel::HLERequestContext& ctx) {
rb.PushIpcInterface<IStorage>(system, std::move(buffer));
}
-void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContext& ctx) {
+void ILibraryAppletCreator::CreateTransferMemoryStorage(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
@@ -1252,7 +1265,7 @@ void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContex
}
auto transfer_mem =
- system.CurrentProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(handle);
+ system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(handle);
if (transfer_mem.IsNull()) {
LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle);
@@ -1261,16 +1274,16 @@ void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContex
return;
}
- 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};
+ std::vector<u8> memory(transfer_mem->GetSize());
+ system.ApplicationMemory().ReadBlock(transfer_mem->GetSourceAddress(), memory.data(),
+ memory.size());
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IStorage>(system, std::move(memory));
}
-void ILibraryAppletCreator::CreateHandleStorage(Kernel::HLERequestContext& ctx) {
+void ILibraryAppletCreator::CreateHandleStorage(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const s64 size{rp.Pop<s64>()};
@@ -1286,7 +1299,7 @@ void ILibraryAppletCreator::CreateHandleStorage(Kernel::HLERequestContext& ctx)
}
auto transfer_mem =
- system.CurrentProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(handle);
+ system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(handle);
if (transfer_mem.IsNull()) {
LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle);
@@ -1295,9 +1308,9 @@ void ILibraryAppletCreator::CreateHandleStorage(Kernel::HLERequestContext& ctx)
return;
}
- 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};
+ std::vector<u8> memory(transfer_mem->GetSize());
+ system.ApplicationMemory().ReadBlock(transfer_mem->GetSourceAddress(), memory.data(),
+ memory.size());
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
@@ -1323,7 +1336,7 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_)
{24, nullptr, "GetLaunchStorageInfoForDebug"},
{25, &IApplicationFunctions::ExtendSaveData, "ExtendSaveData"},
{26, &IApplicationFunctions::GetSaveDataSize, "GetSaveDataSize"},
- {27, nullptr, "CreateCacheStorage"},
+ {27, &IApplicationFunctions::CreateCacheStorage, "CreateCacheStorage"},
{28, nullptr, "GetSaveDataSizeMax"},
{29, nullptr, "GetCacheStorageMax"},
{30, &IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed, "BeginBlockingHomeButtonShortAndLongPressed"},
@@ -1393,29 +1406,28 @@ IApplicationFunctions::~IApplicationFunctions() {
service_context.CloseEvent(health_warning_disappeared_system_event);
}
-void IApplicationFunctions::EnableApplicationCrashReport(Kernel::HLERequestContext& ctx) {
+void IApplicationFunctions::EnableApplicationCrashReport(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
-void IApplicationFunctions::InitializeApplicationCopyrightFrameBuffer(
- Kernel::HLERequestContext& ctx) {
+void IApplicationFunctions::InitializeApplicationCopyrightFrameBuffer(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
-void IApplicationFunctions::SetApplicationCopyrightImage(Kernel::HLERequestContext& ctx) {
+void IApplicationFunctions::SetApplicationCopyrightImage(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
-void IApplicationFunctions::SetApplicationCopyrightVisibility(Kernel::HLERequestContext& ctx) {
+void IApplicationFunctions::SetApplicationCopyrightVisibility(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto is_visible = rp.Pop<bool>();
@@ -1425,37 +1437,35 @@ void IApplicationFunctions::SetApplicationCopyrightVisibility(Kernel::HLERequest
rb.Push(ResultSuccess);
}
-void IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed(
- Kernel::HLERequestContext& ctx) {
+void IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
-void IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed(
- Kernel::HLERequestContext& ctx) {
+void IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
-void IApplicationFunctions::BeginBlockingHomeButton(Kernel::HLERequestContext& ctx) {
+void IApplicationFunctions::BeginBlockingHomeButton(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
-void IApplicationFunctions::EndBlockingHomeButton(Kernel::HLERequestContext& ctx) {
+void IApplicationFunctions::EndBlockingHomeButton(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
-void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) {
+void IApplicationFunctions::PopLaunchParameter(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto kind = rp.PopEnum<LaunchParameterKind>();
@@ -1465,11 +1475,12 @@ void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) {
const auto backend = BCAT::CreateBackendFromSettings(system, [this](u64 tid) {
return system.GetFileSystemController().GetBCATDirectory(tid);
});
- const auto build_id_full = system.GetCurrentProcessBuildID();
+ const auto build_id_full = system.GetApplicationProcessBuildID();
u64 build_id{};
std::memcpy(&build_id, build_id_full.data(), sizeof(u64));
- auto data = backend->GetLaunchParameter({system.GetCurrentProcessProgramID(), build_id});
+ auto data =
+ backend->GetLaunchParameter({system.GetApplicationProcessProgramID(), build_id});
if (data.has_value()) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
@@ -1503,25 +1514,24 @@ void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) {
LOG_ERROR(Service_AM, "Attempted to load launch parameter but none was found!");
IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ERR_NO_DATA_IN_CHANNEL);
+ rb.Push(AM::ResultNoDataInChannel);
}
-void IApplicationFunctions::CreateApplicationAndRequestToStartForQuest(
- Kernel::HLERequestContext& ctx) {
+void IApplicationFunctions::CreateApplicationAndRequestToStartForQuest(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
-void IApplicationFunctions::EnsureSaveData(Kernel::HLERequestContext& ctx) {
+void IApplicationFunctions::EnsureSaveData(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
u128 user_id = rp.PopRaw<u128>();
LOG_DEBUG(Service_AM, "called, uid={:016X}{:016X}", user_id[1], user_id[0]);
FileSys::SaveDataAttribute attribute{};
- attribute.title_id = system.GetCurrentProcessProgramID();
+ attribute.title_id = system.GetApplicationProcessProgramID();
attribute.user_id = user_id;
attribute.type = FileSys::SaveDataType::SaveData;
const auto res = system.GetFileSystemController().CreateSaveData(
@@ -1532,7 +1542,7 @@ void IApplicationFunctions::EnsureSaveData(Kernel::HLERequestContext& ctx) {
rb.Push<u64>(0);
}
-void IApplicationFunctions::SetTerminateResult(Kernel::HLERequestContext& ctx) {
+void IApplicationFunctions::SetTerminateResult(HLERequestContext& ctx) {
// Takes an input u32 Result, no output.
// For example, in some cases official apps use this with error 0x2A2 then
// uses svcBreak.
@@ -1545,13 +1555,13 @@ void IApplicationFunctions::SetTerminateResult(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void IApplicationFunctions::GetDisplayVersion(Kernel::HLERequestContext& ctx) {
+void IApplicationFunctions::GetDisplayVersion(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
std::array<u8, 0x10> version_string{};
const auto res = [this] {
- const auto title_id = system.GetCurrentProcessProgramID();
+ const auto title_id = system.GetApplicationProcessProgramID();
const FileSys::PatchManager pm{title_id, system.GetFileSystemController(),
system.GetContentProvider()};
@@ -1570,7 +1580,7 @@ void IApplicationFunctions::GetDisplayVersion(Kernel::HLERequestContext& ctx) {
const auto& version = res.first->GetVersionString();
std::copy(version.begin(), version.end(), version_string.begin());
} else {
- constexpr char default_version[]{"1.0.0"};
+ static constexpr char default_version[]{"1.0.0"};
std::memcpy(version_string.data(), default_version, sizeof(default_version));
}
@@ -1579,7 +1589,7 @@ void IApplicationFunctions::GetDisplayVersion(Kernel::HLERequestContext& ctx) {
rb.PushRaw(version_string);
}
-void IApplicationFunctions::GetDesiredLanguage(Kernel::HLERequestContext& ctx) {
+void IApplicationFunctions::GetDesiredLanguage(HLERequestContext& ctx) {
// TODO(bunnei): This should be configurable
LOG_DEBUG(Service_AM, "called");
@@ -1588,7 +1598,7 @@ void IApplicationFunctions::GetDesiredLanguage(Kernel::HLERequestContext& ctx) {
u32 supported_languages = 0;
const auto res = [this] {
- const auto title_id = system.GetCurrentProcessProgramID();
+ const auto title_id = system.GetApplicationProcessProgramID();
const FileSys::PatchManager pm{title_id, system.GetFileSystemController(),
system.GetContentProvider()};
@@ -1635,7 +1645,7 @@ void IApplicationFunctions::GetDesiredLanguage(Kernel::HLERequestContext& ctx) {
rb.Push(*res_code);
}
-void IApplicationFunctions::IsGamePlayRecordingSupported(Kernel::HLERequestContext& ctx) {
+void IApplicationFunctions::IsGamePlayRecordingSupported(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
constexpr bool gameplay_recording_supported = false;
@@ -1645,21 +1655,21 @@ void IApplicationFunctions::IsGamePlayRecordingSupported(Kernel::HLERequestConte
rb.Push(gameplay_recording_supported);
}
-void IApplicationFunctions::InitializeGamePlayRecording(Kernel::HLERequestContext& ctx) {
+void IApplicationFunctions::InitializeGamePlayRecording(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
-void IApplicationFunctions::SetGamePlayRecordingState(Kernel::HLERequestContext& ctx) {
+void IApplicationFunctions::SetGamePlayRecordingState(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
-void IApplicationFunctions::NotifyRunning(Kernel::HLERequestContext& ctx) {
+void IApplicationFunctions::NotifyRunning(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
@@ -1667,7 +1677,7 @@ void IApplicationFunctions::NotifyRunning(Kernel::HLERequestContext& ctx) {
rb.Push<u8>(0); // Unknown, seems to be ignored by official processes
}
-void IApplicationFunctions::GetPseudoDeviceId(Kernel::HLERequestContext& ctx) {
+void IApplicationFunctions::GetPseudoDeviceId(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 6};
@@ -1678,7 +1688,7 @@ void IApplicationFunctions::GetPseudoDeviceId(Kernel::HLERequestContext& ctx) {
rb.Push<u64>(0);
}
-void IApplicationFunctions::ExtendSaveData(Kernel::HLERequestContext& ctx) {
+void IApplicationFunctions::ExtendSaveData(HLERequestContext& ctx) {
struct Parameters {
FileSys::SaveDataType type;
u128 user_id;
@@ -1696,7 +1706,8 @@ void IApplicationFunctions::ExtendSaveData(Kernel::HLERequestContext& ctx) {
static_cast<u8>(type), user_id[1], user_id[0], new_normal_size, new_journal_size);
system.GetFileSystemController().WriteSaveDataSize(
- type, system.GetCurrentProcessProgramID(), user_id, {new_normal_size, new_journal_size});
+ type, system.GetApplicationProcessProgramID(), user_id,
+ {new_normal_size, new_journal_size});
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
@@ -1706,7 +1717,7 @@ void IApplicationFunctions::ExtendSaveData(Kernel::HLERequestContext& ctx) {
rb.Push<u64>(0);
}
-void IApplicationFunctions::GetSaveDataSize(Kernel::HLERequestContext& ctx) {
+void IApplicationFunctions::GetSaveDataSize(HLERequestContext& ctx) {
struct Parameters {
FileSys::SaveDataType type;
u128 user_id;
@@ -1720,7 +1731,7 @@ void IApplicationFunctions::GetSaveDataSize(Kernel::HLERequestContext& ctx) {
user_id[0]);
const auto size = system.GetFileSystemController().ReadSaveDataSize(
- type, system.GetCurrentProcessProgramID(), user_id);
+ type, system.GetApplicationProcessProgramID(), user_id);
IPC::ResponseBuilder rb{ctx, 6};
rb.Push(ResultSuccess);
@@ -1728,7 +1739,37 @@ void IApplicationFunctions::GetSaveDataSize(Kernel::HLERequestContext& ctx) {
rb.Push(size.journal);
}
-void IApplicationFunctions::QueryApplicationPlayStatistics(Kernel::HLERequestContext& ctx) {
+void IApplicationFunctions::CreateCacheStorage(HLERequestContext& ctx) {
+ struct InputParameters {
+ u16 index;
+ s64 size;
+ s64 journal_size;
+ };
+ static_assert(sizeof(InputParameters) == 24);
+
+ struct OutputParameters {
+ u32 storage_target;
+ u64 required_size;
+ };
+ static_assert(sizeof(OutputParameters) == 16);
+
+ IPC::RequestParser rp{ctx};
+ const auto params = rp.PopRaw<InputParameters>();
+
+ LOG_WARNING(Service_AM, "(STUBBED) called with index={}, size={:#x}, journal_size={:#x}",
+ params.index, params.size, params.journal_size);
+
+ const OutputParameters resp{
+ .storage_target = 1,
+ .required_size = 0,
+ };
+
+ IPC::ResponseBuilder rb{ctx, 6};
+ rb.Push(ResultSuccess);
+ rb.PushRaw(resp);
+}
+
+void IApplicationFunctions::QueryApplicationPlayStatistics(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
@@ -1736,7 +1777,7 @@ void IApplicationFunctions::QueryApplicationPlayStatistics(Kernel::HLERequestCon
rb.Push<u32>(0);
}
-void IApplicationFunctions::QueryApplicationPlayStatisticsByUid(Kernel::HLERequestContext& ctx) {
+void IApplicationFunctions::QueryApplicationPlayStatisticsByUid(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
@@ -1744,7 +1785,7 @@ void IApplicationFunctions::QueryApplicationPlayStatisticsByUid(Kernel::HLEReque
rb.Push<u32>(0);
}
-void IApplicationFunctions::ExecuteProgram(Kernel::HLERequestContext& ctx) {
+void IApplicationFunctions::ExecuteProgram(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::RequestParser rp{ctx};
@@ -1758,21 +1799,21 @@ void IApplicationFunctions::ExecuteProgram(Kernel::HLERequestContext& ctx) {
system.ExecuteProgram(program_index);
}
-void IApplicationFunctions::ClearUserChannel(Kernel::HLERequestContext& ctx) {
+void IApplicationFunctions::ClearUserChannel(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
-void IApplicationFunctions::UnpopToUserChannel(Kernel::HLERequestContext& ctx) {
+void IApplicationFunctions::UnpopToUserChannel(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
-void IApplicationFunctions::GetPreviousProgramIndex(Kernel::HLERequestContext& ctx) {
+void IApplicationFunctions::GetPreviousProgramIndex(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
@@ -1780,7 +1821,7 @@ void IApplicationFunctions::GetPreviousProgramIndex(Kernel::HLERequestContext& c
rb.Push<s32>(previous_program_index);
}
-void IApplicationFunctions::GetGpuErrorDetectedSystemEvent(Kernel::HLERequestContext& ctx) {
+void IApplicationFunctions::GetGpuErrorDetectedSystemEvent(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2, 1};
@@ -1788,7 +1829,7 @@ void IApplicationFunctions::GetGpuErrorDetectedSystemEvent(Kernel::HLERequestCon
rb.PushCopyObjects(gpu_error_detected_event->GetReadableEvent());
}
-void IApplicationFunctions::GetFriendInvitationStorageChannelEvent(Kernel::HLERequestContext& ctx) {
+void IApplicationFunctions::GetFriendInvitationStorageChannelEvent(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 1};
@@ -1796,15 +1837,14 @@ void IApplicationFunctions::GetFriendInvitationStorageChannelEvent(Kernel::HLERe
rb.PushCopyObjects(friend_invitation_storage_channel_event->GetReadableEvent());
}
-void IApplicationFunctions::TryPopFromFriendInvitationStorageChannel(
- Kernel::HLERequestContext& ctx) {
- LOG_WARNING(Service_AM, "(STUBBED) called");
+void IApplicationFunctions::TryPopFromFriendInvitationStorageChannel(HLERequestContext& ctx) {
+ LOG_DEBUG(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ERR_NO_DATA_IN_CHANNEL);
+ rb.Push(AM::ResultNoDataInChannel);
}
-void IApplicationFunctions::GetNotificationStorageChannelEvent(Kernel::HLERequestContext& ctx) {
+void IApplicationFunctions::GetNotificationStorageChannelEvent(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 1};
@@ -1812,7 +1852,7 @@ void IApplicationFunctions::GetNotificationStorageChannelEvent(Kernel::HLEReques
rb.PushCopyObjects(notification_storage_channel_event->GetReadableEvent());
}
-void IApplicationFunctions::GetHealthWarningDisappearedSystemEvent(Kernel::HLERequestContext& ctx) {
+void IApplicationFunctions::GetHealthWarningDisappearedSystemEvent(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 1};
@@ -1820,25 +1860,28 @@ void IApplicationFunctions::GetHealthWarningDisappearedSystemEvent(Kernel::HLERe
rb.PushCopyObjects(health_warning_disappeared_system_event->GetReadableEvent());
}
-void IApplicationFunctions::PrepareForJit(Kernel::HLERequestContext& ctx) {
+void IApplicationFunctions::PrepareForJit(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
-void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nvflinger,
- Core::System& system) {
+void LoopProcess(Nvnflinger::Nvnflinger& nvnflinger, Core::System& system) {
auto message_queue = std::make_shared<AppletMessageQueue>(system);
// Needed on game boot
message_queue->PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged);
- std::make_shared<AppletAE>(nvflinger, message_queue, system)->InstallAsService(service_manager);
- std::make_shared<AppletOE>(nvflinger, message_queue, system)->InstallAsService(service_manager);
- std::make_shared<IdleSys>(system)->InstallAsService(service_manager);
- std::make_shared<OMM>(system)->InstallAsService(service_manager);
- std::make_shared<SPSM>(system)->InstallAsService(service_manager);
- std::make_shared<TCAP>(system)->InstallAsService(service_manager);
+ auto server_manager = std::make_unique<ServerManager>(system);
+
+ server_manager->RegisterNamedService(
+ "appletAE", std::make_shared<AppletAE>(nvnflinger, message_queue, system));
+ server_manager->RegisterNamedService(
+ "appletOE", std::make_shared<AppletOE>(nvnflinger, message_queue, system));
+ server_manager->RegisterNamedService("idle:sys", std::make_shared<IdleSys>(system));
+ server_manager->RegisterNamedService("omm", std::make_shared<OMM>(system));
+ server_manager->RegisterNamedService("spsm", std::make_shared<SPSM>(system));
+ ServerManager::RunServer(std::move(server_manager));
}
IHomeMenuFunctions::IHomeMenuFunctions(Core::System& system_)
@@ -1855,6 +1898,8 @@ IHomeMenuFunctions::IHomeMenuFunctions(Core::System& system_)
{31, nullptr, "GetWriterLockAccessorEx"},
{40, nullptr, "IsSleepEnabled"},
{41, nullptr, "IsRebootEnabled"},
+ {50, nullptr, "LaunchSystemApplet"},
+ {51, nullptr, "LaunchStarter"},
{100, nullptr, "PopRequestLaunchApplicationForDebug"},
{110, nullptr, "IsForceTerminateApplicationDisabledForDebug"},
{200, nullptr, "LaunchDevMenu"},
@@ -1872,14 +1917,14 @@ IHomeMenuFunctions::~IHomeMenuFunctions() {
service_context.CloseEvent(pop_from_general_channel_event);
}
-void IHomeMenuFunctions::RequestToGetForeground(Kernel::HLERequestContext& ctx) {
+void IHomeMenuFunctions::RequestToGetForeground(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
-void IHomeMenuFunctions::GetPopFromGeneralChannelEvent(Kernel::HLERequestContext& ctx) {
+void IHomeMenuFunctions::GetPopFromGeneralChannelEvent(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2, 1};
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h
index a0fbfcfc5..d4fd163da 100644
--- a/src/core/hle/service/am/am.h
+++ b/src/core/hle/service/am/am.h
@@ -12,11 +12,12 @@
namespace Kernel {
class KernelCore;
+class KReadableEvent;
class KTransferMemory;
} // namespace Kernel
-namespace Service::NVFlinger {
-class NVFlinger;
+namespace Service::Nvnflinger {
+class Nvnflinger;
}
namespace Service::AM {
@@ -109,8 +110,8 @@ public:
~IWindowController() override;
private:
- void GetAppletResourceUserId(Kernel::HLERequestContext& ctx);
- void AcquireForegroundRights(Kernel::HLERequestContext& ctx);
+ void GetAppletResourceUserId(HLERequestContext& ctx);
+ void AcquireForegroundRights(HLERequestContext& ctx);
};
class IAudioController final : public ServiceFramework<IAudioController> {
@@ -119,11 +120,11 @@ public:
~IAudioController() override;
private:
- void SetExpectedMasterVolume(Kernel::HLERequestContext& ctx);
- void GetMainAppletExpectedMasterVolume(Kernel::HLERequestContext& ctx);
- void GetLibraryAppletExpectedMasterVolume(Kernel::HLERequestContext& ctx);
- void ChangeMainAppletMasterVolume(Kernel::HLERequestContext& ctx);
- void SetTransparentAudioRate(Kernel::HLERequestContext& ctx);
+ void SetExpectedMasterVolume(HLERequestContext& ctx);
+ void GetMainAppletExpectedMasterVolume(HLERequestContext& ctx);
+ void GetLibraryAppletExpectedMasterVolume(HLERequestContext& ctx);
+ void ChangeMainAppletMasterVolume(HLERequestContext& ctx);
+ void SetTransparentAudioRate(HLERequestContext& ctx);
static constexpr float min_allowed_volume = 0.0f;
static constexpr float max_allowed_volume = 1.0f;
@@ -153,36 +154,36 @@ public:
class ISelfController final : public ServiceFramework<ISelfController> {
public:
- explicit ISelfController(Core::System& system_, NVFlinger::NVFlinger& nvflinger_);
+ explicit ISelfController(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger_);
~ISelfController() override;
private:
- void Exit(Kernel::HLERequestContext& ctx);
- void LockExit(Kernel::HLERequestContext& ctx);
- void UnlockExit(Kernel::HLERequestContext& ctx);
- void EnterFatalSection(Kernel::HLERequestContext& ctx);
- void LeaveFatalSection(Kernel::HLERequestContext& ctx);
- void GetLibraryAppletLaunchableEvent(Kernel::HLERequestContext& ctx);
- void SetScreenShotPermission(Kernel::HLERequestContext& ctx);
- void SetOperationModeChangedNotification(Kernel::HLERequestContext& ctx);
- void SetPerformanceModeChangedNotification(Kernel::HLERequestContext& ctx);
- void SetFocusHandlingMode(Kernel::HLERequestContext& ctx);
- void SetRestartMessageEnabled(Kernel::HLERequestContext& ctx);
- void SetOutOfFocusSuspendingEnabled(Kernel::HLERequestContext& ctx);
- void SetAlbumImageOrientation(Kernel::HLERequestContext& ctx);
- void CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx);
- void CreateManagedDisplaySeparableLayer(Kernel::HLERequestContext& ctx);
- void SetHandlesRequestToDisplay(Kernel::HLERequestContext& ctx);
- void SetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx);
- void GetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx);
- void ReportUserIsActive(Kernel::HLERequestContext& ctx);
- void SetAutoSleepDisabled(Kernel::HLERequestContext& ctx);
- void IsAutoSleepDisabled(Kernel::HLERequestContext& ctx);
- void GetAccumulatedSuspendedTickValue(Kernel::HLERequestContext& ctx);
- void GetAccumulatedSuspendedTickChangedEvent(Kernel::HLERequestContext& ctx);
- void SetAlbumImageTakenNotificationEnabled(Kernel::HLERequestContext& ctx);
- void SaveCurrentScreenshot(Kernel::HLERequestContext& ctx);
- void SetRecordVolumeMuted(Kernel::HLERequestContext& ctx);
+ void Exit(HLERequestContext& ctx);
+ void LockExit(HLERequestContext& ctx);
+ void UnlockExit(HLERequestContext& ctx);
+ void EnterFatalSection(HLERequestContext& ctx);
+ void LeaveFatalSection(HLERequestContext& ctx);
+ void GetLibraryAppletLaunchableEvent(HLERequestContext& ctx);
+ void SetScreenShotPermission(HLERequestContext& ctx);
+ void SetOperationModeChangedNotification(HLERequestContext& ctx);
+ void SetPerformanceModeChangedNotification(HLERequestContext& ctx);
+ void SetFocusHandlingMode(HLERequestContext& ctx);
+ void SetRestartMessageEnabled(HLERequestContext& ctx);
+ void SetOutOfFocusSuspendingEnabled(HLERequestContext& ctx);
+ void SetAlbumImageOrientation(HLERequestContext& ctx);
+ void CreateManagedDisplayLayer(HLERequestContext& ctx);
+ void CreateManagedDisplaySeparableLayer(HLERequestContext& ctx);
+ void SetHandlesRequestToDisplay(HLERequestContext& ctx);
+ void SetIdleTimeDetectionExtension(HLERequestContext& ctx);
+ void GetIdleTimeDetectionExtension(HLERequestContext& ctx);
+ void ReportUserIsActive(HLERequestContext& ctx);
+ void SetAutoSleepDisabled(HLERequestContext& ctx);
+ void IsAutoSleepDisabled(HLERequestContext& ctx);
+ void GetAccumulatedSuspendedTickValue(HLERequestContext& ctx);
+ void GetAccumulatedSuspendedTickChangedEvent(HLERequestContext& ctx);
+ void SetAlbumImageTakenNotificationEnabled(HLERequestContext& ctx);
+ void SaveCurrentScreenshot(HLERequestContext& ctx);
+ void SetRecordVolumeMuted(HLERequestContext& ctx);
enum class ScreenshotPermission : u32 {
Inherit = 0,
@@ -190,7 +191,7 @@ private:
Disable = 2,
};
- NVFlinger::NVFlinger& nvflinger;
+ Nvnflinger::Nvnflinger& nvnflinger;
KernelHelpers::ServiceContext service_context;
@@ -235,22 +236,22 @@ private:
CaptureButtonLongPressing,
};
- void GetEventHandle(Kernel::HLERequestContext& ctx);
- void ReceiveMessage(Kernel::HLERequestContext& ctx);
- void GetCurrentFocusState(Kernel::HLERequestContext& ctx);
- void GetDefaultDisplayResolutionChangeEvent(Kernel::HLERequestContext& ctx);
- void GetOperationMode(Kernel::HLERequestContext& ctx);
- void GetPerformanceMode(Kernel::HLERequestContext& ctx);
- void GetBootMode(Kernel::HLERequestContext& ctx);
- void IsVrModeEnabled(Kernel::HLERequestContext& ctx);
- void SetVrModeEnabled(Kernel::HLERequestContext& ctx);
- void SetLcdBacklighOffEnabled(Kernel::HLERequestContext& ctx);
- void BeginVrModeEx(Kernel::HLERequestContext& ctx);
- void EndVrModeEx(Kernel::HLERequestContext& ctx);
- void GetDefaultDisplayResolution(Kernel::HLERequestContext& ctx);
- void SetCpuBoostMode(Kernel::HLERequestContext& ctx);
- void PerformSystemButtonPressingIfInFocus(Kernel::HLERequestContext& ctx);
- void SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled(Kernel::HLERequestContext& ctx);
+ void GetEventHandle(HLERequestContext& ctx);
+ void ReceiveMessage(HLERequestContext& ctx);
+ void GetCurrentFocusState(HLERequestContext& ctx);
+ void GetDefaultDisplayResolutionChangeEvent(HLERequestContext& ctx);
+ void GetOperationMode(HLERequestContext& ctx);
+ void GetPerformanceMode(HLERequestContext& ctx);
+ void GetBootMode(HLERequestContext& ctx);
+ void IsVrModeEnabled(HLERequestContext& ctx);
+ void SetVrModeEnabled(HLERequestContext& ctx);
+ void SetLcdBacklighOffEnabled(HLERequestContext& ctx);
+ void BeginVrModeEx(HLERequestContext& ctx);
+ void EndVrModeEx(HLERequestContext& ctx);
+ void GetDefaultDisplayResolution(HLERequestContext& ctx);
+ void SetCpuBoostMode(HLERequestContext& ctx);
+ void PerformSystemButtonPressingIfInFocus(HLERequestContext& ctx);
+ void SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled(HLERequestContext& ctx);
std::shared_ptr<AppletMessageQueue> msg_queue;
bool vr_mode_state{};
@@ -283,7 +284,7 @@ public:
private:
void Register();
- void Open(Kernel::HLERequestContext& ctx);
+ void Open(HLERequestContext& ctx);
std::shared_ptr<IStorageImpl> impl;
};
@@ -294,9 +295,9 @@ public:
~IStorageAccessor() override;
private:
- void GetSize(Kernel::HLERequestContext& ctx);
- void Write(Kernel::HLERequestContext& ctx);
- void Read(Kernel::HLERequestContext& ctx);
+ void GetSize(HLERequestContext& ctx);
+ void Write(HLERequestContext& ctx);
+ void Read(HLERequestContext& ctx);
IStorage& backing;
};
@@ -307,10 +308,10 @@ public:
~ILibraryAppletCreator() override;
private:
- void CreateLibraryApplet(Kernel::HLERequestContext& ctx);
- void CreateStorage(Kernel::HLERequestContext& ctx);
- void CreateTransferMemoryStorage(Kernel::HLERequestContext& ctx);
- void CreateHandleStorage(Kernel::HLERequestContext& ctx);
+ void CreateLibraryApplet(HLERequestContext& ctx);
+ void CreateStorage(HLERequestContext& ctx);
+ void CreateTransferMemoryStorage(HLERequestContext& ctx);
+ void CreateHandleStorage(HLERequestContext& ctx);
};
class IApplicationFunctions final : public ServiceFramework<IApplicationFunctions> {
@@ -319,39 +320,40 @@ public:
~IApplicationFunctions() override;
private:
- void PopLaunchParameter(Kernel::HLERequestContext& ctx);
- void CreateApplicationAndRequestToStartForQuest(Kernel::HLERequestContext& ctx);
- void EnsureSaveData(Kernel::HLERequestContext& ctx);
- void SetTerminateResult(Kernel::HLERequestContext& ctx);
- void GetDisplayVersion(Kernel::HLERequestContext& ctx);
- void GetDesiredLanguage(Kernel::HLERequestContext& ctx);
- void IsGamePlayRecordingSupported(Kernel::HLERequestContext& ctx);
- void InitializeGamePlayRecording(Kernel::HLERequestContext& ctx);
- void SetGamePlayRecordingState(Kernel::HLERequestContext& ctx);
- void NotifyRunning(Kernel::HLERequestContext& ctx);
- void GetPseudoDeviceId(Kernel::HLERequestContext& ctx);
- void ExtendSaveData(Kernel::HLERequestContext& ctx);
- void GetSaveDataSize(Kernel::HLERequestContext& ctx);
- void BeginBlockingHomeButtonShortAndLongPressed(Kernel::HLERequestContext& ctx);
- void EndBlockingHomeButtonShortAndLongPressed(Kernel::HLERequestContext& ctx);
- void BeginBlockingHomeButton(Kernel::HLERequestContext& ctx);
- void EndBlockingHomeButton(Kernel::HLERequestContext& ctx);
- void EnableApplicationCrashReport(Kernel::HLERequestContext& ctx);
- void InitializeApplicationCopyrightFrameBuffer(Kernel::HLERequestContext& ctx);
- void SetApplicationCopyrightImage(Kernel::HLERequestContext& ctx);
- void SetApplicationCopyrightVisibility(Kernel::HLERequestContext& ctx);
- void QueryApplicationPlayStatistics(Kernel::HLERequestContext& ctx);
- void QueryApplicationPlayStatisticsByUid(Kernel::HLERequestContext& ctx);
- void ExecuteProgram(Kernel::HLERequestContext& ctx);
- void ClearUserChannel(Kernel::HLERequestContext& ctx);
- void UnpopToUserChannel(Kernel::HLERequestContext& ctx);
- void GetPreviousProgramIndex(Kernel::HLERequestContext& ctx);
- void GetGpuErrorDetectedSystemEvent(Kernel::HLERequestContext& ctx);
- void GetFriendInvitationStorageChannelEvent(Kernel::HLERequestContext& ctx);
- void TryPopFromFriendInvitationStorageChannel(Kernel::HLERequestContext& ctx);
- void GetNotificationStorageChannelEvent(Kernel::HLERequestContext& ctx);
- void GetHealthWarningDisappearedSystemEvent(Kernel::HLERequestContext& ctx);
- void PrepareForJit(Kernel::HLERequestContext& ctx);
+ void PopLaunchParameter(HLERequestContext& ctx);
+ void CreateApplicationAndRequestToStartForQuest(HLERequestContext& ctx);
+ void EnsureSaveData(HLERequestContext& ctx);
+ void SetTerminateResult(HLERequestContext& ctx);
+ void GetDisplayVersion(HLERequestContext& ctx);
+ void GetDesiredLanguage(HLERequestContext& ctx);
+ void IsGamePlayRecordingSupported(HLERequestContext& ctx);
+ void InitializeGamePlayRecording(HLERequestContext& ctx);
+ void SetGamePlayRecordingState(HLERequestContext& ctx);
+ void NotifyRunning(HLERequestContext& ctx);
+ void GetPseudoDeviceId(HLERequestContext& ctx);
+ void ExtendSaveData(HLERequestContext& ctx);
+ void GetSaveDataSize(HLERequestContext& ctx);
+ void CreateCacheStorage(HLERequestContext& ctx);
+ void BeginBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx);
+ void EndBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx);
+ void BeginBlockingHomeButton(HLERequestContext& ctx);
+ void EndBlockingHomeButton(HLERequestContext& ctx);
+ void EnableApplicationCrashReport(HLERequestContext& ctx);
+ void InitializeApplicationCopyrightFrameBuffer(HLERequestContext& ctx);
+ void SetApplicationCopyrightImage(HLERequestContext& ctx);
+ void SetApplicationCopyrightVisibility(HLERequestContext& ctx);
+ void QueryApplicationPlayStatistics(HLERequestContext& ctx);
+ void QueryApplicationPlayStatisticsByUid(HLERequestContext& ctx);
+ void ExecuteProgram(HLERequestContext& ctx);
+ void ClearUserChannel(HLERequestContext& ctx);
+ void UnpopToUserChannel(HLERequestContext& ctx);
+ void GetPreviousProgramIndex(HLERequestContext& ctx);
+ void GetGpuErrorDetectedSystemEvent(HLERequestContext& ctx);
+ void GetFriendInvitationStorageChannelEvent(HLERequestContext& ctx);
+ void TryPopFromFriendInvitationStorageChannel(HLERequestContext& ctx);
+ void GetNotificationStorageChannelEvent(HLERequestContext& ctx);
+ void GetHealthWarningDisappearedSystemEvent(HLERequestContext& ctx);
+ void PrepareForJit(HLERequestContext& ctx);
KernelHelpers::ServiceContext service_context;
@@ -370,8 +372,8 @@ public:
~IHomeMenuFunctions() override;
private:
- void RequestToGetForeground(Kernel::HLERequestContext& ctx);
- void GetPopFromGeneralChannelEvent(Kernel::HLERequestContext& ctx);
+ void RequestToGetForeground(HLERequestContext& ctx);
+ void GetPopFromGeneralChannelEvent(HLERequestContext& ctx);
KernelHelpers::ServiceContext service_context;
@@ -396,8 +398,6 @@ public:
~IProcessWindingController() override;
};
-/// Registers all AM services with the specified service manager.
-void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nvflinger,
- Core::System& system);
+void LoopProcess(Nvnflinger::Nvnflinger& nvnflinger, Core::System& system);
} // namespace Service::AM
diff --git a/src/core/hle/service/am/applet_ae.cpp b/src/core/hle/service/am/applet_ae.cpp
index d7719da35..2764f7ceb 100644
--- a/src/core/hle/service/am/applet_ae.cpp
+++ b/src/core/hle/service/am/applet_ae.cpp
@@ -3,20 +3,20 @@
#include "common/logging/log.h"
#include "core/core.h"
-#include "core/hle/ipc_helpers.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/applet_ae.h"
-#include "core/hle/service/nvflinger/nvflinger.h"
+#include "core/hle/service/ipc_helpers.h"
+#include "core/hle/service/nvnflinger/nvnflinger.h"
namespace Service::AM {
class ILibraryAppletProxy final : public ServiceFramework<ILibraryAppletProxy> {
public:
- explicit ILibraryAppletProxy(NVFlinger::NVFlinger& nvflinger_,
+ explicit ILibraryAppletProxy(Nvnflinger::Nvnflinger& nvnflinger_,
std::shared_ptr<AppletMessageQueue> msg_queue_,
Core::System& system_)
- : ServiceFramework{system_, "ILibraryAppletProxy"}, nvflinger{nvflinger_},
- msg_queue{std::move(msg_queue_)} {
+ : ServiceFramework{system_, "ILibraryAppletProxy"},
+ nvnflinger{nvnflinger_}, msg_queue{std::move(msg_queue_)} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &ILibraryAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"},
@@ -36,7 +36,7 @@ public:
}
private:
- void GetCommonStateGetter(Kernel::HLERequestContext& ctx) {
+ void GetCommonStateGetter(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -44,15 +44,15 @@ private:
rb.PushIpcInterface<ICommonStateGetter>(system, msg_queue);
}
- void GetSelfController(Kernel::HLERequestContext& ctx) {
+ void GetSelfController(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
- rb.PushIpcInterface<ISelfController>(system, nvflinger);
+ rb.PushIpcInterface<ISelfController>(system, nvnflinger);
}
- void GetWindowController(Kernel::HLERequestContext& ctx) {
+ void GetWindowController(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -60,7 +60,7 @@ private:
rb.PushIpcInterface<IWindowController>(system);
}
- void GetAudioController(Kernel::HLERequestContext& ctx) {
+ void GetAudioController(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -68,7 +68,7 @@ private:
rb.PushIpcInterface<IAudioController>(system);
}
- void GetDisplayController(Kernel::HLERequestContext& ctx) {
+ void GetDisplayController(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -76,7 +76,7 @@ private:
rb.PushIpcInterface<IDisplayController>(system);
}
- void GetProcessWindingController(Kernel::HLERequestContext& ctx) {
+ void GetProcessWindingController(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -84,7 +84,7 @@ private:
rb.PushIpcInterface<IProcessWindingController>(system);
}
- void GetDebugFunctions(Kernel::HLERequestContext& ctx) {
+ void GetDebugFunctions(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -92,7 +92,7 @@ private:
rb.PushIpcInterface<IDebugFunctions>(system);
}
- void GetLibraryAppletCreator(Kernel::HLERequestContext& ctx) {
+ void GetLibraryAppletCreator(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -100,7 +100,7 @@ private:
rb.PushIpcInterface<ILibraryAppletCreator>(system);
}
- void GetApplicationFunctions(Kernel::HLERequestContext& ctx) {
+ void GetApplicationFunctions(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -108,17 +108,17 @@ private:
rb.PushIpcInterface<IApplicationFunctions>(system);
}
- NVFlinger::NVFlinger& nvflinger;
+ Nvnflinger::Nvnflinger& nvnflinger;
std::shared_ptr<AppletMessageQueue> msg_queue;
};
class ISystemAppletProxy final : public ServiceFramework<ISystemAppletProxy> {
public:
- explicit ISystemAppletProxy(NVFlinger::NVFlinger& nvflinger_,
+ explicit ISystemAppletProxy(Nvnflinger::Nvnflinger& nvnflinger_,
std::shared_ptr<AppletMessageQueue> msg_queue_,
Core::System& system_)
- : ServiceFramework{system_, "ISystemAppletProxy"}, nvflinger{nvflinger_},
- msg_queue{std::move(msg_queue_)} {
+ : ServiceFramework{system_, "ISystemAppletProxy"},
+ nvnflinger{nvnflinger_}, msg_queue{std::move(msg_queue_)} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &ISystemAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"},
@@ -140,7 +140,7 @@ public:
}
private:
- void GetCommonStateGetter(Kernel::HLERequestContext& ctx) {
+ void GetCommonStateGetter(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -148,15 +148,15 @@ private:
rb.PushIpcInterface<ICommonStateGetter>(system, msg_queue);
}
- void GetSelfController(Kernel::HLERequestContext& ctx) {
+ void GetSelfController(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
- rb.PushIpcInterface<ISelfController>(system, nvflinger);
+ rb.PushIpcInterface<ISelfController>(system, nvnflinger);
}
- void GetWindowController(Kernel::HLERequestContext& ctx) {
+ void GetWindowController(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -164,7 +164,7 @@ private:
rb.PushIpcInterface<IWindowController>(system);
}
- void GetAudioController(Kernel::HLERequestContext& ctx) {
+ void GetAudioController(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -172,7 +172,7 @@ private:
rb.PushIpcInterface<IAudioController>(system);
}
- void GetDisplayController(Kernel::HLERequestContext& ctx) {
+ void GetDisplayController(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -180,7 +180,7 @@ private:
rb.PushIpcInterface<IDisplayController>(system);
}
- void GetDebugFunctions(Kernel::HLERequestContext& ctx) {
+ void GetDebugFunctions(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -188,7 +188,7 @@ private:
rb.PushIpcInterface<IDebugFunctions>(system);
}
- void GetLibraryAppletCreator(Kernel::HLERequestContext& ctx) {
+ void GetLibraryAppletCreator(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -196,7 +196,7 @@ private:
rb.PushIpcInterface<ILibraryAppletCreator>(system);
}
- void GetHomeMenuFunctions(Kernel::HLERequestContext& ctx) {
+ void GetHomeMenuFunctions(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -204,7 +204,7 @@ private:
rb.PushIpcInterface<IHomeMenuFunctions>(system);
}
- void GetGlobalStateController(Kernel::HLERequestContext& ctx) {
+ void GetGlobalStateController(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -212,7 +212,7 @@ private:
rb.PushIpcInterface<IGlobalStateController>(system);
}
- void GetApplicationCreator(Kernel::HLERequestContext& ctx) {
+ void GetApplicationCreator(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -220,38 +220,38 @@ private:
rb.PushIpcInterface<IApplicationCreator>(system);
}
- NVFlinger::NVFlinger& nvflinger;
+ Nvnflinger::Nvnflinger& nvnflinger;
std::shared_ptr<AppletMessageQueue> msg_queue;
};
-void AppletAE::OpenSystemAppletProxy(Kernel::HLERequestContext& ctx) {
+void AppletAE::OpenSystemAppletProxy(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
- rb.PushIpcInterface<ISystemAppletProxy>(nvflinger, msg_queue, system);
+ rb.PushIpcInterface<ISystemAppletProxy>(nvnflinger, msg_queue, system);
}
-void AppletAE::OpenLibraryAppletProxy(Kernel::HLERequestContext& ctx) {
+void AppletAE::OpenLibraryAppletProxy(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
- rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger, msg_queue, system);
+ rb.PushIpcInterface<ILibraryAppletProxy>(nvnflinger, msg_queue, system);
}
-void AppletAE::OpenLibraryAppletProxyOld(Kernel::HLERequestContext& ctx) {
+void AppletAE::OpenLibraryAppletProxyOld(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
- rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger, msg_queue, system);
+ rb.PushIpcInterface<ILibraryAppletProxy>(nvnflinger, msg_queue, system);
}
-AppletAE::AppletAE(NVFlinger::NVFlinger& nvflinger_, std::shared_ptr<AppletMessageQueue> msg_queue_,
- Core::System& system_)
- : ServiceFramework{system_, "appletAE"}, nvflinger{nvflinger_}, msg_queue{
- std::move(msg_queue_)} {
+AppletAE::AppletAE(Nvnflinger::Nvnflinger& nvnflinger_,
+ std::shared_ptr<AppletMessageQueue> msg_queue_, Core::System& system_)
+ : ServiceFramework{system_, "appletAE"}, nvnflinger{nvnflinger_}, msg_queue{
+ std::move(msg_queue_)} {
// clang-format off
static const FunctionInfo functions[] = {
{100, &AppletAE::OpenSystemAppletProxy, "OpenSystemAppletProxy"},
diff --git a/src/core/hle/service/am/applet_ae.h b/src/core/hle/service/am/applet_ae.h
index 2147976a6..538ce2903 100644
--- a/src/core/hle/service/am/applet_ae.h
+++ b/src/core/hle/service/am/applet_ae.h
@@ -12,8 +12,8 @@ namespace FileSystem {
class FileSystemController;
}
-namespace NVFlinger {
-class NVFlinger;
+namespace Nvnflinger {
+class Nvnflinger;
}
namespace AM {
@@ -22,18 +22,18 @@ class AppletMessageQueue;
class AppletAE final : public ServiceFramework<AppletAE> {
public:
- explicit AppletAE(NVFlinger::NVFlinger& nvflinger_,
+ explicit AppletAE(Nvnflinger::Nvnflinger& nvnflinger_,
std::shared_ptr<AppletMessageQueue> msg_queue_, Core::System& system_);
~AppletAE() override;
const std::shared_ptr<AppletMessageQueue>& GetMessageQueue() const;
private:
- void OpenSystemAppletProxy(Kernel::HLERequestContext& ctx);
- void OpenLibraryAppletProxy(Kernel::HLERequestContext& ctx);
- void OpenLibraryAppletProxyOld(Kernel::HLERequestContext& ctx);
+ void OpenSystemAppletProxy(HLERequestContext& ctx);
+ void OpenLibraryAppletProxy(HLERequestContext& ctx);
+ void OpenLibraryAppletProxyOld(HLERequestContext& ctx);
- NVFlinger::NVFlinger& nvflinger;
+ Nvnflinger::Nvnflinger& nvnflinger;
std::shared_ptr<AppletMessageQueue> msg_queue;
};
diff --git a/src/core/hle/service/am/applet_oe.cpp b/src/core/hle/service/am/applet_oe.cpp
index 00fc4202c..d6c565d85 100644
--- a/src/core/hle/service/am/applet_oe.cpp
+++ b/src/core/hle/service/am/applet_oe.cpp
@@ -2,20 +2,20 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/logging/log.h"
-#include "core/hle/ipc_helpers.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/applet_oe.h"
-#include "core/hle/service/nvflinger/nvflinger.h"
+#include "core/hle/service/ipc_helpers.h"
+#include "core/hle/service/nvnflinger/nvnflinger.h"
namespace Service::AM {
class IApplicationProxy final : public ServiceFramework<IApplicationProxy> {
public:
- explicit IApplicationProxy(NVFlinger::NVFlinger& nvflinger_,
+ explicit IApplicationProxy(Nvnflinger::Nvnflinger& nvnflinger_,
std::shared_ptr<AppletMessageQueue> msg_queue_,
Core::System& system_)
- : ServiceFramework{system_, "IApplicationProxy"}, nvflinger{nvflinger_},
- msg_queue{std::move(msg_queue_)} {
+ : ServiceFramework{system_, "IApplicationProxy"},
+ nvnflinger{nvnflinger_}, msg_queue{std::move(msg_queue_)} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &IApplicationProxy::GetCommonStateGetter, "GetCommonStateGetter"},
@@ -34,7 +34,7 @@ public:
}
private:
- void GetAudioController(Kernel::HLERequestContext& ctx) {
+ void GetAudioController(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -42,7 +42,7 @@ private:
rb.PushIpcInterface<IAudioController>(system);
}
- void GetDisplayController(Kernel::HLERequestContext& ctx) {
+ void GetDisplayController(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -50,7 +50,7 @@ private:
rb.PushIpcInterface<IDisplayController>(system);
}
- void GetDebugFunctions(Kernel::HLERequestContext& ctx) {
+ void GetDebugFunctions(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -58,7 +58,7 @@ private:
rb.PushIpcInterface<IDebugFunctions>(system);
}
- void GetWindowController(Kernel::HLERequestContext& ctx) {
+ void GetWindowController(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -66,15 +66,15 @@ private:
rb.PushIpcInterface<IWindowController>(system);
}
- void GetSelfController(Kernel::HLERequestContext& ctx) {
+ void GetSelfController(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
- rb.PushIpcInterface<ISelfController>(system, nvflinger);
+ rb.PushIpcInterface<ISelfController>(system, nvnflinger);
}
- void GetCommonStateGetter(Kernel::HLERequestContext& ctx) {
+ void GetCommonStateGetter(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -82,7 +82,7 @@ private:
rb.PushIpcInterface<ICommonStateGetter>(system, msg_queue);
}
- void GetLibraryAppletCreator(Kernel::HLERequestContext& ctx) {
+ void GetLibraryAppletCreator(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -90,7 +90,7 @@ private:
rb.PushIpcInterface<ILibraryAppletCreator>(system);
}
- void GetApplicationFunctions(Kernel::HLERequestContext& ctx) {
+ void GetApplicationFunctions(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -98,22 +98,22 @@ private:
rb.PushIpcInterface<IApplicationFunctions>(system);
}
- NVFlinger::NVFlinger& nvflinger;
+ Nvnflinger::Nvnflinger& nvnflinger;
std::shared_ptr<AppletMessageQueue> msg_queue;
};
-void AppletOE::OpenApplicationProxy(Kernel::HLERequestContext& ctx) {
+void AppletOE::OpenApplicationProxy(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
- rb.PushIpcInterface<IApplicationProxy>(nvflinger, msg_queue, system);
+ rb.PushIpcInterface<IApplicationProxy>(nvnflinger, msg_queue, system);
}
-AppletOE::AppletOE(NVFlinger::NVFlinger& nvflinger_, std::shared_ptr<AppletMessageQueue> msg_queue_,
- Core::System& system_)
- : ServiceFramework{system_, "appletOE"}, nvflinger{nvflinger_}, msg_queue{
- std::move(msg_queue_)} {
+AppletOE::AppletOE(Nvnflinger::Nvnflinger& nvnflinger_,
+ std::shared_ptr<AppletMessageQueue> msg_queue_, Core::System& system_)
+ : ServiceFramework{system_, "appletOE"}, nvnflinger{nvnflinger_}, msg_queue{
+ std::move(msg_queue_)} {
static const FunctionInfo functions[] = {
{0, &AppletOE::OpenApplicationProxy, "OpenApplicationProxy"},
};
diff --git a/src/core/hle/service/am/applet_oe.h b/src/core/hle/service/am/applet_oe.h
index 8fea249f1..39eccc4ab 100644
--- a/src/core/hle/service/am/applet_oe.h
+++ b/src/core/hle/service/am/applet_oe.h
@@ -12,8 +12,8 @@ namespace FileSystem {
class FileSystemController;
}
-namespace NVFlinger {
-class NVFlinger;
+namespace Nvnflinger {
+class Nvnflinger;
}
namespace AM {
@@ -22,16 +22,16 @@ class AppletMessageQueue;
class AppletOE final : public ServiceFramework<AppletOE> {
public:
- explicit AppletOE(NVFlinger::NVFlinger& nvflinger_,
+ explicit AppletOE(Nvnflinger::Nvnflinger& nvnflinger_,
std::shared_ptr<AppletMessageQueue> msg_queue_, Core::System& system_);
~AppletOE() override;
const std::shared_ptr<AppletMessageQueue>& GetMessageQueue() const;
private:
- void OpenApplicationProxy(Kernel::HLERequestContext& ctx);
+ void OpenApplicationProxy(HLERequestContext& ctx);
- NVFlinger::NVFlinger& nvflinger;
+ Nvnflinger::Nvnflinger& nvnflinger;
std::shared_ptr<AppletMessageQueue> msg_queue;
};
diff --git a/src/core/hle/service/am/applets/applet_cabinet.cpp b/src/core/hle/service/am/applets/applet_cabinet.cpp
index d0969b0f1..19ed184e8 100644
--- a/src/core/hle/service/am/applets/applet_cabinet.cpp
+++ b/src/core/hle/service/am/applets/applet_cabinet.cpp
@@ -11,7 +11,7 @@
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/applets/applet_cabinet.h"
#include "core/hle/service/mii/mii_manager.h"
-#include "core/hle/service/nfp/nfp_device.h"
+#include "core/hle/service/nfc/common/device.h"
namespace Service::AM::Applets {
@@ -72,10 +72,10 @@ void Cabinet::Execute() {
// TODO: listen on all controllers
if (nfp_device == nullptr) {
- nfp_device = std::make_shared<Service::NFP::NfpDevice>(
+ nfp_device = std::make_shared<Service::NFC::NfcDevice>(
system.HIDCore().GetFirstNpadId(), system, service_context, availability_change_event);
nfp_device->Initialize();
- nfp_device->StartDetection(Service::NFP::TagProtocol::All);
+ nfp_device->StartDetection(Service::NFC::NfcProtocol::All);
}
const Core::Frontend::CabinetParameters parameters{
@@ -106,20 +106,22 @@ void Cabinet::DisplayCompleted(bool apply_changes, std::string_view amiibo_name)
Cancel();
}
- if (nfp_device->GetCurrentState() != Service::NFP::DeviceState::TagFound &&
- nfp_device->GetCurrentState() != Service::NFP::DeviceState::TagMounted) {
+ if (nfp_device->GetCurrentState() != Service::NFC::DeviceState::TagFound &&
+ nfp_device->GetCurrentState() != Service::NFC::DeviceState::TagMounted) {
Cancel();
}
- if (nfp_device->GetCurrentState() == Service::NFP::DeviceState::TagFound) {
- nfp_device->Mount(Service::NFP::MountTarget::All);
+ if (nfp_device->GetCurrentState() == Service::NFC::DeviceState::TagFound) {
+ nfp_device->Mount(Service::NFP::ModelType::Amiibo, Service::NFP::MountTarget::All);
}
switch (applet_input_common.applet_mode) {
case Service::NFP::CabinetMode::StartNicknameAndOwnerSettings: {
- Service::NFP::AmiiboName name{};
- std::memcpy(name.data(), amiibo_name.data(), std::min(amiibo_name.size(), name.size() - 1));
- nfp_device->SetNicknameAndOwner(name);
+ Service::NFP::RegisterInfoPrivate register_info{};
+ std::memcpy(register_info.amiibo_name.data(), amiibo_name.data(),
+ std::min(amiibo_name.size(), register_info.amiibo_name.size() - 1));
+
+ nfp_device->SetRegisterInfoPrivate(register_info);
break;
}
case Service::NFP::CabinetMode::StartGameDataEraser:
@@ -129,7 +131,7 @@ void Cabinet::DisplayCompleted(bool apply_changes, std::string_view amiibo_name)
nfp_device->RestoreAmiibo();
break;
case Service::NFP::CabinetMode::StartFormatter:
- nfp_device->DeleteAllData();
+ nfp_device->Format();
break;
default:
UNIMPLEMENTED_MSG("Unknown CabinetMode={}", applet_input_common.applet_mode);
@@ -174,4 +176,9 @@ void Cabinet::Cancel() {
broker.SignalStateChanged();
}
+Result Cabinet::RequestExit() {
+ frontend.Close();
+ R_SUCCEED();
+}
+
} // namespace Service::AM::Applets
diff --git a/src/core/hle/service/am/applets/applet_cabinet.h b/src/core/hle/service/am/applets/applet_cabinet.h
index 84197a807..b56427021 100644
--- a/src/core/hle/service/am/applets/applet_cabinet.h
+++ b/src/core/hle/service/am/applets/applet_cabinet.h
@@ -19,8 +19,8 @@ namespace Core {
class System;
} // namespace Core
-namespace Service::NFP {
-class NfpDevice;
+namespace Service::NFC {
+class NfcDevice;
}
namespace Service::AM::Applets {
@@ -89,13 +89,14 @@ public:
void Execute() override;
void DisplayCompleted(bool apply_changes, std::string_view amiibo_name);
void Cancel();
+ Result RequestExit() override;
private:
const Core::Frontend::CabinetApplet& frontend;
Core::System& system;
bool is_complete{false};
- std::shared_ptr<Service::NFP::NfpDevice> nfp_device;
+ std::shared_ptr<Service::NFC::NfcDevice> nfp_device;
Kernel::KEvent* availability_change_event;
KernelHelpers::ServiceContext service_context;
StartParamForAmiiboSettings applet_input_common{};
diff --git a/src/core/hle/service/am/applets/applet_controller.cpp b/src/core/hle/service/am/applets/applet_controller.cpp
index b418031de..9840d2547 100644
--- a/src/core/hle/service/am/applets/applet_controller.cpp
+++ b/src/core/hle/service/am/applets/applet_controller.cpp
@@ -19,10 +19,9 @@
namespace Service::AM::Applets {
-// This error code (0x183ACA) is thrown when the applet fails to initialize.
-[[maybe_unused]] constexpr Result ERR_CONTROLLER_APPLET_3101{ErrorModule::HID, 3101};
-// This error code (0x183CCA) is thrown when the u32 result in ControllerSupportResultInfo is 2.
-[[maybe_unused]] constexpr Result ERR_CONTROLLER_APPLET_3102{ErrorModule::HID, 3102};
+[[maybe_unused]] constexpr Result ResultControllerSupportCanceled{ErrorModule::HID, 3101};
+[[maybe_unused]] constexpr Result ResultControllerSupportNotSupportedNpadStyle{ErrorModule::HID,
+ 3102};
static Core::Frontend::ControllerParameters ConvertToFrontendParameters(
ControllerSupportArgPrivate private_arg, ControllerSupportArgHeader header, bool enable_text,
@@ -225,7 +224,8 @@ void Controller::Execute() {
parameters.allow_dual_joycons, parameters.allow_left_joycon,
parameters.allow_right_joycon);
- frontend.ReconfigureControllers([this] { ConfigurationComplete(); }, parameters);
+ frontend.ReconfigureControllers(
+ [this](bool is_success) { ConfigurationComplete(is_success); }, parameters);
break;
}
case ControllerSupportMode::ShowControllerStrapGuide:
@@ -233,16 +233,16 @@ void Controller::Execute() {
case ControllerSupportMode::ShowControllerKeyRemappingForSystem:
UNIMPLEMENTED_MSG("ControllerSupportMode={} is not implemented",
controller_private_arg.mode);
- ConfigurationComplete();
+ ConfigurationComplete(true);
break;
default: {
- ConfigurationComplete();
+ ConfigurationComplete(true);
break;
}
}
}
-void Controller::ConfigurationComplete() {
+void Controller::ConfigurationComplete(bool is_success) {
ControllerSupportResultInfo result_info{};
// If enable_single_mode is enabled, player_count is 1 regardless of any other parameters.
@@ -251,7 +251,8 @@ void Controller::ConfigurationComplete() {
result_info.selected_id = static_cast<u32>(system.HIDCore().GetFirstNpadId());
- result_info.result = 0;
+ result_info.result =
+ is_success ? ControllerSupportResult::Success : ControllerSupportResult::Cancel;
LOG_DEBUG(Service_HID, "Result Info: player_count={}, selected_id={}, result={}",
result_info.player_count, result_info.selected_id, result_info.result);
@@ -263,4 +264,9 @@ void Controller::ConfigurationComplete() {
broker.SignalStateChanged();
}
+Result Controller::RequestExit() {
+ frontend.Close();
+ R_SUCCEED();
+}
+
} // namespace Service::AM::Applets
diff --git a/src/core/hle/service/am/applets/applet_controller.h b/src/core/hle/service/am/applets/applet_controller.h
index 1f9adec65..f6c64f633 100644
--- a/src/core/hle/service/am/applets/applet_controller.h
+++ b/src/core/hle/service/am/applets/applet_controller.h
@@ -48,6 +48,11 @@ enum class ControllerSupportCaller : u8 {
MaxControllerSupportCaller,
};
+enum class ControllerSupportResult : u32 {
+ Success = 0,
+ Cancel = 2,
+};
+
struct ControllerSupportArgPrivate {
u32 arg_private_size{};
u32 arg_size{};
@@ -112,7 +117,7 @@ struct ControllerSupportResultInfo {
s8 player_count{};
INSERT_PADDING_BYTES(3);
u32 selected_id{};
- u32 result{};
+ ControllerSupportResult result{};
};
static_assert(sizeof(ControllerSupportResultInfo) == 0xC,
"ControllerSupportResultInfo has incorrect size.");
@@ -129,8 +134,9 @@ public:
Result GetStatus() const override;
void ExecuteInteractive() override;
void Execute() override;
+ Result RequestExit() override;
- void ConfigurationComplete();
+ void ConfigurationComplete(bool is_success);
private:
const Core::Frontend::ControllerApplet& frontend;
diff --git a/src/core/hle/service/am/applets/applet_error.cpp b/src/core/hle/service/am/applets/applet_error.cpp
index bae0d99a6..b46ea840c 100644
--- a/src/core/hle/service/am/applets/applet_error.cpp
+++ b/src/core/hle/service/am/applets/applet_error.cpp
@@ -166,7 +166,7 @@ void Error::Execute() {
}
const auto callback = [this] { DisplayCompleted(); };
- const auto title_id = system.GetCurrentProcessProgramID();
+ const auto title_id = system.GetApplicationProcessProgramID();
const auto& reporter{system.GetReporter()};
switch (mode) {
@@ -209,4 +209,9 @@ void Error::DisplayCompleted() {
broker.SignalStateChanged();
}
+Result Error::RequestExit() {
+ frontend.Close();
+ R_SUCCEED();
+}
+
} // namespace Service::AM::Applets
diff --git a/src/core/hle/service/am/applets/applet_error.h b/src/core/hle/service/am/applets/applet_error.h
index d78d6f1d1..d822a32bb 100644
--- a/src/core/hle/service/am/applets/applet_error.h
+++ b/src/core/hle/service/am/applets/applet_error.h
@@ -34,6 +34,7 @@ public:
Result GetStatus() const override;
void ExecuteInteractive() override;
void Execute() override;
+ Result RequestExit() override;
void DisplayCompleted();
diff --git a/src/core/hle/service/am/applets/applet_general_backend.cpp b/src/core/hle/service/am/applets/applet_general_backend.cpp
index e50acdaf6..8b352020e 100644
--- a/src/core/hle/service/am/applets/applet_general_backend.cpp
+++ b/src/core/hle/service/am/applets/applet_general_backend.cpp
@@ -150,6 +150,11 @@ void Auth::AuthFinished(bool is_successful) {
broker.SignalStateChanged();
}
+Result Auth::RequestExit() {
+ frontend.Close();
+ R_SUCCEED();
+}
+
PhotoViewer::PhotoViewer(Core::System& system_, LibraryAppletMode applet_mode_,
const Core::Frontend::PhotoViewerApplet& frontend_)
: Applet{system_, applet_mode_}, frontend{frontend_}, system{system_} {}
@@ -186,7 +191,7 @@ void PhotoViewer::Execute() {
const auto callback = [this] { ViewFinished(); };
switch (mode) {
case PhotoViewerAppletMode::CurrentApp:
- frontend.ShowPhotosForApplication(system.GetCurrentProcessProgramID(), callback);
+ frontend.ShowPhotosForApplication(system.GetApplicationProcessProgramID(), callback);
break;
case PhotoViewerAppletMode::AllApps:
frontend.ShowAllPhotos(callback);
@@ -202,6 +207,11 @@ void PhotoViewer::ViewFinished() {
broker.SignalStateChanged();
}
+Result PhotoViewer::RequestExit() {
+ frontend.Close();
+ R_SUCCEED();
+}
+
StubApplet::StubApplet(Core::System& system_, AppletId id_, LibraryAppletMode applet_mode_)
: Applet{system_, applet_mode_}, id{id_}, system{system_} {}
@@ -250,4 +260,9 @@ void StubApplet::Execute() {
broker.SignalStateChanged();
}
+Result StubApplet::RequestExit() {
+ // Nothing to do.
+ R_SUCCEED();
+}
+
} // namespace Service::AM::Applets
diff --git a/src/core/hle/service/am/applets/applet_general_backend.h b/src/core/hle/service/am/applets/applet_general_backend.h
index a9f2535a2..34ecaebb9 100644
--- a/src/core/hle/service/am/applets/applet_general_backend.h
+++ b/src/core/hle/service/am/applets/applet_general_backend.h
@@ -28,6 +28,7 @@ public:
Result GetStatus() const override;
void ExecuteInteractive() override;
void Execute() override;
+ Result RequestExit() override;
void AuthFinished(bool is_successful = true);
@@ -59,6 +60,7 @@ public:
Result GetStatus() const override;
void ExecuteInteractive() override;
void Execute() override;
+ Result RequestExit() override;
void ViewFinished();
@@ -80,6 +82,7 @@ public:
Result GetStatus() const override;
void ExecuteInteractive() override;
void Execute() override;
+ Result RequestExit() override;
private:
AppletId id;
diff --git a/src/core/hle/service/am/applets/applet_mii_edit.cpp b/src/core/hle/service/am/applets/applet_mii_edit.cpp
index ae80ef506..d1f652c09 100644
--- a/src/core/hle/service/am/applets/applet_mii_edit.cpp
+++ b/src/core/hle/service/am/applets/applet_mii_edit.cpp
@@ -135,4 +135,9 @@ void MiiEdit::MiiEditOutputForCharInfoEditing(MiiEditResult result,
broker.SignalStateChanged();
}
+Result MiiEdit::RequestExit() {
+ frontend.Close();
+ R_SUCCEED();
+}
+
} // namespace Service::AM::Applets
diff --git a/src/core/hle/service/am/applets/applet_mii_edit.h b/src/core/hle/service/am/applets/applet_mii_edit.h
index d18dd3cf5..3f46fae1b 100644
--- a/src/core/hle/service/am/applets/applet_mii_edit.h
+++ b/src/core/hle/service/am/applets/applet_mii_edit.h
@@ -25,6 +25,7 @@ public:
Result GetStatus() const override;
void ExecuteInteractive() override;
void Execute() override;
+ Result RequestExit() override;
void MiiEditOutput(MiiEditResult result, s32 index);
diff --git a/src/core/hle/service/am/applets/applet_profile_select.cpp b/src/core/hle/service/am/applets/applet_profile_select.cpp
index c738db028..89cb323e9 100644
--- a/src/core/hle/service/am/applets/applet_profile_select.cpp
+++ b/src/core/hle/service/am/applets/applet_profile_select.cpp
@@ -7,13 +7,12 @@
#include "common/string_util.h"
#include "core/core.h"
#include "core/frontend/applets/profile_select.h"
+#include "core/hle/service/acc/errors.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/applets/applet_profile_select.h"
namespace Service::AM::Applets {
-constexpr Result ERR_USER_CANCELLED_SELECTION{ErrorModule::Account, 1};
-
ProfileSelect::ProfileSelect(Core::System& system_, LibraryAppletMode applet_mode_,
const Core::Frontend::ProfileSelectApplet& frontend_)
: Applet{system_, applet_mode_}, frontend{frontend_}, system{system_} {}
@@ -26,13 +25,29 @@ void ProfileSelect::Initialize() {
final_data.clear();
Applet::Initialize();
+ profile_select_version = ProfileSelectAppletVersion{common_args.library_version};
const auto user_config_storage = broker.PopNormalDataToApplet();
ASSERT(user_config_storage != nullptr);
const auto& user_config = user_config_storage->GetData();
- ASSERT(user_config.size() >= sizeof(UserSelectionConfig));
- std::memcpy(&config, user_config.data(), sizeof(UserSelectionConfig));
+ LOG_INFO(Service_AM, "Initializing Profile Select Applet with version={}",
+ profile_select_version);
+
+ switch (profile_select_version) {
+ case ProfileSelectAppletVersion::Version1:
+ ASSERT(user_config.size() == sizeof(UiSettingsV1));
+ std::memcpy(&config_old, user_config.data(), sizeof(UiSettingsV1));
+ break;
+ case ProfileSelectAppletVersion::Version2:
+ case ProfileSelectAppletVersion::Version3:
+ ASSERT(user_config.size() == sizeof(UiSettings));
+ std::memcpy(&config, user_config.data(), sizeof(UiSettings));
+ break;
+ default:
+ UNIMPLEMENTED_MSG("Unknown profile_select_version = {}", profile_select_version);
+ break;
+ }
}
bool ProfileSelect::TransactionComplete() const {
@@ -53,25 +68,56 @@ void ProfileSelect::Execute() {
return;
}
- frontend.SelectProfile([this](std::optional<Common::UUID> uuid) { SelectionComplete(uuid); });
+ Core::Frontend::ProfileSelectParameters parameters{};
+
+ switch (profile_select_version) {
+ case ProfileSelectAppletVersion::Version1:
+ parameters = {
+ .mode = config_old.mode,
+ .invalid_uid_list = config_old.invalid_uid_list,
+ .display_options = config_old.display_options,
+ .purpose = UserSelectionPurpose::General,
+ };
+ break;
+ case ProfileSelectAppletVersion::Version2:
+ case ProfileSelectAppletVersion::Version3:
+ parameters = {
+ .mode = config.mode,
+ .invalid_uid_list = config.invalid_uid_list,
+ .display_options = config.display_options,
+ .purpose = config.purpose,
+ };
+ break;
+ default:
+ UNIMPLEMENTED_MSG("Unknown profile_select_version = {}", profile_select_version);
+ break;
+ }
+
+ frontend.SelectProfile([this](std::optional<Common::UUID> uuid) { SelectionComplete(uuid); },
+ parameters);
}
void ProfileSelect::SelectionComplete(std::optional<Common::UUID> uuid) {
- UserSelectionOutput output{};
+ UiReturnArg output{};
if (uuid.has_value() && uuid->IsValid()) {
output.result = 0;
output.uuid_selected = *uuid;
} else {
- status = ERR_USER_CANCELLED_SELECTION;
- output.result = ERR_USER_CANCELLED_SELECTION.raw;
+ status = Account::ResultCancelledByUser;
+ output.result = Account::ResultCancelledByUser.raw;
output.uuid_selected = Common::InvalidUUID;
}
- final_data = std::vector<u8>(sizeof(UserSelectionOutput));
+ final_data = std::vector<u8>(sizeof(UiReturnArg));
std::memcpy(final_data.data(), &output, final_data.size());
broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(final_data)));
broker.SignalStateChanged();
}
+Result ProfileSelect::RequestExit() {
+ frontend.Close();
+ R_SUCCEED();
+}
+
} // namespace Service::AM::Applets
diff --git a/src/core/hle/service/am/applets/applet_profile_select.h b/src/core/hle/service/am/applets/applet_profile_select.h
index b77f1d205..369f9250f 100644
--- a/src/core/hle/service/am/applets/applet_profile_select.h
+++ b/src/core/hle/service/am/applets/applet_profile_select.h
@@ -16,19 +16,100 @@ class System;
namespace Service::AM::Applets {
-struct UserSelectionConfig {
- // TODO(DarkLordZach): RE this structure
- // It seems to be flags and the like that determine the UI of the applet on the switch... from
- // my research this is safe to ignore for now.
- INSERT_PADDING_BYTES(0xA0);
+enum class ProfileSelectAppletVersion : u32 {
+ Version1 = 0x1, // 1.0.0+
+ Version2 = 0x10000, // 2.0.0+
+ Version3 = 0x20000, // 6.0.0+
};
-static_assert(sizeof(UserSelectionConfig) == 0xA0, "UserSelectionConfig has incorrect size.");
-struct UserSelectionOutput {
+// This is nn::account::UiMode
+enum class UiMode {
+ UserSelector,
+ UserCreator,
+ EnsureNetworkServiceAccountAvailable,
+ UserIconEditor,
+ UserNicknameEditor,
+ UserCreatorForStarter,
+ NintendoAccountAuthorizationRequestContext,
+ IntroduceExternalNetworkServiceAccount,
+ IntroduceExternalNetworkServiceAccountForRegistration,
+ NintendoAccountNnidLinker,
+ LicenseRequirementsForNetworkService,
+ LicenseRequirementsForNetworkServiceWithUserContextImpl,
+ UserCreatorForImmediateNaLoginTest,
+ UserQualificationPromoter,
+};
+
+// This is nn::account::UserSelectionPurpose
+enum class UserSelectionPurpose {
+ General,
+ GameCardRegistration,
+ EShopLaunch,
+ EShopItemShow,
+ PicturePost,
+ NintendoAccountLinkage,
+ SettingsUpdate,
+ SaveDataDeletion,
+ UserMigration,
+ SaveDataTransfer,
+};
+
+// This is nn::account::NintendoAccountStartupDialogType
+enum class NintendoAccountStartupDialogType {
+ LoginAndCreate,
+ Login,
+ Create,
+};
+
+// This is nn::account::UserSelectionSettingsForSystemService
+struct UserSelectionSettingsForSystemService {
+ UserSelectionPurpose purpose;
+ bool enable_user_creation;
+ INSERT_PADDING_BYTES(0x3);
+};
+static_assert(sizeof(UserSelectionSettingsForSystemService) == 0x8,
+ "UserSelectionSettingsForSystemService has incorrect size.");
+
+struct UiSettingsDisplayOptions {
+ bool is_network_service_account_required;
+ bool is_skip_enabled;
+ bool is_system_or_launcher;
+ bool is_registration_permitted;
+ bool show_skip_button;
+ bool aditional_select;
+ bool show_user_selector;
+ bool is_unqualified_user_selectable;
+};
+static_assert(sizeof(UiSettingsDisplayOptions) == 0x8,
+ "UiSettingsDisplayOptions has incorrect size.");
+
+struct UiSettingsV1 {
+ UiMode mode;
+ INSERT_PADDING_BYTES(0x4);
+ std::array<Common::UUID, 8> invalid_uid_list;
+ u64 application_id;
+ UiSettingsDisplayOptions display_options;
+};
+static_assert(sizeof(UiSettingsV1) == 0x98, "UiSettings has incorrect size.");
+
+// This is nn::account::UiSettings
+struct UiSettings {
+ UiMode mode;
+ INSERT_PADDING_BYTES(0x4);
+ std::array<Common::UUID, 8> invalid_uid_list;
+ u64 application_id;
+ UiSettingsDisplayOptions display_options;
+ UserSelectionPurpose purpose;
+ INSERT_PADDING_BYTES(0x4);
+};
+static_assert(sizeof(UiSettings) == 0xA0, "UiSettings has incorrect size.");
+
+// This is nn::account::UiReturnArg
+struct UiReturnArg {
u64 result;
Common::UUID uuid_selected;
};
-static_assert(sizeof(UserSelectionOutput) == 0x18, "UserSelectionOutput has incorrect size.");
+static_assert(sizeof(UiReturnArg) == 0x18, "UiReturnArg has incorrect size.");
class ProfileSelect final : public Applet {
public:
@@ -42,13 +123,17 @@ public:
Result GetStatus() const override;
void ExecuteInteractive() override;
void Execute() override;
+ Result RequestExit() override;
void SelectionComplete(std::optional<Common::UUID> uuid);
private:
const Core::Frontend::ProfileSelectApplet& frontend;
- UserSelectionConfig config;
+ UiSettings config;
+ UiSettingsV1 config_old;
+ ProfileSelectAppletVersion profile_select_version;
+
bool complete = false;
Result status = ResultSuccess;
std::vector<u8> final_data;
diff --git a/src/core/hle/service/am/applets/applet_software_keyboard.cpp b/src/core/hle/service/am/applets/applet_software_keyboard.cpp
index c18236045..4145bb84f 100644
--- a/src/core/hle/service/am/applets/applet_software_keyboard.cpp
+++ b/src/core/hle/service/am/applets/applet_software_keyboard.cpp
@@ -770,6 +770,11 @@ void SoftwareKeyboard::ExitKeyboard() {
broker.SignalStateChanged();
}
+Result SoftwareKeyboard::RequestExit() {
+ frontend.Close();
+ R_SUCCEED();
+}
+
// Inline Software Keyboard Requests
void SoftwareKeyboard::RequestFinalize(const std::vector<u8>& request_data) {
diff --git a/src/core/hle/service/am/applets/applet_software_keyboard.h b/src/core/hle/service/am/applets/applet_software_keyboard.h
index b01b31c98..2e919811b 100644
--- a/src/core/hle/service/am/applets/applet_software_keyboard.h
+++ b/src/core/hle/service/am/applets/applet_software_keyboard.h
@@ -31,6 +31,7 @@ public:
Result GetStatus() const override;
void ExecuteInteractive() override;
void Execute() override;
+ Result RequestExit() override;
/**
* Submits the input text to the application.
diff --git a/src/core/hle/service/am/applets/applet_web_browser.cpp b/src/core/hle/service/am/applets/applet_web_browser.cpp
index 14aa6f69e..2accf7898 100644
--- a/src/core/hle/service/am/applets/applet_web_browser.cpp
+++ b/src/core/hle/service/am/applets/applet_web_browser.cpp
@@ -363,6 +363,11 @@ void WebBrowser::WebBrowserExit(WebExitReason exit_reason, std::string last_url)
broker.SignalStateChanged();
}
+Result WebBrowser::RequestExit() {
+ frontend.Close();
+ R_SUCCEED();
+}
+
bool WebBrowser::InputTLVExistsInMap(WebArgInputTLVType input_tlv_type) const {
return web_arg_input_tlv_map.find(input_tlv_type) != web_arg_input_tlv_map.end();
}
@@ -393,7 +398,7 @@ void WebBrowser::InitializeOffline() {
switch (document_kind) {
case DocumentKind::OfflineHtmlPage:
default:
- title_id = system.GetCurrentProcessProgramID();
+ title_id = system.GetApplicationProcessProgramID();
nca_type = FileSys::ContentRecordType::HtmlDocument;
additional_paths = "html-document";
break;
diff --git a/src/core/hle/service/am/applets/applet_web_browser.h b/src/core/hle/service/am/applets/applet_web_browser.h
index fd727fac8..99fe18659 100644
--- a/src/core/hle/service/am/applets/applet_web_browser.h
+++ b/src/core/hle/service/am/applets/applet_web_browser.h
@@ -35,6 +35,7 @@ public:
Result GetStatus() const override;
void ExecuteInteractive() override;
void Execute() override;
+ Result RequestExit() override;
void ExtractOfflineRomFS();
diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h
index a22eb62a8..12f374199 100644
--- a/src/core/hle/service/am/applets/applets.h
+++ b/src/core/hle/service/am/applets/applets.h
@@ -142,6 +142,7 @@ public:
virtual Result GetStatus() const = 0;
virtual void ExecuteInteractive() = 0;
virtual void Execute() = 0;
+ virtual Result RequestExit() = 0;
AppletDataBroker& GetBroker() {
return broker;
diff --git a/src/core/hle/service/am/tcap.cpp b/src/core/hle/service/am/tcap.cpp
deleted file mode 100644
index 818420e22..000000000
--- a/src/core/hle/service/am/tcap.cpp
+++ /dev/null
@@ -1,22 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#include "core/hle/service/am/tcap.h"
-
-namespace Service::AM {
-
-TCAP::TCAP(Core::System& system_) : ServiceFramework{system_, "tcap"} {
- // clang-format off
- static const FunctionInfo functions[] = {
- {0, nullptr, "GetContinuousHighSkinTemperatureEvent"},
- {1, nullptr, "SetOperationMode"},
- {2, nullptr, "LoadAndApplySettings"},
- };
- // clang-format on
-
- RegisterHandlers(functions);
-}
-
-TCAP::~TCAP() = default;
-
-} // namespace Service::AM
diff --git a/src/core/hle/service/am/tcap.h b/src/core/hle/service/am/tcap.h
deleted file mode 100644
index 6b2148c29..000000000
--- a/src/core/hle/service/am/tcap.h
+++ /dev/null
@@ -1,20 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#pragma once
-
-#include "core/hle/service/service.h"
-
-namespace Core {
-class System;
-}
-
-namespace Service::AM {
-
-class TCAP final : public ServiceFramework<TCAP> {
-public:
- explicit TCAP(Core::System& system_);
- ~TCAP() override;
-};
-
-} // namespace Service::AM
diff --git a/src/core/hle/service/aoc/aoc_u.cpp b/src/core/hle/service/aoc/aoc_u.cpp
index 368ccd52f..38c2138e8 100644
--- a/src/core/hle/service/aoc/aoc_u.cpp
+++ b/src/core/hle/service/aoc/aoc_u.cpp
@@ -14,9 +14,10 @@
#include "core/file_sys/nca_metadata.h"
#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/service/aoc/aoc_u.h"
+#include "core/hle/service/ipc_helpers.h"
+#include "core/hle/service/server_manager.h"
#include "core/loader/loader.h"
namespace Service::AOC {
@@ -68,7 +69,7 @@ public:
}
private:
- void SetDefaultDeliveryTarget(Kernel::HLERequestContext& ctx) {
+ void SetDefaultDeliveryTarget(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto unknown_1 = rp.Pop<u64>();
@@ -80,7 +81,7 @@ private:
rb.Push(ResultSuccess);
}
- void SetDeliveryTarget(Kernel::HLERequestContext& ctx) {
+ void SetDeliveryTarget(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto unknown_1 = rp.Pop<u64>();
@@ -92,7 +93,7 @@ private:
rb.Push(ResultSuccess);
}
- void GetPurchasedEventReadableHandle(Kernel::HLERequestContext& ctx) {
+ void GetPurchasedEventReadableHandle(HLERequestContext& ctx) {
LOG_WARNING(Service_AOC, "called");
IPC::ResponseBuilder rb{ctx, 2, 1};
@@ -129,6 +130,9 @@ AOC_U::AOC_U(Core::System& system_)
{101, &AOC_U::CreatePermanentEcPurchasedEventManager, "CreatePermanentEcPurchasedEventManager"},
{110, nullptr, "CreateContentsServiceManager"},
{200, nullptr, "SetRequiredAddOnContentsOnContentsAvailabilityTransition"},
+ {300, nullptr, "SetupHostAddOnContent"},
+ {301, nullptr, "GetRegisteredAddOnContentPath"},
+ {302, nullptr, "UpdateCachedList"},
};
// clang-format on
@@ -141,7 +145,7 @@ AOC_U::~AOC_U() {
service_context.CloseEvent(aoc_change_event);
}
-void AOC_U::CountAddOnContent(Kernel::HLERequestContext& ctx) {
+void AOC_U::CountAddOnContent(HLERequestContext& ctx) {
struct Parameters {
u64 process_id;
};
@@ -155,7 +159,7 @@ void AOC_U::CountAddOnContent(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
- const auto current = system.GetCurrentProcessProgramID();
+ const auto current = system.GetApplicationProcessProgramID();
const auto& disabled = Settings::values.disabled_addons[current];
if (std::find(disabled.begin(), disabled.end(), "DLC") != disabled.end()) {
@@ -168,7 +172,7 @@ void AOC_U::CountAddOnContent(Kernel::HLERequestContext& ctx) {
[current](u64 tid) { return CheckAOCTitleIDMatchesBase(tid, current); })));
}
-void AOC_U::ListAddOnContent(Kernel::HLERequestContext& ctx) {
+void AOC_U::ListAddOnContent(HLERequestContext& ctx) {
struct Parameters {
u32 offset;
u32 count;
@@ -182,7 +186,7 @@ void AOC_U::ListAddOnContent(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_AOC, "called with offset={}, count={}, process_id={}", offset, count,
process_id);
- const auto current = system.GetCurrentProcessProgramID();
+ const auto current = system.GetApplicationProcessProgramID();
std::vector<u32> out;
const auto& disabled = Settings::values.disabled_addons[current];
@@ -214,7 +218,7 @@ void AOC_U::ListAddOnContent(Kernel::HLERequestContext& ctx) {
rb.Push(out_count);
}
-void AOC_U::GetAddOnContentBaseId(Kernel::HLERequestContext& ctx) {
+void AOC_U::GetAddOnContentBaseId(HLERequestContext& ctx) {
struct Parameters {
u64 process_id;
};
@@ -228,7 +232,7 @@ void AOC_U::GetAddOnContentBaseId(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
- const auto title_id = system.GetCurrentProcessProgramID();
+ const auto title_id = system.GetApplicationProcessProgramID();
const FileSys::PatchManager pm{title_id, system.GetFileSystemController(),
system.GetContentProvider()};
@@ -241,7 +245,7 @@ void AOC_U::GetAddOnContentBaseId(Kernel::HLERequestContext& ctx) {
rb.Push(res.first->GetDLCBaseTitleId());
}
-void AOC_U::PrepareAddOnContent(Kernel::HLERequestContext& ctx) {
+void AOC_U::PrepareAddOnContent(HLERequestContext& ctx) {
struct Parameters {
s32 addon_index;
u64 process_id;
@@ -258,7 +262,7 @@ void AOC_U::PrepareAddOnContent(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void AOC_U::GetAddOnContentListChangedEvent(Kernel::HLERequestContext& ctx) {
+void AOC_U::GetAddOnContentListChangedEvent(HLERequestContext& ctx) {
LOG_WARNING(Service_AOC, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2, 1};
@@ -266,7 +270,7 @@ void AOC_U::GetAddOnContentListChangedEvent(Kernel::HLERequestContext& ctx) {
rb.PushCopyObjects(aoc_change_event->GetReadableEvent());
}
-void AOC_U::GetAddOnContentListChangedEventWithProcessId(Kernel::HLERequestContext& ctx) {
+void AOC_U::GetAddOnContentListChangedEventWithProcessId(HLERequestContext& ctx) {
LOG_WARNING(Service_AOC, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2, 1};
@@ -274,28 +278,28 @@ void AOC_U::GetAddOnContentListChangedEventWithProcessId(Kernel::HLERequestConte
rb.PushCopyObjects(aoc_change_event->GetReadableEvent());
}
-void AOC_U::NotifyMountAddOnContent(Kernel::HLERequestContext& ctx) {
+void AOC_U::NotifyMountAddOnContent(HLERequestContext& ctx) {
LOG_WARNING(Service_AOC, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
-void AOC_U::NotifyUnmountAddOnContent(Kernel::HLERequestContext& ctx) {
+void AOC_U::NotifyUnmountAddOnContent(HLERequestContext& ctx) {
LOG_WARNING(Service_AOC, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
-void AOC_U::CheckAddOnContentMountStatus(Kernel::HLERequestContext& ctx) {
+void AOC_U::CheckAddOnContentMountStatus(HLERequestContext& ctx) {
LOG_WARNING(Service_AOC, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
-void AOC_U::CreateEcPurchasedEventManager(Kernel::HLERequestContext& ctx) {
+void AOC_U::CreateEcPurchasedEventManager(HLERequestContext& ctx) {
LOG_WARNING(Service_AOC, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -303,7 +307,7 @@ void AOC_U::CreateEcPurchasedEventManager(Kernel::HLERequestContext& ctx) {
rb.PushIpcInterface<IPurchaseEventManager>(system);
}
-void AOC_U::CreatePermanentEcPurchasedEventManager(Kernel::HLERequestContext& ctx) {
+void AOC_U::CreatePermanentEcPurchasedEventManager(HLERequestContext& ctx) {
LOG_WARNING(Service_AOC, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -311,8 +315,10 @@ void AOC_U::CreatePermanentEcPurchasedEventManager(Kernel::HLERequestContext& ct
rb.PushIpcInterface<IPurchaseEventManager>(system);
}
-void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
- std::make_shared<AOC_U>(system)->InstallAsService(service_manager);
+void LoopProcess(Core::System& system) {
+ auto server_manager = std::make_unique<ServerManager>(system);
+ server_manager->RegisterNamedService("aoc:u", std::make_shared<AOC_U>(system));
+ ServerManager::RunServer(std::move(server_manager));
}
} // namespace Service::AOC
diff --git a/src/core/hle/service/aoc/aoc_u.h b/src/core/hle/service/aoc/aoc_u.h
index 6c1ce601a..12ccfeb6a 100644
--- a/src/core/hle/service/aoc/aoc_u.h
+++ b/src/core/hle/service/aoc/aoc_u.h
@@ -22,17 +22,17 @@ public:
~AOC_U() override;
private:
- void CountAddOnContent(Kernel::HLERequestContext& ctx);
- void ListAddOnContent(Kernel::HLERequestContext& ctx);
- void GetAddOnContentBaseId(Kernel::HLERequestContext& ctx);
- void PrepareAddOnContent(Kernel::HLERequestContext& ctx);
- void GetAddOnContentListChangedEvent(Kernel::HLERequestContext& ctx);
- void GetAddOnContentListChangedEventWithProcessId(Kernel::HLERequestContext& ctx);
- void NotifyMountAddOnContent(Kernel::HLERequestContext& ctx);
- void NotifyUnmountAddOnContent(Kernel::HLERequestContext& ctx);
- void CheckAddOnContentMountStatus(Kernel::HLERequestContext& ctx);
- void CreateEcPurchasedEventManager(Kernel::HLERequestContext& ctx);
- void CreatePermanentEcPurchasedEventManager(Kernel::HLERequestContext& ctx);
+ void CountAddOnContent(HLERequestContext& ctx);
+ void ListAddOnContent(HLERequestContext& ctx);
+ void GetAddOnContentBaseId(HLERequestContext& ctx);
+ void PrepareAddOnContent(HLERequestContext& ctx);
+ void GetAddOnContentListChangedEvent(HLERequestContext& ctx);
+ void GetAddOnContentListChangedEventWithProcessId(HLERequestContext& ctx);
+ void NotifyMountAddOnContent(HLERequestContext& ctx);
+ void NotifyUnmountAddOnContent(HLERequestContext& ctx);
+ void CheckAddOnContentMountStatus(HLERequestContext& ctx);
+ void CreateEcPurchasedEventManager(HLERequestContext& ctx);
+ void CreatePermanentEcPurchasedEventManager(HLERequestContext& ctx);
std::vector<u64> add_on_content;
KernelHelpers::ServiceContext service_context;
@@ -40,7 +40,6 @@ private:
Kernel::KEvent* aoc_change_event;
};
-/// Registers all AOC services with the specified service manager.
-void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system);
+void LoopProcess(Core::System& system);
} // namespace Service::AOC
diff --git a/src/core/hle/service/apm/apm.cpp b/src/core/hle/service/apm/apm.cpp
index 8a338d9b1..c23ff293d 100644
--- a/src/core/hle/service/apm/apm.cpp
+++ b/src/core/hle/service/apm/apm.cpp
@@ -4,22 +4,24 @@
#include "core/core.h"
#include "core/hle/service/apm/apm.h"
#include "core/hle/service/apm/apm_interface.h"
+#include "core/hle/service/server_manager.h"
namespace Service::APM {
Module::Module() = default;
Module::~Module() = default;
-void InstallInterfaces(Core::System& system) {
- auto module_ = std::make_shared<Module>();
- std::make_shared<APM>(system, module_, system.GetAPMController(), "apm")
- ->InstallAsService(system.ServiceManager());
- std::make_shared<APM>(system, module_, system.GetAPMController(), "apm:p")
- ->InstallAsService(system.ServiceManager());
- std::make_shared<APM>(system, module_, system.GetAPMController(), "apm:am")
- ->InstallAsService(system.ServiceManager());
- std::make_shared<APM_Sys>(system, system.GetAPMController())
- ->InstallAsService(system.ServiceManager());
+void LoopProcess(Core::System& system) {
+ auto module = std::make_shared<Module>();
+ auto server_manager = std::make_unique<ServerManager>(system);
+
+ server_manager->RegisterNamedService(
+ "apm", std::make_shared<APM>(system, module, system.GetAPMController(), "apm"));
+ server_manager->RegisterNamedService(
+ "apm:am", std::make_shared<APM>(system, module, system.GetAPMController(), "apm:am"));
+ server_manager->RegisterNamedService(
+ "apm:sys", std::make_shared<APM_Sys>(system, system.GetAPMController()));
+ ServerManager::RunServer(std::move(server_manager));
}
} // namespace Service::APM
diff --git a/src/core/hle/service/apm/apm.h b/src/core/hle/service/apm/apm.h
index 0fecc766a..e188b4e44 100644
--- a/src/core/hle/service/apm/apm.h
+++ b/src/core/hle/service/apm/apm.h
@@ -15,7 +15,6 @@ public:
~Module();
};
-/// Registers all AM services with the specified service manager.
-void InstallInterfaces(Core::System& system);
+void LoopProcess(Core::System& system);
} // namespace Service::APM
diff --git a/src/core/hle/service/apm/apm_controller.cpp b/src/core/hle/service/apm/apm_controller.cpp
index d6de84066..227fdd0cf 100644
--- a/src/core/hle/service/apm/apm_controller.cpp
+++ b/src/core/hle/service/apm/apm_controller.cpp
@@ -56,7 +56,7 @@ void Controller::SetPerformanceConfiguration(PerformanceMode mode,
}
void Controller::SetFromCpuBoostMode(CpuBoostMode mode) {
- constexpr std::array<PerformanceConfiguration, 3> BOOST_MODE_TO_CONFIG_MAP{{
+ static constexpr std::array<PerformanceConfiguration, 3> BOOST_MODE_TO_CONFIG_MAP{{
PerformanceConfiguration::Config7,
PerformanceConfiguration::Config13,
PerformanceConfiguration::Config15,
diff --git a/src/core/hle/service/apm/apm_interface.cpp b/src/core/hle/service/apm/apm_interface.cpp
index 041fc16bd..d29051ee7 100644
--- a/src/core/hle/service/apm/apm_interface.cpp
+++ b/src/core/hle/service/apm/apm_interface.cpp
@@ -2,10 +2,10 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/logging/log.h"
-#include "core/hle/ipc_helpers.h"
#include "core/hle/service/apm/apm.h"
#include "core/hle/service/apm/apm_controller.h"
#include "core/hle/service/apm/apm_interface.h"
+#include "core/hle/service/ipc_helpers.h"
namespace Service::APM {
@@ -22,7 +22,7 @@ public:
}
private:
- void SetPerformanceConfiguration(Kernel::HLERequestContext& ctx) {
+ void SetPerformanceConfiguration(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto mode = rp.PopEnum<PerformanceMode>();
@@ -35,7 +35,7 @@ private:
rb.Push(ResultSuccess);
}
- void GetPerformanceConfiguration(Kernel::HLERequestContext& ctx) {
+ void GetPerformanceConfiguration(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto mode = rp.PopEnum<PerformanceMode>();
@@ -46,7 +46,7 @@ private:
rb.PushEnum(controller.GetCurrentPerformanceConfiguration(mode));
}
- void SetCpuOverclockEnabled(Kernel::HLERequestContext& ctx) {
+ void SetCpuOverclockEnabled(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto cpu_overclock_enabled = rp.Pop<bool>();
@@ -74,7 +74,7 @@ APM::APM(Core::System& system_, std::shared_ptr<Module> apm_, Controller& contro
APM::~APM() = default;
-void APM::OpenSession(Kernel::HLERequestContext& ctx) {
+void APM::OpenSession(HLERequestContext& ctx) {
LOG_DEBUG(Service_APM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -82,14 +82,14 @@ void APM::OpenSession(Kernel::HLERequestContext& ctx) {
rb.PushIpcInterface<ISession>(system, controller);
}
-void APM::GetPerformanceMode(Kernel::HLERequestContext& ctx) {
+void APM::GetPerformanceMode(HLERequestContext& ctx) {
LOG_DEBUG(Service_APM, "called");
IPC::ResponseBuilder rb{ctx, 2};
rb.PushEnum(controller.GetCurrentPerformanceMode());
}
-void APM::IsCpuOverclockEnabled(Kernel::HLERequestContext& ctx) {
+void APM::IsCpuOverclockEnabled(HLERequestContext& ctx) {
LOG_WARNING(Service_APM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
@@ -117,7 +117,7 @@ APM_Sys::APM_Sys(Core::System& system_, Controller& controller_)
APM_Sys::~APM_Sys() = default;
-void APM_Sys::GetPerformanceEvent(Kernel::HLERequestContext& ctx) {
+void APM_Sys::GetPerformanceEvent(HLERequestContext& ctx) {
LOG_DEBUG(Service_APM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -125,7 +125,7 @@ void APM_Sys::GetPerformanceEvent(Kernel::HLERequestContext& ctx) {
rb.PushIpcInterface<ISession>(system, controller);
}
-void APM_Sys::SetCpuBoostMode(Kernel::HLERequestContext& ctx) {
+void APM_Sys::SetCpuBoostMode(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto mode = rp.PopEnum<CpuBoostMode>();
@@ -137,7 +137,7 @@ void APM_Sys::SetCpuBoostMode(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void APM_Sys::GetCurrentPerformanceConfiguration(Kernel::HLERequestContext& ctx) {
+void APM_Sys::GetCurrentPerformanceConfiguration(HLERequestContext& ctx) {
LOG_DEBUG(Service_APM, "called");
IPC::ResponseBuilder rb{ctx, 3};
diff --git a/src/core/hle/service/apm/apm_interface.h b/src/core/hle/service/apm/apm_interface.h
index 0740fd4ba..58718453b 100644
--- a/src/core/hle/service/apm/apm_interface.h
+++ b/src/core/hle/service/apm/apm_interface.h
@@ -17,9 +17,9 @@ public:
~APM() override;
private:
- void OpenSession(Kernel::HLERequestContext& ctx);
- void GetPerformanceMode(Kernel::HLERequestContext& ctx);
- void IsCpuOverclockEnabled(Kernel::HLERequestContext& ctx);
+ void OpenSession(HLERequestContext& ctx);
+ void GetPerformanceMode(HLERequestContext& ctx);
+ void IsCpuOverclockEnabled(HLERequestContext& ctx);
std::shared_ptr<Module> apm;
Controller& controller;
@@ -30,11 +30,11 @@ public:
explicit APM_Sys(Core::System& system_, Controller& controller);
~APM_Sys() override;
- void SetCpuBoostMode(Kernel::HLERequestContext& ctx);
+ void SetCpuBoostMode(HLERequestContext& ctx);
private:
- void GetPerformanceEvent(Kernel::HLERequestContext& ctx);
- void GetCurrentPerformanceConfiguration(Kernel::HLERequestContext& ctx);
+ void GetPerformanceEvent(HLERequestContext& ctx);
+ void GetCurrentPerformanceConfiguration(HLERequestContext& ctx);
Controller& controller;
};
diff --git a/src/core/hle/service/audio/audctl.cpp b/src/core/hle/service/audio/audctl.cpp
index 5abf22ba4..7ad93be6b 100644
--- a/src/core/hle/service/audio/audctl.cpp
+++ b/src/core/hle/service/audio/audctl.cpp
@@ -2,8 +2,8 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/logging/log.h"
-#include "core/hle/ipc_helpers.h"
#include "core/hle/service/audio/audctl.h"
+#include "core/hle/service/ipc_helpers.h"
namespace Service::Audio {
@@ -72,7 +72,7 @@ AudCtl::AudCtl(Core::System& system_) : ServiceFramework{system_, "audctl"} {
AudCtl::~AudCtl() = default;
-void AudCtl::GetTargetVolumeMin(Kernel::HLERequestContext& ctx) {
+void AudCtl::GetTargetVolumeMin(HLERequestContext& ctx) {
LOG_DEBUG(Audio, "called.");
// This service function is currently hardcoded on the
@@ -84,7 +84,7 @@ void AudCtl::GetTargetVolumeMin(Kernel::HLERequestContext& ctx) {
rb.Push(target_min_volume);
}
-void AudCtl::GetTargetVolumeMax(Kernel::HLERequestContext& ctx) {
+void AudCtl::GetTargetVolumeMax(HLERequestContext& ctx) {
LOG_DEBUG(Audio, "called.");
// This service function is currently hardcoded on the
diff --git a/src/core/hle/service/audio/audctl.h b/src/core/hle/service/audio/audctl.h
index a27ff6cfe..8e31ac237 100644
--- a/src/core/hle/service/audio/audctl.h
+++ b/src/core/hle/service/audio/audctl.h
@@ -17,8 +17,8 @@ public:
~AudCtl() override;
private:
- void GetTargetVolumeMin(Kernel::HLERequestContext& ctx);
- void GetTargetVolumeMax(Kernel::HLERequestContext& ctx);
+ void GetTargetVolumeMin(HLERequestContext& ctx);
+ void GetTargetVolumeMax(HLERequestContext& ctx);
};
} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/auddbg.cpp b/src/core/hle/service/audio/auddbg.cpp
deleted file mode 100644
index 5541af300..000000000
--- a/src/core/hle/service/audio/auddbg.cpp
+++ /dev/null
@@ -1,21 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#include "core/hle/service/audio/auddbg.h"
-
-namespace Service::Audio {
-
-AudDbg::AudDbg(Core::System& system_, const char* name) : ServiceFramework{system_, name} {
- // clang-format off
- static const FunctionInfo functions[] = {
- {0, nullptr, "RequestSuspendForDebug"},
- {1, nullptr, "RequestResumeForDebug"},
- };
- // clang-format on
-
- RegisterHandlers(functions);
-}
-
-AudDbg::~AudDbg() = default;
-
-} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/auddbg.h b/src/core/hle/service/audio/auddbg.h
deleted file mode 100644
index 8f26be5dc..000000000
--- a/src/core/hle/service/audio/auddbg.h
+++ /dev/null
@@ -1,20 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#pragma once
-
-#include "core/hle/service/service.h"
-
-namespace Core {
-class System;
-}
-
-namespace Service::Audio {
-
-class AudDbg final : public ServiceFramework<AudDbg> {
-public:
- explicit AudDbg(Core::System& system_, const char* name);
- ~AudDbg() override;
-};
-
-} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audin_a.cpp b/src/core/hle/service/audio/audin_a.cpp
deleted file mode 100644
index 98f4a6048..000000000
--- a/src/core/hle/service/audio/audin_a.cpp
+++ /dev/null
@@ -1,23 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#include "core/hle/service/audio/audin_a.h"
-
-namespace Service::Audio {
-
-AudInA::AudInA(Core::System& system_) : ServiceFramework{system_, "audin:a"} {
- // clang-format off
- static const FunctionInfo functions[] = {
- {0, nullptr, "RequestSuspend"},
- {1, nullptr, "RequestResume"},
- {2, nullptr, "GetProcessMasterVolume"},
- {3, nullptr, "SetProcessMasterVolume"},
- };
- // clang-format on
-
- RegisterHandlers(functions);
-}
-
-AudInA::~AudInA() = default;
-
-} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audin_a.h b/src/core/hle/service/audio/audin_a.h
deleted file mode 100644
index 19a927de5..000000000
--- a/src/core/hle/service/audio/audin_a.h
+++ /dev/null
@@ -1,20 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#pragma once
-
-#include "core/hle/service/service.h"
-
-namespace Core {
-class System;
-}
-
-namespace Service::Audio {
-
-class AudInA final : public ServiceFramework<AudInA> {
-public:
- explicit AudInA(Core::System& system_);
- ~AudInA() override;
-};
-
-} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audin_u.cpp b/src/core/hle/service/audio/audin_u.cpp
index 053e8f9dd..c8d574993 100644
--- a/src/core/hle/service/audio/audin_u.cpp
+++ b/src/core/hle/service/audio/audin_u.cpp
@@ -5,11 +5,12 @@
#include "audio_core/renderer/audio_device.h"
#include "common/common_funcs.h"
#include "common/logging/log.h"
+#include "common/settings.h"
#include "common/string_util.h"
#include "core/core.h"
-#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/k_event.h"
#include "core/hle/service/audio/audin_u.h"
+#include "core/hle/service/ipc_helpers.h"
namespace Service::Audio {
using namespace AudioCore::AudioIn;
@@ -61,7 +62,7 @@ public:
}
private:
- void GetAudioInState(Kernel::HLERequestContext& ctx) {
+ void GetAudioInState(HLERequestContext& ctx) {
const auto state = static_cast<u32>(impl->GetState());
LOG_DEBUG(Service_Audio, "called. State={}", state);
@@ -71,7 +72,7 @@ private:
rb.Push(state);
}
- void Start(Kernel::HLERequestContext& ctx) {
+ void Start(HLERequestContext& ctx) {
LOG_DEBUG(Service_Audio, "called");
auto result = impl->StartSystem();
@@ -80,7 +81,7 @@ private:
rb.Push(result);
}
- void Stop(Kernel::HLERequestContext& ctx) {
+ void Stop(HLERequestContext& ctx) {
LOG_DEBUG(Service_Audio, "called");
auto result = impl->StopSystem();
@@ -89,7 +90,7 @@ private:
rb.Push(result);
}
- void AppendAudioInBuffer(Kernel::HLERequestContext& ctx) {
+ void AppendAudioInBuffer(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
u64 tag = rp.PopRaw<u64>();
@@ -111,7 +112,7 @@ private:
rb.Push(result);
}
- void RegisterBufferEvent(Kernel::HLERequestContext& ctx) {
+ void RegisterBufferEvent(HLERequestContext& ctx) {
LOG_DEBUG(Service_Audio, "called");
auto& buffer_event = impl->GetBufferEvent();
@@ -121,27 +122,21 @@ private:
rb.PushCopyObjects(buffer_event);
}
- void GetReleasedAudioInBuffer(Kernel::HLERequestContext& ctx) {
+ void GetReleasedAudioInBuffer(HLERequestContext& ctx) {
const auto write_buffer_size = ctx.GetWriteBufferNumElements<u64>();
- std::vector<u64> released_buffers(write_buffer_size);
+ tmp_buffer.resize_destructive(write_buffer_size);
+ tmp_buffer[0] = 0;
- const auto count = impl->GetReleasedBuffers(released_buffers);
+ const auto count = impl->GetReleasedBuffers(tmp_buffer);
- [[maybe_unused]] std::string tags{};
- for (u32 i = 0; i < count; i++) {
- tags += fmt::format("{:08X}, ", released_buffers[i]);
- }
- [[maybe_unused]] auto sessionid{impl->GetSystem().GetSessionId()};
- LOG_TRACE(Service_Audio, "called. Session {} released {} buffers: {}", sessionid, count,
- tags);
+ ctx.WriteBuffer(tmp_buffer);
- ctx.WriteBuffer(released_buffers);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(count);
}
- void ContainsAudioInBuffer(Kernel::HLERequestContext& ctx) {
+ void ContainsAudioInBuffer(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u64 tag{rp.Pop<u64>()};
@@ -154,7 +149,7 @@ private:
rb.Push(buffer_queued);
}
- void GetAudioInBufferCount(Kernel::HLERequestContext& ctx) {
+ void GetAudioInBufferCount(HLERequestContext& ctx) {
const auto buffer_count = impl->GetBufferCount();
LOG_DEBUG(Service_Audio, "called. Buffer count={}", buffer_count);
@@ -165,7 +160,7 @@ private:
rb.Push(buffer_count);
}
- void SetDeviceGain(Kernel::HLERequestContext& ctx) {
+ void SetDeviceGain(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto volume{rp.Pop<f32>()};
@@ -177,7 +172,7 @@ private:
rb.Push(ResultSuccess);
}
- void GetDeviceGain(Kernel::HLERequestContext& ctx) {
+ void GetDeviceGain(HLERequestContext& ctx) {
auto volume{impl->GetVolume()};
LOG_DEBUG(Service_Audio, "called. Gain {}", volume);
@@ -187,7 +182,7 @@ private:
rb.Push(volume);
}
- void FlushAudioInBuffers(Kernel::HLERequestContext& ctx) {
+ void FlushAudioInBuffers(HLERequestContext& ctx) {
bool flushed{impl->FlushAudioInBuffers()};
LOG_DEBUG(Service_Audio, "called. Were any buffers flushed? {}", flushed);
@@ -200,12 +195,12 @@ private:
KernelHelpers::ServiceContext service_context;
Kernel::KEvent* event;
std::shared_ptr<AudioCore::AudioIn::In> impl;
+ Common::ScratchBuffer<u64> tmp_buffer;
};
AudInU::AudInU(Core::System& system_)
- : ServiceFramework{system_, "audin:u", ServiceThreadType::CreateNew},
- service_context{system_, "AudInU"}, impl{std::make_unique<AudioCore::AudioIn::Manager>(
- system_)} {
+ : ServiceFramework{system_, "audin:u"}, service_context{system_, "AudInU"},
+ impl{std::make_unique<AudioCore::AudioIn::Manager>(system_)} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &AudInU::ListAudioIns, "ListAudioIns"},
@@ -222,7 +217,7 @@ AudInU::AudInU(Core::System& system_)
AudInU::~AudInU() = default;
-void AudInU::ListAudioIns(Kernel::HLERequestContext& ctx) {
+void AudInU::ListAudioIns(HLERequestContext& ctx) {
using namespace AudioCore::AudioRenderer;
LOG_DEBUG(Service_Audio, "called");
@@ -242,7 +237,7 @@ void AudInU::ListAudioIns(Kernel::HLERequestContext& ctx) {
rb.Push(out_count);
}
-void AudInU::ListAudioInsAutoFiltered(Kernel::HLERequestContext& ctx) {
+void AudInU::ListAudioInsAutoFiltered(HLERequestContext& ctx) {
using namespace AudioCore::AudioRenderer;
LOG_DEBUG(Service_Audio, "called");
@@ -262,7 +257,7 @@ void AudInU::ListAudioInsAutoFiltered(Kernel::HLERequestContext& ctx) {
rb.Push(out_count);
}
-void AudInU::OpenAudioIn(Kernel::HLERequestContext& ctx) {
+void AudInU::OpenAudioIn(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
auto in_params{rp.PopRaw<AudioInParameter>()};
auto applet_resource_user_id{rp.PopRaw<u64>()};
@@ -312,7 +307,7 @@ void AudInU::OpenAudioIn(Kernel::HLERequestContext& ctx) {
rb.PushIpcInterface<IAudioIn>(audio_in);
}
-void AudInU::OpenAudioInProtocolSpecified(Kernel::HLERequestContext& ctx) {
+void AudInU::OpenAudioInProtocolSpecified(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
auto protocol_specified{rp.PopRaw<u64>()};
auto in_params{rp.PopRaw<AudioInParameter>()};
diff --git a/src/core/hle/service/audio/audin_u.h b/src/core/hle/service/audio/audin_u.h
index b45fda78a..51e770ff9 100644
--- a/src/core/hle/service/audio/audin_u.h
+++ b/src/core/hle/service/audio/audin_u.h
@@ -12,10 +12,6 @@ namespace Core {
class System;
}
-namespace Kernel {
-class HLERequestContext;
-}
-
namespace AudioCore::AudioOut {
class Manager;
class In;
@@ -29,11 +25,11 @@ public:
~AudInU() override;
private:
- void ListAudioIns(Kernel::HLERequestContext& ctx);
- void ListAudioInsAutoFiltered(Kernel::HLERequestContext& ctx);
- void OpenInOutImpl(Kernel::HLERequestContext& ctx);
- void OpenAudioIn(Kernel::HLERequestContext& ctx);
- void OpenAudioInProtocolSpecified(Kernel::HLERequestContext& ctx);
+ void ListAudioIns(HLERequestContext& ctx);
+ void ListAudioInsAutoFiltered(HLERequestContext& ctx);
+ void OpenInOutImpl(HLERequestContext& ctx);
+ void OpenAudioIn(HLERequestContext& ctx);
+ void OpenAudioInProtocolSpecified(HLERequestContext& ctx);
KernelHelpers::ServiceContext service_context;
std::unique_ptr<AudioCore::AudioIn::Manager> impl;
diff --git a/src/core/hle/service/audio/audio.cpp b/src/core/hle/service/audio/audio.cpp
index 97da71dfa..dccd16309 100644
--- a/src/core/hle/service/audio/audio.cpp
+++ b/src/core/hle/service/audio/audio.cpp
@@ -1,40 +1,31 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
+#include "core/core.h"
#include "core/hle/service/audio/audctl.h"
-#include "core/hle/service/audio/auddbg.h"
-#include "core/hle/service/audio/audin_a.h"
#include "core/hle/service/audio/audin_u.h"
#include "core/hle/service/audio/audio.h"
-#include "core/hle/service/audio/audout_a.h"
#include "core/hle/service/audio/audout_u.h"
#include "core/hle/service/audio/audrec_a.h"
#include "core/hle/service/audio/audrec_u.h"
-#include "core/hle/service/audio/audren_a.h"
#include "core/hle/service/audio/audren_u.h"
-#include "core/hle/service/audio/codecctl.h"
#include "core/hle/service/audio/hwopus.h"
+#include "core/hle/service/server_manager.h"
#include "core/hle/service/service.h"
namespace Service::Audio {
-void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
- std::make_shared<AudCtl>(system)->InstallAsService(service_manager);
- std::make_shared<AudOutA>(system)->InstallAsService(service_manager);
- std::make_shared<AudOutU>(system)->InstallAsService(service_manager);
- std::make_shared<AudInA>(system)->InstallAsService(service_manager);
- std::make_shared<AudInU>(system)->InstallAsService(service_manager);
- std::make_shared<AudRecA>(system)->InstallAsService(service_manager);
- std::make_shared<AudRecU>(system)->InstallAsService(service_manager);
- std::make_shared<AudRenA>(system)->InstallAsService(service_manager);
- std::make_shared<AudRenU>(system)->InstallAsService(service_manager);
- std::make_shared<CodecCtl>(system)->InstallAsService(service_manager);
- std::make_shared<HwOpus>(system)->InstallAsService(service_manager);
+void LoopProcess(Core::System& system) {
+ auto server_manager = std::make_unique<ServerManager>(system);
- std::make_shared<AudDbg>(system, "audin:d")->InstallAsService(service_manager);
- std::make_shared<AudDbg>(system, "audout:d")->InstallAsService(service_manager);
- std::make_shared<AudDbg>(system, "audrec:d")->InstallAsService(service_manager);
- std::make_shared<AudDbg>(system, "audren:d")->InstallAsService(service_manager);
+ server_manager->RegisterNamedService("audctl", std::make_shared<AudCtl>(system));
+ server_manager->RegisterNamedService("audout:u", std::make_shared<AudOutU>(system));
+ server_manager->RegisterNamedService("audin:u", std::make_shared<AudInU>(system));
+ server_manager->RegisterNamedService("audrec:a", std::make_shared<AudRecA>(system));
+ server_manager->RegisterNamedService("audrec:u", std::make_shared<AudRecU>(system));
+ server_manager->RegisterNamedService("audren:u", std::make_shared<AudRenU>(system));
+ server_manager->RegisterNamedService("hwopus", std::make_shared<HwOpus>(system));
+ ServerManager::RunServer(std::move(server_manager));
}
} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audio.h b/src/core/hle/service/audio/audio.h
index bbb2214e4..d70f022c7 100644
--- a/src/core/hle/service/audio/audio.h
+++ b/src/core/hle/service/audio/audio.h
@@ -13,7 +13,6 @@ class ServiceManager;
namespace Service::Audio {
-/// Registers all Audio services with the specified service manager.
-void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system);
+void LoopProcess(Core::System& system);
} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audout_a.cpp b/src/core/hle/service/audio/audout_a.cpp
deleted file mode 100644
index 5ecb99236..000000000
--- a/src/core/hle/service/audio/audout_a.cpp
+++ /dev/null
@@ -1,25 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#include "core/hle/service/audio/audout_a.h"
-
-namespace Service::Audio {
-
-AudOutA::AudOutA(Core::System& system_) : ServiceFramework{system_, "audout:a"} {
- // clang-format off
- static const FunctionInfo functions[] = {
- {0, nullptr, "RequestSuspend"},
- {1, nullptr, "RequestResume"},
- {2, nullptr, "GetProcessMasterVolume"},
- {3, nullptr, "SetProcessMasterVolume"},
- {4, nullptr, "GetProcessRecordVolume"},
- {5, nullptr, "SetProcessRecordVolume"},
- };
- // clang-format on
-
- RegisterHandlers(functions);
-}
-
-AudOutA::~AudOutA() = default;
-
-} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audout_a.h b/src/core/hle/service/audio/audout_a.h
deleted file mode 100644
index f641cffeb..000000000
--- a/src/core/hle/service/audio/audout_a.h
+++ /dev/null
@@ -1,20 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#pragma once
-
-#include "core/hle/service/service.h"
-
-namespace Core {
-class System;
-}
-
-namespace Service::Audio {
-
-class AudOutA final : public ServiceFramework<AudOutA> {
-public:
- explicit AudOutA(Core::System& system_);
- ~AudOutA() override;
-};
-
-} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp
index 29751f075..032c8c11f 100644
--- a/src/core/hle/service/audio/audout_u.cpp
+++ b/src/core/hle/service/audio/audout_u.cpp
@@ -12,10 +12,10 @@
#include "common/string_util.h"
#include "common/swap.h"
#include "core/core.h"
-#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/k_event.h"
#include "core/hle/service/audio/audout_u.h"
#include "core/hle/service/audio/errors.h"
+#include "core/hle/service/ipc_helpers.h"
#include "core/memory.h"
namespace Service::Audio {
@@ -26,9 +26,8 @@ public:
explicit IAudioOut(Core::System& system_, AudioCore::AudioOut::Manager& manager,
size_t session_id, const std::string& device_name,
const AudioOutParameter& in_params, u32 handle, u64 applet_resource_user_id)
- : ServiceFramework{system_, "IAudioOut", ServiceThreadType::CreateNew},
- service_context{system_, "IAudioOut"}, event{service_context.CreateEvent(
- "AudioOutEvent")},
+ : ServiceFramework{system_, "IAudioOut"}, service_context{system_, "IAudioOut"},
+ event{service_context.CreateEvent("AudioOutEvent")},
impl{std::make_shared<AudioCore::AudioOut::Out>(system_, manager, event, session_id)} {
// clang-format off
@@ -50,12 +49,6 @@ public:
};
// clang-format on
RegisterHandlers(functions);
-
- if (impl->GetSystem()
- .Initialize(device_name, in_params, handle, applet_resource_user_id)
- .IsError()) {
- LOG_ERROR(Service_Audio, "Failed to initialize the AudioOut System!");
- }
}
~IAudioOut() override {
@@ -68,7 +61,7 @@ public:
}
private:
- void GetAudioOutState(Kernel::HLERequestContext& ctx) {
+ void GetAudioOutState(HLERequestContext& ctx) {
const auto state = static_cast<u32>(impl->GetState());
LOG_DEBUG(Service_Audio, "called. State={}", state);
@@ -78,7 +71,7 @@ private:
rb.Push(state);
}
- void Start(Kernel::HLERequestContext& ctx) {
+ void Start(HLERequestContext& ctx) {
LOG_DEBUG(Service_Audio, "called");
auto result = impl->StartSystem();
@@ -87,7 +80,7 @@ private:
rb.Push(result);
}
- void Stop(Kernel::HLERequestContext& ctx) {
+ void Stop(HLERequestContext& ctx) {
LOG_DEBUG(Service_Audio, "called");
auto result = impl->StopSystem();
@@ -96,7 +89,7 @@ private:
rb.Push(result);
}
- void AppendAudioOutBuffer(Kernel::HLERequestContext& ctx) {
+ void AppendAudioOutBuffer(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
u64 tag = rp.PopRaw<u64>();
@@ -118,7 +111,7 @@ private:
rb.Push(result);
}
- void RegisterBufferEvent(Kernel::HLERequestContext& ctx) {
+ void RegisterBufferEvent(HLERequestContext& ctx) {
LOG_DEBUG(Service_Audio, "called");
auto& buffer_event = impl->GetBufferEvent();
@@ -128,27 +121,21 @@ private:
rb.PushCopyObjects(buffer_event);
}
- void GetReleasedAudioOutBuffers(Kernel::HLERequestContext& ctx) {
+ void GetReleasedAudioOutBuffers(HLERequestContext& ctx) {
const auto write_buffer_size = ctx.GetWriteBufferNumElements<u64>();
- std::vector<u64> released_buffers(write_buffer_size);
+ tmp_buffer.resize_destructive(write_buffer_size);
+ tmp_buffer[0] = 0;
- const auto count = impl->GetReleasedBuffers(released_buffers);
+ const auto count = impl->GetReleasedBuffers(tmp_buffer);
- [[maybe_unused]] std::string tags{};
- for (u32 i = 0; i < count; i++) {
- tags += fmt::format("{:08X}, ", released_buffers[i]);
- }
- [[maybe_unused]] const auto sessionid{impl->GetSystem().GetSessionId()};
- LOG_TRACE(Service_Audio, "called. Session {} released {} buffers: {}", sessionid, count,
- tags);
+ ctx.WriteBuffer(tmp_buffer);
- ctx.WriteBuffer(released_buffers);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(count);
}
- void ContainsAudioOutBuffer(Kernel::HLERequestContext& ctx) {
+ void ContainsAudioOutBuffer(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u64 tag{rp.Pop<u64>()};
@@ -161,7 +148,7 @@ private:
rb.Push(buffer_queued);
}
- void GetAudioOutBufferCount(Kernel::HLERequestContext& ctx) {
+ void GetAudioOutBufferCount(HLERequestContext& ctx) {
const auto buffer_count = impl->GetBufferCount();
LOG_DEBUG(Service_Audio, "called. Buffer count={}", buffer_count);
@@ -172,7 +159,7 @@ private:
rb.Push(buffer_count);
}
- void GetAudioOutPlayedSampleCount(Kernel::HLERequestContext& ctx) {
+ void GetAudioOutPlayedSampleCount(HLERequestContext& ctx) {
const auto samples_played = impl->GetPlayedSampleCount();
LOG_DEBUG(Service_Audio, "called. Played samples={}", samples_played);
@@ -183,7 +170,7 @@ private:
rb.Push(samples_played);
}
- void FlushAudioOutBuffers(Kernel::HLERequestContext& ctx) {
+ void FlushAudioOutBuffers(HLERequestContext& ctx) {
bool flushed{impl->FlushAudioOutBuffers()};
LOG_DEBUG(Service_Audio, "called. Were any buffers flushed? {}", flushed);
@@ -193,7 +180,7 @@ private:
rb.Push(flushed);
}
- void SetAudioOutVolume(Kernel::HLERequestContext& ctx) {
+ void SetAudioOutVolume(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto volume = rp.Pop<f32>();
@@ -205,7 +192,7 @@ private:
rb.Push(ResultSuccess);
}
- void GetAudioOutVolume(Kernel::HLERequestContext& ctx) {
+ void GetAudioOutVolume(HLERequestContext& ctx) {
const auto volume = impl->GetVolume();
LOG_DEBUG(Service_Audio, "called. Volume={}", volume);
@@ -218,12 +205,12 @@ private:
KernelHelpers::ServiceContext service_context;
Kernel::KEvent* event;
std::shared_ptr<AudioCore::AudioOut::Out> impl;
+ Common::ScratchBuffer<u64> tmp_buffer;
};
AudOutU::AudOutU(Core::System& system_)
- : ServiceFramework{system_, "audout:u", ServiceThreadType::CreateNew},
- service_context{system_, "AudOutU"}, impl{std::make_unique<AudioCore::AudioOut::Manager>(
- system_)} {
+ : ServiceFramework{system_, "audout:u"}, service_context{system_, "AudOutU"},
+ impl{std::make_unique<AudioCore::AudioOut::Manager>(system_)} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &AudOutU::ListAudioOuts, "ListAudioOuts"},
@@ -238,7 +225,7 @@ AudOutU::AudOutU(Core::System& system_)
AudOutU::~AudOutU() = default;
-void AudOutU::ListAudioOuts(Kernel::HLERequestContext& ctx) {
+void AudOutU::ListAudioOuts(HLERequestContext& ctx) {
using namespace AudioCore::AudioRenderer;
std::scoped_lock l{impl->mutex};
@@ -260,7 +247,7 @@ void AudOutU::ListAudioOuts(Kernel::HLERequestContext& ctx) {
rb.Push<u32>(static_cast<u32>(device_names.size()));
}
-void AudOutU::OpenAudioOut(Kernel::HLERequestContext& ctx) {
+void AudOutU::OpenAudioOut(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
auto in_params{rp.PopRaw<AudioOutParameter>()};
auto applet_resource_user_id{rp.PopRaw<u64>()};
@@ -289,6 +276,14 @@ void AudOutU::OpenAudioOut(Kernel::HLERequestContext& ctx) {
auto audio_out = std::make_shared<IAudioOut>(system, *impl, new_session_id, device_name,
in_params, handle, applet_resource_user_id);
+ result = audio_out->GetImpl()->GetSystem().Initialize(device_name, in_params, handle,
+ applet_resource_user_id);
+ if (result.IsError()) {
+ LOG_ERROR(Service_Audio, "Failed to initialize the AudioOut System!");
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+ return;
+ }
impl->sessions[new_session_id] = audio_out->GetImpl();
impl->applet_resource_user_ids[new_session_id] = applet_resource_user_id;
diff --git a/src/core/hle/service/audio/audout_u.h b/src/core/hle/service/audio/audout_u.h
index fdc0ee754..8f288c6e0 100644
--- a/src/core/hle/service/audio/audout_u.h
+++ b/src/core/hle/service/audio/audout_u.h
@@ -12,10 +12,6 @@ namespace Core {
class System;
}
-namespace Kernel {
-class HLERequestContext;
-}
-
namespace AudioCore::AudioOut {
class Manager;
class Out;
@@ -31,8 +27,8 @@ public:
~AudOutU() override;
private:
- void ListAudioOuts(Kernel::HLERequestContext& ctx);
- void OpenAudioOut(Kernel::HLERequestContext& ctx);
+ void ListAudioOuts(HLERequestContext& ctx);
+ void OpenAudioOut(HLERequestContext& ctx);
KernelHelpers::ServiceContext service_context;
std::unique_ptr<AudioCore::AudioOut::Manager> impl;
diff --git a/src/core/hle/service/audio/audren_a.cpp b/src/core/hle/service/audio/audren_a.cpp
deleted file mode 100644
index e775ac3bf..000000000
--- a/src/core/hle/service/audio/audren_a.cpp
+++ /dev/null
@@ -1,27 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#include "core/hle/service/audio/audren_a.h"
-
-namespace Service::Audio {
-
-AudRenA::AudRenA(Core::System& system_) : ServiceFramework{system_, "audren:a"} {
- // clang-format off
- static const FunctionInfo functions[] = {
- {0, nullptr, "RequestSuspend"},
- {1, nullptr, "RequestResume"},
- {2, nullptr, "GetProcessMasterVolume"},
- {3, nullptr, "SetProcessMasterVolume"},
- {4, nullptr, "RegisterAppletResourceUserId"},
- {5, nullptr, "UnregisterAppletResourceUserId"},
- {6, nullptr, "GetProcessRecordVolume"},
- {7, nullptr, "SetProcessRecordVolume"},
- };
- // clang-format on
-
- RegisterHandlers(functions);
-}
-
-AudRenA::~AudRenA() = default;
-
-} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audren_a.h b/src/core/hle/service/audio/audren_a.h
deleted file mode 100644
index 9e08b4245..000000000
--- a/src/core/hle/service/audio/audren_a.h
+++ /dev/null
@@ -1,20 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#pragma once
-
-#include "core/hle/service/service.h"
-
-namespace Core {
-class System;
-}
-
-namespace Service::Audio {
-
-class AudRenA final : public ServiceFramework<AudRenA> {
-public:
- explicit AudRenA(Core::System& system_);
- ~AudRenA() override;
-};
-
-} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp
index 3a1c231b6..12845c23a 100644
--- a/src/core/hle/service/audio/audren_u.cpp
+++ b/src/core/hle/service/audio/audren_u.cpp
@@ -17,12 +17,12 @@
#include "common/polyfill_ranges.h"
#include "common/string_util.h"
#include "core/core.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_transfer_memory.h"
#include "core/hle/service/audio/audren_u.h"
#include "core/hle/service/audio/errors.h"
+#include "core/hle/service/ipc_helpers.h"
#include "core/memory.h"
using namespace AudioCore::AudioRenderer;
@@ -35,10 +35,9 @@ public:
AudioCore::AudioRendererParameterInternal& params,
Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size,
u32 process_handle, u64 applet_resource_user_id, s32 session_id)
- : ServiceFramework{system_, "IAudioRenderer", ServiceThreadType::CreateNew},
- service_context{system_, "IAudioRenderer"}, rendered_event{service_context.CreateEvent(
- "IAudioRendererEvent")},
- manager{manager_}, impl{std::make_unique<Renderer>(system_, manager, rendered_event)} {
+ : ServiceFramework{system_, "IAudioRenderer"}, service_context{system_, "IAudioRenderer"},
+ rendered_event{service_context.CreateEvent("IAudioRendererEvent")}, manager{manager_},
+ impl{std::make_unique<Renderer>(system_, manager, rendered_event)} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &IAudioRenderer::GetSampleRate, "GetSampleRate"},
@@ -69,7 +68,7 @@ public:
}
private:
- void GetSampleRate(Kernel::HLERequestContext& ctx) {
+ void GetSampleRate(HLERequestContext& ctx) {
const auto sample_rate{impl->GetSystem().GetSampleRate()};
LOG_DEBUG(Service_Audio, "called. Sample rate {}", sample_rate);
@@ -79,7 +78,7 @@ private:
rb.Push(sample_rate);
}
- void GetSampleCount(Kernel::HLERequestContext& ctx) {
+ void GetSampleCount(HLERequestContext& ctx) {
const auto sample_count{impl->GetSystem().GetSampleCount()};
LOG_DEBUG(Service_Audio, "called. Sample count {}", sample_count);
@@ -89,7 +88,7 @@ private:
rb.Push(sample_count);
}
- void GetState(Kernel::HLERequestContext& ctx) {
+ void GetState(HLERequestContext& ctx) {
const u32 state{!impl->GetSystem().IsActive()};
LOG_DEBUG(Service_Audio, "called, state {}", state);
@@ -99,7 +98,7 @@ private:
rb.Push(state);
}
- void GetMixBufferCount(Kernel::HLERequestContext& ctx) {
+ void GetMixBufferCount(HLERequestContext& ctx) {
LOG_DEBUG(Service_Audio, "called");
const auto buffer_count{impl->GetSystem().GetMixBufferCount()};
@@ -109,36 +108,34 @@ private:
rb.Push(buffer_count);
}
- void RequestUpdate(Kernel::HLERequestContext& ctx) {
+ void RequestUpdate(HLERequestContext& ctx) {
LOG_TRACE(Service_Audio, "called");
- std::vector<u8> input{ctx.ReadBuffer(0)};
+ const auto input{ctx.ReadBuffer(0)};
// These buffers are written manually to avoid an issue with WriteBuffer throwing errors for
// checking size 0. Performance size is 0 for most games.
- std::vector<u8> output{};
- std::vector<u8> performance{};
auto is_buffer_b{ctx.BufferDescriptorB()[0].Size() != 0};
if (is_buffer_b) {
const auto buffersB{ctx.BufferDescriptorB()};
- output.resize(buffersB[0].Size(), 0);
- performance.resize(buffersB[1].Size(), 0);
+ tmp_output.resize_destructive(buffersB[0].Size());
+ tmp_performance.resize_destructive(buffersB[1].Size());
} else {
const auto buffersC{ctx.BufferDescriptorC()};
- output.resize(buffersC[0].Size(), 0);
- performance.resize(buffersC[1].Size(), 0);
+ tmp_output.resize_destructive(buffersC[0].Size());
+ tmp_performance.resize_destructive(buffersC[1].Size());
}
- auto result = impl->RequestUpdate(input, performance, output);
+ auto result = impl->RequestUpdate(input, tmp_performance, tmp_output);
if (result.IsSuccess()) {
if (is_buffer_b) {
- ctx.WriteBufferB(output.data(), output.size(), 0);
- ctx.WriteBufferB(performance.data(), performance.size(), 1);
+ ctx.WriteBufferB(tmp_output.data(), tmp_output.size(), 0);
+ ctx.WriteBufferB(tmp_performance.data(), tmp_performance.size(), 1);
} else {
- ctx.WriteBufferC(output.data(), output.size(), 0);
- ctx.WriteBufferC(performance.data(), performance.size(), 1);
+ ctx.WriteBufferC(tmp_output.data(), tmp_output.size(), 0);
+ ctx.WriteBufferC(tmp_performance.data(), tmp_performance.size(), 1);
}
} else {
LOG_ERROR(Service_Audio, "RequestUpdate failed error 0x{:02X}!", result.description);
@@ -148,7 +145,7 @@ private:
rb.Push(result);
}
- void Start(Kernel::HLERequestContext& ctx) {
+ void Start(HLERequestContext& ctx) {
LOG_DEBUG(Service_Audio, "called");
impl->Start();
@@ -157,7 +154,7 @@ private:
rb.Push(ResultSuccess);
}
- void Stop(Kernel::HLERequestContext& ctx) {
+ void Stop(HLERequestContext& ctx) {
LOG_DEBUG(Service_Audio, "called");
impl->Stop();
@@ -166,12 +163,12 @@ private:
rb.Push(ResultSuccess);
}
- void QuerySystemEvent(Kernel::HLERequestContext& ctx) {
+ void QuerySystemEvent(HLERequestContext& ctx) {
LOG_DEBUG(Service_Audio, "called");
if (impl->GetSystem().GetExecutionMode() == AudioCore::ExecutionMode::Manual) {
IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ERR_NOT_SUPPORTED);
+ rb.Push(Audio::ResultNotSupported);
return;
}
@@ -180,7 +177,7 @@ private:
rb.PushCopyObjects(rendered_event->GetReadableEvent());
}
- void SetRenderingTimeLimit(Kernel::HLERequestContext& ctx) {
+ void SetRenderingTimeLimit(HLERequestContext& ctx) {
LOG_DEBUG(Service_Audio, "called");
IPC::RequestParser rp{ctx};
@@ -193,7 +190,7 @@ private:
rb.Push(ResultSuccess);
}
- void GetRenderingTimeLimit(Kernel::HLERequestContext& ctx) {
+ void GetRenderingTimeLimit(HLERequestContext& ctx) {
LOG_DEBUG(Service_Audio, "called");
auto& system_ = impl->GetSystem();
@@ -204,11 +201,11 @@ private:
rb.Push(time);
}
- void ExecuteAudioRendererRendering(Kernel::HLERequestContext& ctx) {
+ void ExecuteAudioRendererRendering(HLERequestContext& ctx) {
LOG_DEBUG(Service_Audio, "called");
}
- void SetVoiceDropParameter(Kernel::HLERequestContext& ctx) {
+ void SetVoiceDropParameter(HLERequestContext& ctx) {
LOG_DEBUG(Service_Audio, "called");
IPC::RequestParser rp{ctx};
@@ -221,7 +218,7 @@ private:
rb.Push(ResultSuccess);
}
- void GetVoiceDropParameter(Kernel::HLERequestContext& ctx) {
+ void GetVoiceDropParameter(HLERequestContext& ctx) {
LOG_DEBUG(Service_Audio, "called");
auto& system_ = impl->GetSystem();
@@ -236,6 +233,8 @@ private:
Kernel::KEvent* rendered_event;
Manager& manager;
std::unique_ptr<Renderer> impl;
+ Common::ScratchBuffer<u8> tmp_output;
+ Common::ScratchBuffer<u8> tmp_performance;
};
class IAudioDevice final : public ServiceFramework<IAudioDevice> {
@@ -243,10 +242,8 @@ class IAudioDevice final : public ServiceFramework<IAudioDevice> {
public:
explicit IAudioDevice(Core::System& system_, u64 applet_resource_user_id, u32 revision,
u32 device_num)
- : ServiceFramework{system_, "IAudioDevice", ServiceThreadType::CreateNew},
- service_context{system_, "IAudioDevice"}, impl{std::make_unique<AudioDevice>(
- system_, applet_resource_user_id,
- revision)},
+ : ServiceFramework{system_, "IAudioDevice"}, service_context{system_, "IAudioDevice"},
+ impl{std::make_unique<AudioDevice>(system_, applet_resource_user_id, revision)},
event{service_context.CreateEvent(fmt::format("IAudioDeviceEvent-{}", device_num))} {
static const FunctionInfo functions[] = {
{0, &IAudioDevice::ListAudioDeviceName, "ListAudioDeviceName"},
@@ -274,7 +271,7 @@ public:
}
private:
- void ListAudioDeviceName(Kernel::HLERequestContext& ctx) {
+ void ListAudioDeviceName(HLERequestContext& ctx) {
const size_t in_count = ctx.GetWriteBufferNumElements<AudioDevice::AudioDeviceName>();
std::vector<AudioDevice::AudioDeviceName> out_names{};
@@ -302,7 +299,7 @@ private:
rb.Push(out_count);
}
- void SetAudioDeviceOutputVolume(Kernel::HLERequestContext& ctx) {
+ void SetAudioDeviceOutputVolume(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const f32 volume = rp.Pop<f32>();
@@ -319,7 +316,7 @@ private:
rb.Push(ResultSuccess);
}
- void GetAudioDeviceOutputVolume(Kernel::HLERequestContext& ctx) {
+ void GetAudioDeviceOutputVolume(HLERequestContext& ctx) {
const auto device_name_buffer = ctx.ReadBuffer();
const std::string name = Common::StringFromBuffer(device_name_buffer);
@@ -335,7 +332,7 @@ private:
rb.Push(volume);
}
- void GetActiveAudioDeviceName(Kernel::HLERequestContext& ctx) {
+ void GetActiveAudioDeviceName(HLERequestContext& ctx) {
const auto write_size = ctx.GetWriteBufferSize();
std::string out_name{"AudioTvOutput"};
@@ -349,7 +346,7 @@ private:
rb.Push(ResultSuccess);
}
- void QueryAudioDeviceSystemEvent(Kernel::HLERequestContext& ctx) {
+ void QueryAudioDeviceSystemEvent(HLERequestContext& ctx) {
LOG_DEBUG(Service_Audio, "(STUBBED) called");
event->Signal();
@@ -359,7 +356,7 @@ private:
rb.PushCopyObjects(event->GetReadableEvent());
}
- void GetActiveChannelCount(Kernel::HLERequestContext& ctx) {
+ void GetActiveChannelCount(HLERequestContext& ctx) {
const auto& sink{system.AudioCore().GetOutputSink()};
u32 channel_count{sink.GetDeviceChannels()};
@@ -371,7 +368,7 @@ private:
rb.Push<u32>(channel_count);
}
- void QueryAudioDeviceInputEvent(Kernel::HLERequestContext& ctx) {
+ void QueryAudioDeviceInputEvent(HLERequestContext& ctx) {
LOG_DEBUG(Service_Audio, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2, 1};
@@ -379,7 +376,7 @@ private:
rb.PushCopyObjects(event->GetReadableEvent());
}
- void QueryAudioDeviceOutputEvent(Kernel::HLERequestContext& ctx) {
+ void QueryAudioDeviceOutputEvent(HLERequestContext& ctx) {
LOG_DEBUG(Service_Audio, "called");
IPC::ResponseBuilder rb{ctx, 2, 1};
@@ -387,7 +384,7 @@ private:
rb.PushCopyObjects(event->GetReadableEvent());
}
- void ListAudioOutputDeviceName(Kernel::HLERequestContext& ctx) {
+ void ListAudioOutputDeviceName(HLERequestContext& ctx) {
const size_t in_count = ctx.GetWriteBufferNumElements<AudioDevice::AudioDeviceName>();
std::vector<AudioDevice::AudioDeviceName> out_names{};
@@ -421,7 +418,7 @@ private:
};
AudRenU::AudRenU(Core::System& system_)
- : ServiceFramework{system_, "audren:u", ServiceThreadType::CreateNew},
+ : ServiceFramework{system_, "audren:u"},
service_context{system_, "audren:u"}, impl{std::make_unique<Manager>(system_)} {
// clang-format off
static const FunctionInfo functions[] = {
@@ -438,7 +435,7 @@ AudRenU::AudRenU(Core::System& system_)
AudRenU::~AudRenU() = default;
-void AudRenU::OpenAudioRenderer(Kernel::HLERequestContext& ctx) {
+void AudRenU::OpenAudioRenderer(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
AudioCore::AudioRendererParameterInternal params;
@@ -451,11 +448,11 @@ void AudRenU::OpenAudioRenderer(Kernel::HLERequestContext& ctx) {
if (impl->GetSessionCount() + 1 > AudioCore::MaxRendererSessions) {
LOG_ERROR(Service_Audio, "Too many AudioRenderer sessions open!");
IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ERR_MAXIMUM_SESSIONS_REACHED);
+ rb.Push(Audio::ResultOutOfSessions);
return;
}
- const auto& handle_table{system.CurrentProcess()->GetHandleTable()};
+ const auto& handle_table{system.ApplicationProcess()->GetHandleTable()};
auto process{handle_table.GetObject<Kernel::KProcess>(process_handle)};
auto transfer_memory{
process->GetHandleTable().GetObject<Kernel::KTransferMemory>(transfer_memory_handle)};
@@ -464,7 +461,7 @@ void AudRenU::OpenAudioRenderer(Kernel::HLERequestContext& ctx) {
if (session_id == -1) {
LOG_ERROR(Service_Audio, "Tried to open a session that's already in use!");
IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ERR_MAXIMUM_SESSIONS_REACHED);
+ rb.Push(Audio::ResultOutOfSessions);
return;
}
@@ -478,7 +475,7 @@ void AudRenU::OpenAudioRenderer(Kernel::HLERequestContext& ctx) {
applet_resource_user_id, session_id);
}
-void AudRenU::GetWorkBufferSize(Kernel::HLERequestContext& ctx) {
+void AudRenU::GetWorkBufferSize(HLERequestContext& ctx) {
AudioCore::AudioRendererParameterInternal params;
IPC::RequestParser rp{ctx};
@@ -509,7 +506,7 @@ void AudRenU::GetWorkBufferSize(Kernel::HLERequestContext& ctx) {
rb.Push<u64>(size);
}
-void AudRenU::GetAudioDeviceService(Kernel::HLERequestContext& ctx) {
+void AudRenU::GetAudioDeviceService(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto applet_resource_user_id = rp.Pop<u64>();
@@ -523,11 +520,11 @@ void AudRenU::GetAudioDeviceService(Kernel::HLERequestContext& ctx) {
::Common::MakeMagic('R', 'E', 'V', '1'), num_audio_devices++);
}
-void AudRenU::OpenAudioRendererForManualExecution(Kernel::HLERequestContext& ctx) {
+void AudRenU::OpenAudioRendererForManualExecution(HLERequestContext& ctx) {
LOG_DEBUG(Service_Audio, "called");
}
-void AudRenU::GetAudioDeviceServiceWithRevisionInfo(Kernel::HLERequestContext& ctx) {
+void AudRenU::GetAudioDeviceServiceWithRevisionInfo(HLERequestContext& ctx) {
struct Parameters {
u32 revision;
u64 applet_resource_user_id;
diff --git a/src/core/hle/service/audio/audren_u.h b/src/core/hle/service/audio/audren_u.h
index 4384a9b3c..d8e9c8719 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 "audio_core/audio_render_manager.h"
+#include "common/scratch_buffer.h"
#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/service.h"
@@ -11,10 +12,6 @@ namespace Core {
class System;
}
-namespace Kernel {
-class HLERequestContext;
-}
-
namespace Service::Audio {
class IAudioRenderer;
@@ -24,11 +21,11 @@ public:
~AudRenU() override;
private:
- void OpenAudioRenderer(Kernel::HLERequestContext& ctx);
- void GetWorkBufferSize(Kernel::HLERequestContext& ctx);
- void GetAudioDeviceService(Kernel::HLERequestContext& ctx);
- void OpenAudioRendererForManualExecution(Kernel::HLERequestContext& ctx);
- void GetAudioDeviceServiceWithRevisionInfo(Kernel::HLERequestContext& ctx);
+ void OpenAudioRenderer(HLERequestContext& ctx);
+ void GetWorkBufferSize(HLERequestContext& ctx);
+ void GetAudioDeviceService(HLERequestContext& ctx);
+ void OpenAudioRendererForManualExecution(HLERequestContext& ctx);
+ void GetAudioDeviceServiceWithRevisionInfo(HLERequestContext& ctx);
KernelHelpers::ServiceContext service_context;
std::unique_ptr<AudioCore::AudioRenderer::Manager> impl;
diff --git a/src/core/hle/service/audio/codecctl.cpp b/src/core/hle/service/audio/codecctl.cpp
deleted file mode 100644
index 81b956d7e..000000000
--- a/src/core/hle/service/audio/codecctl.cpp
+++ /dev/null
@@ -1,29 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#include "core/hle/service/audio/codecctl.h"
-
-namespace Service::Audio {
-
-CodecCtl::CodecCtl(Core::System& system_) : ServiceFramework{system_, "codecctl"} {
- static const FunctionInfo functions[] = {
- {0, nullptr, "Initialize"},
- {1, nullptr, "Finalize"},
- {2, nullptr, "Sleep"},
- {3, nullptr, "Wake"},
- {4, nullptr, "SetVolume"},
- {5, nullptr, "GetVolumeMax"},
- {6, nullptr, "GetVolumeMin"},
- {7, nullptr, "SetActiveTarget"},
- {8, nullptr, "GetActiveTarget"},
- {9, nullptr, "BindHeadphoneMicJackInterrupt"},
- {10, nullptr, "IsHeadphoneMicJackInserted"},
- {11, nullptr, "ClearHeadphoneMicJackInterrupt"},
- {12, nullptr, "IsRequested"},
- };
- RegisterHandlers(functions);
-}
-
-CodecCtl::~CodecCtl() = default;
-
-} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/codecctl.h b/src/core/hle/service/audio/codecctl.h
deleted file mode 100644
index 34da98212..000000000
--- a/src/core/hle/service/audio/codecctl.h
+++ /dev/null
@@ -1,20 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#pragma once
-
-#include "core/hle/service/service.h"
-
-namespace Core {
-class System;
-}
-
-namespace Service::Audio {
-
-class CodecCtl final : public ServiceFramework<CodecCtl> {
-public:
- explicit CodecCtl(Core::System& system_);
- ~CodecCtl() override;
-};
-
-} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/errors.h b/src/core/hle/service/audio/errors.h
index d706978cb..3d3d3d97a 100644
--- a/src/core/hle/service/audio/errors.h
+++ b/src/core/hle/service/audio/errors.h
@@ -7,17 +7,17 @@
namespace Service::Audio {
-constexpr Result ERR_INVALID_DEVICE_NAME{ErrorModule::Audio, 1};
-constexpr Result ERR_OPERATION_FAILED{ErrorModule::Audio, 2};
-constexpr Result ERR_INVALID_SAMPLE_RATE{ErrorModule::Audio, 3};
-constexpr Result ERR_INSUFFICIENT_BUFFER_SIZE{ErrorModule::Audio, 4};
-constexpr Result ERR_MAXIMUM_SESSIONS_REACHED{ErrorModule::Audio, 5};
-constexpr Result ERR_BUFFER_COUNT_EXCEEDED{ErrorModule::Audio, 8};
-constexpr Result ERR_INVALID_CHANNEL_COUNT{ErrorModule::Audio, 10};
-constexpr Result ERR_INVALID_UPDATE_DATA{ErrorModule::Audio, 41};
-constexpr Result ERR_POOL_MAPPING_FAILED{ErrorModule::Audio, 42};
-constexpr Result ERR_NOT_SUPPORTED{ErrorModule::Audio, 513};
-constexpr Result ERR_INVALID_PROCESS_HANDLE{ErrorModule::Audio, 1536};
-constexpr Result ERR_INVALID_REVISION{ErrorModule::Audio, 1537};
+constexpr Result ResultNotFound{ErrorModule::Audio, 1};
+constexpr Result ResultOperationFailed{ErrorModule::Audio, 2};
+constexpr Result ResultInvalidSampleRate{ErrorModule::Audio, 3};
+constexpr Result ResultInsufficientBuffer{ErrorModule::Audio, 4};
+constexpr Result ResultOutOfSessions{ErrorModule::Audio, 5};
+constexpr Result ResultBufferCountReached{ErrorModule::Audio, 8};
+constexpr Result ResultInvalidChannelCount{ErrorModule::Audio, 10};
+constexpr Result ResultInvalidUpdateInfo{ErrorModule::Audio, 41};
+constexpr Result ResultInvalidAddressInfo{ErrorModule::Audio, 42};
+constexpr Result ResultNotSupported{ErrorModule::Audio, 513};
+constexpr Result ResultInvalidHandle{ErrorModule::Audio, 1536};
+constexpr Result ResultInvalidRevision{ErrorModule::Audio, 1537};
} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/hwopus.cpp b/src/core/hle/service/audio/hwopus.cpp
index 825fb8bcc..c835f6cb7 100644
--- a/src/core/hle/service/audio/hwopus.cpp
+++ b/src/core/hle/service/audio/hwopus.cpp
@@ -11,8 +11,8 @@
#include "common/assert.h"
#include "common/logging/log.h"
-#include "core/hle/ipc_helpers.h"
#include "core/hle/service/audio/hwopus.h"
+#include "core/hle/service/ipc_helpers.h"
namespace Service::Audio {
namespace {
@@ -53,7 +53,7 @@ public:
// Decodes interleaved Opus packets. Optionally allows reporting time taken to
// perform the decoding, as well as any relevant extra behavior.
- void DecodeInterleaved(Kernel::HLERequestContext& ctx, PerfTime perf_time,
+ void DecodeInterleaved(HLERequestContext& ctx, PerfTime perf_time,
ExtraBehavior extra_behavior) {
if (perf_time == PerfTime::Disabled) {
DecodeInterleavedHelper(ctx, nullptr, extra_behavior);
@@ -64,17 +64,17 @@ public:
}
private:
- void DecodeInterleavedHelper(Kernel::HLERequestContext& ctx, u64* performance,
+ void DecodeInterleavedHelper(HLERequestContext& ctx, u64* performance,
ExtraBehavior extra_behavior) {
u32 consumed = 0;
u32 sample_count = 0;
- std::vector<opus_int16> samples(ctx.GetWriteBufferNumElements<opus_int16>());
+ tmp_samples.resize_destructive(ctx.GetWriteBufferNumElements<opus_int16>());
if (extra_behavior == ExtraBehavior::ResetContext) {
ResetDecoderContext();
}
- if (!DecodeOpusData(consumed, sample_count, ctx.ReadBuffer(), samples, performance)) {
+ if (!DecodeOpusData(consumed, sample_count, ctx.ReadBuffer(), tmp_samples, performance)) {
LOG_ERROR(Audio, "Failed to decode opus data");
IPC::ResponseBuilder rb{ctx, 2};
// TODO(ogniK): Use correct error code
@@ -90,11 +90,11 @@ private:
if (performance) {
rb.Push<u64>(*performance);
}
- ctx.WriteBuffer(samples);
+ ctx.WriteBuffer(tmp_samples);
}
- bool DecodeOpusData(u32& consumed, u32& sample_count, const std::vector<u8>& input,
- std::vector<opus_int16>& output, u64* out_performance_time) const {
+ bool DecodeOpusData(u32& consumed, u32& sample_count, std::span<const u8> input,
+ std::span<opus_int16> output, u64* out_performance_time) const {
const auto start_time = std::chrono::steady_clock::now();
const std::size_t raw_output_sz = output.size() * sizeof(opus_int16);
if (sizeof(OpusPacketHeader) > input.size()) {
@@ -154,6 +154,7 @@ private:
OpusDecoderPtr decoder;
u32 sample_rate;
u32 channel_count;
+ Common::ScratchBuffer<opus_int16> tmp_samples;
};
class IHardwareOpusDecoderManager final : public ServiceFramework<IHardwareOpusDecoderManager> {
@@ -180,21 +181,21 @@ public:
}
private:
- void DecodeInterleavedOld(Kernel::HLERequestContext& ctx) {
+ void DecodeInterleavedOld(HLERequestContext& ctx) {
LOG_DEBUG(Audio, "called");
decoder_state.DecodeInterleaved(ctx, OpusDecoderState::PerfTime::Disabled,
OpusDecoderState::ExtraBehavior::None);
}
- void DecodeInterleavedWithPerfOld(Kernel::HLERequestContext& ctx) {
+ void DecodeInterleavedWithPerfOld(HLERequestContext& ctx) {
LOG_DEBUG(Audio, "called");
decoder_state.DecodeInterleaved(ctx, OpusDecoderState::PerfTime::Enabled,
OpusDecoderState::ExtraBehavior::None);
}
- void DecodeInterleaved(Kernel::HLERequestContext& ctx) {
+ void DecodeInterleaved(HLERequestContext& ctx) {
LOG_DEBUG(Audio, "called");
IPC::RequestParser rp{ctx};
@@ -231,7 +232,7 @@ std::array<u8, 2> CreateMappingTable(u32 channel_count) {
}
} // Anonymous namespace
-void HwOpus::GetWorkBufferSize(Kernel::HLERequestContext& ctx) {
+void HwOpus::GetWorkBufferSize(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto sample_rate = rp.Pop<u32>();
const auto channel_count = rp.Pop<u32>();
@@ -251,11 +252,11 @@ void HwOpus::GetWorkBufferSize(Kernel::HLERequestContext& ctx) {
rb.Push<u32>(worker_buffer_sz);
}
-void HwOpus::GetWorkBufferSizeEx(Kernel::HLERequestContext& ctx) {
+void HwOpus::GetWorkBufferSizeEx(HLERequestContext& ctx) {
GetWorkBufferSize(ctx);
}
-void HwOpus::GetWorkBufferSizeForMultiStreamEx(Kernel::HLERequestContext& ctx) {
+void HwOpus::GetWorkBufferSizeForMultiStreamEx(HLERequestContext& ctx) {
OpusMultiStreamParametersEx param;
std::memcpy(&param, ctx.ReadBuffer().data(), ctx.GetReadBufferSize());
@@ -281,7 +282,7 @@ void HwOpus::GetWorkBufferSizeForMultiStreamEx(Kernel::HLERequestContext& ctx) {
rb.Push<u32>(worker_buffer_sz);
}
-void HwOpus::OpenHardwareOpusDecoder(Kernel::HLERequestContext& ctx) {
+void HwOpus::OpenHardwareOpusDecoder(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto sample_rate = rp.Pop<u32>();
const auto channel_count = rp.Pop<u32>();
@@ -319,7 +320,7 @@ void HwOpus::OpenHardwareOpusDecoder(Kernel::HLERequestContext& ctx) {
system, OpusDecoderState{std::move(decoder), sample_rate, channel_count});
}
-void HwOpus::OpenHardwareOpusDecoderEx(Kernel::HLERequestContext& ctx) {
+void HwOpus::OpenHardwareOpusDecoderEx(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto sample_rate = rp.Pop<u32>();
const auto channel_count = rp.Pop<u32>();
@@ -362,6 +363,8 @@ HwOpus::HwOpus(Core::System& system_) : ServiceFramework{system_, "hwopus"} {
{5, &HwOpus::GetWorkBufferSizeEx, "GetWorkBufferSizeEx"},
{6, nullptr, "OpenHardwareOpusDecoderForMultiStreamEx"},
{7, &HwOpus::GetWorkBufferSizeForMultiStreamEx, "GetWorkBufferSizeForMultiStreamEx"},
+ {8, nullptr, "GetWorkBufferSizeExEx"},
+ {9, nullptr, "GetWorkBufferSizeForMultiStreamExEx"},
};
RegisterHandlers(functions);
}
diff --git a/src/core/hle/service/audio/hwopus.h b/src/core/hle/service/audio/hwopus.h
index e6092e290..ece65c02c 100644
--- a/src/core/hle/service/audio/hwopus.h
+++ b/src/core/hle/service/audio/hwopus.h
@@ -27,11 +27,11 @@ public:
~HwOpus() override;
private:
- void OpenHardwareOpusDecoder(Kernel::HLERequestContext& ctx);
- void OpenHardwareOpusDecoderEx(Kernel::HLERequestContext& ctx);
- void GetWorkBufferSize(Kernel::HLERequestContext& ctx);
- void GetWorkBufferSizeEx(Kernel::HLERequestContext& ctx);
- void GetWorkBufferSizeForMultiStreamEx(Kernel::HLERequestContext& ctx);
+ void OpenHardwareOpusDecoder(HLERequestContext& ctx);
+ void OpenHardwareOpusDecoderEx(HLERequestContext& ctx);
+ void GetWorkBufferSize(HLERequestContext& ctx);
+ void GetWorkBufferSizeEx(HLERequestContext& ctx);
+ void GetWorkBufferSizeForMultiStreamEx(HLERequestContext& ctx);
};
} // namespace Service::Audio
diff --git a/src/core/hle/service/bcat/bcat_module.cpp b/src/core/hle/service/bcat/bcat_module.cpp
index cbe690a5d..a6281913a 100644
--- a/src/core/hle/service/bcat/bcat_module.cpp
+++ b/src/core/hle/service/bcat/bcat_module.cpp
@@ -9,12 +9,13 @@
#include "common/string_util.h"
#include "core/core.h"
#include "core/file_sys/vfs.h"
-#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/k_readable_event.h"
#include "core/hle/service/bcat/backend/backend.h"
#include "core/hle/service/bcat/bcat.h"
#include "core/hle/service/bcat/bcat_module.h"
#include "core/hle/service/filesystem/filesystem.h"
+#include "core/hle/service/ipc_helpers.h"
+#include "core/hle/service/server_manager.h"
namespace Service::BCAT {
@@ -50,8 +51,7 @@ BCATDigest DigestFile(const FileSys::VirtualFile& file) {
// For a name to be valid it must be non-empty, must have a null terminating character as the final
// char, can only contain numbers, letters, underscores and a hyphen if directory and a period if
// file.
-bool VerifyNameValidInternal(Kernel::HLERequestContext& ctx, std::array<char, 0x20> name,
- char match_char) {
+bool VerifyNameValidInternal(HLERequestContext& ctx, std::array<char, 0x20> name, char match_char) {
const auto null_chars = std::count(name.begin(), name.end(), 0);
const auto bad_chars = std::count_if(name.begin(), name.end(), [match_char](char c) {
return !std::isalnum(static_cast<u8>(c)) && c != '_' && c != match_char && c != '\0';
@@ -66,11 +66,11 @@ bool VerifyNameValidInternal(Kernel::HLERequestContext& ctx, std::array<char, 0x
return true;
}
-bool VerifyNameValidDir(Kernel::HLERequestContext& ctx, DirectoryName name) {
+bool VerifyNameValidDir(HLERequestContext& ctx, DirectoryName name) {
return VerifyNameValidInternal(ctx, name, '-');
}
-bool VerifyNameValidFile(Kernel::HLERequestContext& ctx, FileName name) {
+bool VerifyNameValidFile(HLERequestContext& ctx, FileName name) {
return VerifyNameValidInternal(ctx, name, '.');
}
@@ -98,7 +98,7 @@ public:
}
private:
- void GetEvent(Kernel::HLERequestContext& ctx) {
+ void GetEvent(HLERequestContext& ctx) {
LOG_DEBUG(Service_BCAT, "called");
IPC::ResponseBuilder rb{ctx, 2, 1};
@@ -106,7 +106,7 @@ private:
rb.PushCopyObjects(event);
}
- void GetImpl(Kernel::HLERequestContext& ctx) {
+ void GetImpl(HLERequestContext& ctx) {
LOG_DEBUG(Service_BCAT, "called");
ctx.WriteBuffer(impl);
@@ -173,11 +173,11 @@ private:
progress_backend.GetImpl());
}
- void RequestSyncDeliveryCache(Kernel::HLERequestContext& ctx) {
+ void RequestSyncDeliveryCache(HLERequestContext& ctx) {
LOG_DEBUG(Service_BCAT, "called");
- backend.Synchronize({system.GetCurrentProcessProgramID(),
- GetCurrentBuildID(system.GetCurrentProcessBuildID())},
+ backend.Synchronize({system.GetApplicationProcessProgramID(),
+ GetCurrentBuildID(system.GetApplicationProcessBuildID())},
GetProgressBackend(SyncType::Normal));
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -185,7 +185,7 @@ private:
rb.PushIpcInterface(CreateProgressService(SyncType::Normal));
}
- void RequestSyncDeliveryCacheWithDirectoryName(Kernel::HLERequestContext& ctx) {
+ void RequestSyncDeliveryCacheWithDirectoryName(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto name_raw = rp.PopRaw<DirectoryName>();
const auto name =
@@ -193,8 +193,8 @@ private:
LOG_DEBUG(Service_BCAT, "called, name={}", name);
- backend.SynchronizeDirectory({system.GetCurrentProcessProgramID(),
- GetCurrentBuildID(system.GetCurrentProcessBuildID())},
+ backend.SynchronizeDirectory({system.GetApplicationProcessProgramID(),
+ GetCurrentBuildID(system.GetApplicationProcessBuildID())},
name, GetProgressBackend(SyncType::Directory));
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -202,7 +202,7 @@ private:
rb.PushIpcInterface(CreateProgressService(SyncType::Directory));
}
- void SetPassphrase(Kernel::HLERequestContext& ctx) {
+ void SetPassphrase(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto title_id = rp.PopRaw<u64>();
@@ -234,7 +234,7 @@ private:
rb.Push(ResultSuccess);
}
- void ClearDeliveryCacheStorage(Kernel::HLERequestContext& ctx) {
+ void ClearDeliveryCacheStorage(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto title_id = rp.PopRaw<u64>();
@@ -270,7 +270,7 @@ private:
std::array<ProgressServiceBackend, static_cast<size_t>(SyncType::Count)> progress;
};
-void Module::Interface::CreateBcatService(Kernel::HLERequestContext& ctx) {
+void Module::Interface::CreateBcatService(HLERequestContext& ctx) {
LOG_DEBUG(Service_BCAT, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -295,7 +295,7 @@ public:
}
private:
- void Open(Kernel::HLERequestContext& ctx) {
+ void Open(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto dir_name_raw = rp.PopRaw<DirectoryName>();
const auto file_name_raw = rp.PopRaw<FileName>();
@@ -339,7 +339,7 @@ private:
rb.Push(ResultSuccess);
}
- void Read(Kernel::HLERequestContext& ctx) {
+ void Read(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto offset{rp.PopRaw<u64>()};
@@ -362,7 +362,7 @@ private:
rb.Push<u64>(buffer.size());
}
- void GetSize(Kernel::HLERequestContext& ctx) {
+ void GetSize(HLERequestContext& ctx) {
LOG_DEBUG(Service_BCAT, "called");
if (current_file == nullptr) {
@@ -376,7 +376,7 @@ private:
rb.Push<u64>(current_file->GetSize());
}
- void GetDigest(Kernel::HLERequestContext& ctx) {
+ void GetDigest(HLERequestContext& ctx) {
LOG_DEBUG(Service_BCAT, "called");
if (current_file == nullptr) {
@@ -411,7 +411,7 @@ public:
}
private:
- void Open(Kernel::HLERequestContext& ctx) {
+ void Open(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto name_raw = rp.PopRaw<DirectoryName>();
const auto name =
@@ -442,7 +442,7 @@ private:
rb.Push(ResultSuccess);
}
- void Read(Kernel::HLERequestContext& ctx) {
+ void Read(HLERequestContext& ctx) {
auto write_size = ctx.GetWriteBufferNumElements<DeliveryCacheDirectoryEntry>();
LOG_DEBUG(Service_BCAT, "called, write_size={:016X}", write_size);
@@ -472,7 +472,7 @@ private:
rb.Push(static_cast<u32>(write_size * sizeof(DeliveryCacheDirectoryEntry)));
}
- void GetCount(Kernel::HLERequestContext& ctx) {
+ void GetCount(HLERequestContext& ctx) {
LOG_DEBUG(Service_BCAT, "called");
if (current_dir == nullptr) {
@@ -516,7 +516,7 @@ public:
}
private:
- void CreateFileService(Kernel::HLERequestContext& ctx) {
+ void CreateFileService(HLERequestContext& ctx) {
LOG_DEBUG(Service_BCAT, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -524,7 +524,7 @@ private:
rb.PushIpcInterface<IDeliveryCacheFileService>(system, root);
}
- void CreateDirectoryService(Kernel::HLERequestContext& ctx) {
+ void CreateDirectoryService(HLERequestContext& ctx) {
LOG_DEBUG(Service_BCAT, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -532,7 +532,7 @@ private:
rb.PushIpcInterface<IDeliveryCacheDirectoryService>(system, root);
}
- void EnumerateDeliveryCacheDirectory(Kernel::HLERequestContext& ctx) {
+ void EnumerateDeliveryCacheDirectory(HLERequestContext& ctx) {
auto size = ctx.GetWriteBufferNumElements<DirectoryName>();
LOG_DEBUG(Service_BCAT, "called, size={:016X}", size);
@@ -551,17 +551,16 @@ private:
u64 next_read_index = 0;
};
-void Module::Interface::CreateDeliveryCacheStorageService(Kernel::HLERequestContext& ctx) {
+void Module::Interface::CreateDeliveryCacheStorageService(HLERequestContext& ctx) {
LOG_DEBUG(Service_BCAT, "called");
- const auto title_id = system.GetCurrentProcessProgramID();
+ const auto title_id = system.GetApplicationProcessProgramID();
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IDeliveryCacheStorageService>(system, fsc.GetBCATDirectory(title_id));
}
-void Module::Interface::CreateDeliveryCacheStorageServiceWithApplicationId(
- Kernel::HLERequestContext& ctx) {
+void Module::Interface::CreateDeliveryCacheStorageServiceWithApplicationId(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto title_id = rp.PopRaw<u64>();
@@ -585,16 +584,23 @@ Module::Interface::Interface(Core::System& system_, std::shared_ptr<Module> modu
Module::Interface::~Interface() = default;
-void InstallInterfaces(Core::System& system) {
+void LoopProcess(Core::System& system) {
+ auto server_manager = std::make_unique<ServerManager>(system);
auto module = std::make_shared<Module>();
- std::make_shared<BCAT>(system, module, system.GetFileSystemController(), "bcat:a")
- ->InstallAsService(system.ServiceManager());
- std::make_shared<BCAT>(system, module, system.GetFileSystemController(), "bcat:m")
- ->InstallAsService(system.ServiceManager());
- std::make_shared<BCAT>(system, module, system.GetFileSystemController(), "bcat:u")
- ->InstallAsService(system.ServiceManager());
- std::make_shared<BCAT>(system, module, system.GetFileSystemController(), "bcat:s")
- ->InstallAsService(system.ServiceManager());
+
+ server_manager->RegisterNamedService(
+ "bcat:a",
+ std::make_shared<BCAT>(system, module, system.GetFileSystemController(), "bcat:a"));
+ server_manager->RegisterNamedService(
+ "bcat:m",
+ std::make_shared<BCAT>(system, module, system.GetFileSystemController(), "bcat:m"));
+ server_manager->RegisterNamedService(
+ "bcat:u",
+ std::make_shared<BCAT>(system, module, system.GetFileSystemController(), "bcat:u"));
+ server_manager->RegisterNamedService(
+ "bcat:s",
+ std::make_shared<BCAT>(system, module, system.GetFileSystemController(), "bcat:s"));
+ ServerManager::RunServer(std::move(server_manager));
}
} // namespace Service::BCAT
diff --git a/src/core/hle/service/bcat/bcat_module.h b/src/core/hle/service/bcat/bcat_module.h
index b2fcf9bfb..87576288b 100644
--- a/src/core/hle/service/bcat/bcat_module.h
+++ b/src/core/hle/service/bcat/bcat_module.h
@@ -27,9 +27,9 @@ public:
FileSystem::FileSystemController& fsc_, const char* name);
~Interface() override;
- void CreateBcatService(Kernel::HLERequestContext& ctx);
- void CreateDeliveryCacheStorageService(Kernel::HLERequestContext& ctx);
- void CreateDeliveryCacheStorageServiceWithApplicationId(Kernel::HLERequestContext& ctx);
+ void CreateBcatService(HLERequestContext& ctx);
+ void CreateDeliveryCacheStorageService(HLERequestContext& ctx);
+ void CreateDeliveryCacheStorageServiceWithApplicationId(HLERequestContext& ctx);
protected:
FileSystem::FileSystemController& fsc;
@@ -39,8 +39,7 @@ public:
};
};
-/// Registers all BCAT services with the specified service manager.
-void InstallInterfaces(Core::System& system);
+void LoopProcess(Core::System& system);
} // namespace BCAT
diff --git a/src/core/hle/service/bpc/bpc.cpp b/src/core/hle/service/bpc/bpc.cpp
index 466163538..91b15e256 100644
--- a/src/core/hle/service/bpc/bpc.cpp
+++ b/src/core/hle/service/bpc/bpc.cpp
@@ -4,8 +4,8 @@
#include <memory>
#include "core/hle/service/bpc/bpc.h"
+#include "core/hle/service/server_manager.h"
#include "core/hle/service/service.h"
-#include "core/hle/service/sm/sm.h"
namespace Service::BPC {
@@ -54,9 +54,12 @@ public:
}
};
-void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
- std::make_shared<BPC>(system)->InstallAsService(sm);
- std::make_shared<BPC_R>(system)->InstallAsService(sm);
+void LoopProcess(Core::System& system) {
+ auto server_manager = std::make_unique<ServerManager>(system);
+
+ server_manager->RegisterNamedService("bpc", std::make_shared<BPC>(system));
+ server_manager->RegisterNamedService("bpc:r", std::make_shared<BPC_R>(system));
+ ServerManager::RunServer(std::move(server_manager));
}
} // namespace Service::BPC
diff --git a/src/core/hle/service/bpc/bpc.h b/src/core/hle/service/bpc/bpc.h
index 8adc2f962..524391ddb 100644
--- a/src/core/hle/service/bpc/bpc.h
+++ b/src/core/hle/service/bpc/bpc.h
@@ -13,6 +13,6 @@ class ServiceManager;
namespace Service::BPC {
-void InstallInterfaces(SM::ServiceManager& sm, Core::System& system);
+void LoopProcess(Core::System& system);
} // namespace Service::BPC
diff --git a/src/core/hle/service/btdrv/btdrv.cpp b/src/core/hle/service/btdrv/btdrv.cpp
index ec7e5320c..38cdd57ad 100644
--- a/src/core/hle/service/btdrv/btdrv.cpp
+++ b/src/core/hle/service/btdrv/btdrv.cpp
@@ -3,10 +3,11 @@
#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/service/btdrv/btdrv.h"
+#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/kernel_helpers.h"
+#include "core/hle/service/server_manager.h"
#include "core/hle/service/service.h"
#include "core/hle/service/sm/sm.h"
@@ -40,7 +41,7 @@ public:
}
private:
- void RegisterBleEvent(Kernel::HLERequestContext& ctx) {
+ void RegisterBleEvent(HLERequestContext& ctx) {
LOG_WARNING(Service_BTM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2, 1};
@@ -196,9 +197,12 @@ public:
}
};
-void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
- std::make_shared<BtDrv>(system)->InstallAsService(sm);
- std::make_shared<Bt>(system)->InstallAsService(sm);
+void LoopProcess(Core::System& system) {
+ auto server_manager = std::make_unique<ServerManager>(system);
+
+ server_manager->RegisterNamedService("btdrv", std::make_shared<BtDrv>(system));
+ server_manager->RegisterNamedService("bt", std::make_shared<Bt>(system));
+ ServerManager::RunServer(std::move(server_manager));
}
} // namespace Service::BtDrv
diff --git a/src/core/hle/service/btdrv/btdrv.h b/src/core/hle/service/btdrv/btdrv.h
index 9cbe2926f..42713860e 100644
--- a/src/core/hle/service/btdrv/btdrv.h
+++ b/src/core/hle/service/btdrv/btdrv.h
@@ -13,7 +13,6 @@ class System;
namespace Service::BtDrv {
-/// Registers all BtDrv services with the specified service manager.
-void InstallInterfaces(SM::ServiceManager& sm, Core::System& system);
+void LoopProcess(Core::System& system);
} // namespace Service::BtDrv
diff --git a/src/core/hle/service/btm/btm.cpp b/src/core/hle/service/btm/btm.cpp
index eebf85e03..8069f75b7 100644
--- a/src/core/hle/service/btm/btm.cpp
+++ b/src/core/hle/service/btm/btm.cpp
@@ -5,10 +5,11 @@
#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/service/btm/btm.h"
+#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/kernel_helpers.h"
+#include "core/hle/service/server_manager.h"
#include "core/hle/service/service.h"
namespace Service::BTM {
@@ -69,35 +70,39 @@ public:
}
private:
- void AcquireBleScanEvent(Kernel::HLERequestContext& ctx) {
+ void AcquireBleScanEvent(HLERequestContext& ctx) {
LOG_WARNING(Service_BTM, "(STUBBED) called");
- IPC::ResponseBuilder rb{ctx, 2, 1};
+ IPC::ResponseBuilder rb{ctx, 3, 1};
rb.Push(ResultSuccess);
+ rb.Push(true);
rb.PushCopyObjects(scan_event->GetReadableEvent());
}
- void AcquireBleConnectionEvent(Kernel::HLERequestContext& ctx) {
+ void AcquireBleConnectionEvent(HLERequestContext& ctx) {
LOG_WARNING(Service_BTM, "(STUBBED) called");
- IPC::ResponseBuilder rb{ctx, 2, 1};
+ IPC::ResponseBuilder rb{ctx, 3, 1};
rb.Push(ResultSuccess);
+ rb.Push(true);
rb.PushCopyObjects(connection_event->GetReadableEvent());
}
- void AcquireBleServiceDiscoveryEvent(Kernel::HLERequestContext& ctx) {
+ void AcquireBleServiceDiscoveryEvent(HLERequestContext& ctx) {
LOG_WARNING(Service_BTM, "(STUBBED) called");
- IPC::ResponseBuilder rb{ctx, 2, 1};
+ IPC::ResponseBuilder rb{ctx, 3, 1};
rb.Push(ResultSuccess);
+ rb.Push(true);
rb.PushCopyObjects(service_discovery_event->GetReadableEvent());
}
- void AcquireBleMtuConfigEvent(Kernel::HLERequestContext& ctx) {
+ void AcquireBleMtuConfigEvent(HLERequestContext& ctx) {
LOG_WARNING(Service_BTM, "(STUBBED) called");
- IPC::ResponseBuilder rb{ctx, 2, 1};
+ IPC::ResponseBuilder rb{ctx, 3, 1};
rb.Push(ResultSuccess);
+ rb.Push(true);
rb.PushCopyObjects(config_event->GetReadableEvent());
}
@@ -121,7 +126,7 @@ public:
}
private:
- void GetCore(Kernel::HLERequestContext& ctx) {
+ void GetCore(HLERequestContext& ctx) {
LOG_DEBUG(Service_BTM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -302,7 +307,7 @@ public:
}
private:
- void GetCore(Kernel::HLERequestContext& ctx) {
+ void GetCore(HLERequestContext& ctx) {
LOG_DEBUG(Service_BTM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -311,11 +316,14 @@ private:
}
};
-void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
- std::make_shared<BTM>(system)->InstallAsService(sm);
- std::make_shared<BTM_DBG>(system)->InstallAsService(sm);
- std::make_shared<BTM_SYS>(system)->InstallAsService(sm);
- std::make_shared<BTM_USR>(system)->InstallAsService(sm);
+void LoopProcess(Core::System& system) {
+ auto server_manager = std::make_unique<ServerManager>(system);
+
+ server_manager->RegisterNamedService("btm", std::make_shared<BTM>(system));
+ server_manager->RegisterNamedService("btm:dbg", std::make_shared<BTM_DBG>(system));
+ server_manager->RegisterNamedService("btm:sys", std::make_shared<BTM_SYS>(system));
+ server_manager->RegisterNamedService("btm:u", std::make_shared<BTM_USR>(system));
+ ServerManager::RunServer(std::move(server_manager));
}
} // namespace Service::BTM
diff --git a/src/core/hle/service/btm/btm.h b/src/core/hle/service/btm/btm.h
index 9dcda1848..a99b34364 100644
--- a/src/core/hle/service/btm/btm.h
+++ b/src/core/hle/service/btm/btm.h
@@ -13,6 +13,6 @@ class System;
namespace Service::BTM {
-void InstallInterfaces(SM::ServiceManager& sm, Core::System& system);
+void LoopProcess(Core::System& system);
} // namespace Service::BTM
diff --git a/src/core/hle/service/caps/caps.cpp b/src/core/hle/service/caps/caps.cpp
index 13940a8c9..610fe9940 100644
--- a/src/core/hle/service/caps/caps.cpp
+++ b/src/core/hle/service/caps/caps.cpp
@@ -8,17 +8,21 @@
#include "core/hle/service/caps/caps_ss.h"
#include "core/hle/service/caps/caps_su.h"
#include "core/hle/service/caps/caps_u.h"
+#include "core/hle/service/server_manager.h"
#include "core/hle/service/service.h"
namespace Service::Capture {
-void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
- std::make_shared<CAPS_A>(system)->InstallAsService(sm);
- std::make_shared<CAPS_C>(system)->InstallAsService(sm);
- std::make_shared<CAPS_U>(system)->InstallAsService(sm);
- std::make_shared<CAPS_SC>(system)->InstallAsService(sm);
- std::make_shared<CAPS_SS>(system)->InstallAsService(sm);
- std::make_shared<CAPS_SU>(system)->InstallAsService(sm);
+void LoopProcess(Core::System& system) {
+ auto server_manager = std::make_unique<ServerManager>(system);
+
+ server_manager->RegisterNamedService("caps:a", std::make_shared<CAPS_A>(system));
+ server_manager->RegisterNamedService("caps:c", std::make_shared<CAPS_C>(system));
+ server_manager->RegisterNamedService("caps:u", std::make_shared<CAPS_U>(system));
+ server_manager->RegisterNamedService("caps:sc", std::make_shared<CAPS_SC>(system));
+ server_manager->RegisterNamedService("caps:ss", std::make_shared<CAPS_SS>(system));
+ server_manager->RegisterNamedService("caps:su", std::make_shared<CAPS_SU>(system));
+ ServerManager::RunServer(std::move(server_manager));
}
} // namespace Service::Capture
diff --git a/src/core/hle/service/caps/caps.h b/src/core/hle/service/caps/caps.h
index 3e89c82cb..15f0ecfaa 100644
--- a/src/core/hle/service/caps/caps.h
+++ b/src/core/hle/service/caps/caps.h
@@ -90,7 +90,6 @@ struct ApplicationAlbumFileEntry {
static_assert(sizeof(ApplicationAlbumFileEntry) == 0x30,
"ApplicationAlbumFileEntry has incorrect size.");
-/// Registers all Capture services with the specified service manager.
-void InstallInterfaces(SM::ServiceManager& sm, Core::System& system);
+void LoopProcess(Core::System& system);
} // namespace Service::Capture
diff --git a/src/core/hle/service/caps/caps_a.h b/src/core/hle/service/caps/caps_a.h
index 319c173d8..98a21a5ad 100644
--- a/src/core/hle/service/caps/caps_a.h
+++ b/src/core/hle/service/caps/caps_a.h
@@ -9,10 +9,6 @@ namespace Core {
class System;
}
-namespace Kernel {
-class HLERequestContext;
-}
-
namespace Service::Capture {
class CAPS_A final : public ServiceFramework<CAPS_A> {
diff --git a/src/core/hle/service/caps/caps_c.cpp b/src/core/hle/service/caps/caps_c.cpp
index 725a2e3a7..fc77e35cd 100644
--- a/src/core/hle/service/caps/caps_c.cpp
+++ b/src/core/hle/service/caps/caps_c.cpp
@@ -2,8 +2,8 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/logging/log.h"
-#include "core/hle/ipc_helpers.h"
#include "core/hle/service/caps/caps_c.h"
+#include "core/hle/service/ipc_helpers.h"
namespace Service::Capture {
@@ -74,7 +74,7 @@ CAPS_C::CAPS_C(Core::System& system_) : ServiceFramework{system_, "caps:c"} {
CAPS_C::~CAPS_C() = default;
-void CAPS_C::SetShimLibraryVersion(Kernel::HLERequestContext& ctx) {
+void CAPS_C::SetShimLibraryVersion(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto library_version{rp.Pop<u64>()};
const auto applet_resource_user_id{rp.Pop<u64>()};
diff --git a/src/core/hle/service/caps/caps_c.h b/src/core/hle/service/caps/caps_c.h
index 983a4212d..537b3a2e3 100644
--- a/src/core/hle/service/caps/caps_c.h
+++ b/src/core/hle/service/caps/caps_c.h
@@ -9,10 +9,6 @@ namespace Core {
class System;
}
-namespace Kernel {
-class HLERequestContext;
-}
-
namespace Service::Capture {
class CAPS_C final : public ServiceFramework<CAPS_C> {
@@ -21,7 +17,7 @@ public:
~CAPS_C() override;
private:
- void SetShimLibraryVersion(Kernel::HLERequestContext& ctx);
+ void SetShimLibraryVersion(HLERequestContext& ctx);
};
} // namespace Service::Capture
diff --git a/src/core/hle/service/caps/caps_su.cpp b/src/core/hle/service/caps/caps_su.cpp
index fcb496756..3b11cc95c 100644
--- a/src/core/hle/service/caps/caps_su.cpp
+++ b/src/core/hle/service/caps/caps_su.cpp
@@ -2,8 +2,8 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/logging/log.h"
-#include "core/hle/ipc_helpers.h"
#include "core/hle/service/caps/caps_su.h"
+#include "core/hle/service/ipc_helpers.h"
namespace Service::Capture {
@@ -23,7 +23,7 @@ CAPS_SU::CAPS_SU(Core::System& system_) : ServiceFramework{system_, "caps:su"} {
CAPS_SU::~CAPS_SU() = default;
-void CAPS_SU::SetShimLibraryVersion(Kernel::HLERequestContext& ctx) {
+void CAPS_SU::SetShimLibraryVersion(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto library_version{rp.Pop<u64>()};
const auto applet_resource_user_id{rp.Pop<u64>()};
diff --git a/src/core/hle/service/caps/caps_su.h b/src/core/hle/service/caps/caps_su.h
index c9a1d507b..c6398858d 100644
--- a/src/core/hle/service/caps/caps_su.h
+++ b/src/core/hle/service/caps/caps_su.h
@@ -9,10 +9,6 @@ namespace Core {
class System;
}
-namespace Kernel {
-class HLERequestContext;
-}
-
namespace Service::Capture {
class CAPS_SU final : public ServiceFramework<CAPS_SU> {
@@ -21,7 +17,7 @@ public:
~CAPS_SU() override;
private:
- void SetShimLibraryVersion(Kernel::HLERequestContext& ctx);
+ void SetShimLibraryVersion(HLERequestContext& ctx);
};
} // namespace Service::Capture
diff --git a/src/core/hle/service/caps/caps_u.cpp b/src/core/hle/service/caps/caps_u.cpp
index 5fbba8673..bffe0f8d0 100644
--- a/src/core/hle/service/caps/caps_u.cpp
+++ b/src/core/hle/service/caps/caps_u.cpp
@@ -2,9 +2,9 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/logging/log.h"
-#include "core/hle/ipc_helpers.h"
#include "core/hle/service/caps/caps.h"
#include "core/hle/service/caps/caps_u.h"
+#include "core/hle/service/ipc_helpers.h"
namespace Service::Capture {
@@ -52,7 +52,7 @@ CAPS_U::CAPS_U(Core::System& system_) : ServiceFramework{system_, "caps:u"} {
CAPS_U::~CAPS_U() = default;
-void CAPS_U::SetShimLibraryVersion(Kernel::HLERequestContext& ctx) {
+void CAPS_U::SetShimLibraryVersion(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto library_version{rp.Pop<u64>()};
const auto applet_resource_user_id{rp.Pop<u64>()};
@@ -64,7 +64,7 @@ void CAPS_U::SetShimLibraryVersion(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void CAPS_U::GetAlbumContentsFileListForApplication(Kernel::HLERequestContext& ctx) {
+void CAPS_U::GetAlbumContentsFileListForApplication(HLERequestContext& ctx) {
// Takes a type-0x6 output buffer containing an array of ApplicationAlbumFileEntry, a PID, an
// u8 ContentType, two s64s, and an u64 AppletResourceUserId. Returns an output u64 for total
// output entries (which is copied to a s32 by official SW).
@@ -93,7 +93,7 @@ void CAPS_U::GetAlbumContentsFileListForApplication(Kernel::HLERequestContext& c
rb.Push(total_entries_2);
}
-void CAPS_U::GetAlbumFileList3AaeAruid(Kernel::HLERequestContext& ctx) {
+void CAPS_U::GetAlbumFileList3AaeAruid(HLERequestContext& ctx) {
GetAlbumContentsFileListForApplication(ctx);
}
diff --git a/src/core/hle/service/caps/caps_u.h b/src/core/hle/service/caps/caps_u.h
index c3d4b9cea..e8dd037d7 100644
--- a/src/core/hle/service/caps/caps_u.h
+++ b/src/core/hle/service/caps/caps_u.h
@@ -9,10 +9,6 @@ namespace Core {
class System;
}
-namespace Kernel {
-class HLERequestContext;
-}
-
namespace Service::Capture {
class CAPS_U final : public ServiceFramework<CAPS_U> {
@@ -21,9 +17,9 @@ public:
~CAPS_U() override;
private:
- void SetShimLibraryVersion(Kernel::HLERequestContext& ctx);
- void GetAlbumContentsFileListForApplication(Kernel::HLERequestContext& ctx);
- void GetAlbumFileList3AaeAruid(Kernel::HLERequestContext& ctx);
+ void SetShimLibraryVersion(HLERequestContext& ctx);
+ void GetAlbumContentsFileListForApplication(HLERequestContext& ctx);
+ void GetAlbumFileList3AaeAruid(HLERequestContext& ctx);
};
} // namespace Service::Capture
diff --git a/src/core/hle/service/erpt/erpt.cpp b/src/core/hle/service/erpt/erpt.cpp
index 923c0022a..3ea862fad 100644
--- a/src/core/hle/service/erpt/erpt.cpp
+++ b/src/core/hle/service/erpt/erpt.cpp
@@ -4,6 +4,7 @@
#include <memory>
#include "core/hle/service/erpt/erpt.h"
+#include "core/hle/service/server_manager.h"
#include "core/hle/service/service.h"
#include "core/hle/service/sm/sm.h"
@@ -52,9 +53,13 @@ public:
}
};
-void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
- std::make_shared<ErrorReportContext>(system)->InstallAsService(sm);
- std::make_shared<ErrorReportSession>(system)->InstallAsService(sm);
+void LoopProcess(Core::System& system) {
+ auto server_manager = std::make_unique<ServerManager>(system);
+
+ server_manager->RegisterNamedService("erpt:c", std::make_shared<ErrorReportContext>(system));
+ server_manager->RegisterNamedService("erpt:r", std::make_shared<ErrorReportSession>(system));
+
+ ServerManager::RunServer(std::move(server_manager));
}
} // namespace Service::ERPT
diff --git a/src/core/hle/service/erpt/erpt.h b/src/core/hle/service/erpt/erpt.h
index 507d626ec..60094f556 100644
--- a/src/core/hle/service/erpt/erpt.h
+++ b/src/core/hle/service/erpt/erpt.h
@@ -7,13 +7,8 @@ namespace Core {
class System;
}
-namespace Service::SM {
-class ServiceManager;
-}
-
namespace Service::ERPT {
-/// Registers all ERPT services with the specified service manager.
-void InstallInterfaces(SM::ServiceManager& sm, Core::System& system);
+void LoopProcess(Core::System& system);
} // namespace Service::ERPT
diff --git a/src/core/hle/service/es/es.cpp b/src/core/hle/service/es/es.cpp
index d183e5829..446f46b3c 100644
--- a/src/core/hle/service/es/es.cpp
+++ b/src/core/hle/service/es/es.cpp
@@ -2,8 +2,9 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/crypto/key_manager.h"
-#include "core/hle/ipc_helpers.h"
#include "core/hle/service/es/es.h"
+#include "core/hle/service/ipc_helpers.h"
+#include "core/hle/service/server_manager.h"
#include "core/hle/service/service.h"
namespace Service::ES {
@@ -109,7 +110,7 @@ public:
}
private:
- bool CheckRightsId(Kernel::HLERequestContext& ctx, const u128& rights_id) {
+ bool CheckRightsId(HLERequestContext& ctx, const u128& rights_id) {
if (rights_id == u128{}) {
LOG_ERROR(Service_ETicket, "The rights ID was invalid!");
IPC::ResponseBuilder rb{ctx, 2};
@@ -120,9 +121,9 @@ private:
return true;
}
- void ImportTicket(Kernel::HLERequestContext& ctx) {
+ void ImportTicket(HLERequestContext& ctx) {
const auto ticket = ctx.ReadBuffer();
- const auto cert = ctx.ReadBuffer(1);
+ [[maybe_unused]] const auto cert = ctx.ReadBuffer(1);
if (ticket.size() < sizeof(Core::Crypto::Ticket)) {
LOG_ERROR(Service_ETicket, "The input buffer is not large enough!");
@@ -145,7 +146,7 @@ private:
rb.Push(ResultSuccess);
}
- void GetTitleKey(Kernel::HLERequestContext& ctx) {
+ void GetTitleKey(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto rights_id = rp.PopRaw<u128>();
@@ -171,7 +172,7 @@ private:
rb.Push(ResultSuccess);
}
- void CountCommonTicket(Kernel::HLERequestContext& ctx) {
+ void CountCommonTicket(HLERequestContext& ctx) {
LOG_DEBUG(Service_ETicket, "called");
const u32 count = static_cast<u32>(keys.GetCommonTickets().size());
@@ -181,7 +182,7 @@ private:
rb.Push<u32>(count);
}
- void CountPersonalizedTicket(Kernel::HLERequestContext& ctx) {
+ void CountPersonalizedTicket(HLERequestContext& ctx) {
LOG_DEBUG(Service_ETicket, "called");
const u32 count = static_cast<u32>(keys.GetPersonalizedTickets().size());
@@ -191,7 +192,7 @@ private:
rb.Push<u32>(count);
}
- void ListCommonTicketRightsIds(Kernel::HLERequestContext& ctx) {
+ void ListCommonTicketRightsIds(HLERequestContext& ctx) {
size_t out_entries = 0;
if (!keys.GetCommonTickets().empty()) {
out_entries = ctx.GetWriteBufferNumElements<u128>();
@@ -212,7 +213,7 @@ private:
rb.Push<u32>(static_cast<u32>(out_entries));
}
- void ListPersonalizedTicketRightsIds(Kernel::HLERequestContext& ctx) {
+ void ListPersonalizedTicketRightsIds(HLERequestContext& ctx) {
size_t out_entries = 0;
if (!keys.GetPersonalizedTickets().empty()) {
out_entries = ctx.GetWriteBufferNumElements<u128>();
@@ -234,7 +235,7 @@ private:
rb.Push<u32>(static_cast<u32>(out_entries));
}
- void GetCommonTicketSize(Kernel::HLERequestContext& ctx) {
+ void GetCommonTicketSize(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto rights_id = rp.PopRaw<u128>();
@@ -250,7 +251,7 @@ private:
rb.Push<u64>(ticket.GetSize());
}
- void GetPersonalizedTicketSize(Kernel::HLERequestContext& ctx) {
+ void GetPersonalizedTicketSize(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto rights_id = rp.PopRaw<u128>();
@@ -266,7 +267,7 @@ private:
rb.Push<u64>(ticket.GetSize());
}
- void GetCommonTicketData(Kernel::HLERequestContext& ctx) {
+ void GetCommonTicketData(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto rights_id = rp.PopRaw<u128>();
@@ -285,7 +286,7 @@ private:
rb.Push<u64>(write_size);
}
- void GetPersonalizedTicketData(Kernel::HLERequestContext& ctx) {
+ void GetPersonalizedTicketData(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto rights_id = rp.PopRaw<u128>();
@@ -307,8 +308,11 @@ private:
Core::Crypto::KeyManager& keys = Core::Crypto::KeyManager::Instance();
};
-void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
- std::make_shared<ETicket>(system)->InstallAsService(service_manager);
+void LoopProcess(Core::System& system) {
+ auto server_manager = std::make_unique<ServerManager>(system);
+
+ server_manager->RegisterNamedService("es", std::make_shared<ETicket>(system));
+ ServerManager::RunServer(std::move(server_manager));
}
} // namespace Service::ES
diff --git a/src/core/hle/service/es/es.h b/src/core/hle/service/es/es.h
index 530563550..317680625 100644
--- a/src/core/hle/service/es/es.h
+++ b/src/core/hle/service/es/es.h
@@ -7,13 +7,8 @@ namespace Core {
class System;
}
-namespace Service::SM {
-class ServiceManager;
-}
-
namespace Service::ES {
-/// Registers all ES services with the specified service manager.
-void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system);
+void LoopProcess(Core::System& system);
} // namespace Service::ES
diff --git a/src/core/hle/service/eupld/eupld.cpp b/src/core/hle/service/eupld/eupld.cpp
index d1553ace0..3cf27513a 100644
--- a/src/core/hle/service/eupld/eupld.cpp
+++ b/src/core/hle/service/eupld/eupld.cpp
@@ -4,8 +4,8 @@
#include <memory>
#include "core/hle/service/eupld/eupld.h"
+#include "core/hle/service/server_manager.h"
#include "core/hle/service/service.h"
-#include "core/hle/service/sm/sm.h"
namespace Service::EUPLD {
@@ -44,9 +44,12 @@ public:
}
};
-void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
- std::make_shared<ErrorUploadContext>(system)->InstallAsService(sm);
- std::make_shared<ErrorUploadRequest>(system)->InstallAsService(sm);
+void LoopProcess(Core::System& system) {
+ auto server_manager = std::make_unique<ServerManager>(system);
+
+ server_manager->RegisterNamedService("eupld:c", std::make_shared<ErrorUploadContext>(system));
+ server_manager->RegisterNamedService("eupld:r", std::make_shared<ErrorUploadRequest>(system));
+ ServerManager::RunServer(std::move(server_manager));
}
} // namespace Service::EUPLD
diff --git a/src/core/hle/service/eupld/eupld.h b/src/core/hle/service/eupld/eupld.h
index 5de8219be..8eb0a5b4f 100644
--- a/src/core/hle/service/eupld/eupld.h
+++ b/src/core/hle/service/eupld/eupld.h
@@ -7,13 +7,8 @@ namespace Core {
class System;
}
-namespace Service::SM {
-class ServiceManager;
-}
-
namespace Service::EUPLD {
-/// Registers all EUPLD services with the specified service manager.
-void InstallInterfaces(SM::ServiceManager& sm, Core::System& system);
+void LoopProcess(Core::System& system);
} // namespace Service::EUPLD
diff --git a/src/core/hle/service/fatal/fatal.cpp b/src/core/hle/service/fatal/fatal.cpp
index 27675615b..fe2ed8df8 100644
--- a/src/core/hle/service/fatal/fatal.cpp
+++ b/src/core/hle/service/fatal/fatal.cpp
@@ -9,10 +9,11 @@
#include "common/scm_rev.h"
#include "common/swap.h"
#include "core/core.h"
-#include "core/hle/ipc_helpers.h"
#include "core/hle/service/fatal/fatal.h"
#include "core/hle/service/fatal/fatal_p.h"
#include "core/hle/service/fatal/fatal_u.h"
+#include "core/hle/service/ipc_helpers.h"
+#include "core/hle/service/server_manager.h"
#include "core/reporter.h"
namespace Service::Fatal {
@@ -63,7 +64,7 @@ enum class FatalType : u32 {
};
static void GenerateErrorReport(Core::System& system, Result error_code, const FatalInfo& info) {
- const auto title_id = system.GetCurrentProcessProgramID();
+ const auto title_id = system.GetApplicationProcessProgramID();
std::string crash_report = fmt::format(
"Yuzu {}-{} crash report\n"
"Title ID: {:016x}\n"
@@ -125,7 +126,7 @@ static void ThrowFatalError(Core::System& system, Result error_code, FatalType f
}
}
-void Module::Interface::ThrowFatal(Kernel::HLERequestContext& ctx) {
+void Module::Interface::ThrowFatal(HLERequestContext& ctx) {
LOG_ERROR(Service_Fatal, "called");
IPC::RequestParser rp{ctx};
const auto error_code = rp.Pop<Result>();
@@ -135,7 +136,7 @@ void Module::Interface::ThrowFatal(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void Module::Interface::ThrowFatalWithPolicy(Kernel::HLERequestContext& ctx) {
+void Module::Interface::ThrowFatalWithPolicy(HLERequestContext& ctx) {
LOG_ERROR(Service_Fatal, "called");
IPC::RequestParser rp(ctx);
const auto error_code = rp.Pop<Result>();
@@ -147,7 +148,7 @@ void Module::Interface::ThrowFatalWithPolicy(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void Module::Interface::ThrowFatalWithCpuContext(Kernel::HLERequestContext& ctx) {
+void Module::Interface::ThrowFatalWithCpuContext(HLERequestContext& ctx) {
LOG_ERROR(Service_Fatal, "called");
IPC::RequestParser rp(ctx);
const auto error_code = rp.Pop<Result>();
@@ -163,10 +164,13 @@ void Module::Interface::ThrowFatalWithCpuContext(Kernel::HLERequestContext& ctx)
rb.Push(ResultSuccess);
}
-void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
+void LoopProcess(Core::System& system) {
+ auto server_manager = std::make_unique<ServerManager>(system);
auto module = std::make_shared<Module>();
- std::make_shared<Fatal_P>(module, system)->InstallAsService(service_manager);
- std::make_shared<Fatal_U>(module, system)->InstallAsService(service_manager);
+
+ server_manager->RegisterNamedService("fatal:p", std::make_shared<Fatal_P>(module, system));
+ server_manager->RegisterNamedService("fatal:u", std::make_shared<Fatal_U>(module, system));
+ ServerManager::RunServer(std::move(server_manager));
}
} // namespace Service::Fatal
diff --git a/src/core/hle/service/fatal/fatal.h b/src/core/hle/service/fatal/fatal.h
index a7a310f7b..f1c110406 100644
--- a/src/core/hle/service/fatal/fatal.h
+++ b/src/core/hle/service/fatal/fatal.h
@@ -19,15 +19,15 @@ public:
const char* name);
~Interface() override;
- void ThrowFatal(Kernel::HLERequestContext& ctx);
- void ThrowFatalWithPolicy(Kernel::HLERequestContext& ctx);
- void ThrowFatalWithCpuContext(Kernel::HLERequestContext& ctx);
+ void ThrowFatal(HLERequestContext& ctx);
+ void ThrowFatalWithPolicy(HLERequestContext& ctx);
+ void ThrowFatalWithCpuContext(HLERequestContext& ctx);
protected:
std::shared_ptr<Module> module;
};
};
-void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system);
+void LoopProcess(Core::System& system);
} // namespace Service::Fatal
diff --git a/src/core/hle/service/fgm/fgm.cpp b/src/core/hle/service/fgm/fgm.cpp
index 7e9fb0385..6b3f77be2 100644
--- a/src/core/hle/service/fgm/fgm.cpp
+++ b/src/core/hle/service/fgm/fgm.cpp
@@ -3,8 +3,9 @@
#include <memory>
-#include "core/hle/ipc_helpers.h"
#include "core/hle/service/fgm/fgm.h"
+#include "core/hle/service/ipc_helpers.h"
+#include "core/hle/service/server_manager.h"
#include "core/hle/service/service.h"
#include "core/hle/service/sm/sm.h"
@@ -39,7 +40,7 @@ public:
}
private:
- void Initialize(Kernel::HLERequestContext& ctx) {
+ void Initialize(HLERequestContext& ctx) {
LOG_DEBUG(Service_FGM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -63,11 +64,14 @@ public:
}
};
-void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
- std::make_shared<FGM>(system, "fgm")->InstallAsService(sm);
- std::make_shared<FGM>(system, "fgm:0")->InstallAsService(sm);
- std::make_shared<FGM>(system, "fgm:9")->InstallAsService(sm);
- std::make_shared<FGM_DBG>(system)->InstallAsService(sm);
+void LoopProcess(Core::System& system) {
+ auto server_manager = std::make_unique<ServerManager>(system);
+
+ server_manager->RegisterNamedService("fgm", std::make_shared<FGM>(system, "fgm"));
+ server_manager->RegisterNamedService("fgm:0", std::make_shared<FGM>(system, "fgm:0"));
+ server_manager->RegisterNamedService("fgm:9", std::make_shared<FGM>(system, "fgm:9"));
+ server_manager->RegisterNamedService("fgm:dbg", std::make_shared<FGM_DBG>(system));
+ ServerManager::RunServer(std::move(server_manager));
}
} // namespace Service::FGM
diff --git a/src/core/hle/service/fgm/fgm.h b/src/core/hle/service/fgm/fgm.h
index 077e48812..9d2465c0f 100644
--- a/src/core/hle/service/fgm/fgm.h
+++ b/src/core/hle/service/fgm/fgm.h
@@ -7,12 +7,8 @@ namespace Core {
class System;
}
-namespace Service::SM {
-class ServiceManager;
-}
-
namespace Service::FGM {
-void InstallInterfaces(SM::ServiceManager& sm, Core::System& system);
+void LoopProcess(Core::System& system);
} // namespace Service::FGM
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp
index 11c604a0f..dfcdd3ada 100644
--- a/src/core/hle/service/filesystem/filesystem.cpp
+++ b/src/core/hle/service/filesystem/filesystem.cpp
@@ -23,6 +23,7 @@
#include "core/hle/service/filesystem/fsp_ldr.h"
#include "core/hle/service/filesystem/fsp_pr.h"
#include "core/hle/service/filesystem/fsp_srv.h"
+#include "core/hle/service/server_manager.h"
#include "core/loader/loader.h"
namespace Service::FileSystem {
@@ -317,7 +318,7 @@ ResultVal<FileSys::VirtualFile> FileSystemController::OpenRomFSCurrentProcess()
return ResultUnknown;
}
- return romfs_factory->OpenCurrentProcess(system.GetCurrentProcessProgramID());
+ return romfs_factory->OpenCurrentProcess(system.GetApplicationProcessProgramID());
}
ResultVal<FileSys::VirtualFile> FileSystemController::OpenPatchedRomFS(
@@ -502,7 +503,7 @@ FileSys::SaveDataSize FileSystemController::ReadSaveDataSize(FileSys::SaveDataTy
const auto res = system.GetAppLoader().ReadControlData(nacp);
if (res != Loader::ResultStatus::Success) {
- const FileSys::PatchManager pm{system.GetCurrentProcessProgramID(),
+ const FileSys::PatchManager pm{system.GetApplicationProcessProgramID(),
system.GetFileSystemController(),
system.GetContentProvider()};
const auto metadata = pm.GetControlMetadata();
@@ -796,10 +797,13 @@ void FileSystemController::CreateFactories(FileSys::VfsFilesystem& vfs, bool ove
}
}
-void InstallInterfaces(Core::System& system) {
- std::make_shared<FSP_LDR>(system)->InstallAsService(system.ServiceManager());
- std::make_shared<FSP_PR>(system)->InstallAsService(system.ServiceManager());
- std::make_shared<FSP_SRV>(system)->InstallAsService(system.ServiceManager());
+void LoopProcess(Core::System& system) {
+ auto server_manager = std::make_unique<ServerManager>(system);
+
+ server_manager->RegisterNamedService("fsp-ldr", std::make_shared<FSP_LDR>(system));
+ server_manager->RegisterNamedService("fsp:pr", std::make_shared<FSP_PR>(system));
+ server_manager->RegisterNamedService("fsp-srv", std::make_shared<FSP_SRV>(system));
+ ServerManager::RunServer(std::move(server_manager));
}
} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h
index 5b27de9fa..a5c1c9d3e 100644
--- a/src/core/hle/service/filesystem/filesystem.h
+++ b/src/core/hle/service/filesystem/filesystem.h
@@ -139,7 +139,7 @@ private:
Core::System& system;
};
-void InstallInterfaces(Core::System& system);
+void LoopProcess(Core::System& system);
// A class that wraps a VfsDirectory with methods that return ResultVal and Result instead of
// pointers and booleans. This makes using a VfsDirectory with switch services much easier and
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp
index fbb16a7da..427dbc8b3 100644
--- a/src/core/hle/service/filesystem/fsp_srv.cpp
+++ b/src/core/hle/service/filesystem/fsp_srv.cpp
@@ -24,9 +24,11 @@
#include "core/file_sys/savedata_factory.h"
#include "core/file_sys/system_archive/system_archive.h"
#include "core/file_sys/vfs.h"
-#include "core/hle/ipc_helpers.h"
+#include "core/hle/result.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/filesystem/fsp_srv.h"
+#include "core/hle/service/hle_ipc.h"
+#include "core/hle/service/ipc_helpers.h"
#include "core/reporter.h"
namespace Service::FileSystem {
@@ -57,8 +59,7 @@ enum class FileSystemType : u8 {
class IStorage final : public ServiceFramework<IStorage> {
public:
explicit IStorage(Core::System& system_, FileSys::VirtualFile backend_)
- : ServiceFramework{system_, "IStorage", ServiceThreadType::CreateNew},
- backend(std::move(backend_)) {
+ : ServiceFramework{system_, "IStorage"}, backend(std::move(backend_)) {
static const FunctionInfo functions[] = {
{0, &IStorage::Read, "Read"},
{1, nullptr, "Write"},
@@ -73,7 +74,7 @@ public:
private:
FileSys::VirtualFile backend;
- void Read(Kernel::HLERequestContext& ctx) {
+ void Read(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const s64 offset = rp.Pop<s64>();
const s64 length = rp.Pop<s64>();
@@ -103,7 +104,7 @@ private:
rb.Push(ResultSuccess);
}
- void GetSize(Kernel::HLERequestContext& ctx) {
+ void GetSize(HLERequestContext& ctx) {
const u64 size = backend->GetSize();
LOG_DEBUG(Service_FS, "called, size={}", size);
@@ -116,8 +117,7 @@ private:
class IFile final : public ServiceFramework<IFile> {
public:
explicit IFile(Core::System& system_, FileSys::VirtualFile backend_)
- : ServiceFramework{system_, "IFile", ServiceThreadType::CreateNew},
- backend(std::move(backend_)) {
+ : ServiceFramework{system_, "IFile"}, backend(std::move(backend_)) {
static const FunctionInfo functions[] = {
{0, &IFile::Read, "Read"},
{1, &IFile::Write, "Write"},
@@ -133,7 +133,7 @@ public:
private:
FileSys::VirtualFile backend;
- void Read(Kernel::HLERequestContext& ctx) {
+ void Read(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u64 option = rp.Pop<u64>();
const s64 offset = rp.Pop<s64>();
@@ -167,7 +167,7 @@ private:
rb.Push(static_cast<u64>(output.size()));
}
- void Write(Kernel::HLERequestContext& ctx) {
+ void Write(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u64 option = rp.Pop<u64>();
const s64 offset = rp.Pop<s64>();
@@ -190,7 +190,7 @@ private:
return;
}
- const std::vector<u8> data = ctx.ReadBuffer();
+ const auto data = ctx.ReadBuffer();
ASSERT_MSG(
static_cast<s64>(data.size()) <= length,
@@ -210,7 +210,7 @@ private:
rb.Push(ResultSuccess);
}
- void Flush(Kernel::HLERequestContext& ctx) {
+ void Flush(HLERequestContext& ctx) {
LOG_DEBUG(Service_FS, "called");
// Exists for SDK compatibiltity -- No need to flush file.
@@ -219,7 +219,7 @@ private:
rb.Push(ResultSuccess);
}
- void SetSize(Kernel::HLERequestContext& ctx) {
+ void SetSize(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u64 size = rp.Pop<u64>();
LOG_DEBUG(Service_FS, "called, size={}", size);
@@ -230,7 +230,7 @@ private:
rb.Push(ResultSuccess);
}
- void GetSize(Kernel::HLERequestContext& ctx) {
+ void GetSize(HLERequestContext& ctx) {
const u64 size = backend->GetSize();
LOG_DEBUG(Service_FS, "called, size={}", size);
@@ -254,8 +254,7 @@ static void BuildEntryIndex(std::vector<FileSys::Entry>& entries, const std::vec
class IDirectory final : public ServiceFramework<IDirectory> {
public:
explicit IDirectory(Core::System& system_, FileSys::VirtualDir backend_)
- : ServiceFramework{system_, "IDirectory", ServiceThreadType::CreateNew},
- backend(std::move(backend_)) {
+ : ServiceFramework{system_, "IDirectory"}, backend(std::move(backend_)) {
static const FunctionInfo functions[] = {
{0, &IDirectory::Read, "Read"},
{1, &IDirectory::GetEntryCount, "GetEntryCount"},
@@ -273,7 +272,7 @@ private:
std::vector<FileSys::Entry> entries;
u64 next_entry_index = 0;
- void Read(Kernel::HLERequestContext& ctx) {
+ void Read(HLERequestContext& ctx) {
LOG_DEBUG(Service_FS, "called.");
// Calculate how many entries we can fit in the output buffer
@@ -297,7 +296,7 @@ private:
rb.Push(actual_entries);
}
- void GetEntryCount(Kernel::HLERequestContext& ctx) {
+ void GetEntryCount(HLERequestContext& ctx) {
LOG_DEBUG(Service_FS, "called");
u64 count = entries.size() - next_entry_index;
@@ -311,8 +310,8 @@ private:
class IFileSystem final : public ServiceFramework<IFileSystem> {
public:
explicit IFileSystem(Core::System& system_, FileSys::VirtualDir backend_, SizeGetter size_)
- : ServiceFramework{system_, "IFileSystem", ServiceThreadType::CreateNew},
- backend{std::move(backend_)}, size{std::move(size_)} {
+ : ServiceFramework{system_, "IFileSystem"}, backend{std::move(backend_)}, size{std::move(
+ size_)} {
static const FunctionInfo functions[] = {
{0, &IFileSystem::CreateFile, "CreateFile"},
{1, &IFileSystem::DeleteFile, "DeleteFile"},
@@ -334,7 +333,7 @@ public:
RegisterHandlers(functions);
}
- void CreateFile(Kernel::HLERequestContext& ctx) {
+ void CreateFile(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto file_buffer = ctx.ReadBuffer();
@@ -350,7 +349,7 @@ public:
rb.Push(backend.CreateFile(name, file_size));
}
- void DeleteFile(Kernel::HLERequestContext& ctx) {
+ void DeleteFile(HLERequestContext& ctx) {
const auto file_buffer = ctx.ReadBuffer();
const std::string name = Common::StringFromBuffer(file_buffer);
@@ -360,7 +359,7 @@ public:
rb.Push(backend.DeleteFile(name));
}
- void CreateDirectory(Kernel::HLERequestContext& ctx) {
+ void CreateDirectory(HLERequestContext& ctx) {
const auto file_buffer = ctx.ReadBuffer();
const std::string name = Common::StringFromBuffer(file_buffer);
@@ -370,7 +369,7 @@ public:
rb.Push(backend.CreateDirectory(name));
}
- void DeleteDirectory(Kernel::HLERequestContext& ctx) {
+ void DeleteDirectory(HLERequestContext& ctx) {
const auto file_buffer = ctx.ReadBuffer();
const std::string name = Common::StringFromBuffer(file_buffer);
@@ -380,7 +379,7 @@ public:
rb.Push(backend.DeleteDirectory(name));
}
- void DeleteDirectoryRecursively(Kernel::HLERequestContext& ctx) {
+ void DeleteDirectoryRecursively(HLERequestContext& ctx) {
const auto file_buffer = ctx.ReadBuffer();
const std::string name = Common::StringFromBuffer(file_buffer);
@@ -390,7 +389,7 @@ public:
rb.Push(backend.DeleteDirectoryRecursively(name));
}
- void CleanDirectoryRecursively(Kernel::HLERequestContext& ctx) {
+ void CleanDirectoryRecursively(HLERequestContext& ctx) {
const auto file_buffer = ctx.ReadBuffer();
const std::string name = Common::StringFromBuffer(file_buffer);
@@ -400,12 +399,9 @@ public:
rb.Push(backend.CleanDirectoryRecursively(name));
}
- void RenameFile(Kernel::HLERequestContext& ctx) {
- std::vector<u8> buffer = ctx.ReadBuffer(0);
- const std::string src_name = Common::StringFromBuffer(buffer);
-
- buffer = ctx.ReadBuffer(1);
- const std::string dst_name = Common::StringFromBuffer(buffer);
+ void RenameFile(HLERequestContext& ctx) {
+ const std::string src_name = Common::StringFromBuffer(ctx.ReadBuffer(0));
+ const std::string dst_name = Common::StringFromBuffer(ctx.ReadBuffer(1));
LOG_DEBUG(Service_FS, "called. file '{}' to file '{}'", src_name, dst_name);
@@ -413,7 +409,7 @@ public:
rb.Push(backend.RenameFile(src_name, dst_name));
}
- void OpenFile(Kernel::HLERequestContext& ctx) {
+ void OpenFile(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto file_buffer = ctx.ReadBuffer();
@@ -437,7 +433,7 @@ public:
rb.PushIpcInterface<IFile>(std::move(file));
}
- void OpenDirectory(Kernel::HLERequestContext& ctx) {
+ void OpenDirectory(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto file_buffer = ctx.ReadBuffer();
@@ -462,7 +458,7 @@ public:
rb.PushIpcInterface<IDirectory>(std::move(directory));
}
- void GetEntryType(Kernel::HLERequestContext& ctx) {
+ void GetEntryType(HLERequestContext& ctx) {
const auto file_buffer = ctx.ReadBuffer();
const std::string name = Common::StringFromBuffer(file_buffer);
@@ -480,14 +476,14 @@ public:
rb.Push<u32>(static_cast<u32>(*result));
}
- void Commit(Kernel::HLERequestContext& ctx) {
+ void Commit(HLERequestContext& ctx) {
LOG_WARNING(Service_FS, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
- void GetFreeSpaceSize(Kernel::HLERequestContext& ctx) {
+ void GetFreeSpaceSize(HLERequestContext& ctx) {
LOG_DEBUG(Service_FS, "called");
IPC::ResponseBuilder rb{ctx, 4};
@@ -495,7 +491,7 @@ public:
rb.Push(size.get_free_size());
}
- void GetTotalSpaceSize(Kernel::HLERequestContext& ctx) {
+ void GetTotalSpaceSize(HLERequestContext& ctx) {
LOG_DEBUG(Service_FS, "called");
IPC::ResponseBuilder rb{ctx, 4};
@@ -503,7 +499,7 @@ public:
rb.Push(size.get_total_size());
}
- void GetFileTimeStampRaw(Kernel::HLERequestContext& ctx) {
+ void GetFileTimeStampRaw(HLERequestContext& ctx) {
const auto file_buffer = ctx.ReadBuffer();
const std::string name = Common::StringFromBuffer(file_buffer);
@@ -539,7 +535,7 @@ public:
FindAllSaves(space);
}
- void ReadSaveDataInfo(Kernel::HLERequestContext& ctx) {
+ void ReadSaveDataInfo(HLERequestContext& ctx) {
LOG_DEBUG(Service_FS, "called");
// Calculate how many entries we can fit in the output buffer
@@ -558,9 +554,9 @@ public:
// Write the data to memory
ctx.WriteBuffer(begin, range_size);
- IPC::ResponseBuilder rb{ctx, 3};
+ IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
- rb.Push<u32>(static_cast<u32>(actual_entries));
+ rb.Push<u64>(actual_entries);
}
private:
@@ -718,7 +714,7 @@ FSP_SRV::FSP_SRV(Core::System& system_)
{59, nullptr, "WriteSaveDataFileSystemExtraData"},
{60, nullptr, "OpenSaveDataInfoReader"},
{61, &FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId, "OpenSaveDataInfoReaderBySaveDataSpaceId"},
- {62, nullptr, "OpenCacheStorageList"},
+ {62, &FSP_SRV::OpenSaveDataInfoReaderOnlyCacheStorage, "OpenSaveDataInfoReaderOnlyCacheStorage"},
{64, nullptr, "OpenSaveDataInternalStorageFileSystem"},
{65, nullptr, "UpdateSaveDataMacForDebug"},
{66, nullptr, "WriteSaveDataFileSystemExtraData2"},
@@ -817,7 +813,7 @@ FSP_SRV::FSP_SRV(Core::System& system_)
FSP_SRV::~FSP_SRV() = default;
-void FSP_SRV::SetCurrentProcess(Kernel::HLERequestContext& ctx) {
+void FSP_SRV::SetCurrentProcess(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
current_process_id = rp.Pop<u64>();
@@ -827,7 +823,7 @@ void FSP_SRV::SetCurrentProcess(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void FSP_SRV::OpenFileSystemWithPatch(Kernel::HLERequestContext& ctx) {
+void FSP_SRV::OpenFileSystemWithPatch(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto type = rp.PopRaw<FileSystemType>();
@@ -838,7 +834,7 @@ void FSP_SRV::OpenFileSystemWithPatch(Kernel::HLERequestContext& ctx) {
rb.Push(ResultUnknown);
}
-void FSP_SRV::OpenSdCardFileSystem(Kernel::HLERequestContext& ctx) {
+void FSP_SRV::OpenSdCardFileSystem(HLERequestContext& ctx) {
LOG_DEBUG(Service_FS, "called");
auto filesystem =
@@ -850,7 +846,7 @@ void FSP_SRV::OpenSdCardFileSystem(Kernel::HLERequestContext& ctx) {
rb.PushIpcInterface<IFileSystem>(std::move(filesystem));
}
-void FSP_SRV::CreateSaveDataFileSystem(Kernel::HLERequestContext& ctx) {
+void FSP_SRV::CreateSaveDataFileSystem(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
auto save_struct = rp.PopRaw<FileSys::SaveDataAttribute>();
@@ -866,7 +862,7 @@ void FSP_SRV::CreateSaveDataFileSystem(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void FSP_SRV::OpenSaveDataFileSystem(Kernel::HLERequestContext& ctx) {
+void FSP_SRV::OpenSaveDataFileSystem(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
@@ -911,12 +907,12 @@ void FSP_SRV::OpenSaveDataFileSystem(Kernel::HLERequestContext& ctx) {
rb.PushIpcInterface<IFileSystem>(std::move(filesystem));
}
-void FSP_SRV::OpenReadOnlySaveDataFileSystem(Kernel::HLERequestContext& ctx) {
+void FSP_SRV::OpenReadOnlySaveDataFileSystem(HLERequestContext& ctx) {
LOG_WARNING(Service_FS, "(STUBBED) called, delegating to 51 OpenSaveDataFilesystem");
OpenSaveDataFileSystem(ctx);
}
-void FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId(Kernel::HLERequestContext& ctx) {
+void FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto space = rp.PopRaw<FileSys::SaveDataSpaceId>();
LOG_INFO(Service_FS, "called, space={}", space);
@@ -927,15 +923,23 @@ void FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId(Kernel::HLERequestContext&
std::make_shared<ISaveDataInfoReader>(system, space, fsc));
}
-void FSP_SRV::WriteSaveDataFileSystemExtraDataBySaveDataAttribute(Kernel::HLERequestContext& ctx) {
+void FSP_SRV::OpenSaveDataInfoReaderOnlyCacheStorage(HLERequestContext& ctx) {
+ LOG_WARNING(Service_FS, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ rb.Push(ResultSuccess);
+ rb.PushIpcInterface<ISaveDataInfoReader>(system, FileSys::SaveDataSpaceId::TemporaryStorage,
+ fsc);
+}
+
+void FSP_SRV::WriteSaveDataFileSystemExtraDataBySaveDataAttribute(HLERequestContext& ctx) {
LOG_WARNING(Service_FS, "(STUBBED) called.");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
-void FSP_SRV::ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(
- Kernel::HLERequestContext& ctx) {
+void FSP_SRV::ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
@@ -961,26 +965,30 @@ void FSP_SRV::ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(
rb.Push(flags);
}
-void FSP_SRV::OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) {
+void FSP_SRV::OpenDataStorageByCurrentProcess(HLERequestContext& ctx) {
LOG_DEBUG(Service_FS, "called");
- 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};
- rb.Push(ResultUnknown);
- return;
+ if (!romfs) {
+ 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};
+ rb.Push(ResultUnknown);
+ return;
+ }
+
+ romfs = current_romfs.Unwrap();
}
- auto storage = std::make_shared<IStorage>(system, std::move(current_romfs.Unwrap()));
+ auto storage = std::make_shared<IStorage>(system, romfs);
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IStorage>(std::move(storage));
}
-void FSP_SRV::OpenDataStorageByDataId(Kernel::HLERequestContext& ctx) {
+void FSP_SRV::OpenDataStorageByDataId(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto storage_id = rp.PopRaw<FileSys::StorageId>();
const auto unknown = rp.PopRaw<u32>();
@@ -1020,7 +1028,7 @@ void FSP_SRV::OpenDataStorageByDataId(Kernel::HLERequestContext& ctx) {
rb.PushIpcInterface<IStorage>(std::move(storage));
}
-void FSP_SRV::OpenPatchDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) {
+void FSP_SRV::OpenPatchDataStorageByCurrentProcess(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto storage_id = rp.PopRaw<FileSys::StorageId>();
@@ -1032,15 +1040,16 @@ void FSP_SRV::OpenPatchDataStorageByCurrentProcess(Kernel::HLERequestContext& ct
rb.Push(FileSys::ERROR_ENTITY_NOT_FOUND);
}
-void FSP_SRV::OpenDataStorageWithProgramIndex(Kernel::HLERequestContext& ctx) {
+void FSP_SRV::OpenDataStorageWithProgramIndex(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto program_index = rp.PopRaw<u8>();
LOG_DEBUG(Service_FS, "called, program_index={}", program_index);
- auto patched_romfs = fsc.OpenPatchedRomFSWithProgramIndex(
- system.GetCurrentProcessProgramID(), program_index, FileSys::ContentRecordType::Program);
+ auto patched_romfs =
+ fsc.OpenPatchedRomFSWithProgramIndex(system.GetApplicationProcessProgramID(), program_index,
+ FileSys::ContentRecordType::Program);
if (patched_romfs.Failed()) {
// TODO: Find the right error code to use here
@@ -1058,7 +1067,7 @@ void FSP_SRV::OpenDataStorageWithProgramIndex(Kernel::HLERequestContext& ctx) {
rb.PushIpcInterface<IStorage>(std::move(storage));
}
-void FSP_SRV::DisableAutoSaveDataCreation(Kernel::HLERequestContext& ctx) {
+void FSP_SRV::DisableAutoSaveDataCreation(HLERequestContext& ctx) {
LOG_DEBUG(Service_FS, "called");
fsc.SetAutoSaveDataCreation(false);
@@ -1067,7 +1076,7 @@ void FSP_SRV::DisableAutoSaveDataCreation(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void FSP_SRV::SetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) {
+void FSP_SRV::SetGlobalAccessLogMode(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
access_log_mode = rp.PopEnum<AccessLogMode>();
@@ -1077,7 +1086,7 @@ void FSP_SRV::SetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void FSP_SRV::GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) {
+void FSP_SRV::GetGlobalAccessLogMode(HLERequestContext& ctx) {
LOG_DEBUG(Service_FS, "called");
IPC::ResponseBuilder rb{ctx, 3};
@@ -1085,8 +1094,8 @@ void FSP_SRV::GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) {
rb.PushEnum(access_log_mode);
}
-void FSP_SRV::OutputAccessLogToSdCard(Kernel::HLERequestContext& ctx) {
- const auto raw = ctx.ReadBuffer();
+void FSP_SRV::OutputAccessLogToSdCard(HLERequestContext& ctx) {
+ const auto raw = ctx.ReadBufferCopy();
auto log = Common::StringFromFixedZeroTerminatedBuffer(
reinterpret_cast<const char*>(raw.data()), raw.size());
@@ -1098,7 +1107,7 @@ void FSP_SRV::OutputAccessLogToSdCard(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void FSP_SRV::GetProgramIndexForAccessLog(Kernel::HLERequestContext& ctx) {
+void FSP_SRV::GetProgramIndexForAccessLog(HLERequestContext& ctx) {
LOG_DEBUG(Service_FS, "called");
IPC::ResponseBuilder rb{ctx, 4};
@@ -1107,7 +1116,7 @@ void FSP_SRV::GetProgramIndexForAccessLog(Kernel::HLERequestContext& ctx) {
rb.Push(access_log_program_index);
}
-void FSP_SRV::GetCacheStorageSize(Kernel::HLERequestContext& ctx) {
+void FSP_SRV::GetCacheStorageSize(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto index{rp.Pop<s32>()};
@@ -1133,14 +1142,14 @@ public:
private:
FileSys::VirtualFile backend;
- void Add(Kernel::HLERequestContext& ctx) {
+ void Add(HLERequestContext& ctx) {
LOG_WARNING(Service_FS, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
- void Commit(Kernel::HLERequestContext& ctx) {
+ void Commit(HLERequestContext& ctx) {
LOG_WARNING(Service_FS, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
@@ -1148,7 +1157,7 @@ private:
}
};
-void FSP_SRV::OpenMultiCommitManager(Kernel::HLERequestContext& ctx) {
+void FSP_SRV::OpenMultiCommitManager(HLERequestContext& ctx) {
LOG_DEBUG(Service_FS, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
diff --git a/src/core/hle/service/filesystem/fsp_srv.h b/src/core/hle/service/filesystem/fsp_srv.h
index 3d88b97f9..4f3c2f6de 100644
--- a/src/core/hle/service/filesystem/fsp_srv.h
+++ b/src/core/hle/service/filesystem/fsp_srv.h
@@ -35,26 +35,27 @@ public:
~FSP_SRV() override;
private:
- void SetCurrentProcess(Kernel::HLERequestContext& ctx);
- void OpenFileSystemWithPatch(Kernel::HLERequestContext& ctx);
- void OpenSdCardFileSystem(Kernel::HLERequestContext& ctx);
- void CreateSaveDataFileSystem(Kernel::HLERequestContext& ctx);
- void OpenSaveDataFileSystem(Kernel::HLERequestContext& ctx);
- void OpenReadOnlySaveDataFileSystem(Kernel::HLERequestContext& ctx);
- void OpenSaveDataInfoReaderBySaveDataSpaceId(Kernel::HLERequestContext& ctx);
- void WriteSaveDataFileSystemExtraDataBySaveDataAttribute(Kernel::HLERequestContext& ctx);
- void ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(Kernel::HLERequestContext& ctx);
- void OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx);
- void OpenDataStorageByDataId(Kernel::HLERequestContext& ctx);
- void OpenPatchDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx);
- void OpenDataStorageWithProgramIndex(Kernel::HLERequestContext& ctx);
- void DisableAutoSaveDataCreation(Kernel::HLERequestContext& ctx);
- void SetGlobalAccessLogMode(Kernel::HLERequestContext& ctx);
- void GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx);
- void OutputAccessLogToSdCard(Kernel::HLERequestContext& ctx);
- void GetProgramIndexForAccessLog(Kernel::HLERequestContext& ctx);
- void OpenMultiCommitManager(Kernel::HLERequestContext& ctx);
- void GetCacheStorageSize(Kernel::HLERequestContext& ctx);
+ void SetCurrentProcess(HLERequestContext& ctx);
+ void OpenFileSystemWithPatch(HLERequestContext& ctx);
+ void OpenSdCardFileSystem(HLERequestContext& ctx);
+ void CreateSaveDataFileSystem(HLERequestContext& ctx);
+ void OpenSaveDataFileSystem(HLERequestContext& ctx);
+ void OpenReadOnlySaveDataFileSystem(HLERequestContext& ctx);
+ void OpenSaveDataInfoReaderBySaveDataSpaceId(HLERequestContext& ctx);
+ void OpenSaveDataInfoReaderOnlyCacheStorage(HLERequestContext& ctx);
+ void WriteSaveDataFileSystemExtraDataBySaveDataAttribute(HLERequestContext& ctx);
+ void ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(HLERequestContext& ctx);
+ void OpenDataStorageByCurrentProcess(HLERequestContext& ctx);
+ void OpenDataStorageByDataId(HLERequestContext& ctx);
+ void OpenPatchDataStorageByCurrentProcess(HLERequestContext& ctx);
+ void OpenDataStorageWithProgramIndex(HLERequestContext& ctx);
+ void DisableAutoSaveDataCreation(HLERequestContext& ctx);
+ void SetGlobalAccessLogMode(HLERequestContext& ctx);
+ void GetGlobalAccessLogMode(HLERequestContext& ctx);
+ void OutputAccessLogToSdCard(HLERequestContext& ctx);
+ void GetProgramIndexForAccessLog(HLERequestContext& ctx);
+ void OpenMultiCommitManager(HLERequestContext& ctx);
+ void GetCacheStorageSize(HLERequestContext& ctx);
FileSystemController& fsc;
const FileSys::ContentProvider& content_provider;
diff --git a/src/core/hle/service/friend/errors.h b/src/core/hle/service/friend/errors.h
deleted file mode 100644
index ff525d865..000000000
--- a/src/core/hle/service/friend/errors.h
+++ /dev/null
@@ -1,11 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#pragma once
-
-#include "core/hle/result.h"
-
-namespace Service::Friend {
-
-constexpr Result ERR_NO_NOTIFICATIONS{ErrorModule::Account, 15};
-}
diff --git a/src/core/hle/service/friend/friend.cpp b/src/core/hle/service/friend/friend.cpp
index fad532115..9d05f9801 100644
--- a/src/core/hle/service/friend/friend.cpp
+++ b/src/core/hle/service/friend/friend.cpp
@@ -5,12 +5,13 @@
#include "common/logging/log.h"
#include "common/uuid.h"
#include "core/core.h"
-#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/k_event.h"
-#include "core/hle/service/friend/errors.h"
+#include "core/hle/service/acc/errors.h"
#include "core/hle/service/friend/friend.h"
#include "core/hle/service/friend/friend_interface.h"
+#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/kernel_helpers.h"
+#include "core/hle/service/server_manager.h"
namespace Service::Friend {
@@ -135,7 +136,7 @@ private:
};
static_assert(sizeof(SizedFriendFilter) == 0x10, "SizedFriendFilter is an invalid size");
- void GetCompletionEvent(Kernel::HLERequestContext& ctx) {
+ void GetCompletionEvent(HLERequestContext& ctx) {
LOG_DEBUG(Service_Friend, "called");
IPC::ResponseBuilder rb{ctx, 2, 1};
@@ -143,7 +144,7 @@ private:
rb.PushCopyObjects(completion_event->GetReadableEvent());
}
- void GetBlockedUserListIds(Kernel::HLERequestContext& ctx) {
+ void GetBlockedUserListIds(HLERequestContext& ctx) {
// This is safe to stub, as there should be no adverse consequences from reporting no
// blocked users.
LOG_WARNING(Service_Friend, "(STUBBED) called");
@@ -152,21 +153,21 @@ private:
rb.Push<u32>(0); // Indicates there are no blocked users
}
- void DeclareCloseOnlinePlaySession(Kernel::HLERequestContext& ctx) {
+ void DeclareCloseOnlinePlaySession(HLERequestContext& ctx) {
// Stub used by Splatoon 2
LOG_WARNING(Service_Friend, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
- void UpdateUserPresence(Kernel::HLERequestContext& ctx) {
+ void UpdateUserPresence(HLERequestContext& ctx) {
// Stub used by Retro City Rampage
LOG_WARNING(Service_Friend, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
- void GetPlayHistoryRegistrationKey(Kernel::HLERequestContext& ctx) {
+ void GetPlayHistoryRegistrationKey(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto local_play = rp.Pop<bool>();
const auto uuid = rp.PopRaw<Common::UUID>();
@@ -178,7 +179,7 @@ private:
rb.Push(ResultSuccess);
}
- void GetFriendList(Kernel::HLERequestContext& ctx) {
+ void GetFriendList(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto friend_offset = rp.Pop<u32>();
const auto uuid = rp.PopRaw<Common::UUID>();
@@ -194,7 +195,7 @@ private:
// TODO(ogniK): Return a buffer of u64s which are the "NetworkServiceAccountId"
}
- void CheckFriendListAvailability(Kernel::HLERequestContext& ctx) {
+ void CheckFriendListAvailability(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto uuid{rp.PopRaw<Common::UUID>()};
@@ -233,7 +234,7 @@ public:
}
private:
- void GetEvent(Kernel::HLERequestContext& ctx) {
+ void GetEvent(HLERequestContext& ctx) {
LOG_DEBUG(Service_Friend, "called");
IPC::ResponseBuilder rb{ctx, 2, 1};
@@ -241,7 +242,7 @@ private:
rb.PushCopyObjects(notification_event->GetReadableEvent());
}
- void Clear(Kernel::HLERequestContext& ctx) {
+ void Clear(HLERequestContext& ctx) {
LOG_DEBUG(Service_Friend, "called");
while (!notifications.empty()) {
notifications.pop();
@@ -252,13 +253,13 @@ private:
rb.Push(ResultSuccess);
}
- void Pop(Kernel::HLERequestContext& ctx) {
+ void Pop(HLERequestContext& ctx) {
LOG_DEBUG(Service_Friend, "called");
if (notifications.empty()) {
LOG_ERROR(Service_Friend, "No notifications in queue!");
IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ERR_NO_NOTIFICATIONS);
+ rb.Push(Account::ResultNoNotifications);
return;
}
@@ -311,14 +312,14 @@ private:
States states{};
};
-void Module::Interface::CreateFriendService(Kernel::HLERequestContext& ctx) {
+void Module::Interface::CreateFriendService(HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IFriendService>(system);
LOG_DEBUG(Service_Friend, "called");
}
-void Module::Interface::CreateNotificationService(Kernel::HLERequestContext& ctx) {
+void Module::Interface::CreateNotificationService(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
auto uuid = rp.PopRaw<Common::UUID>();
@@ -335,13 +336,22 @@ Module::Interface::Interface(std::shared_ptr<Module> module_, Core::System& syst
Module::Interface::~Interface() = default;
-void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
+void LoopProcess(Core::System& system) {
+ auto server_manager = std::make_unique<ServerManager>(system);
auto module = std::make_shared<Module>();
- std::make_shared<Friend>(module, system, "friend:a")->InstallAsService(service_manager);
- std::make_shared<Friend>(module, system, "friend:m")->InstallAsService(service_manager);
- std::make_shared<Friend>(module, system, "friend:s")->InstallAsService(service_manager);
- std::make_shared<Friend>(module, system, "friend:u")->InstallAsService(service_manager);
- std::make_shared<Friend>(module, system, "friend:v")->InstallAsService(service_manager);
+
+ server_manager->RegisterNamedService("friend:a",
+ std::make_shared<Friend>(module, system, "friend:a"));
+ server_manager->RegisterNamedService("friend:m",
+ std::make_shared<Friend>(module, system, "friend:m"));
+ server_manager->RegisterNamedService("friend:s",
+ std::make_shared<Friend>(module, system, "friend:s"));
+ server_manager->RegisterNamedService("friend:u",
+ std::make_shared<Friend>(module, system, "friend:u"));
+ server_manager->RegisterNamedService("friend:v",
+ std::make_shared<Friend>(module, system, "friend:v"));
+
+ ServerManager::RunServer(std::move(server_manager));
}
} // namespace Service::Friend
diff --git a/src/core/hle/service/friend/friend.h b/src/core/hle/service/friend/friend.h
index 444da8b35..2824dc786 100644
--- a/src/core/hle/service/friend/friend.h
+++ b/src/core/hle/service/friend/friend.h
@@ -19,15 +19,14 @@ public:
const char* name);
~Interface() override;
- void CreateFriendService(Kernel::HLERequestContext& ctx);
- void CreateNotificationService(Kernel::HLERequestContext& ctx);
+ void CreateFriendService(HLERequestContext& ctx);
+ void CreateNotificationService(HLERequestContext& ctx);
protected:
std::shared_ptr<Module> module;
};
};
-/// Registers all Friend services with the specified service manager.
-void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system);
+void LoopProcess(Core::System& system);
} // namespace Service::Friend
diff --git a/src/core/hle/service/glue/arp.cpp b/src/core/hle/service/glue/arp.cpp
index 49b6d45fe..ed6fcb5f6 100644
--- a/src/core/hle/service/glue/arp.cpp
+++ b/src/core/hle/service/glue/arp.cpp
@@ -5,12 +5,12 @@
#include "common/logging/log.h"
#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/service/glue/arp.h"
#include "core/hle/service/glue/errors.h"
#include "core/hle/service/glue/glue_manager.h"
+#include "core/hle/service/ipc_helpers.h"
namespace Service::Glue {
@@ -18,14 +18,14 @@ namespace {
std::optional<u64> GetTitleIDForProcessID(const Core::System& system, u64 process_id) {
const auto& list = system.Kernel().GetProcessList();
const auto iter = std::find_if(list.begin(), list.end(), [&process_id](const auto& process) {
- return process->GetProcessID() == process_id;
+ return process->GetProcessId() == process_id;
});
if (iter == list.end()) {
return std::nullopt;
}
- return (*iter)->GetProgramID();
+ return (*iter)->GetProgramId();
}
} // Anonymous namespace
@@ -51,7 +51,7 @@ ARP_R::ARP_R(Core::System& system_, const ARPManager& manager_)
ARP_R::~ARP_R() = default;
-void ARP_R::GetApplicationLaunchProperty(Kernel::HLERequestContext& ctx) {
+void ARP_R::GetApplicationLaunchProperty(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto process_id = rp.PopRaw<u64>();
@@ -61,7 +61,7 @@ void ARP_R::GetApplicationLaunchProperty(Kernel::HLERequestContext& ctx) {
if (!title_id.has_value()) {
LOG_ERROR(Service_ARP, "Failed to get title ID for process ID!");
IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ERR_NOT_REGISTERED);
+ rb.Push(Glue::ResultProcessIdNotRegistered);
return;
}
@@ -79,7 +79,7 @@ void ARP_R::GetApplicationLaunchProperty(Kernel::HLERequestContext& ctx) {
rb.PushRaw(*res);
}
-void ARP_R::GetApplicationLaunchPropertyWithApplicationId(Kernel::HLERequestContext& ctx) {
+void ARP_R::GetApplicationLaunchPropertyWithApplicationId(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto title_id = rp.PopRaw<u64>();
@@ -99,7 +99,7 @@ void ARP_R::GetApplicationLaunchPropertyWithApplicationId(Kernel::HLERequestCont
rb.PushRaw(*res);
}
-void ARP_R::GetApplicationControlProperty(Kernel::HLERequestContext& ctx) {
+void ARP_R::GetApplicationControlProperty(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto process_id = rp.PopRaw<u64>();
@@ -109,7 +109,7 @@ void ARP_R::GetApplicationControlProperty(Kernel::HLERequestContext& ctx) {
if (!title_id.has_value()) {
LOG_ERROR(Service_ARP, "Failed to get title ID for process ID!");
IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ERR_NOT_REGISTERED);
+ rb.Push(Glue::ResultProcessIdNotRegistered);
return;
}
@@ -128,7 +128,7 @@ void ARP_R::GetApplicationControlProperty(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void ARP_R::GetApplicationControlPropertyWithApplicationId(Kernel::HLERequestContext& ctx) {
+void ARP_R::GetApplicationControlPropertyWithApplicationId(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto title_id = rp.PopRaw<u64>();
@@ -169,7 +169,7 @@ public:
}
private:
- void Issue(Kernel::HLERequestContext& ctx) {
+ void Issue(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto process_id = rp.PopRaw<u64>();
@@ -178,7 +178,7 @@ private:
if (process_id == 0) {
LOG_ERROR(Service_ARP, "Must have non-zero process ID!");
IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ERR_INVALID_PROCESS_ID);
+ rb.Push(Glue::ResultInvalidProcessId);
return;
}
@@ -186,7 +186,7 @@ private:
LOG_ERROR(Service_ARP,
"Attempted to issue registrar, but registrar is already issued!");
IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ERR_INVALID_ACCESS);
+ rb.Push(Glue::ResultAlreadyBound);
return;
}
@@ -197,7 +197,7 @@ private:
rb.Push(ResultSuccess);
}
- void SetApplicationLaunchProperty(Kernel::HLERequestContext& ctx) {
+ void SetApplicationLaunchProperty(HLERequestContext& ctx) {
LOG_DEBUG(Service_ARP, "called");
if (issued) {
@@ -205,7 +205,7 @@ private:
Service_ARP,
"Attempted to set application launch property, but registrar is already issued!");
IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ERR_INVALID_ACCESS);
+ rb.Push(Glue::ResultAlreadyBound);
return;
}
@@ -216,7 +216,7 @@ private:
rb.Push(ResultSuccess);
}
- void SetApplicationControlProperty(Kernel::HLERequestContext& ctx) {
+ void SetApplicationControlProperty(HLERequestContext& ctx) {
LOG_DEBUG(Service_ARP, "called");
if (issued) {
@@ -224,11 +224,12 @@ private:
Service_ARP,
"Attempted to set application control property, but registrar is already issued!");
IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ERR_INVALID_ACCESS);
+ rb.Push(Glue::ResultAlreadyBound);
return;
}
- control = ctx.ReadBuffer();
+ // TODO: Can this be a span?
+ control = ctx.ReadBufferCopy();
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
@@ -255,14 +256,14 @@ ARP_W::ARP_W(Core::System& system_, ARPManager& manager_)
ARP_W::~ARP_W() = default;
-void ARP_W::AcquireRegistrar(Kernel::HLERequestContext& ctx) {
+void ARP_W::AcquireRegistrar(HLERequestContext& ctx) {
LOG_DEBUG(Service_ARP, "called");
registrar = std::make_shared<IRegistrar>(
system, [this](u64 process_id, ApplicationLaunchProperty launch, std::vector<u8> control) {
const auto res = GetTitleIDForProcessID(system, process_id);
if (!res.has_value()) {
- return ERR_NOT_REGISTERED;
+ return Glue::ResultProcessIdNotRegistered;
}
return manager.Register(*res, launch, std::move(control));
@@ -273,7 +274,7 @@ void ARP_W::AcquireRegistrar(Kernel::HLERequestContext& ctx) {
rb.PushIpcInterface(registrar);
}
-void ARP_W::UnregisterApplicationInstance(Kernel::HLERequestContext& ctx) {
+void ARP_W::UnregisterApplicationInstance(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto process_id = rp.PopRaw<u64>();
@@ -282,7 +283,7 @@ void ARP_W::UnregisterApplicationInstance(Kernel::HLERequestContext& ctx) {
if (process_id == 0) {
LOG_ERROR(Service_ARP, "Must have non-zero process ID!");
IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ERR_INVALID_PROCESS_ID);
+ rb.Push(Glue::ResultInvalidProcessId);
return;
}
@@ -291,7 +292,7 @@ void ARP_W::UnregisterApplicationInstance(Kernel::HLERequestContext& ctx) {
if (!title_id.has_value()) {
LOG_ERROR(Service_ARP, "No title ID for process ID!");
IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ERR_NOT_REGISTERED);
+ rb.Push(Glue::ResultProcessIdNotRegistered);
return;
}
diff --git a/src/core/hle/service/glue/arp.h b/src/core/hle/service/glue/arp.h
index 06c992e88..5bce80175 100644
--- a/src/core/hle/service/glue/arp.h
+++ b/src/core/hle/service/glue/arp.h
@@ -16,10 +16,10 @@ public:
~ARP_R() override;
private:
- void GetApplicationLaunchProperty(Kernel::HLERequestContext& ctx);
- void GetApplicationLaunchPropertyWithApplicationId(Kernel::HLERequestContext& ctx);
- void GetApplicationControlProperty(Kernel::HLERequestContext& ctx);
- void GetApplicationControlPropertyWithApplicationId(Kernel::HLERequestContext& ctx);
+ void GetApplicationLaunchProperty(HLERequestContext& ctx);
+ void GetApplicationLaunchPropertyWithApplicationId(HLERequestContext& ctx);
+ void GetApplicationControlProperty(HLERequestContext& ctx);
+ void GetApplicationControlPropertyWithApplicationId(HLERequestContext& ctx);
const ARPManager& manager;
};
@@ -30,8 +30,8 @@ public:
~ARP_W() override;
private:
- void AcquireRegistrar(Kernel::HLERequestContext& ctx);
- void UnregisterApplicationInstance(Kernel::HLERequestContext& ctx);
+ void AcquireRegistrar(HLERequestContext& ctx);
+ void UnregisterApplicationInstance(HLERequestContext& ctx);
ARPManager& manager;
std::shared_ptr<IRegistrar> registrar;
diff --git a/src/core/hle/service/glue/bgtc.cpp b/src/core/hle/service/glue/bgtc.cpp
index 3248091c3..ae22ac4f7 100644
--- a/src/core/hle/service/glue/bgtc.cpp
+++ b/src/core/hle/service/glue/bgtc.cpp
@@ -3,8 +3,8 @@
#include "common/logging/log.h"
#include "core/core.h"
-#include "core/hle/ipc_helpers.h"
#include "core/hle/service/glue/bgtc.h"
+#include "core/hle/service/ipc_helpers.h"
namespace Service::Glue {
@@ -20,7 +20,7 @@ BGTC_T::BGTC_T(Core::System& system_) : ServiceFramework{system_, "bgtc:t"} {
BGTC_T::~BGTC_T() = default;
-void BGTC_T::OpenTaskService(Kernel::HLERequestContext& ctx) {
+void BGTC_T::OpenTaskService(HLERequestContext& ctx) {
LOG_DEBUG(Service_BGTC, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
diff --git a/src/core/hle/service/glue/bgtc.h b/src/core/hle/service/glue/bgtc.h
index d6e2baec1..5a5d9c9a7 100644
--- a/src/core/hle/service/glue/bgtc.h
+++ b/src/core/hle/service/glue/bgtc.h
@@ -16,7 +16,7 @@ public:
explicit BGTC_T(Core::System& system_);
~BGTC_T() override;
- void OpenTaskService(Kernel::HLERequestContext& ctx);
+ void OpenTaskService(HLERequestContext& ctx);
};
class ITaskService final : public ServiceFramework<ITaskService> {
diff --git a/src/core/hle/service/glue/errors.h b/src/core/hle/service/glue/errors.h
index d4ce7f44e..30feaa5c0 100644
--- a/src/core/hle/service/glue/errors.h
+++ b/src/core/hle/service/glue/errors.h
@@ -7,9 +7,8 @@
namespace Service::Glue {
-constexpr Result ERR_INVALID_RESOURCE{ErrorModule::ARP, 30};
-constexpr Result ERR_INVALID_PROCESS_ID{ErrorModule::ARP, 31};
-constexpr Result ERR_INVALID_ACCESS{ErrorModule::ARP, 42};
-constexpr Result ERR_NOT_REGISTERED{ErrorModule::ARP, 102};
+constexpr Result ResultInvalidProcessId{ErrorModule::ARP, 31};
+constexpr Result ResultAlreadyBound{ErrorModule::ARP, 42};
+constexpr Result ResultProcessIdNotRegistered{ErrorModule::ARP, 102};
} // namespace Service::Glue
diff --git a/src/core/hle/service/glue/glue.cpp b/src/core/hle/service/glue/glue.cpp
index 717f2562b..993c3d21d 100644
--- a/src/core/hle/service/glue/glue.cpp
+++ b/src/core/hle/service/glue/glue.cpp
@@ -8,25 +8,30 @@
#include "core/hle/service/glue/ectx.h"
#include "core/hle/service/glue/glue.h"
#include "core/hle/service/glue/notif.h"
+#include "core/hle/service/server_manager.h"
namespace Service::Glue {
-void InstallInterfaces(Core::System& system) {
+void LoopProcess(Core::System& system) {
+ auto server_manager = std::make_unique<ServerManager>(system);
+
// ARP
- std::make_shared<ARP_R>(system, system.GetARPManager())
- ->InstallAsService(system.ServiceManager());
- std::make_shared<ARP_W>(system, system.GetARPManager())
- ->InstallAsService(system.ServiceManager());
+ server_manager->RegisterNamedService("arp:r",
+ std::make_shared<ARP_R>(system, system.GetARPManager()));
+ server_manager->RegisterNamedService("arp:w",
+ std::make_shared<ARP_W>(system, system.GetARPManager()));
// BackGround Task Controller
- std::make_shared<BGTC_T>(system)->InstallAsService(system.ServiceManager());
- std::make_shared<BGTC_SC>(system)->InstallAsService(system.ServiceManager());
+ server_manager->RegisterNamedService("bgtc:t", std::make_shared<BGTC_T>(system));
+ server_manager->RegisterNamedService("bgtc:sc", std::make_shared<BGTC_SC>(system));
// Error Context
- std::make_shared<ECTX_AW>(system)->InstallAsService(system.ServiceManager());
+ server_manager->RegisterNamedService("ectx:aw", std::make_shared<ECTX_AW>(system));
// Notification Services for application
- std::make_shared<NOTIF_A>(system)->InstallAsService(system.ServiceManager());
+ server_manager->RegisterNamedService("notif:a", std::make_shared<NOTIF_A>(system));
+
+ ServerManager::RunServer(std::move(server_manager));
}
} // namespace Service::Glue
diff --git a/src/core/hle/service/glue/glue.h b/src/core/hle/service/glue/glue.h
index ae7c6d235..2a906f5ad 100644
--- a/src/core/hle/service/glue/glue.h
+++ b/src/core/hle/service/glue/glue.h
@@ -9,7 +9,6 @@ class System;
namespace Service::Glue {
-/// Registers all Glue services with the specified service manager.
-void InstallInterfaces(Core::System& system);
+void LoopProcess(Core::System& system);
} // namespace Service::Glue
diff --git a/src/core/hle/service/glue/glue_manager.cpp b/src/core/hle/service/glue/glue_manager.cpp
index 8a654cdca..4bf67921b 100644
--- a/src/core/hle/service/glue/glue_manager.cpp
+++ b/src/core/hle/service/glue/glue_manager.cpp
@@ -17,12 +17,12 @@ ARPManager::~ARPManager() = default;
ResultVal<ApplicationLaunchProperty> ARPManager::GetLaunchProperty(u64 title_id) const {
if (title_id == 0) {
- return ERR_INVALID_PROCESS_ID;
+ return Glue::ResultInvalidProcessId;
}
const auto iter = entries.find(title_id);
if (iter == entries.end()) {
- return ERR_NOT_REGISTERED;
+ return Glue::ResultProcessIdNotRegistered;
}
return iter->second.launch;
@@ -30,12 +30,12 @@ ResultVal<ApplicationLaunchProperty> ARPManager::GetLaunchProperty(u64 title_id)
ResultVal<std::vector<u8>> ARPManager::GetControlProperty(u64 title_id) const {
if (title_id == 0) {
- return ERR_INVALID_PROCESS_ID;
+ return Glue::ResultInvalidProcessId;
}
const auto iter = entries.find(title_id);
if (iter == entries.end()) {
- return ERR_NOT_REGISTERED;
+ return Glue::ResultProcessIdNotRegistered;
}
return iter->second.control;
@@ -44,12 +44,12 @@ ResultVal<std::vector<u8>> ARPManager::GetControlProperty(u64 title_id) const {
Result ARPManager::Register(u64 title_id, ApplicationLaunchProperty launch,
std::vector<u8> control) {
if (title_id == 0) {
- return ERR_INVALID_PROCESS_ID;
+ return Glue::ResultInvalidProcessId;
}
const auto iter = entries.find(title_id);
if (iter != entries.end()) {
- return ERR_INVALID_ACCESS;
+ return Glue::ResultAlreadyBound;
}
entries.insert_or_assign(title_id, MapEntry{launch, std::move(control)});
@@ -58,12 +58,12 @@ Result ARPManager::Register(u64 title_id, ApplicationLaunchProperty launch,
Result ARPManager::Unregister(u64 title_id) {
if (title_id == 0) {
- return ERR_INVALID_PROCESS_ID;
+ return Glue::ResultInvalidProcessId;
}
const auto iter = entries.find(title_id);
if (iter == entries.end()) {
- return ERR_NOT_REGISTERED;
+ return Glue::ResultProcessIdNotRegistered;
}
entries.erase(iter);
diff --git a/src/core/hle/service/glue/glue_manager.h b/src/core/hle/service/glue/glue_manager.h
index cd0b092ac..1cf53d9d9 100644
--- a/src/core/hle/service/glue/glue_manager.h
+++ b/src/core/hle/service/glue/glue_manager.h
@@ -30,23 +30,23 @@ public:
~ARPManager();
// Returns the ApplicationLaunchProperty corresponding to the provided title ID if it was
- // previously registered, otherwise ERR_NOT_REGISTERED if it was never registered or
- // ERR_INVALID_PROCESS_ID if the title ID is 0.
+ // previously registered, otherwise ResultProcessIdNotRegistered if it was never registered or
+ // ResultInvalidProcessId if the title ID is 0.
ResultVal<ApplicationLaunchProperty> GetLaunchProperty(u64 title_id) const;
// Returns a vector of the raw bytes of NACP data (necessarily 0x4000 in size) corresponding to
- // the provided title ID if it was previously registered, otherwise ERR_NOT_REGISTERED if it was
- // never registered or ERR_INVALID_PROCESS_ID if the title ID is 0.
+ // the provided title ID if it was previously registered, otherwise ResultProcessIdNotRegistered
+ // if it was never registered or ResultInvalidProcessId if the title ID is 0.
ResultVal<std::vector<u8>> GetControlProperty(u64 title_id) const;
// Adds a new entry to the internal database with the provided parameters, returning
- // ERR_INVALID_ACCESS if attempting to re-register a title ID without an intermediate Unregister
- // step, and ERR_INVALID_PROCESS_ID if the title ID is 0.
+ // ResultProcessIdNotRegistered if attempting to re-register a title ID without an intermediate
+ // Unregister step, and ResultInvalidProcessId if the title ID is 0.
Result Register(u64 title_id, ApplicationLaunchProperty launch, std::vector<u8> control);
// Removes the registration for the provided title ID from the database, returning
- // ERR_NOT_REGISTERED if it doesn't exist in the database and ERR_INVALID_PROCESS_ID if the
- // title ID is 0.
+ // ResultProcessIdNotRegistered if it doesn't exist in the database and ResultInvalidProcessId
+ // if the title ID is 0.
Result Unregister(u64 title_id);
// Removes all entries from the database, always succeeds. Should only be used when resetting
diff --git a/src/core/hle/service/glue/notif.cpp b/src/core/hle/service/glue/notif.cpp
index 3ace2dabd..fec4ad86c 100644
--- a/src/core/hle/service/glue/notif.cpp
+++ b/src/core/hle/service/glue/notif.cpp
@@ -6,8 +6,8 @@
#include "common/assert.h"
#include "common/logging/log.h"
-#include "core/hle/ipc_helpers.h"
#include "core/hle/service/glue/notif.h"
+#include "core/hle/service/ipc_helpers.h"
namespace Service::Glue {
@@ -28,7 +28,7 @@ NOTIF_A::NOTIF_A(Core::System& system_) : ServiceFramework{system_, "notif:a"} {
NOTIF_A::~NOTIF_A() = default;
-void NOTIF_A::RegisterAlarmSetting(Kernel::HLERequestContext& ctx) {
+void NOTIF_A::RegisterAlarmSetting(HLERequestContext& ctx) {
const auto alarm_setting_buffer_size = ctx.GetReadBufferSize(0);
const auto application_parameter_size = ctx.GetReadBufferSize(1);
@@ -63,7 +63,7 @@ void NOTIF_A::RegisterAlarmSetting(Kernel::HLERequestContext& ctx) {
rb.Push(new_alarm.alarm_setting_id);
}
-void NOTIF_A::UpdateAlarmSetting(Kernel::HLERequestContext& ctx) {
+void NOTIF_A::UpdateAlarmSetting(HLERequestContext& ctx) {
const auto alarm_setting_buffer_size = ctx.GetReadBufferSize(0);
const auto application_parameter_size = ctx.GetReadBufferSize(1);
@@ -91,7 +91,7 @@ void NOTIF_A::UpdateAlarmSetting(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void NOTIF_A::ListAlarmSettings(Kernel::HLERequestContext& ctx) {
+void NOTIF_A::ListAlarmSettings(HLERequestContext& ctx) {
LOG_INFO(Service_NOTIF, "called, alarm_count={}", alarms.size());
// TODO: Only return alarms of this game id
@@ -102,7 +102,7 @@ void NOTIF_A::ListAlarmSettings(Kernel::HLERequestContext& ctx) {
rb.Push(static_cast<u32>(alarms.size()));
}
-void NOTIF_A::LoadApplicationParameter(Kernel::HLERequestContext& ctx) {
+void NOTIF_A::LoadApplicationParameter(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto alarm_setting_id{rp.Pop<AlarmSettingId>()};
@@ -126,7 +126,7 @@ void NOTIF_A::LoadApplicationParameter(Kernel::HLERequestContext& ctx) {
rb.Push(static_cast<u32>(application_parameter.size()));
}
-void NOTIF_A::DeleteAlarmSetting(Kernel::HLERequestContext& ctx) {
+void NOTIF_A::DeleteAlarmSetting(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto alarm_setting_id{rp.Pop<AlarmSettingId>()};
@@ -140,7 +140,7 @@ void NOTIF_A::DeleteAlarmSetting(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void NOTIF_A::Initialize(Kernel::HLERequestContext& ctx) {
+void NOTIF_A::Initialize(HLERequestContext& ctx) {
// TODO: Load previous alarms from config
LOG_WARNING(Service_NOTIF, "(STUBBED) called");
diff --git a/src/core/hle/service/glue/notif.h b/src/core/hle/service/glue/notif.h
index 4467e1f35..b1187f3a3 100644
--- a/src/core/hle/service/glue/notif.h
+++ b/src/core/hle/service/glue/notif.h
@@ -56,12 +56,12 @@ private:
};
static_assert(sizeof(AlarmSetting) == 0x40, "AlarmSetting is an invalid size");
- void RegisterAlarmSetting(Kernel::HLERequestContext& ctx);
- void UpdateAlarmSetting(Kernel::HLERequestContext& ctx);
- void ListAlarmSettings(Kernel::HLERequestContext& ctx);
- void LoadApplicationParameter(Kernel::HLERequestContext& ctx);
- void DeleteAlarmSetting(Kernel::HLERequestContext& ctx);
- void Initialize(Kernel::HLERequestContext& ctx);
+ void RegisterAlarmSetting(HLERequestContext& ctx);
+ void UpdateAlarmSetting(HLERequestContext& ctx);
+ void ListAlarmSettings(HLERequestContext& ctx);
+ void LoadApplicationParameter(HLERequestContext& ctx);
+ void DeleteAlarmSetting(HLERequestContext& ctx);
+ void Initialize(HLERequestContext& ctx);
std::vector<AlarmSetting>::iterator GetAlarmFromId(AlarmSettingId alarm_setting_id);
diff --git a/src/core/hle/service/grc/grc.cpp b/src/core/hle/service/grc/grc.cpp
index 4b684f6d0..64275da36 100644
--- a/src/core/hle/service/grc/grc.cpp
+++ b/src/core/hle/service/grc/grc.cpp
@@ -4,8 +4,8 @@
#include <memory>
#include "core/hle/service/grc/grc.h"
+#include "core/hle/service/server_manager.h"
#include "core/hle/service/service.h"
-#include "core/hle/service/sm/sm.h"
namespace Service::GRC {
@@ -26,8 +26,11 @@ public:
}
};
-void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
- std::make_shared<GRC>(system)->InstallAsService(sm);
+void LoopProcess(Core::System& system) {
+ auto server_manager = std::make_unique<ServerManager>(system);
+
+ server_manager->RegisterNamedService("grc:c", std::make_shared<GRC>(system));
+ ServerManager::RunServer(std::move(server_manager));
}
} // namespace Service::GRC
diff --git a/src/core/hle/service/grc/grc.h b/src/core/hle/service/grc/grc.h
index f8c2f8dab..a3f8a5b90 100644
--- a/src/core/hle/service/grc/grc.h
+++ b/src/core/hle/service/grc/grc.h
@@ -7,12 +7,8 @@ namespace Core {
class System;
}
-namespace Service::SM {
-class ServiceManager;
-}
-
namespace Service::GRC {
-void InstallInterfaces(SM::ServiceManager& sm, Core::System& system);
+void LoopProcess(Core::System& system);
} // namespace Service::GRC
diff --git a/src/core/hle/service/hid/controllers/console_sixaxis.cpp b/src/core/hle/service/hid/controllers/console_sixaxis.cpp
index bb3cba910..bcb272eaf 100644
--- a/src/core/hle/service/hid/controllers/console_sixaxis.cpp
+++ b/src/core/hle/service/hid/controllers/console_sixaxis.cpp
@@ -1,17 +1,18 @@
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
+#include "core/core.h"
#include "core/core_timing.h"
#include "core/hid/emulated_console.h"
#include "core/hid/hid_core.h"
#include "core/hle/service/hid/controllers/console_sixaxis.h"
+#include "core/memory.h"
namespace Service::HID {
constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3C200;
-Controller_ConsoleSixAxis::Controller_ConsoleSixAxis(Core::HID::HIDCore& hid_core_,
- u8* raw_shared_memory_)
- : ControllerBase{hid_core_} {
+Controller_ConsoleSixAxis::Controller_ConsoleSixAxis(Core::System& system_, u8* raw_shared_memory_)
+ : ControllerBase{system_.HIDCore()}, system{system_} {
console = hid_core.GetEmulatedConsole();
static_assert(SHARED_MEMORY_OFFSET + sizeof(ConsoleSharedMemory) < shared_memory_size,
"ConsoleSharedMemory is bigger than the shared memory");
@@ -26,7 +27,7 @@ void Controller_ConsoleSixAxis::OnInit() {}
void Controller_ConsoleSixAxis::OnRelease() {}
void Controller_ConsoleSixAxis::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
- if (!IsControllerActivated() || !is_transfer_memory_set) {
+ if (!IsControllerActivated() || transfer_memory == 0) {
seven_sixaxis_lifo.buffer_count = 0;
seven_sixaxis_lifo.buffer_tail = 0;
return;
@@ -59,11 +60,11 @@ void Controller_ConsoleSixAxis::OnUpdate(const Core::Timing::CoreTiming& core_ti
// Update seven six axis transfer memory
seven_sixaxis_lifo.WriteNextEntry(next_seven_sixaxis_state);
- std::memcpy(transfer_memory, &seven_sixaxis_lifo, sizeof(seven_sixaxis_lifo));
+ system.ApplicationMemory().WriteBlock(transfer_memory, &seven_sixaxis_lifo,
+ sizeof(seven_sixaxis_lifo));
}
-void Controller_ConsoleSixAxis::SetTransferMemoryPointer(u8* t_mem) {
- is_transfer_memory_set = true;
+void Controller_ConsoleSixAxis::SetTransferMemoryAddress(Common::ProcessAddress t_mem) {
transfer_memory = t_mem;
}
diff --git a/src/core/hle/service/hid/controllers/console_sixaxis.h b/src/core/hle/service/hid/controllers/console_sixaxis.h
index 2fd11538f..7015d924c 100644
--- a/src/core/hle/service/hid/controllers/console_sixaxis.h
+++ b/src/core/hle/service/hid/controllers/console_sixaxis.h
@@ -5,11 +5,15 @@
#include <array>
-#include "common/common_types.h"
#include "common/quaternion.h"
+#include "common/typed_address.h"
#include "core/hle/service/hid/controllers/controller_base.h"
#include "core/hle/service/hid/ring_lifo.h"
+namespace Core {
+class System;
+} // namespace Core
+
namespace Core::HID {
class EmulatedConsole;
} // namespace Core::HID
@@ -17,7 +21,7 @@ class EmulatedConsole;
namespace Service::HID {
class Controller_ConsoleSixAxis final : public ControllerBase {
public:
- explicit Controller_ConsoleSixAxis(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
+ explicit Controller_ConsoleSixAxis(Core::System& system_, u8* raw_shared_memory_);
~Controller_ConsoleSixAxis() override;
// Called when the controller is initialized
@@ -30,7 +34,7 @@ public:
void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
// Called on InitializeSevenSixAxisSensor
- void SetTransferMemoryPointer(u8* t_mem);
+ void SetTransferMemoryAddress(Common::ProcessAddress t_mem);
// Called on ResetSevenSixAxisSensorTimestamp
void ResetTimestamp();
@@ -62,12 +66,13 @@ private:
static_assert(sizeof(seven_sixaxis_lifo) == 0xA70, "SevenSixAxisState is an invalid size");
SevenSixAxisState next_seven_sixaxis_state{};
- u8* transfer_memory = nullptr;
+ Common::ProcessAddress transfer_memory{};
ConsoleSharedMemory* shared_memory = nullptr;
Core::HID::EmulatedConsole* console = nullptr;
- bool is_transfer_memory_set = false;
u64 last_saved_timestamp{};
u64 last_global_timestamp{};
+
+ Core::System& system;
};
} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/gesture.cpp b/src/core/hle/service/hid/controllers/gesture.cpp
index 32e0708ba..03432f7cb 100644
--- a/src/core/hle/service/hid/controllers/gesture.cpp
+++ b/src/core/hle/service/hid/controllers/gesture.cpp
@@ -55,7 +55,7 @@ void Controller_Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
static_cast<f32>(shared_memory->gesture_lifo.timestamp - last_update_timestamp) /
(1000 * 1000 * 1000);
- // Only update if necesary
+ // Only update if necessary
if (!ShouldUpdateGesture(gesture, time_difference)) {
return;
}
@@ -65,6 +65,11 @@ void Controller_Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
}
void Controller_Gesture::ReadTouchInput() {
+ if (!Settings::values.touchscreen.enabled) {
+ fingers = {};
+ return;
+ }
+
const auto touch_status = console->GetTouch();
for (std::size_t id = 0; id < fingers.size(); ++id) {
fingers[id] = touch_status[id];
diff --git a/src/core/hle/service/hid/controllers/mouse.cpp b/src/core/hle/service/hid/controllers/mouse.cpp
index b11cb438d..0afc66681 100644
--- a/src/core/hle/service/hid/controllers/mouse.cpp
+++ b/src/core/hle/service/hid/controllers/mouse.cpp
@@ -33,10 +33,11 @@ void Controller_Mouse::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
return;
}
+ next_state = {};
+
const auto& last_entry = shared_memory->mouse_lifo.ReadCurrentEntry().state;
next_state.sampling_number = last_entry.sampling_number + 1;
- next_state.attribute.raw = 0;
if (Settings::values.mouse_enabled) {
const auto& mouse_button_state = emulated_devices->GetMouseButtons();
const auto& mouse_position_state = emulated_devices->GetMousePosition();
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index 2f871de31..28818c813 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -70,7 +70,6 @@ Result Controller_NPad::VerifyValidSixAxisSensorHandle(
const Core::HID::SixAxisSensorHandle& device_handle) {
const auto npad_id = IsNpadIdValid(static_cast<Core::HID::NpadIdType>(device_handle.npad_id));
const bool device_index = device_handle.device_index < Core::HID::DeviceIndex::MaxDeviceIndex;
- const bool npad_type = device_handle.npad_type < Core::HID::NpadStyleIndex::MaxNpadType;
if (!npad_id) {
return InvalidNpadId;
@@ -78,10 +77,6 @@ Result Controller_NPad::VerifyValidSixAxisSensorHandle(
if (!device_index) {
return NpadDeviceIndexOutOfRange;
}
- // This doesn't get validated on nnsdk
- if (!npad_type) {
- return NpadInvalidHandle;
- }
return ResultSuccess;
}
@@ -272,6 +267,8 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) {
}
break;
case Core::HID::NpadStyleIndex::JoyconLeft:
+ shared_memory->fullkey_color.attribute = ColorAttribute::Ok;
+ shared_memory->fullkey_color.fullkey = body_colors.left;
shared_memory->joycon_color.attribute = ColorAttribute::Ok;
shared_memory->joycon_color.left = body_colors.left;
shared_memory->battery_level_dual = battery_level.left.battery_level;
@@ -285,6 +282,8 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) {
shared_memory->sixaxis_left_properties.is_newly_assigned.Assign(1);
break;
case Core::HID::NpadStyleIndex::JoyconRight:
+ shared_memory->fullkey_color.attribute = ColorAttribute::Ok;
+ shared_memory->fullkey_color.fullkey = body_colors.right;
shared_memory->joycon_color.attribute = ColorAttribute::Ok;
shared_memory->joycon_color.right = body_colors.right;
shared_memory->battery_level_right = battery_level.right.battery_level;
@@ -332,6 +331,20 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) {
controller.is_connected = true;
controller.device->Connect();
+ controller.device->SetLedPattern();
+ if (controller_type == Core::HID::NpadStyleIndex::JoyconDual) {
+ if (controller.is_dual_left_connected) {
+ controller.device->SetPollingMode(Core::HID::EmulatedDeviceIndex::LeftIndex,
+ Common::Input::PollingMode::Active);
+ }
+ if (controller.is_dual_right_connected) {
+ controller.device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
+ Common::Input::PollingMode::Active);
+ }
+ } else {
+ controller.device->SetPollingMode(Core::HID::EmulatedDeviceIndex::AllDevices,
+ Common::Input::PollingMode::Active);
+ }
SignalStyleSetChangedEvent(npad_id);
WriteEmptyEntry(controller.shared_memory);
}
@@ -410,6 +423,9 @@ void Controller_NPad::RequestPadStateUpdate(Core::HID::NpadIdType npad_id) {
return;
}
+ // This function is unique to yuzu for the turbo buttons and motion to work properly
+ controller.device->StatusUpdate();
+
auto& pad_entry = controller.npad_pad_state;
auto& trigger_entry = controller.npad_trigger_state;
const auto button_state = controller.device->GetNpadButtons();
@@ -737,11 +753,20 @@ Core::HID::NpadStyleTag Controller_NPad::GetSupportedStyleSet() const {
return hid_core.GetSupportedStyleTag();
}
-void Controller_NPad::SetSupportedNpadIdTypes(u8* data, std::size_t length) {
+Result Controller_NPad::SetSupportedNpadIdTypes(std::span<const u8> data) {
+ constexpr std::size_t max_number_npad_ids = 0xa;
+ const auto length = data.size();
ASSERT(length > 0 && (length % sizeof(u32)) == 0);
+ const std::size_t elements = length / sizeof(u32);
+
+ if (elements > max_number_npad_ids) {
+ return InvalidArraySize;
+ }
+
supported_npad_id_types.clear();
- supported_npad_id_types.resize(length / sizeof(u32));
- std::memcpy(supported_npad_id_types.data(), data, length);
+ supported_npad_id_types.resize(elements);
+ std::memcpy(supported_npad_id_types.data(), data.data(), length);
+ return ResultSuccess;
}
void Controller_NPad::GetSupportedNpadIdTypes(u32* data, std::size_t max_length) {
@@ -789,12 +814,12 @@ Controller_NPad::NpadCommunicationMode Controller_NPad::GetNpadCommunicationMode
return communication_mode;
}
-Result Controller_NPad::SetNpadMode(Core::HID::NpadIdType npad_id,
- NpadJoyDeviceType npad_device_type,
- NpadJoyAssignmentMode assignment_mode) {
+bool Controller_NPad::SetNpadMode(Core::HID::NpadIdType& new_npad_id, Core::HID::NpadIdType npad_id,
+ NpadJoyDeviceType npad_device_type,
+ NpadJoyAssignmentMode assignment_mode) {
if (!IsNpadIdValid(npad_id)) {
LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id);
- return InvalidNpadId;
+ return false;
}
auto& controller = GetControllerFromNpadIdType(npad_id);
@@ -803,7 +828,7 @@ Result Controller_NPad::SetNpadMode(Core::HID::NpadIdType npad_id,
}
if (!controller.device->IsConnected()) {
- return ResultSuccess;
+ return false;
}
if (assignment_mode == NpadJoyAssignmentMode::Dual) {
@@ -812,52 +837,52 @@ Result Controller_NPad::SetNpadMode(Core::HID::NpadIdType npad_id,
controller.is_dual_left_connected = true;
controller.is_dual_right_connected = false;
UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id, true);
- return ResultSuccess;
+ return false;
}
if (controller.device->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconRight) {
DisconnectNpad(npad_id);
controller.is_dual_left_connected = false;
controller.is_dual_right_connected = true;
UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id, true);
- return ResultSuccess;
+ return false;
}
- return ResultSuccess;
+ return false;
}
// This is for NpadJoyAssignmentMode::Single
// Only JoyconDual get affected by this function
if (controller.device->GetNpadStyleIndex() != Core::HID::NpadStyleIndex::JoyconDual) {
- return ResultSuccess;
+ return false;
}
if (controller.is_dual_left_connected && !controller.is_dual_right_connected) {
DisconnectNpad(npad_id);
UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconLeft, npad_id, true);
- return ResultSuccess;
+ return false;
}
if (!controller.is_dual_left_connected && controller.is_dual_right_connected) {
DisconnectNpad(npad_id);
UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconRight, npad_id, true);
- return ResultSuccess;
+ return false;
}
// We have two controllers connected to the same npad_id we need to split them
- const auto npad_id_2 = hid_core.GetFirstDisconnectedNpadId();
- auto& controller_2 = GetControllerFromNpadIdType(npad_id_2);
+ new_npad_id = hid_core.GetFirstDisconnectedNpadId();
+ auto& controller_2 = GetControllerFromNpadIdType(new_npad_id);
DisconnectNpad(npad_id);
if (npad_device_type == NpadJoyDeviceType::Left) {
UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconLeft, npad_id, true);
controller_2.is_dual_left_connected = false;
controller_2.is_dual_right_connected = true;
- UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id_2, true);
+ UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconDual, new_npad_id, true);
} else {
UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconRight, npad_id, true);
controller_2.is_dual_left_connected = true;
controller_2.is_dual_right_connected = false;
- UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id_2, true);
+ UpdateControllerAt(Core::HID::NpadStyleIndex::JoyconDual, new_npad_id, true);
}
- return ResultSuccess;
+ return true;
}
bool Controller_NPad::VibrateControllerAtIndex(Core::HID::NpadIdType npad_id,
@@ -954,8 +979,8 @@ void Controller_NPad::VibrateController(
}
void Controller_NPad::VibrateControllers(
- const std::vector<Core::HID::VibrationDeviceHandle>& vibration_device_handles,
- const std::vector<Core::HID::VibrationValue>& vibration_values) {
+ std::span<const Core::HID::VibrationDeviceHandle> vibration_device_handles,
+ std::span<const Core::HID::VibrationValue> vibration_values) {
if (!Settings::values.vibration_enabled.GetValue() && !permit_vibration_session_enabled) {
return;
}
@@ -1101,8 +1126,10 @@ Result Controller_NPad::DisconnectNpad(Core::HID::NpadIdType npad_id) {
WriteEmptyEntry(shared_memory);
return ResultSuccess;
}
+
Result Controller_NPad::SetGyroscopeZeroDriftMode(
- const Core::HID::SixAxisSensorHandle& sixaxis_handle, GyroscopeZeroDriftMode drift_mode) {
+ const Core::HID::SixAxisSensorHandle& sixaxis_handle,
+ Core::HID::GyroscopeZeroDriftMode drift_mode) {
const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle);
if (is_valid.IsError()) {
LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
@@ -1110,14 +1137,16 @@ Result Controller_NPad::SetGyroscopeZeroDriftMode(
}
auto& sixaxis = GetSixaxisState(sixaxis_handle);
+ auto& controller = GetControllerFromHandle(sixaxis_handle);
sixaxis.gyroscope_zero_drift_mode = drift_mode;
+ controller.device->SetGyroscopeZeroDriftMode(drift_mode);
return ResultSuccess;
}
Result Controller_NPad::GetGyroscopeZeroDriftMode(
const Core::HID::SixAxisSensorHandle& sixaxis_handle,
- GyroscopeZeroDriftMode& drift_mode) const {
+ Core::HID::GyroscopeZeroDriftMode& drift_mode) const {
const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle);
if (is_valid.IsError()) {
LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
@@ -1355,7 +1384,8 @@ Result Controller_NPad::MergeSingleJoyAsDualJoy(Core::HID::NpadIdType npad_id_1,
return NpadIsDualJoycon;
}
- // Disconnect the joycon at the second id and connect the dual joycon at the first index.
+ // Disconnect the joycons and connect them as dual joycon at the first index.
+ DisconnectNpad(npad_id_1);
DisconnectNpad(npad_id_2);
controller_1.is_dual_left_connected = true;
controller_1.is_dual_right_connected = true;
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index 1a589cca2..776411261 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -6,6 +6,7 @@
#include <array>
#include <atomic>
#include <mutex>
+#include <span>
#include "common/bit_field.h"
#include "common/common_types.h"
@@ -51,13 +52,6 @@ public:
// When the controller is requesting a motion update for the shared memory
void OnMotionUpdate(const Core::Timing::CoreTiming& core_timing) override;
- // This is nn::hid::GyroscopeZeroDriftMode
- enum class GyroscopeZeroDriftMode : u32 {
- Loose = 0,
- Standard = 1,
- Tight = 2,
- };
-
// This is nn::hid::NpadJoyHoldType
enum class NpadJoyHoldType : u64 {
Vertical = 0,
@@ -95,7 +89,7 @@ public:
void SetSupportedStyleSet(Core::HID::NpadStyleTag style_set);
Core::HID::NpadStyleTag GetSupportedStyleSet() const;
- void SetSupportedNpadIdTypes(u8* data, std::size_t length);
+ Result SetSupportedNpadIdTypes(std::span<const u8> data);
void GetSupportedNpadIdTypes(u32* data, std::size_t max_length);
std::size_t GetSupportedNpadIdTypesSize() const;
@@ -108,8 +102,8 @@ public:
void SetNpadCommunicationMode(NpadCommunicationMode communication_mode_);
NpadCommunicationMode GetNpadCommunicationMode() const;
- Result SetNpadMode(Core::HID::NpadIdType npad_id, NpadJoyDeviceType npad_device_type,
- NpadJoyAssignmentMode assignment_mode);
+ bool SetNpadMode(Core::HID::NpadIdType& new_npad_id, Core::HID::NpadIdType npad_id,
+ NpadJoyDeviceType npad_device_type, NpadJoyAssignmentMode assignment_mode);
bool VibrateControllerAtIndex(Core::HID::NpadIdType npad_id, std::size_t device_index,
const Core::HID::VibrationValue& vibration_value);
@@ -118,8 +112,8 @@ public:
const Core::HID::VibrationValue& vibration_value);
void VibrateControllers(
- const std::vector<Core::HID::VibrationDeviceHandle>& vibration_device_handles,
- const std::vector<Core::HID::VibrationValue>& vibration_values);
+ std::span<const Core::HID::VibrationDeviceHandle> vibration_device_handles,
+ std::span<const Core::HID::VibrationValue> vibration_values);
Core::HID::VibrationValue GetLastVibration(
const Core::HID::VibrationDeviceHandle& vibration_device_handle) const;
@@ -145,9 +139,9 @@ public:
Result DisconnectNpad(Core::HID::NpadIdType npad_id);
Result SetGyroscopeZeroDriftMode(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
- GyroscopeZeroDriftMode drift_mode);
+ Core::HID::GyroscopeZeroDriftMode drift_mode);
Result GetGyroscopeZeroDriftMode(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
- GyroscopeZeroDriftMode& drift_mode) const;
+ Core::HID::GyroscopeZeroDriftMode& drift_mode) const;
Result IsSixAxisSensorAtRest(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
bool& is_at_rest) const;
Result IsFirmwareUpdateAvailableForSixAxisSensor(
@@ -488,7 +482,8 @@ private:
Core::HID::SixAxisSensorFusionParameters fusion{};
Core::HID::SixAxisSensorCalibrationParameter calibration{};
Core::HID::SixAxisSensorIcInformation ic_information{};
- GyroscopeZeroDriftMode gyroscope_zero_drift_mode{GyroscopeZeroDriftMode::Standard};
+ Core::HID::GyroscopeZeroDriftMode gyroscope_zero_drift_mode{
+ Core::HID::GyroscopeZeroDriftMode::Standard};
};
struct NpadControllerData {
diff --git a/src/core/hle/service/hid/controllers/palma.cpp b/src/core/hle/service/hid/controllers/palma.cpp
index 4564ea1e2..14c67e454 100644
--- a/src/core/hle/service/hid/controllers/palma.cpp
+++ b/src/core/hle/service/hid/controllers/palma.cpp
@@ -152,7 +152,7 @@ Result Controller_Palma::WritePalmaRgbLedPatternEntry(const PalmaConnectionHandl
}
Result Controller_Palma::WritePalmaWaveEntry(const PalmaConnectionHandle& handle, PalmaWaveSet wave,
- u8* t_mem, u64 size) {
+ Common::ProcessAddress t_mem, u64 size) {
if (handle.npad_id != active_handle.npad_id) {
return InvalidPalmaHandle;
}
diff --git a/src/core/hle/service/hid/controllers/palma.h b/src/core/hle/service/hid/controllers/palma.h
index 1d7fc94e1..a0491a819 100644
--- a/src/core/hle/service/hid/controllers/palma.h
+++ b/src/core/hle/service/hid/controllers/palma.h
@@ -5,7 +5,7 @@
#include <array>
#include "common/common_funcs.h"
-#include "common/common_types.h"
+#include "common/typed_address.h"
#include "core/hle/service/hid/controllers/controller_base.h"
#include "core/hle/service/hid/errors.h"
@@ -125,8 +125,8 @@ public:
Result ReadPalmaUniqueCode(const PalmaConnectionHandle& handle);
Result SetPalmaUniqueCodeInvalid(const PalmaConnectionHandle& handle);
Result WritePalmaRgbLedPatternEntry(const PalmaConnectionHandle& handle, u64 unknown);
- Result WritePalmaWaveEntry(const PalmaConnectionHandle& handle, PalmaWaveSet wave, u8* t_mem,
- u64 size);
+ Result WritePalmaWaveEntry(const PalmaConnectionHandle& handle, PalmaWaveSet wave,
+ Common::ProcessAddress t_mem, u64 size);
Result SetPalmaDataBaseIdentificationVersion(const PalmaConnectionHandle& handle,
s32 database_id_version_);
Result GetPalmaDataBaseIdentificationVersion(const PalmaConnectionHandle& handle);
diff --git a/src/core/hle/service/hid/controllers/stubbed.cpp b/src/core/hle/service/hid/controllers/stubbed.cpp
index df9ee0c3f..9e2f3ab21 100644
--- a/src/core/hle/service/hid/controllers/stubbed.cpp
+++ b/src/core/hle/service/hid/controllers/stubbed.cpp
@@ -26,7 +26,7 @@ void Controller_Stubbed::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
}
CommonHeader header{};
- header.timestamp = core_timing.GetCPUTicks();
+ header.timestamp = core_timing.GetGlobalTimeNs().count();
header.total_entry_count = 17;
header.entry_count = 0;
header.last_entry_index = 0;
diff --git a/src/core/hle/service/hid/controllers/touchscreen.cpp b/src/core/hle/service/hid/controllers/touchscreen.cpp
index 1da8d3eb0..3ef91df4b 100644
--- a/src/core/hle/service/hid/controllers/touchscreen.cpp
+++ b/src/core/hle/service/hid/controllers/touchscreen.cpp
@@ -32,7 +32,7 @@ void Controller_Touchscreen::OnInit() {}
void Controller_Touchscreen::OnRelease() {}
void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
- shared_memory->touch_screen_lifo.timestamp = core_timing.GetCPUTicks();
+ shared_memory->touch_screen_lifo.timestamp = core_timing.GetGlobalTimeNs().count();
if (!IsControllerActivated()) {
shared_memory->touch_screen_lifo.buffer_count = 0;
@@ -58,6 +58,11 @@ void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timin
}
if (!finger.pressed && current_touch.pressed) {
+ // Ignore all touch fingers if disabled
+ if (!Settings::values.touchscreen.enabled) {
+ continue;
+ }
+
finger.attribute.start_touch.Assign(1);
finger.pressed = true;
finger.position = current_touch.position;
@@ -80,7 +85,7 @@ void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timin
const auto active_fingers_count =
static_cast<std::size_t>(std::distance(active_fingers.begin(), end_iter));
- const u64 tick = core_timing.GetCPUTicks();
+ const u64 timestamp = static_cast<u64>(core_timing.GetGlobalTimeNs().count());
const auto& last_entry = shared_memory->touch_screen_lifo.ReadCurrentEntry().state;
next_state.sampling_number = last_entry.sampling_number + 1;
@@ -97,8 +102,8 @@ void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timin
touch_entry.diameter_x = Settings::values.touchscreen.diameter_x;
touch_entry.diameter_y = Settings::values.touchscreen.diameter_y;
touch_entry.rotation_angle = Settings::values.touchscreen.rotation_angle;
- touch_entry.delta_time = tick - active_fingers[id].last_touch;
- fingers[active_fingers[id].id].last_touch = tick;
+ touch_entry.delta_time = timestamp - active_fingers[id].last_touch;
+ fingers[active_fingers[id].id].last_touch = timestamp;
touch_entry.finger = active_fingers[id].id;
touch_entry.attribute.raw = active_fingers[id].attribute.raw;
} else {
diff --git a/src/core/hle/service/hid/errors.h b/src/core/hle/service/hid/errors.h
index 76208e9a4..9585bdaf0 100644
--- a/src/core/hle/service/hid/errors.h
+++ b/src/core/hle/service/hid/errors.h
@@ -18,6 +18,7 @@ constexpr Result NpadIsDualJoycon{ErrorModule::HID, 601};
constexpr Result NpadIsSameType{ErrorModule::HID, 602};
constexpr Result InvalidNpadId{ErrorModule::HID, 709};
constexpr Result NpadNotConnected{ErrorModule::HID, 710};
+constexpr Result InvalidArraySize{ErrorModule::HID, 715};
constexpr Result InvalidPalmaHandle{ErrorModule::HID, 3302};
} // namespace Service::HID
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index bf28440c6..2bf1d8a27 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -8,7 +8,6 @@
#include "core/core.h"
#include "core/core_timing.h"
#include "core/hid/hid_core.h"
-#include "core/hle/ipc_helpers.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"
@@ -18,6 +17,8 @@
#include "core/hle/service/hid/hidbus.h"
#include "core/hle/service/hid/irs.h"
#include "core/hle/service/hid/xcd.h"
+#include "core/hle/service/ipc_helpers.h"
+#include "core/hle/service/server_manager.h"
#include "core/memory.h"
#include "core/hle/service/hid/controllers/console_sixaxis.h"
@@ -63,6 +64,7 @@ IAppletResource::IAppletResource(Core::System& system_,
MakeControllerWithServiceContext<Controller_NPad>(HidController::NPad, shared_memory);
MakeController<Controller_Gesture>(HidController::Gesture, shared_memory);
MakeController<Controller_ConsoleSixAxis>(HidController::ConsoleSixAxisSensor, shared_memory);
+ MakeController<Controller_Stubbed>(HidController::DebugMouse, shared_memory);
MakeControllerWithServiceContext<Controller_Palma>(HidController::Palma, shared_memory);
// Homebrew doesn't try to activate some controllers, so we activate them by default
@@ -74,6 +76,7 @@ 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::DebugMouse).SetCommonHeaderOffset(0x3DC00);
// Register update callbacks
npad_update_event = Core::Timing::CreateEvent(
@@ -135,7 +138,7 @@ IAppletResource::~IAppletResource() {
system.CoreTiming().UnscheduleEvent(motion_update_event, 0);
}
-void IAppletResource::GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) {
+void IAppletResource::GetSharedMemoryHandle(HLERequestContext& ctx) {
LOG_DEBUG(Service_HID, "called");
IPC::ResponseBuilder rb{ctx, 2, 1};
@@ -200,7 +203,7 @@ public:
}
private:
- void InitializeVibrationDevice(Kernel::HLERequestContext& ctx) {
+ void InitializeVibrationDevice(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto vibration_device_handle{rp.PopRaw<Core::HID::VibrationDeviceHandle>()};
@@ -236,6 +239,7 @@ Hid::Hid(Core::System& system_)
{1, &Hid::ActivateDebugPad, "ActivateDebugPad"},
{11, &Hid::ActivateTouchScreen, "ActivateTouchScreen"},
{21, &Hid::ActivateMouse, "ActivateMouse"},
+ {26, nullptr, "ActivateDebugMouse"},
{31, &Hid::ActivateKeyboard, "ActivateKeyboard"},
{32, &Hid::SendKeyboardLockKeyEvent, "SendKeyboardLockKeyEvent"},
{40, nullptr, "AcquireXpadIdEventHandle"},
@@ -298,7 +302,7 @@ Hid::Hid(Core::System& system_)
{130, &Hid::SwapNpadAssignment, "SwapNpadAssignment"},
{131, &Hid::IsUnintendedHomeButtonInputProtectionEnabled, "IsUnintendedHomeButtonInputProtectionEnabled"},
{132, &Hid::EnableUnintendedHomeButtonInputProtection, "EnableUnintendedHomeButtonInputProtection"},
- {133, nullptr, "SetNpadJoyAssignmentModeSingleWithDestination"},
+ {133, &Hid::SetNpadJoyAssignmentModeSingleWithDestination, "SetNpadJoyAssignmentModeSingleWithDestination"},
{134, &Hid::SetNpadAnalogStickUseCenterClamp, "SetNpadAnalogStickUseCenterClamp"},
{135, &Hid::SetNpadCaptureButtonAssignment, "SetNpadCaptureButtonAssignment"},
{136, &Hid::ClearNpadCaptureButtonAssignment, "ClearNpadCaptureButtonAssignment"},
@@ -378,7 +382,7 @@ Hid::Hid(Core::System& system_)
Hid::~Hid() = default;
-void Hid::CreateAppletResource(Kernel::HLERequestContext& ctx) {
+void Hid::CreateAppletResource(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()};
@@ -393,7 +397,7 @@ void Hid::CreateAppletResource(Kernel::HLERequestContext& ctx) {
rb.PushIpcInterface<IAppletResource>(applet_resource);
}
-void Hid::ActivateDebugPad(Kernel::HLERequestContext& ctx) {
+void Hid::ActivateDebugPad(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()};
@@ -405,7 +409,7 @@ void Hid::ActivateDebugPad(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void Hid::ActivateTouchScreen(Kernel::HLERequestContext& ctx) {
+void Hid::ActivateTouchScreen(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()};
@@ -417,7 +421,7 @@ void Hid::ActivateTouchScreen(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void Hid::ActivateMouse(Kernel::HLERequestContext& ctx) {
+void Hid::ActivateMouse(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()};
@@ -429,7 +433,7 @@ void Hid::ActivateMouse(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void Hid::ActivateKeyboard(Kernel::HLERequestContext& ctx) {
+void Hid::ActivateKeyboard(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()};
@@ -441,7 +445,7 @@ void Hid::ActivateKeyboard(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void Hid::SendKeyboardLockKeyEvent(Kernel::HLERequestContext& ctx) {
+void Hid::SendKeyboardLockKeyEvent(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto flags{rp.Pop<u32>()};
@@ -451,7 +455,7 @@ void Hid::SendKeyboardLockKeyEvent(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void Hid::ActivateXpad(Kernel::HLERequestContext& ctx) {
+void Hid::ActivateXpad(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
u32 basic_xpad_id;
@@ -471,7 +475,7 @@ void Hid::ActivateXpad(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void Hid::GetXpadIDs(Kernel::HLERequestContext& ctx) {
+void Hid::GetXpadIDs(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()};
@@ -482,7 +486,7 @@ void Hid::GetXpadIDs(Kernel::HLERequestContext& ctx) {
rb.Push(0);
}
-void Hid::ActivateSixAxisSensor(Kernel::HLERequestContext& ctx) {
+void Hid::ActivateSixAxisSensor(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
u32 basic_xpad_id;
@@ -502,7 +506,7 @@ void Hid::ActivateSixAxisSensor(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void Hid::DeactivateSixAxisSensor(Kernel::HLERequestContext& ctx) {
+void Hid::DeactivateSixAxisSensor(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
u32 basic_xpad_id;
@@ -522,7 +526,7 @@ void Hid::DeactivateSixAxisSensor(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void Hid::StartSixAxisSensor(Kernel::HLERequestContext& ctx) {
+void Hid::StartSixAxisSensor(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
Core::HID::SixAxisSensorHandle sixaxis_handle;
@@ -545,7 +549,7 @@ void Hid::StartSixAxisSensor(Kernel::HLERequestContext& ctx) {
rb.Push(result);
}
-void Hid::StopSixAxisSensor(Kernel::HLERequestContext& ctx) {
+void Hid::StopSixAxisSensor(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
Core::HID::SixAxisSensorHandle sixaxis_handle;
@@ -568,7 +572,7 @@ void Hid::StopSixAxisSensor(Kernel::HLERequestContext& ctx) {
rb.Push(result);
}
-void Hid::IsSixAxisSensorFusionEnabled(Kernel::HLERequestContext& ctx) {
+void Hid::IsSixAxisSensorFusionEnabled(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
Core::HID::SixAxisSensorHandle sixaxis_handle;
@@ -594,7 +598,7 @@ void Hid::IsSixAxisSensorFusionEnabled(Kernel::HLERequestContext& ctx) {
rb.Push(is_enabled);
}
-void Hid::EnableSixAxisSensorFusion(Kernel::HLERequestContext& ctx) {
+void Hid::EnableSixAxisSensorFusion(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
bool enable_sixaxis_sensor_fusion;
@@ -621,7 +625,7 @@ void Hid::EnableSixAxisSensorFusion(Kernel::HLERequestContext& ctx) {
rb.Push(result);
}
-void Hid::SetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx) {
+void Hid::SetSixAxisSensorFusionParameters(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
Core::HID::SixAxisSensorHandle sixaxis_handle;
@@ -648,7 +652,7 @@ void Hid::SetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx) {
rb.Push(result);
}
-void Hid::GetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx) {
+void Hid::GetSixAxisSensorFusionParameters(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
Core::HID::SixAxisSensorHandle sixaxis_handle;
@@ -675,7 +679,7 @@ void Hid::GetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx) {
rb.PushRaw(fusion_parameters);
}
-void Hid::ResetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx) {
+void Hid::ResetSixAxisSensorFusionParameters(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
Core::HID::SixAxisSensorHandle sixaxis_handle;
@@ -686,7 +690,7 @@ void Hid::ResetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx) {
const auto parameters{rp.PopRaw<Parameters>()};
- // Since these parameters are unknow just use what HW outputs
+ // Since these parameters are unknown just use what HW outputs
const Core::HID::SixAxisSensorFusionParameters fusion_parameters{
.parameter1 = 0.03f,
.parameter2 = 0.4f,
@@ -709,10 +713,10 @@ void Hid::ResetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx) {
rb.Push(result2);
}
-void Hid::SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) {
+void Hid::SetGyroscopeZeroDriftMode(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto sixaxis_handle{rp.PopRaw<Core::HID::SixAxisSensorHandle>()};
- const auto drift_mode{rp.PopEnum<Controller_NPad::GyroscopeZeroDriftMode>()};
+ const auto drift_mode{rp.PopEnum<Core::HID::GyroscopeZeroDriftMode>()};
const auto applet_resource_user_id{rp.Pop<u64>()};
auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
@@ -728,7 +732,7 @@ void Hid::SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) {
rb.Push(result);
}
-void Hid::GetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) {
+void Hid::GetGyroscopeZeroDriftMode(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
Core::HID::SixAxisSensorHandle sixaxis_handle;
@@ -739,7 +743,7 @@ void Hid::GetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) {
const auto parameters{rp.PopRaw<Parameters>()};
- auto drift_mode{Controller_NPad::GyroscopeZeroDriftMode::Standard};
+ auto drift_mode{Core::HID::GyroscopeZeroDriftMode::Standard};
auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
const auto result = controller.GetGyroscopeZeroDriftMode(parameters.sixaxis_handle, drift_mode);
@@ -753,7 +757,7 @@ void Hid::GetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) {
rb.PushEnum(drift_mode);
}
-void Hid::ResetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) {
+void Hid::ResetGyroscopeZeroDriftMode(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
Core::HID::SixAxisSensorHandle sixaxis_handle;
@@ -764,7 +768,7 @@ void Hid::ResetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) {
const auto parameters{rp.PopRaw<Parameters>()};
- const auto drift_mode{Controller_NPad::GyroscopeZeroDriftMode::Standard};
+ const auto drift_mode{Core::HID::GyroscopeZeroDriftMode::Standard};
auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
const auto result = controller.SetGyroscopeZeroDriftMode(parameters.sixaxis_handle, drift_mode);
@@ -777,7 +781,7 @@ void Hid::ResetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) {
rb.Push(result);
}
-void Hid::IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) {
+void Hid::IsSixAxisSensorAtRest(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
Core::HID::SixAxisSensorHandle sixaxis_handle;
@@ -802,7 +806,7 @@ void Hid::IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) {
rb.Push(is_at_rest);
}
-void Hid::IsFirmwareUpdateAvailableForSixAxisSensor(Kernel::HLERequestContext& ctx) {
+void Hid::IsFirmwareUpdateAvailableForSixAxisSensor(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
Core::HID::SixAxisSensorHandle sixaxis_handle;
@@ -829,7 +833,7 @@ void Hid::IsFirmwareUpdateAvailableForSixAxisSensor(Kernel::HLERequestContext& c
rb.Push(is_firmware_available);
}
-void Hid::EnableSixAxisSensorUnalteredPassthrough(Kernel::HLERequestContext& ctx) {
+void Hid::EnableSixAxisSensorUnalteredPassthrough(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
bool enabled;
@@ -855,7 +859,7 @@ void Hid::EnableSixAxisSensorUnalteredPassthrough(Kernel::HLERequestContext& ctx
rb.Push(result);
}
-void Hid::IsSixAxisSensorUnalteredPassthroughEnabled(Kernel::HLERequestContext& ctx) {
+void Hid::IsSixAxisSensorUnalteredPassthroughEnabled(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
Core::HID::SixAxisSensorHandle sixaxis_handle;
@@ -882,7 +886,7 @@ void Hid::IsSixAxisSensorUnalteredPassthroughEnabled(Kernel::HLERequestContext&
rb.Push(is_unaltered_sisxaxis_enabled);
}
-void Hid::LoadSixAxisSensorCalibrationParameter(Kernel::HLERequestContext& ctx) {
+void Hid::LoadSixAxisSensorCalibrationParameter(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
Core::HID::SixAxisSensorHandle sixaxis_handle;
@@ -912,7 +916,7 @@ void Hid::LoadSixAxisSensorCalibrationParameter(Kernel::HLERequestContext& ctx)
rb.Push(result);
}
-void Hid::GetSixAxisSensorIcInformation(Kernel::HLERequestContext& ctx) {
+void Hid::GetSixAxisSensorIcInformation(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
Core::HID::SixAxisSensorHandle sixaxis_handle;
@@ -942,7 +946,7 @@ void Hid::GetSixAxisSensorIcInformation(Kernel::HLERequestContext& ctx) {
rb.Push(result);
}
-void Hid::ResetIsSixAxisSensorDeviceNewlyAssigned(Kernel::HLERequestContext& ctx) {
+void Hid::ResetIsSixAxisSensorDeviceNewlyAssigned(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
Core::HID::SixAxisSensorHandle sixaxis_handle;
@@ -967,7 +971,7 @@ void Hid::ResetIsSixAxisSensorDeviceNewlyAssigned(Kernel::HLERequestContext& ctx
rb.Push(result);
}
-void Hid::ActivateGesture(Kernel::HLERequestContext& ctx) {
+void Hid::ActivateGesture(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
u32 unknown;
@@ -987,7 +991,7 @@ void Hid::ActivateGesture(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void Hid::SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) {
+void Hid::SetSupportedNpadStyleSet(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
Core::HID::NpadStyleSet supported_styleset;
@@ -1008,7 +1012,7 @@ void Hid::SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void Hid::GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) {
+void Hid::GetSupportedNpadStyleSet(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()};
@@ -1021,20 +1025,20 @@ void Hid::GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) {
.raw);
}
-void Hid::SetSupportedNpadIdType(Kernel::HLERequestContext& ctx) {
+void Hid::SetSupportedNpadIdType(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()};
- applet_resource->GetController<Controller_NPad>(HidController::NPad)
- .SetSupportedNpadIdTypes(ctx.ReadBuffer().data(), ctx.GetReadBufferSize());
+ const auto result = applet_resource->GetController<Controller_NPad>(HidController::NPad)
+ .SetSupportedNpadIdTypes(ctx.ReadBuffer());
LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
+ rb.Push(result);
}
-void Hid::ActivateNpad(Kernel::HLERequestContext& ctx) {
+void Hid::ActivateNpad(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()};
@@ -1046,7 +1050,7 @@ void Hid::ActivateNpad(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void Hid::DeactivateNpad(Kernel::HLERequestContext& ctx) {
+void Hid::DeactivateNpad(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()};
@@ -1058,7 +1062,7 @@ void Hid::DeactivateNpad(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void Hid::AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) {
+void Hid::AcquireNpadStyleSetUpdateEventHandle(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
Core::HID::NpadIdType npad_id;
@@ -1083,7 +1087,7 @@ void Hid::AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) {
.GetStyleSetChangedEvent(parameters.npad_id));
}
-void Hid::DisconnectNpad(Kernel::HLERequestContext& ctx) {
+void Hid::DisconnectNpad(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
Core::HID::NpadIdType npad_id;
@@ -1104,7 +1108,7 @@ void Hid::DisconnectNpad(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void Hid::GetPlayerLedPattern(Kernel::HLERequestContext& ctx) {
+void Hid::GetPlayerLedPattern(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto npad_id{rp.PopEnum<Core::HID::NpadIdType>()};
@@ -1119,7 +1123,7 @@ void Hid::GetPlayerLedPattern(Kernel::HLERequestContext& ctx) {
rb.Push(pattern.raw);
}
-void Hid::ActivateNpadWithRevision(Kernel::HLERequestContext& ctx) {
+void Hid::ActivateNpadWithRevision(HLERequestContext& ctx) {
// Should have no effect with how our npad sets up the data
IPC::RequestParser rp{ctx};
struct Parameters {
@@ -1140,7 +1144,7 @@ void Hid::ActivateNpadWithRevision(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void Hid::SetNpadJoyHoldType(Kernel::HLERequestContext& ctx) {
+void Hid::SetNpadJoyHoldType(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()};
const auto hold_type{rp.PopEnum<Controller_NPad::NpadJoyHoldType>()};
@@ -1154,7 +1158,7 @@ void Hid::SetNpadJoyHoldType(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void Hid::GetNpadJoyHoldType(Kernel::HLERequestContext& ctx) {
+void Hid::GetNpadJoyHoldType(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()};
@@ -1165,7 +1169,7 @@ void Hid::GetNpadJoyHoldType(Kernel::HLERequestContext& ctx) {
rb.PushEnum(applet_resource->GetController<Controller_NPad>(HidController::NPad).GetHoldType());
}
-void Hid::SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx) {
+void Hid::SetNpadJoyAssignmentModeSingleByDefault(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
Core::HID::NpadIdType npad_id;
@@ -1176,8 +1180,10 @@ void Hid::SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx
const auto parameters{rp.PopRaw<Parameters>()};
+ Core::HID::NpadIdType new_npad_id{};
auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
- controller.SetNpadMode(parameters.npad_id, Controller_NPad::NpadJoyDeviceType::Left,
+ controller.SetNpadMode(new_npad_id, parameters.npad_id,
+ Controller_NPad::NpadJoyDeviceType::Left,
Controller_NPad::NpadJoyAssignmentMode::Single);
LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id,
@@ -1187,7 +1193,7 @@ void Hid::SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx
rb.Push(ResultSuccess);
}
-void Hid::SetNpadJoyAssignmentModeSingle(Kernel::HLERequestContext& ctx) {
+void Hid::SetNpadJoyAssignmentModeSingle(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
Core::HID::NpadIdType npad_id;
@@ -1199,8 +1205,9 @@ void Hid::SetNpadJoyAssignmentModeSingle(Kernel::HLERequestContext& ctx) {
const auto parameters{rp.PopRaw<Parameters>()};
+ Core::HID::NpadIdType new_npad_id{};
auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
- controller.SetNpadMode(parameters.npad_id, parameters.npad_joy_device_type,
+ controller.SetNpadMode(new_npad_id, parameters.npad_id, parameters.npad_joy_device_type,
Controller_NPad::NpadJoyAssignmentMode::Single);
LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}",
@@ -1211,7 +1218,7 @@ void Hid::SetNpadJoyAssignmentModeSingle(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void Hid::SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) {
+void Hid::SetNpadJoyAssignmentModeDual(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
Core::HID::NpadIdType npad_id;
@@ -1222,8 +1229,10 @@ void Hid::SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) {
const auto parameters{rp.PopRaw<Parameters>()};
+ Core::HID::NpadIdType new_npad_id{};
auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
- controller.SetNpadMode(parameters.npad_id, {}, Controller_NPad::NpadJoyAssignmentMode::Dual);
+ controller.SetNpadMode(new_npad_id, parameters.npad_id, {},
+ Controller_NPad::NpadJoyAssignmentMode::Dual);
LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id,
parameters.applet_resource_user_id);
@@ -1232,7 +1241,7 @@ void Hid::SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void Hid::MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) {
+void Hid::MergeSingleJoyAsDualJoy(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto npad_id_1{rp.PopEnum<Core::HID::NpadIdType>()};
const auto npad_id_2{rp.PopEnum<Core::HID::NpadIdType>()};
@@ -1248,7 +1257,7 @@ void Hid::MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) {
rb.Push(result);
}
-void Hid::StartLrAssignmentMode(Kernel::HLERequestContext& ctx) {
+void Hid::StartLrAssignmentMode(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()};
@@ -1260,7 +1269,7 @@ void Hid::StartLrAssignmentMode(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void Hid::StopLrAssignmentMode(Kernel::HLERequestContext& ctx) {
+void Hid::StopLrAssignmentMode(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()};
@@ -1272,7 +1281,7 @@ void Hid::StopLrAssignmentMode(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void Hid::SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) {
+void Hid::SetNpadHandheldActivationMode(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()};
const auto activation_mode{rp.PopEnum<Controller_NPad::NpadHandheldActivationMode>()};
@@ -1287,7 +1296,7 @@ void Hid::SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void Hid::GetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) {
+void Hid::GetNpadHandheldActivationMode(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()};
@@ -1299,7 +1308,7 @@ void Hid::GetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) {
.GetNpadHandheldActivationMode());
}
-void Hid::SwapNpadAssignment(Kernel::HLERequestContext& ctx) {
+void Hid::SwapNpadAssignment(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto npad_id_1{rp.PopEnum<Core::HID::NpadIdType>()};
const auto npad_id_2{rp.PopEnum<Core::HID::NpadIdType>()};
@@ -1315,7 +1324,7 @@ void Hid::SwapNpadAssignment(Kernel::HLERequestContext& ctx) {
rb.Push(result);
}
-void Hid::IsUnintendedHomeButtonInputProtectionEnabled(Kernel::HLERequestContext& ctx) {
+void Hid::IsUnintendedHomeButtonInputProtectionEnabled(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
Core::HID::NpadIdType npad_id;
@@ -1339,7 +1348,7 @@ void Hid::IsUnintendedHomeButtonInputProtectionEnabled(Kernel::HLERequestContext
rb.Push(is_enabled);
}
-void Hid::EnableUnintendedHomeButtonInputProtection(Kernel::HLERequestContext& ctx) {
+void Hid::EnableUnintendedHomeButtonInputProtection(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
bool unintended_home_button_input_protection;
@@ -1365,7 +1374,35 @@ void Hid::EnableUnintendedHomeButtonInputProtection(Kernel::HLERequestContext& c
rb.Push(result);
}
-void Hid::SetNpadAnalogStickUseCenterClamp(Kernel::HLERequestContext& ctx) {
+void Hid::SetNpadJoyAssignmentModeSingleWithDestination(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ struct Parameters {
+ Core::HID::NpadIdType npad_id;
+ INSERT_PADDING_WORDS_NOINIT(1);
+ u64 applet_resource_user_id;
+ Controller_NPad::NpadJoyDeviceType npad_joy_device_type;
+ };
+ static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size.");
+
+ const auto parameters{rp.PopRaw<Parameters>()};
+
+ Core::HID::NpadIdType new_npad_id{};
+ auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
+ const auto is_reassigned =
+ controller.SetNpadMode(new_npad_id, parameters.npad_id, parameters.npad_joy_device_type,
+ Controller_NPad::NpadJoyAssignmentMode::Single);
+
+ LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}",
+ parameters.npad_id, parameters.applet_resource_user_id,
+ parameters.npad_joy_device_type);
+
+ IPC::ResponseBuilder rb{ctx, 4};
+ rb.Push(ResultSuccess);
+ rb.Push(is_reassigned);
+ rb.PushEnum(new_npad_id);
+}
+
+void Hid::SetNpadAnalogStickUseCenterClamp(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
bool analog_stick_use_center_clamp;
@@ -1388,7 +1425,7 @@ void Hid::SetNpadAnalogStickUseCenterClamp(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void Hid::SetNpadCaptureButtonAssignment(Kernel::HLERequestContext& ctx) {
+void Hid::SetNpadCaptureButtonAssignment(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
Core::HID::NpadStyleSet npad_styleset;
@@ -1408,7 +1445,7 @@ void Hid::SetNpadCaptureButtonAssignment(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void Hid::ClearNpadCaptureButtonAssignment(Kernel::HLERequestContext& ctx) {
+void Hid::ClearNpadCaptureButtonAssignment(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()};
@@ -1419,7 +1456,7 @@ void Hid::ClearNpadCaptureButtonAssignment(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void Hid::GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) {
+void Hid::GetVibrationDeviceInfo(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto vibration_device_handle{rp.PopRaw<Core::HID::VibrationDeviceHandle>()};
const auto& controller =
@@ -1479,7 +1516,7 @@ void Hid::GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) {
rb.PushRaw(vibration_device_info);
}
-void Hid::SendVibrationValue(Kernel::HLERequestContext& ctx) {
+void Hid::SendVibrationValue(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
Core::HID::VibrationDeviceHandle vibration_device_handle;
@@ -1504,7 +1541,7 @@ void Hid::SendVibrationValue(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void Hid::GetActualVibrationValue(Kernel::HLERequestContext& ctx) {
+void Hid::GetActualVibrationValue(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
Core::HID::VibrationDeviceHandle vibration_device_handle;
@@ -1527,7 +1564,7 @@ void Hid::GetActualVibrationValue(Kernel::HLERequestContext& ctx) {
.GetLastVibration(parameters.vibration_device_handle));
}
-void Hid::CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx) {
+void Hid::CreateActiveVibrationDeviceList(HLERequestContext& ctx) {
LOG_DEBUG(Service_HID, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -1535,7 +1572,7 @@ void Hid::CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx) {
rb.PushIpcInterface<IActiveVibrationDeviceList>(system, applet_resource);
}
-void Hid::PermitVibration(Kernel::HLERequestContext& ctx) {
+void Hid::PermitVibration(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto can_vibrate{rp.Pop<bool>()};
@@ -1549,7 +1586,7 @@ void Hid::PermitVibration(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void Hid::IsVibrationPermitted(Kernel::HLERequestContext& ctx) {
+void Hid::IsVibrationPermitted(HLERequestContext& ctx) {
LOG_DEBUG(Service_HID, "called");
// nnSDK checks if a float is greater than zero. We return the bool we stored earlier
@@ -1560,20 +1597,20 @@ void Hid::IsVibrationPermitted(Kernel::HLERequestContext& ctx) {
rb.Push(is_enabled);
}
-void Hid::SendVibrationValues(Kernel::HLERequestContext& ctx) {
+void Hid::SendVibrationValues(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()};
- const auto handles = ctx.ReadBuffer(0);
- const auto vibrations = ctx.ReadBuffer(1);
+ const auto handle_data = ctx.ReadBuffer(0);
+ const auto handle_count = ctx.GetReadBufferNumElements<Core::HID::VibrationDeviceHandle>(0);
+ const auto vibration_data = ctx.ReadBuffer(1);
+ const auto vibration_count = ctx.GetReadBufferNumElements<Core::HID::VibrationValue>(1);
- std::vector<Core::HID::VibrationDeviceHandle> vibration_device_handles(
- handles.size() / sizeof(Core::HID::VibrationDeviceHandle));
- std::vector<Core::HID::VibrationValue> vibration_values(vibrations.size() /
- sizeof(Core::HID::VibrationValue));
-
- std::memcpy(vibration_device_handles.data(), handles.data(), handles.size());
- std::memcpy(vibration_values.data(), vibrations.data(), vibrations.size());
+ auto vibration_device_handles =
+ std::span(reinterpret_cast<const Core::HID::VibrationDeviceHandle*>(handle_data.data()),
+ handle_count);
+ auto vibration_values = std::span(
+ reinterpret_cast<const Core::HID::VibrationValue*>(vibration_data.data()), vibration_count);
applet_resource->GetController<Controller_NPad>(HidController::NPad)
.VibrateControllers(vibration_device_handles, vibration_values);
@@ -1584,7 +1621,7 @@ void Hid::SendVibrationValues(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void Hid::SendVibrationGcErmCommand(Kernel::HLERequestContext& ctx) {
+void Hid::SendVibrationGcErmCommand(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
Core::HID::VibrationDeviceHandle vibration_device_handle;
@@ -1645,7 +1682,7 @@ void Hid::SendVibrationGcErmCommand(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void Hid::GetActualVibrationGcErmCommand(Kernel::HLERequestContext& ctx) {
+void Hid::GetActualVibrationGcErmCommand(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
Core::HID::VibrationDeviceHandle vibration_device_handle;
@@ -1687,7 +1724,7 @@ void Hid::GetActualVibrationGcErmCommand(Kernel::HLERequestContext& ctx) {
rb.PushEnum(gc_erm_command);
}
-void Hid::BeginPermitVibrationSession(Kernel::HLERequestContext& ctx) {
+void Hid::BeginPermitVibrationSession(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()};
@@ -1700,7 +1737,7 @@ void Hid::BeginPermitVibrationSession(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void Hid::EndPermitVibrationSession(Kernel::HLERequestContext& ctx) {
+void Hid::EndPermitVibrationSession(HLERequestContext& ctx) {
applet_resource->GetController<Controller_NPad>(HidController::NPad)
.SetPermitVibrationSession(false);
@@ -1710,7 +1747,7 @@ void Hid::EndPermitVibrationSession(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void Hid::IsVibrationDeviceMounted(Kernel::HLERequestContext& ctx) {
+void Hid::IsVibrationDeviceMounted(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
Core::HID::VibrationDeviceHandle vibration_device_handle;
@@ -1733,7 +1770,7 @@ void Hid::IsVibrationDeviceMounted(Kernel::HLERequestContext& ctx) {
.IsVibrationDeviceMounted(parameters.vibration_device_handle));
}
-void Hid::ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {
+void Hid::ActivateConsoleSixAxisSensor(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()};
@@ -1745,7 +1782,7 @@ void Hid::ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void Hid::StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {
+void Hid::StartConsoleSixAxisSensor(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
Core::HID::ConsoleSixAxisSensorHandle console_sixaxis_handle;
@@ -1765,7 +1802,7 @@ void Hid::StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void Hid::StopConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {
+void Hid::StopConsoleSixAxisSensor(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
Core::HID::ConsoleSixAxisSensorHandle console_sixaxis_handle;
@@ -1785,7 +1822,7 @@ void Hid::StopConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void Hid::ActivateSevenSixAxisSensor(Kernel::HLERequestContext& ctx) {
+void Hid::ActivateSevenSixAxisSensor(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()};
@@ -1797,7 +1834,7 @@ void Hid::ActivateSevenSixAxisSensor(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void Hid::StartSevenSixAxisSensor(Kernel::HLERequestContext& ctx) {
+void Hid::StartSevenSixAxisSensor(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()};
@@ -1808,7 +1845,7 @@ void Hid::StartSevenSixAxisSensor(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void Hid::StopSevenSixAxisSensor(Kernel::HLERequestContext& ctx) {
+void Hid::StopSevenSixAxisSensor(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()};
@@ -1819,7 +1856,7 @@ void Hid::StopSevenSixAxisSensor(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void Hid::InitializeSevenSixAxisSensor(Kernel::HLERequestContext& ctx) {
+void Hid::InitializeSevenSixAxisSensor(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()};
const auto t_mem_1_size{rp.Pop<u64>()};
@@ -1830,7 +1867,7 @@ 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().GetObject<Kernel::KTransferMemory>(
+ auto t_mem_1 = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
t_mem_1_handle);
if (t_mem_1.IsNull()) {
@@ -1840,7 +1877,7 @@ void Hid::InitializeSevenSixAxisSensor(Kernel::HLERequestContext& ctx) {
return;
}
- auto t_mem_2 = system.CurrentProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
+ auto t_mem_2 = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
t_mem_2_handle);
if (t_mem_2.IsNull()) {
@@ -1858,7 +1895,7 @@ void Hid::InitializeSevenSixAxisSensor(Kernel::HLERequestContext& ctx) {
.ActivateController();
applet_resource->GetController<Controller_ConsoleSixAxis>(HidController::ConsoleSixAxisSensor)
- .SetTransferMemoryPointer(system.Memory().GetPointer(t_mem_1->GetSourceAddress()));
+ .SetTransferMemoryAddress(t_mem_1->GetSourceAddress());
LOG_WARNING(Service_HID,
"called, t_mem_1_handle=0x{:08X}, t_mem_2_handle=0x{:08X}, "
@@ -1869,7 +1906,7 @@ void Hid::InitializeSevenSixAxisSensor(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void Hid::FinalizeSevenSixAxisSensor(Kernel::HLERequestContext& ctx) {
+void Hid::FinalizeSevenSixAxisSensor(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()};
@@ -1880,7 +1917,7 @@ void Hid::FinalizeSevenSixAxisSensor(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void Hid::ResetSevenSixAxisSensorTimestamp(Kernel::HLERequestContext& ctx) {
+void Hid::ResetSevenSixAxisSensorTimestamp(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()};
@@ -1893,7 +1930,7 @@ void Hid::ResetSevenSixAxisSensorTimestamp(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void Hid::IsUsbFullKeyControllerEnabled(Kernel::HLERequestContext& ctx) {
+void Hid::IsUsbFullKeyControllerEnabled(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
LOG_WARNING(Service_HID, "(STUBBED) called");
@@ -1903,7 +1940,7 @@ void Hid::IsUsbFullKeyControllerEnabled(Kernel::HLERequestContext& ctx) {
rb.Push(false);
}
-void Hid::GetPalmaConnectionHandle(Kernel::HLERequestContext& ctx) {
+void Hid::GetPalmaConnectionHandle(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
Core::HID::NpadIdType npad_id;
@@ -1926,7 +1963,7 @@ void Hid::GetPalmaConnectionHandle(Kernel::HLERequestContext& ctx) {
rb.PushRaw(handle);
}
-void Hid::InitializePalma(Kernel::HLERequestContext& ctx) {
+void Hid::InitializePalma(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
@@ -1939,7 +1976,7 @@ void Hid::InitializePalma(Kernel::HLERequestContext& ctx) {
rb.Push(result);
}
-void Hid::AcquirePalmaOperationCompleteEvent(Kernel::HLERequestContext& ctx) {
+void Hid::AcquirePalmaOperationCompleteEvent(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
@@ -1952,7 +1989,7 @@ void Hid::AcquirePalmaOperationCompleteEvent(Kernel::HLERequestContext& ctx) {
rb.PushCopyObjects(controller.AcquirePalmaOperationCompleteEvent(connection_handle));
}
-void Hid::GetPalmaOperationInfo(Kernel::HLERequestContext& ctx) {
+void Hid::GetPalmaOperationInfo(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
@@ -1974,7 +2011,7 @@ void Hid::GetPalmaOperationInfo(Kernel::HLERequestContext& ctx) {
rb.Push(static_cast<u64>(operation_type));
}
-void Hid::PlayPalmaActivity(Kernel::HLERequestContext& ctx) {
+void Hid::PlayPalmaActivity(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
const auto palma_activity{rp.Pop<u64>()};
@@ -1989,7 +2026,7 @@ void Hid::PlayPalmaActivity(Kernel::HLERequestContext& ctx) {
rb.Push(result);
}
-void Hid::SetPalmaFrModeType(Kernel::HLERequestContext& ctx) {
+void Hid::SetPalmaFrModeType(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
const auto fr_mode{rp.PopEnum<Controller_Palma::PalmaFrModeType>()};
@@ -2004,7 +2041,7 @@ void Hid::SetPalmaFrModeType(Kernel::HLERequestContext& ctx) {
rb.Push(result);
}
-void Hid::ReadPalmaStep(Kernel::HLERequestContext& ctx) {
+void Hid::ReadPalmaStep(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
@@ -2017,7 +2054,7 @@ void Hid::ReadPalmaStep(Kernel::HLERequestContext& ctx) {
rb.Push(result);
}
-void Hid::EnablePalmaStep(Kernel::HLERequestContext& ctx) {
+void Hid::EnablePalmaStep(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
bool is_enabled;
@@ -2039,7 +2076,7 @@ void Hid::EnablePalmaStep(Kernel::HLERequestContext& ctx) {
rb.Push(result);
}
-void Hid::ResetPalmaStep(Kernel::HLERequestContext& ctx) {
+void Hid::ResetPalmaStep(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
@@ -2052,21 +2089,21 @@ void Hid::ResetPalmaStep(Kernel::HLERequestContext& ctx) {
rb.Push(result);
}
-void Hid::ReadPalmaApplicationSection(Kernel::HLERequestContext& ctx) {
+void Hid::ReadPalmaApplicationSection(HLERequestContext& ctx) {
LOG_WARNING(Service_HID, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
-void Hid::WritePalmaApplicationSection(Kernel::HLERequestContext& ctx) {
+void Hid::WritePalmaApplicationSection(HLERequestContext& ctx) {
LOG_WARNING(Service_HID, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
-void Hid::ReadPalmaUniqueCode(Kernel::HLERequestContext& ctx) {
+void Hid::ReadPalmaUniqueCode(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
@@ -2079,7 +2116,7 @@ void Hid::ReadPalmaUniqueCode(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void Hid::SetPalmaUniqueCodeInvalid(Kernel::HLERequestContext& ctx) {
+void Hid::SetPalmaUniqueCodeInvalid(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
@@ -2092,19 +2129,19 @@ void Hid::SetPalmaUniqueCodeInvalid(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void Hid::WritePalmaActivityEntry(Kernel::HLERequestContext& ctx) {
+void Hid::WritePalmaActivityEntry(HLERequestContext& ctx) {
LOG_CRITICAL(Service_HID, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
-void Hid::WritePalmaRgbLedPatternEntry(Kernel::HLERequestContext& ctx) {
+void Hid::WritePalmaRgbLedPatternEntry(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
const auto unknown{rp.Pop<u64>()};
- const auto buffer = ctx.ReadBuffer();
+ [[maybe_unused]] const auto buffer = ctx.ReadBuffer();
LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}, unknown={}",
connection_handle.npad_id, unknown);
@@ -2116,7 +2153,7 @@ void Hid::WritePalmaRgbLedPatternEntry(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void Hid::WritePalmaWaveEntry(Kernel::HLERequestContext& ctx) {
+void Hid::WritePalmaWaveEntry(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
const auto wave_set{rp.PopEnum<Controller_Palma::PalmaWaveSet>()};
@@ -2127,8 +2164,8 @@ void Hid::WritePalmaWaveEntry(Kernel::HLERequestContext& ctx) {
ASSERT_MSG(t_mem_size == 0x3000, "t_mem_size is not 0x3000 bytes");
- auto t_mem =
- system.CurrentProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(t_mem_handle);
+ auto t_mem = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
+ t_mem_handle);
if (t_mem.IsNull()) {
LOG_ERROR(Service_HID, "t_mem is a nullptr for handle=0x{:08X}", t_mem_handle);
@@ -2145,14 +2182,13 @@ void Hid::WritePalmaWaveEntry(Kernel::HLERequestContext& ctx) {
connection_handle.npad_id, wave_set, unknown, t_mem_handle, t_mem_size, size);
applet_resource->GetController<Controller_Palma>(HidController::Palma)
- .WritePalmaWaveEntry(connection_handle, wave_set,
- system.Memory().GetPointer(t_mem->GetSourceAddress()), t_mem_size);
+ .WritePalmaWaveEntry(connection_handle, wave_set, t_mem->GetSourceAddress(), t_mem_size);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
-void Hid::SetPalmaDataBaseIdentificationVersion(Kernel::HLERequestContext& ctx) {
+void Hid::SetPalmaDataBaseIdentificationVersion(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
s32 database_id_version;
@@ -2174,7 +2210,7 @@ void Hid::SetPalmaDataBaseIdentificationVersion(Kernel::HLERequestContext& ctx)
rb.Push(ResultSuccess);
}
-void Hid::GetPalmaDataBaseIdentificationVersion(Kernel::HLERequestContext& ctx) {
+void Hid::GetPalmaDataBaseIdentificationVersion(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
@@ -2187,14 +2223,14 @@ void Hid::GetPalmaDataBaseIdentificationVersion(Kernel::HLERequestContext& ctx)
rb.Push(ResultSuccess);
}
-void Hid::SuspendPalmaFeature(Kernel::HLERequestContext& ctx) {
+void Hid::SuspendPalmaFeature(HLERequestContext& ctx) {
LOG_WARNING(Service_HID, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
-void Hid::GetPalmaOperationResult(Kernel::HLERequestContext& ctx) {
+void Hid::GetPalmaOperationResult(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
@@ -2207,21 +2243,21 @@ void Hid::GetPalmaOperationResult(Kernel::HLERequestContext& ctx) {
rb.Push(result);
}
-void Hid::ReadPalmaPlayLog(Kernel::HLERequestContext& ctx) {
+void Hid::ReadPalmaPlayLog(HLERequestContext& ctx) {
LOG_WARNING(Service_HID, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
-void Hid::ResetPalmaPlayLog(Kernel::HLERequestContext& ctx) {
+void Hid::ResetPalmaPlayLog(HLERequestContext& ctx) {
LOG_WARNING(Service_HID, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
-void Hid::SetIsPalmaAllConnectable(Kernel::HLERequestContext& ctx) {
+void Hid::SetIsPalmaAllConnectable(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
bool is_palma_all_connectable;
@@ -2243,14 +2279,14 @@ void Hid::SetIsPalmaAllConnectable(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void Hid::SetIsPalmaPairedConnectable(Kernel::HLERequestContext& ctx) {
+void Hid::SetIsPalmaPairedConnectable(HLERequestContext& ctx) {
LOG_WARNING(Service_HID, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
-void Hid::PairPalma(Kernel::HLERequestContext& ctx) {
+void Hid::PairPalma(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
@@ -2263,7 +2299,7 @@ void Hid::PairPalma(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void Hid::SetPalmaBoostMode(Kernel::HLERequestContext& ctx) {
+void Hid::SetPalmaBoostMode(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto palma_boost_mode{rp.Pop<bool>()};
@@ -2276,35 +2312,35 @@ void Hid::SetPalmaBoostMode(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void Hid::CancelWritePalmaWaveEntry(Kernel::HLERequestContext& ctx) {
+void Hid::CancelWritePalmaWaveEntry(HLERequestContext& ctx) {
LOG_WARNING(Service_HID, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
-void Hid::EnablePalmaBoostMode(Kernel::HLERequestContext& ctx) {
+void Hid::EnablePalmaBoostMode(HLERequestContext& ctx) {
LOG_WARNING(Service_HID, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
-void Hid::GetPalmaBluetoothAddress(Kernel::HLERequestContext& ctx) {
+void Hid::GetPalmaBluetoothAddress(HLERequestContext& ctx) {
LOG_WARNING(Service_HID, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
-void Hid::SetDisallowedPalmaConnection(Kernel::HLERequestContext& ctx) {
+void Hid::SetDisallowedPalmaConnection(HLERequestContext& ctx) {
LOG_WARNING(Service_HID, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
-void Hid::SetNpadCommunicationMode(Kernel::HLERequestContext& ctx) {
+void Hid::SetNpadCommunicationMode(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()};
const auto communication_mode{rp.PopEnum<Controller_NPad::NpadCommunicationMode>()};
@@ -2319,7 +2355,7 @@ void Hid::SetNpadCommunicationMode(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void Hid::GetNpadCommunicationMode(Kernel::HLERequestContext& ctx) {
+void Hid::GetNpadCommunicationMode(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
LOG_WARNING(Service_HID, "(STUBBED) called");
@@ -2330,7 +2366,7 @@ void Hid::GetNpadCommunicationMode(Kernel::HLERequestContext& ctx) {
.GetNpadCommunicationMode());
}
-void Hid::SetTouchScreenConfiguration(Kernel::HLERequestContext& ctx) {
+void Hid::SetTouchScreenConfiguration(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto touchscreen_mode{rp.PopRaw<Controller_Touchscreen::TouchScreenConfigurationForNx>()};
const auto applet_resource_user_id{rp.Pop<u64>()};
@@ -2342,7 +2378,7 @@ void Hid::SetTouchScreenConfiguration(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void Hid::IsFirmwareUpdateNeededForNotification(Kernel::HLERequestContext& ctx) {
+void Hid::IsFirmwareUpdateNeededForNotification(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
s32 unknown;
@@ -2380,6 +2416,8 @@ public:
{20, nullptr, "DeactivateMouse"},
{21, nullptr, "SetMouseAutoPilotState"},
{22, nullptr, "UnsetMouseAutoPilotState"},
+ {25, nullptr, "SetDebugMouseAutoPilotState"},
+ {26, nullptr, "UnsetDebugMouseAutoPilotState"},
{30, nullptr, "DeactivateKeyboard"},
{31, nullptr, "SetKeyboardAutoPilotState"},
{32, nullptr, "UnsetKeyboardAutoPilotState"},
@@ -2495,6 +2533,7 @@ public:
{2000, nullptr, "DeactivateDigitizer"},
{2001, nullptr, "SetDigitizerAutoPilotState"},
{2002, nullptr, "UnsetDigitizerAutoPilotState"},
+ {2002, nullptr, "ReloadFirmwareDebugSettings"},
};
// clang-format on
@@ -2713,7 +2752,7 @@ public:
}
private:
- void ApplyNpadSystemCommonPolicy(Kernel::HLERequestContext& ctx) {
+ void ApplyNpadSystemCommonPolicy(HLERequestContext& ctx) {
// We already do this for homebrew so we can just stub it out
LOG_WARNING(Service_HID, "called");
@@ -2721,7 +2760,7 @@ private:
rb.Push(ResultSuccess);
}
- void GetUniquePadsFromNpad(Kernel::HLERequestContext& ctx) {
+ void GetUniquePadsFromNpad(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto npad_id_type{rp.PopEnum<Core::HID::NpadIdType>()};
@@ -2734,30 +2773,20 @@ private:
}
};
-class HidTmp final : public ServiceFramework<HidTmp> {
-public:
- explicit HidTmp(Core::System& system_) : ServiceFramework{system_, "hid:tmp"} {
- // clang-format off
- static const FunctionInfo functions[] = {
- {0, nullptr, "GetConsoleSixAxisSensorCalibrationValues"},
- };
- // clang-format on
-
- RegisterHandlers(functions);
- }
-};
+void LoopProcess(Core::System& system) {
+ auto server_manager = std::make_unique<ServerManager>(system);
-void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
- std::make_shared<Hid>(system)->InstallAsService(service_manager);
- std::make_shared<HidBus>(system)->InstallAsService(service_manager);
- std::make_shared<HidDbg>(system)->InstallAsService(service_manager);
- std::make_shared<HidSys>(system)->InstallAsService(service_manager);
- std::make_shared<HidTmp>(system)->InstallAsService(service_manager);
+ server_manager->RegisterNamedService("hid", std::make_shared<Hid>(system));
+ server_manager->RegisterNamedService("hidbus", std::make_shared<HidBus>(system));
+ server_manager->RegisterNamedService("hid:dbg", std::make_shared<HidDbg>(system));
+ server_manager->RegisterNamedService("hid:sys", std::make_shared<HidSys>(system));
- std::make_shared<Service::IRS::IRS>(system)->InstallAsService(service_manager);
- std::make_shared<Service::IRS::IRS_SYS>(system)->InstallAsService(service_manager);
+ server_manager->RegisterNamedService("irs", std::make_shared<Service::IRS::IRS>(system));
+ server_manager->RegisterNamedService("irs:sys",
+ std::make_shared<Service::IRS::IRS_SYS>(system));
- std::make_shared<XCD_SYS>(system)->InstallAsService(service_manager);
+ server_manager->RegisterNamedService("xcd:sys", std::make_shared<XCD_SYS>(system));
+ system.RunServer(std::move(server_manager));
}
} // namespace Service::HID
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h
index b7c2a23ef..f247b83c2 100644
--- a/src/core/hle/service/hid/hid.h
+++ b/src/core/hle/service/hid/hid.h
@@ -33,6 +33,7 @@ enum class HidController : std::size_t {
NPad,
Gesture,
ConsoleSixAxisSensor,
+ DebugMouse,
Palma,
MaxControllers,
@@ -60,16 +61,22 @@ public:
private:
template <typename T>
void MakeController(HidController controller, u8* shared_memory) {
- controllers[static_cast<std::size_t>(controller)] =
- std::make_unique<T>(system.HIDCore(), shared_memory);
+ if constexpr (std::is_constructible_v<T, Core::System&, u8*>) {
+ controllers[static_cast<std::size_t>(controller)] =
+ std::make_unique<T>(system, shared_memory);
+ } else {
+ controllers[static_cast<std::size_t>(controller)] =
+ std::make_unique<T>(system.HIDCore(), shared_memory);
+ }
}
+
template <typename T>
void MakeControllerWithServiceContext(HidController controller, u8* shared_memory) {
controllers[static_cast<std::size_t>(controller)] =
std::make_unique<T>(system.HIDCore(), shared_memory, service_context);
}
- void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx);
+ void GetSharedMemoryHandle(HLERequestContext& ctx);
void UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
void UpdateNpad(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
void UpdateMouseKeyboard(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
@@ -94,122 +101,122 @@ public:
std::shared_ptr<IAppletResource> GetAppletResource();
private:
- void CreateAppletResource(Kernel::HLERequestContext& ctx);
- void ActivateDebugPad(Kernel::HLERequestContext& ctx);
- void ActivateTouchScreen(Kernel::HLERequestContext& ctx);
- void ActivateMouse(Kernel::HLERequestContext& ctx);
- void ActivateKeyboard(Kernel::HLERequestContext& ctx);
- void SendKeyboardLockKeyEvent(Kernel::HLERequestContext& ctx);
- void ActivateXpad(Kernel::HLERequestContext& ctx);
- void GetXpadIDs(Kernel::HLERequestContext& ctx);
- void ActivateSixAxisSensor(Kernel::HLERequestContext& ctx);
- void DeactivateSixAxisSensor(Kernel::HLERequestContext& ctx);
- void StartSixAxisSensor(Kernel::HLERequestContext& ctx);
- void StopSixAxisSensor(Kernel::HLERequestContext& ctx);
- void IsSixAxisSensorFusionEnabled(Kernel::HLERequestContext& ctx);
- void EnableSixAxisSensorFusion(Kernel::HLERequestContext& ctx);
- void SetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx);
- void GetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx);
- void ResetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx);
- void SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx);
- void GetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx);
- void ResetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx);
- void IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx);
- void IsFirmwareUpdateAvailableForSixAxisSensor(Kernel::HLERequestContext& ctx);
- void EnableSixAxisSensorUnalteredPassthrough(Kernel::HLERequestContext& ctx);
- void IsSixAxisSensorUnalteredPassthroughEnabled(Kernel::HLERequestContext& ctx);
- void LoadSixAxisSensorCalibrationParameter(Kernel::HLERequestContext& ctx);
- void GetSixAxisSensorIcInformation(Kernel::HLERequestContext& ctx);
- void ResetIsSixAxisSensorDeviceNewlyAssigned(Kernel::HLERequestContext& ctx);
- void ActivateGesture(Kernel::HLERequestContext& ctx);
- void SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx);
- void GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx);
- void SetSupportedNpadIdType(Kernel::HLERequestContext& ctx);
- void ActivateNpad(Kernel::HLERequestContext& ctx);
- void DeactivateNpad(Kernel::HLERequestContext& ctx);
- void AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx);
- void DisconnectNpad(Kernel::HLERequestContext& ctx);
- void GetPlayerLedPattern(Kernel::HLERequestContext& ctx);
- void ActivateNpadWithRevision(Kernel::HLERequestContext& ctx);
- void SetNpadJoyHoldType(Kernel::HLERequestContext& ctx);
- void GetNpadJoyHoldType(Kernel::HLERequestContext& ctx);
- void SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx);
- void SetNpadJoyAssignmentModeSingle(Kernel::HLERequestContext& ctx);
- void SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx);
- void MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx);
- void StartLrAssignmentMode(Kernel::HLERequestContext& ctx);
- void StopLrAssignmentMode(Kernel::HLERequestContext& ctx);
- void SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx);
- void GetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx);
- void SwapNpadAssignment(Kernel::HLERequestContext& ctx);
- void IsUnintendedHomeButtonInputProtectionEnabled(Kernel::HLERequestContext& ctx);
- void EnableUnintendedHomeButtonInputProtection(Kernel::HLERequestContext& ctx);
- void SetNpadAnalogStickUseCenterClamp(Kernel::HLERequestContext& ctx);
- void SetNpadCaptureButtonAssignment(Kernel::HLERequestContext& ctx);
- void ClearNpadCaptureButtonAssignment(Kernel::HLERequestContext& ctx);
- void GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx);
- void SendVibrationValue(Kernel::HLERequestContext& ctx);
- void GetActualVibrationValue(Kernel::HLERequestContext& ctx);
- void CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx);
- void PermitVibration(Kernel::HLERequestContext& ctx);
- void IsVibrationPermitted(Kernel::HLERequestContext& ctx);
- void SendVibrationValues(Kernel::HLERequestContext& ctx);
- void SendVibrationGcErmCommand(Kernel::HLERequestContext& ctx);
- void GetActualVibrationGcErmCommand(Kernel::HLERequestContext& ctx);
- void BeginPermitVibrationSession(Kernel::HLERequestContext& ctx);
- void EndPermitVibrationSession(Kernel::HLERequestContext& ctx);
- void IsVibrationDeviceMounted(Kernel::HLERequestContext& ctx);
- void ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx);
- void StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx);
- void StopConsoleSixAxisSensor(Kernel::HLERequestContext& ctx);
- void ActivateSevenSixAxisSensor(Kernel::HLERequestContext& ctx);
- void StartSevenSixAxisSensor(Kernel::HLERequestContext& ctx);
- void StopSevenSixAxisSensor(Kernel::HLERequestContext& ctx);
- void InitializeSevenSixAxisSensor(Kernel::HLERequestContext& ctx);
- void FinalizeSevenSixAxisSensor(Kernel::HLERequestContext& ctx);
- void ResetSevenSixAxisSensorTimestamp(Kernel::HLERequestContext& ctx);
- void IsUsbFullKeyControllerEnabled(Kernel::HLERequestContext& ctx);
- void GetPalmaConnectionHandle(Kernel::HLERequestContext& ctx);
- void InitializePalma(Kernel::HLERequestContext& ctx);
- void AcquirePalmaOperationCompleteEvent(Kernel::HLERequestContext& ctx);
- void GetPalmaOperationInfo(Kernel::HLERequestContext& ctx);
- void PlayPalmaActivity(Kernel::HLERequestContext& ctx);
- void SetPalmaFrModeType(Kernel::HLERequestContext& ctx);
- void ReadPalmaStep(Kernel::HLERequestContext& ctx);
- void EnablePalmaStep(Kernel::HLERequestContext& ctx);
- void ResetPalmaStep(Kernel::HLERequestContext& ctx);
- void ReadPalmaApplicationSection(Kernel::HLERequestContext& ctx);
- void WritePalmaApplicationSection(Kernel::HLERequestContext& ctx);
- void ReadPalmaUniqueCode(Kernel::HLERequestContext& ctx);
- void SetPalmaUniqueCodeInvalid(Kernel::HLERequestContext& ctx);
- void WritePalmaActivityEntry(Kernel::HLERequestContext& ctx);
- void WritePalmaRgbLedPatternEntry(Kernel::HLERequestContext& ctx);
- void WritePalmaWaveEntry(Kernel::HLERequestContext& ctx);
- void SetPalmaDataBaseIdentificationVersion(Kernel::HLERequestContext& ctx);
- void GetPalmaDataBaseIdentificationVersion(Kernel::HLERequestContext& ctx);
- void SuspendPalmaFeature(Kernel::HLERequestContext& ctx);
- void GetPalmaOperationResult(Kernel::HLERequestContext& ctx);
- void ReadPalmaPlayLog(Kernel::HLERequestContext& ctx);
- void ResetPalmaPlayLog(Kernel::HLERequestContext& ctx);
- void SetIsPalmaAllConnectable(Kernel::HLERequestContext& ctx);
- void SetIsPalmaPairedConnectable(Kernel::HLERequestContext& ctx);
- void PairPalma(Kernel::HLERequestContext& ctx);
- void SetPalmaBoostMode(Kernel::HLERequestContext& ctx);
- void CancelWritePalmaWaveEntry(Kernel::HLERequestContext& ctx);
- void EnablePalmaBoostMode(Kernel::HLERequestContext& ctx);
- void GetPalmaBluetoothAddress(Kernel::HLERequestContext& ctx);
- void SetDisallowedPalmaConnection(Kernel::HLERequestContext& ctx);
- void SetNpadCommunicationMode(Kernel::HLERequestContext& ctx);
- void GetNpadCommunicationMode(Kernel::HLERequestContext& ctx);
- void SetTouchScreenConfiguration(Kernel::HLERequestContext& ctx);
- void IsFirmwareUpdateNeededForNotification(Kernel::HLERequestContext& ctx);
+ void CreateAppletResource(HLERequestContext& ctx);
+ void ActivateDebugPad(HLERequestContext& ctx);
+ void ActivateTouchScreen(HLERequestContext& ctx);
+ void ActivateMouse(HLERequestContext& ctx);
+ void ActivateKeyboard(HLERequestContext& ctx);
+ void SendKeyboardLockKeyEvent(HLERequestContext& ctx);
+ void ActivateXpad(HLERequestContext& ctx);
+ void GetXpadIDs(HLERequestContext& ctx);
+ void ActivateSixAxisSensor(HLERequestContext& ctx);
+ void DeactivateSixAxisSensor(HLERequestContext& ctx);
+ void StartSixAxisSensor(HLERequestContext& ctx);
+ void StopSixAxisSensor(HLERequestContext& ctx);
+ void IsSixAxisSensorFusionEnabled(HLERequestContext& ctx);
+ void EnableSixAxisSensorFusion(HLERequestContext& ctx);
+ void SetSixAxisSensorFusionParameters(HLERequestContext& ctx);
+ void GetSixAxisSensorFusionParameters(HLERequestContext& ctx);
+ void ResetSixAxisSensorFusionParameters(HLERequestContext& ctx);
+ void SetGyroscopeZeroDriftMode(HLERequestContext& ctx);
+ void GetGyroscopeZeroDriftMode(HLERequestContext& ctx);
+ void ResetGyroscopeZeroDriftMode(HLERequestContext& ctx);
+ void IsSixAxisSensorAtRest(HLERequestContext& ctx);
+ void IsFirmwareUpdateAvailableForSixAxisSensor(HLERequestContext& ctx);
+ void EnableSixAxisSensorUnalteredPassthrough(HLERequestContext& ctx);
+ void IsSixAxisSensorUnalteredPassthroughEnabled(HLERequestContext& ctx);
+ void LoadSixAxisSensorCalibrationParameter(HLERequestContext& ctx);
+ void GetSixAxisSensorIcInformation(HLERequestContext& ctx);
+ void ResetIsSixAxisSensorDeviceNewlyAssigned(HLERequestContext& ctx);
+ void ActivateGesture(HLERequestContext& ctx);
+ void SetSupportedNpadStyleSet(HLERequestContext& ctx);
+ void GetSupportedNpadStyleSet(HLERequestContext& ctx);
+ void SetSupportedNpadIdType(HLERequestContext& ctx);
+ void ActivateNpad(HLERequestContext& ctx);
+ void DeactivateNpad(HLERequestContext& ctx);
+ void AcquireNpadStyleSetUpdateEventHandle(HLERequestContext& ctx);
+ void DisconnectNpad(HLERequestContext& ctx);
+ void GetPlayerLedPattern(HLERequestContext& ctx);
+ void ActivateNpadWithRevision(HLERequestContext& ctx);
+ void SetNpadJoyHoldType(HLERequestContext& ctx);
+ void GetNpadJoyHoldType(HLERequestContext& ctx);
+ void SetNpadJoyAssignmentModeSingleByDefault(HLERequestContext& ctx);
+ void SetNpadJoyAssignmentModeSingle(HLERequestContext& ctx);
+ void SetNpadJoyAssignmentModeDual(HLERequestContext& ctx);
+ void MergeSingleJoyAsDualJoy(HLERequestContext& ctx);
+ void StartLrAssignmentMode(HLERequestContext& ctx);
+ void StopLrAssignmentMode(HLERequestContext& ctx);
+ void SetNpadHandheldActivationMode(HLERequestContext& ctx);
+ void GetNpadHandheldActivationMode(HLERequestContext& ctx);
+ void SwapNpadAssignment(HLERequestContext& ctx);
+ void IsUnintendedHomeButtonInputProtectionEnabled(HLERequestContext& ctx);
+ void EnableUnintendedHomeButtonInputProtection(HLERequestContext& ctx);
+ void SetNpadJoyAssignmentModeSingleWithDestination(HLERequestContext& ctx);
+ void SetNpadAnalogStickUseCenterClamp(HLERequestContext& ctx);
+ void SetNpadCaptureButtonAssignment(HLERequestContext& ctx);
+ void ClearNpadCaptureButtonAssignment(HLERequestContext& ctx);
+ void GetVibrationDeviceInfo(HLERequestContext& ctx);
+ void SendVibrationValue(HLERequestContext& ctx);
+ void GetActualVibrationValue(HLERequestContext& ctx);
+ void CreateActiveVibrationDeviceList(HLERequestContext& ctx);
+ void PermitVibration(HLERequestContext& ctx);
+ void IsVibrationPermitted(HLERequestContext& ctx);
+ void SendVibrationValues(HLERequestContext& ctx);
+ void SendVibrationGcErmCommand(HLERequestContext& ctx);
+ void GetActualVibrationGcErmCommand(HLERequestContext& ctx);
+ void BeginPermitVibrationSession(HLERequestContext& ctx);
+ void EndPermitVibrationSession(HLERequestContext& ctx);
+ void IsVibrationDeviceMounted(HLERequestContext& ctx);
+ void ActivateConsoleSixAxisSensor(HLERequestContext& ctx);
+ void StartConsoleSixAxisSensor(HLERequestContext& ctx);
+ void StopConsoleSixAxisSensor(HLERequestContext& ctx);
+ void ActivateSevenSixAxisSensor(HLERequestContext& ctx);
+ void StartSevenSixAxisSensor(HLERequestContext& ctx);
+ void StopSevenSixAxisSensor(HLERequestContext& ctx);
+ void InitializeSevenSixAxisSensor(HLERequestContext& ctx);
+ void FinalizeSevenSixAxisSensor(HLERequestContext& ctx);
+ void ResetSevenSixAxisSensorTimestamp(HLERequestContext& ctx);
+ void IsUsbFullKeyControllerEnabled(HLERequestContext& ctx);
+ void GetPalmaConnectionHandle(HLERequestContext& ctx);
+ void InitializePalma(HLERequestContext& ctx);
+ void AcquirePalmaOperationCompleteEvent(HLERequestContext& ctx);
+ void GetPalmaOperationInfo(HLERequestContext& ctx);
+ void PlayPalmaActivity(HLERequestContext& ctx);
+ void SetPalmaFrModeType(HLERequestContext& ctx);
+ void ReadPalmaStep(HLERequestContext& ctx);
+ void EnablePalmaStep(HLERequestContext& ctx);
+ void ResetPalmaStep(HLERequestContext& ctx);
+ void ReadPalmaApplicationSection(HLERequestContext& ctx);
+ void WritePalmaApplicationSection(HLERequestContext& ctx);
+ void ReadPalmaUniqueCode(HLERequestContext& ctx);
+ void SetPalmaUniqueCodeInvalid(HLERequestContext& ctx);
+ void WritePalmaActivityEntry(HLERequestContext& ctx);
+ void WritePalmaRgbLedPatternEntry(HLERequestContext& ctx);
+ void WritePalmaWaveEntry(HLERequestContext& ctx);
+ void SetPalmaDataBaseIdentificationVersion(HLERequestContext& ctx);
+ void GetPalmaDataBaseIdentificationVersion(HLERequestContext& ctx);
+ void SuspendPalmaFeature(HLERequestContext& ctx);
+ void GetPalmaOperationResult(HLERequestContext& ctx);
+ void ReadPalmaPlayLog(HLERequestContext& ctx);
+ void ResetPalmaPlayLog(HLERequestContext& ctx);
+ void SetIsPalmaAllConnectable(HLERequestContext& ctx);
+ void SetIsPalmaPairedConnectable(HLERequestContext& ctx);
+ void PairPalma(HLERequestContext& ctx);
+ void SetPalmaBoostMode(HLERequestContext& ctx);
+ void CancelWritePalmaWaveEntry(HLERequestContext& ctx);
+ void EnablePalmaBoostMode(HLERequestContext& ctx);
+ void GetPalmaBluetoothAddress(HLERequestContext& ctx);
+ void SetDisallowedPalmaConnection(HLERequestContext& ctx);
+ void SetNpadCommunicationMode(HLERequestContext& ctx);
+ void GetNpadCommunicationMode(HLERequestContext& ctx);
+ void SetTouchScreenConfiguration(HLERequestContext& ctx);
+ void IsFirmwareUpdateNeededForNotification(HLERequestContext& ctx);
std::shared_ptr<IAppletResource> applet_resource;
KernelHelpers::ServiceContext service_context;
};
-/// Registers all HID services with the specified service manager.
-void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system);
+void LoopProcess(Core::System& system);
} // namespace Service::HID
diff --git a/src/core/hle/service/hid/hidbus.cpp b/src/core/hle/service/hid/hidbus.cpp
index e5e50845f..80aac221b 100644
--- a/src/core/hle/service/hid/hidbus.cpp
+++ b/src/core/hle/service/hid/hidbus.cpp
@@ -5,9 +5,7 @@
#include "common/settings.h"
#include "core/core.h"
#include "core/core_timing.h"
-#include "core/core_timing_util.h"
#include "core/hid/hid_types.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_shared_memory.h"
@@ -16,6 +14,7 @@
#include "core/hle/service/hid/hidbus/ringcon.h"
#include "core/hle/service/hid/hidbus/starlink.h"
#include "core/hle/service/hid/hidbus/stubbed.h"
+#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/service.h"
#include "core/memory.h"
@@ -91,7 +90,7 @@ std::optional<std::size_t> HidBus::GetDeviceIndexFromHandle(BusHandle handle) co
if (handle.abstracted_pad_id == device_handle.abstracted_pad_id &&
handle.internal_index == device_handle.internal_index &&
handle.player_number == device_handle.player_number &&
- handle.bus_type == device_handle.bus_type &&
+ handle.bus_type_id == device_handle.bus_type_id &&
handle.is_valid == device_handle.is_valid) {
return i;
}
@@ -99,7 +98,7 @@ std::optional<std::size_t> HidBus::GetDeviceIndexFromHandle(BusHandle handle) co
return std::nullopt;
}
-void HidBus::GetBusHandle(Kernel::HLERequestContext& ctx) {
+void HidBus::GetBusHandle(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
Core::HID::NpadIdType npad_id;
@@ -123,7 +122,7 @@ void HidBus::GetBusHandle(Kernel::HLERequestContext& ctx) {
continue;
}
if (static_cast<Core::HID::NpadIdType>(handle.player_number) == parameters.npad_id &&
- handle.bus_type == parameters.bus_type) {
+ handle.bus_type_id == static_cast<u8>(parameters.bus_type)) {
is_handle_found = true;
handle_index = i;
break;
@@ -140,7 +139,7 @@ void HidBus::GetBusHandle(Kernel::HLERequestContext& ctx) {
.abstracted_pad_id = static_cast<u8>(i),
.internal_index = static_cast<u8>(i),
.player_number = static_cast<u8>(parameters.npad_id),
- .bus_type = parameters.bus_type,
+ .bus_type_id = static_cast<u8>(parameters.bus_type),
.is_valid = true,
};
handle_index = i;
@@ -165,14 +164,14 @@ void HidBus::GetBusHandle(Kernel::HLERequestContext& ctx) {
rb.PushRaw(out_data);
}
-void HidBus::IsExternalDeviceConnected(Kernel::HLERequestContext& ctx) {
+void HidBus::IsExternalDeviceConnected(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto bus_handle_{rp.PopRaw<BusHandle>()};
LOG_INFO(Service_HID,
"Called, abstracted_pad_id={}, bus_type={}, internal_index={}, "
"player_number={}, is_valid={}",
- bus_handle_.abstracted_pad_id, bus_handle_.bus_type, bus_handle_.internal_index,
+ bus_handle_.abstracted_pad_id, bus_handle_.bus_type_id, bus_handle_.internal_index,
bus_handle_.player_number, bus_handle_.is_valid);
const auto device_index = GetDeviceIndexFromHandle(bus_handle_);
@@ -193,7 +192,7 @@ void HidBus::IsExternalDeviceConnected(Kernel::HLERequestContext& ctx) {
return;
}
-void HidBus::Initialize(Kernel::HLERequestContext& ctx) {
+void HidBus::Initialize(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto bus_handle_{rp.PopRaw<BusHandle>()};
const auto applet_resource_user_id{rp.Pop<u64>()};
@@ -201,7 +200,7 @@ void HidBus::Initialize(Kernel::HLERequestContext& ctx) {
LOG_INFO(Service_HID,
"called, abstracted_pad_id={} bus_type={} internal_index={} "
"player_number={} is_valid={}, applet_resource_user_id={}",
- bus_handle_.abstracted_pad_id, bus_handle_.bus_type, bus_handle_.internal_index,
+ bus_handle_.abstracted_pad_id, bus_handle_.bus_type_id, bus_handle_.internal_index,
bus_handle_.player_number, bus_handle_.is_valid, applet_resource_user_id);
is_hidbus_enabled = true;
@@ -245,7 +244,7 @@ void HidBus::Initialize(Kernel::HLERequestContext& ctx) {
return;
}
-void HidBus::Finalize(Kernel::HLERequestContext& ctx) {
+void HidBus::Finalize(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto bus_handle_{rp.PopRaw<BusHandle>()};
const auto applet_resource_user_id{rp.Pop<u64>()};
@@ -253,7 +252,7 @@ void HidBus::Finalize(Kernel::HLERequestContext& ctx) {
LOG_INFO(Service_HID,
"called, abstracted_pad_id={}, bus_type={}, internal_index={}, "
"player_number={}, is_valid={}, applet_resource_user_id={}",
- bus_handle_.abstracted_pad_id, bus_handle_.bus_type, bus_handle_.internal_index,
+ bus_handle_.abstracted_pad_id, bus_handle_.bus_type_id, bus_handle_.internal_index,
bus_handle_.player_number, bus_handle_.is_valid, applet_resource_user_id);
const auto device_index = GetDeviceIndexFromHandle(bus_handle_);
@@ -284,7 +283,7 @@ void HidBus::Finalize(Kernel::HLERequestContext& ctx) {
return;
}
-void HidBus::EnableExternalDevice(Kernel::HLERequestContext& ctx) {
+void HidBus::EnableExternalDevice(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
bool enable;
@@ -297,13 +296,13 @@ void HidBus::EnableExternalDevice(Kernel::HLERequestContext& ctx) {
const auto parameters{rp.PopRaw<Parameters>()};
- LOG_INFO(Service_HID,
- "called, enable={}, abstracted_pad_id={}, bus_type={}, internal_index={}, "
- "player_number={}, is_valid={}, inval={}, applet_resource_user_id{}",
- parameters.enable, parameters.bus_handle.abstracted_pad_id,
- parameters.bus_handle.bus_type, parameters.bus_handle.internal_index,
- parameters.bus_handle.player_number, parameters.bus_handle.is_valid, parameters.inval,
- parameters.applet_resource_user_id);
+ LOG_DEBUG(Service_HID,
+ "called, enable={}, abstracted_pad_id={}, bus_type={}, internal_index={}, "
+ "player_number={}, is_valid={}, inval={}, applet_resource_user_id{}",
+ parameters.enable, parameters.bus_handle.abstracted_pad_id,
+ parameters.bus_handle.bus_type_id, parameters.bus_handle.internal_index,
+ parameters.bus_handle.player_number, parameters.bus_handle.is_valid, parameters.inval,
+ parameters.applet_resource_user_id);
const auto device_index = GetDeviceIndexFromHandle(parameters.bus_handle);
@@ -322,15 +321,15 @@ void HidBus::EnableExternalDevice(Kernel::HLERequestContext& ctx) {
return;
}
-void HidBus::GetExternalDeviceId(Kernel::HLERequestContext& ctx) {
+void HidBus::GetExternalDeviceId(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto bus_handle_{rp.PopRaw<BusHandle>()};
- LOG_INFO(Service_HID,
- "called, abstracted_pad_id={}, bus_type={}, internal_index={}, player_number={}, "
- "is_valid={}",
- bus_handle_.abstracted_pad_id, bus_handle_.bus_type, bus_handle_.internal_index,
- bus_handle_.player_number, bus_handle_.is_valid);
+ LOG_DEBUG(Service_HID,
+ "called, abstracted_pad_id={}, bus_type={}, internal_index={}, player_number={}, "
+ "is_valid={}",
+ bus_handle_.abstracted_pad_id, bus_handle_.bus_type_id, bus_handle_.internal_index,
+ bus_handle_.player_number, bus_handle_.is_valid);
const auto device_index = GetDeviceIndexFromHandle(bus_handle_);
@@ -349,7 +348,7 @@ void HidBus::GetExternalDeviceId(Kernel::HLERequestContext& ctx) {
return;
}
-void HidBus::SendCommandAsync(Kernel::HLERequestContext& ctx) {
+void HidBus::SendCommandAsync(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto data = ctx.ReadBuffer();
const auto bus_handle_{rp.PopRaw<BusHandle>()};
@@ -357,7 +356,7 @@ void HidBus::SendCommandAsync(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_HID,
"called, data_size={}, abstracted_pad_id={}, bus_type={}, internal_index={}, "
"player_number={}, is_valid={}",
- data.size(), bus_handle_.abstracted_pad_id, bus_handle_.bus_type,
+ data.size(), bus_handle_.abstracted_pad_id, bus_handle_.bus_type_id,
bus_handle_.internal_index, bus_handle_.player_number, bus_handle_.is_valid);
const auto device_index = GetDeviceIndexFromHandle(bus_handle_);
@@ -377,14 +376,14 @@ void HidBus::SendCommandAsync(Kernel::HLERequestContext& ctx) {
return;
};
-void HidBus::GetSendCommandAsynceResult(Kernel::HLERequestContext& ctx) {
+void HidBus::GetSendCommandAsynceResult(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto bus_handle_{rp.PopRaw<BusHandle>()};
LOG_DEBUG(Service_HID,
"called, abstracted_pad_id={}, bus_type={}, internal_index={}, player_number={}, "
"is_valid={}",
- bus_handle_.abstracted_pad_id, bus_handle_.bus_type, bus_handle_.internal_index,
+ bus_handle_.abstracted_pad_id, bus_handle_.bus_type_id, bus_handle_.internal_index,
bus_handle_.player_number, bus_handle_.is_valid);
const auto device_index = GetDeviceIndexFromHandle(bus_handle_);
@@ -406,14 +405,14 @@ void HidBus::GetSendCommandAsynceResult(Kernel::HLERequestContext& ctx) {
return;
};
-void HidBus::SetEventForSendCommandAsycResult(Kernel::HLERequestContext& ctx) {
+void HidBus::SetEventForSendCommandAsycResult(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto bus_handle_{rp.PopRaw<BusHandle>()};
LOG_INFO(Service_HID,
"called, abstracted_pad_id={}, bus_type={}, internal_index={}, player_number={}, "
"is_valid={}",
- bus_handle_.abstracted_pad_id, bus_handle_.bus_type, bus_handle_.internal_index,
+ bus_handle_.abstracted_pad_id, bus_handle_.bus_type_id, bus_handle_.internal_index,
bus_handle_.player_number, bus_handle_.is_valid);
const auto device_index = GetDeviceIndexFromHandle(bus_handle_);
@@ -432,7 +431,7 @@ void HidBus::SetEventForSendCommandAsycResult(Kernel::HLERequestContext& ctx) {
return;
};
-void HidBus::GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) {
+void HidBus::GetSharedMemoryHandle(HLERequestContext& ctx) {
LOG_DEBUG(Service_HID, "called");
IPC::ResponseBuilder rb{ctx, 2, 1};
@@ -440,7 +439,7 @@ void HidBus::GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) {
rb.PushCopyObjects(&system.Kernel().GetHidBusSharedMem());
}
-void HidBus::EnableJoyPollingReceiveMode(Kernel::HLERequestContext& ctx) {
+void HidBus::EnableJoyPollingReceiveMode(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto t_mem_size{rp.Pop<u32>()};
const auto t_mem_handle{ctx.GetCopyHandle(0)};
@@ -449,8 +448,8 @@ void HidBus::EnableJoyPollingReceiveMode(Kernel::HLERequestContext& ctx) {
ASSERT_MSG(t_mem_size == 0x1000, "t_mem_size is not 0x1000 bytes");
- auto t_mem =
- system.CurrentProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(t_mem_handle);
+ auto t_mem = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
+ t_mem_handle);
if (t_mem.IsNull()) {
LOG_ERROR(Service_HID, "t_mem is a nullptr for handle=0x{:08X}", t_mem_handle);
@@ -464,7 +463,7 @@ void HidBus::EnableJoyPollingReceiveMode(Kernel::HLERequestContext& ctx) {
LOG_INFO(Service_HID,
"called, t_mem_handle=0x{:08X}, polling_mode={}, abstracted_pad_id={}, bus_type={}, "
"internal_index={}, player_number={}, is_valid={}",
- t_mem_handle, polling_mode_, bus_handle_.abstracted_pad_id, bus_handle_.bus_type,
+ t_mem_handle, polling_mode_, bus_handle_.abstracted_pad_id, bus_handle_.bus_type_id,
bus_handle_.internal_index, bus_handle_.player_number, bus_handle_.is_valid);
const auto device_index = GetDeviceIndexFromHandle(bus_handle_);
@@ -472,7 +471,7 @@ void HidBus::EnableJoyPollingReceiveMode(Kernel::HLERequestContext& ctx) {
if (device_index) {
auto& device = devices[device_index.value()].device;
device->SetPollingMode(polling_mode_);
- device->SetTransferMemoryPointer(system.Memory().GetPointer(t_mem->GetSourceAddress()));
+ device->SetTransferMemoryAddress(t_mem->GetSourceAddress());
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
@@ -485,14 +484,14 @@ void HidBus::EnableJoyPollingReceiveMode(Kernel::HLERequestContext& ctx) {
return;
}
-void HidBus::DisableJoyPollingReceiveMode(Kernel::HLERequestContext& ctx) {
+void HidBus::DisableJoyPollingReceiveMode(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto bus_handle_{rp.PopRaw<BusHandle>()};
LOG_INFO(Service_HID,
"called, abstracted_pad_id={}, bus_type={}, internal_index={}, player_number={}, "
"is_valid={}",
- bus_handle_.abstracted_pad_id, bus_handle_.bus_type, bus_handle_.internal_index,
+ bus_handle_.abstracted_pad_id, bus_handle_.bus_type_id, bus_handle_.internal_index,
bus_handle_.player_number, bus_handle_.is_valid);
const auto device_index = GetDeviceIndexFromHandle(bus_handle_);
@@ -512,7 +511,7 @@ void HidBus::DisableJoyPollingReceiveMode(Kernel::HLERequestContext& ctx) {
return;
}
-void HidBus::SetStatusManagerType(Kernel::HLERequestContext& ctx) {
+void HidBus::SetStatusManagerType(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto manager_type{rp.PopEnum<StatusManagerType>()};
diff --git a/src/core/hle/service/hid/hidbus.h b/src/core/hle/service/hid/hidbus.h
index 8c687f678..c29b5e882 100644
--- a/src/core/hle/service/hid/hidbus.h
+++ b/src/core/hle/service/hid/hidbus.h
@@ -41,7 +41,7 @@ private:
};
// This is nn::hidbus::BusType
- enum class BusType : u8 {
+ enum class BusType : u32 {
LeftJoyRail,
RightJoyRail,
InternalBus, // Lark microphone
@@ -54,7 +54,7 @@ private:
u32 abstracted_pad_id;
u8 internal_index;
u8 player_number;
- BusType bus_type;
+ u8 bus_type_id;
bool is_valid;
};
static_assert(sizeof(BusHandle) == 0x8, "BusHandle is an invalid size");
@@ -94,19 +94,19 @@ private:
std::unique_ptr<HidbusBase> device{nullptr};
};
- void GetBusHandle(Kernel::HLERequestContext& ctx);
- void IsExternalDeviceConnected(Kernel::HLERequestContext& ctx);
- void Initialize(Kernel::HLERequestContext& ctx);
- void Finalize(Kernel::HLERequestContext& ctx);
- void EnableExternalDevice(Kernel::HLERequestContext& ctx);
- void GetExternalDeviceId(Kernel::HLERequestContext& ctx);
- void SendCommandAsync(Kernel::HLERequestContext& ctx);
- void GetSendCommandAsynceResult(Kernel::HLERequestContext& ctx);
- void SetEventForSendCommandAsycResult(Kernel::HLERequestContext& ctx);
- void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx);
- void EnableJoyPollingReceiveMode(Kernel::HLERequestContext& ctx);
- void DisableJoyPollingReceiveMode(Kernel::HLERequestContext& ctx);
- void SetStatusManagerType(Kernel::HLERequestContext& ctx);
+ void GetBusHandle(HLERequestContext& ctx);
+ void IsExternalDeviceConnected(HLERequestContext& ctx);
+ void Initialize(HLERequestContext& ctx);
+ void Finalize(HLERequestContext& ctx);
+ void EnableExternalDevice(HLERequestContext& ctx);
+ void GetExternalDeviceId(HLERequestContext& ctx);
+ void SendCommandAsync(HLERequestContext& ctx);
+ void GetSendCommandAsynceResult(HLERequestContext& ctx);
+ void SetEventForSendCommandAsycResult(HLERequestContext& ctx);
+ void GetSharedMemoryHandle(HLERequestContext& ctx);
+ void EnableJoyPollingReceiveMode(HLERequestContext& ctx);
+ void DisableJoyPollingReceiveMode(HLERequestContext& ctx);
+ void SetStatusManagerType(HLERequestContext& ctx);
void UpdateHidbus(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
std::optional<std::size_t> GetDeviceIndexFromHandle(BusHandle handle) const;
@@ -115,8 +115,7 @@ private:
void MakeDevice(BusHandle handle) {
const auto device_index = GetDeviceIndexFromHandle(handle);
if (device_index) {
- devices[device_index.value()].device =
- std::make_unique<T>(system.HIDCore(), service_context);
+ devices[device_index.value()].device = std::make_unique<T>(system, service_context);
}
}
diff --git a/src/core/hle/service/hid/hidbus/hidbus_base.cpp b/src/core/hle/service/hid/hidbus/hidbus_base.cpp
index b569b3c20..ee522c36e 100644
--- a/src/core/hle/service/hid/hidbus/hidbus_base.cpp
+++ b/src/core/hle/service/hid/hidbus/hidbus_base.cpp
@@ -9,8 +9,8 @@
namespace Service::HID {
-HidbusBase::HidbusBase(KernelHelpers::ServiceContext& service_context_)
- : service_context(service_context_) {
+HidbusBase::HidbusBase(Core::System& system_, KernelHelpers::ServiceContext& service_context_)
+ : system(system_), service_context(service_context_) {
send_command_async_event = service_context.CreateEvent("hidbus:SendCommandAsyncEvent");
}
HidbusBase::~HidbusBase() = default;
@@ -59,8 +59,7 @@ void HidbusBase::DisablePollingMode() {
polling_mode_enabled = false;
}
-void HidbusBase::SetTransferMemoryPointer(u8* t_mem) {
- is_transfer_memory_set = true;
+void HidbusBase::SetTransferMemoryAddress(Common::ProcessAddress t_mem) {
transfer_memory = t_mem;
}
diff --git a/src/core/hle/service/hid/hidbus/hidbus_base.h b/src/core/hle/service/hid/hidbus/hidbus_base.h
index d3960f506..ec41684e1 100644
--- a/src/core/hle/service/hid/hidbus/hidbus_base.h
+++ b/src/core/hle/service/hid/hidbus/hidbus_base.h
@@ -4,9 +4,14 @@
#pragma once
#include <array>
-#include "common/common_types.h"
+#include <span>
+#include "common/typed_address.h"
#include "core/hle/result.h"
+namespace Core {
+class System;
+}
+
namespace Kernel {
class KEvent;
class KReadableEvent;
@@ -105,7 +110,7 @@ static_assert(sizeof(ButtonOnlyPollingDataAccessor) == 0x2F0,
class HidbusBase {
public:
- explicit HidbusBase(KernelHelpers::ServiceContext& service_context_);
+ explicit HidbusBase(Core::System& system_, KernelHelpers::ServiceContext& service_context_);
virtual ~HidbusBase();
void ActivateDevice();
@@ -133,7 +138,7 @@ public:
void DisablePollingMode();
// Called on EnableJoyPollingReceiveMode
- void SetTransferMemoryPointer(u8* t_mem);
+ void SetTransferMemoryAddress(Common::ProcessAddress t_mem);
Kernel::KReadableEvent& GetSendCommandAsycEvent() const;
@@ -150,7 +155,7 @@ public:
}
// Assigns a command from data
- virtual bool SetCommand(const std::vector<u8>& data) {
+ virtual bool SetCommand(std::span<const u8> data) {
return {};
}
@@ -169,9 +174,9 @@ protected:
JoyEnableSixAxisDataAccessor enable_sixaxis_data{};
ButtonOnlyPollingDataAccessor button_only_data{};
- u8* transfer_memory{nullptr};
- bool is_transfer_memory_set{};
+ Common::ProcessAddress transfer_memory{};
+ Core::System& system;
Kernel::KEvent* send_command_async_event;
KernelHelpers::ServiceContext& service_context;
};
diff --git a/src/core/hle/service/hid/hidbus/ringcon.cpp b/src/core/hle/service/hid/hidbus/ringcon.cpp
index 57f1a2a26..378108012 100644
--- a/src/core/hle/service/hid/hidbus/ringcon.cpp
+++ b/src/core/hle/service/hid/hidbus/ringcon.cpp
@@ -1,27 +1,33 @@
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
-#include "core/hid/emulated_devices.h"
+#include "core/core.h"
+#include "core/hid/emulated_controller.h"
#include "core/hid/hid_core.h"
#include "core/hle/kernel/k_event.h"
#include "core/hle/kernel/k_readable_event.h"
#include "core/hle/service/hid/hidbus/ringcon.h"
+#include "core/memory.h"
namespace Service::HID {
-RingController::RingController(Core::HID::HIDCore& hid_core_,
+RingController::RingController(Core::System& system_,
KernelHelpers::ServiceContext& service_context_)
- : HidbusBase(service_context_) {
- input = hid_core_.GetEmulatedDevices();
+ : HidbusBase(system_, service_context_) {
+ input = system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1);
}
RingController::~RingController() = default;
void RingController::OnInit() {
+ input->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
+ Common::Input::PollingMode::Ring);
return;
}
void RingController::OnRelease() {
+ input->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
+ Common::Input::PollingMode::Active);
return;
};
@@ -34,7 +40,7 @@ void RingController::OnUpdate() {
return;
}
- if (!polling_mode_enabled || !is_transfer_memory_set) {
+ if (!polling_mode_enabled || transfer_memory == 0) {
return;
}
@@ -58,7 +64,8 @@ void RingController::OnUpdate() {
curr_entry.polling_data.out_size = sizeof(ringcon_value);
std::memcpy(curr_entry.polling_data.data.data(), &ringcon_value, sizeof(ringcon_value));
- std::memcpy(transfer_memory, &enable_sixaxis_data, sizeof(enable_sixaxis_data));
+ system.ApplicationMemory().WriteBlock(transfer_memory, &enable_sixaxis_data,
+ sizeof(enable_sixaxis_data));
break;
}
default:
@@ -112,7 +119,7 @@ std::vector<u8> RingController::GetReply() const {
}
}
-bool RingController::SetCommand(const std::vector<u8>& data) {
+bool RingController::SetCommand(std::span<const u8> data) {
if (data.size() < 4) {
LOG_ERROR(Service_HID, "Command size not supported {}", data.size());
command = RingConCommands::Error;
diff --git a/src/core/hle/service/hid/hidbus/ringcon.h b/src/core/hle/service/hid/hidbus/ringcon.h
index b37df50ac..f42f3ea41 100644
--- a/src/core/hle/service/hid/hidbus/ringcon.h
+++ b/src/core/hle/service/hid/hidbus/ringcon.h
@@ -4,20 +4,20 @@
#pragma once
#include <array>
+#include <span>
#include "common/common_types.h"
#include "core/hle/service/hid/hidbus/hidbus_base.h"
namespace Core::HID {
-class EmulatedDevices;
+class EmulatedController;
} // namespace Core::HID
namespace Service::HID {
class RingController final : public HidbusBase {
public:
- explicit RingController(Core::HID::HIDCore& hid_core_,
- KernelHelpers::ServiceContext& service_context_);
+ explicit RingController(Core::System& system_, KernelHelpers::ServiceContext& service_context_);
~RingController() override;
void OnInit() override;
@@ -31,7 +31,7 @@ public:
u8 GetDeviceId() const override;
// Assigns a command from data
- bool SetCommand(const std::vector<u8>& data) override;
+ bool SetCommand(std::span<const u8> data) override;
// Returns a reply from a command
std::vector<u8> GetReply() const override;
@@ -248,6 +248,6 @@ private:
.zero = {.value = idle_value, .crc = 225},
};
- Core::HID::EmulatedDevices* input;
+ Core::HID::EmulatedController* input;
};
} // namespace Service::HID
diff --git a/src/core/hle/service/hid/hidbus/starlink.cpp b/src/core/hle/service/hid/hidbus/starlink.cpp
index dd439f60a..36573274e 100644
--- a/src/core/hle/service/hid/hidbus/starlink.cpp
+++ b/src/core/hle/service/hid/hidbus/starlink.cpp
@@ -8,8 +8,8 @@
namespace Service::HID {
constexpr u8 DEVICE_ID = 0x28;
-Starlink::Starlink(Core::HID::HIDCore& hid_core_, KernelHelpers::ServiceContext& service_context_)
- : HidbusBase(service_context_) {}
+Starlink::Starlink(Core::System& system_, KernelHelpers::ServiceContext& service_context_)
+ : HidbusBase(system_, service_context_) {}
Starlink::~Starlink() = default;
void Starlink::OnInit() {
@@ -27,7 +27,7 @@ void Starlink::OnUpdate() {
if (!device_enabled) {
return;
}
- if (!polling_mode_enabled || !is_transfer_memory_set) {
+ if (!polling_mode_enabled || transfer_memory == 0) {
return;
}
@@ -42,7 +42,7 @@ std::vector<u8> Starlink::GetReply() const {
return {};
}
-bool Starlink::SetCommand(const std::vector<u8>& data) {
+bool Starlink::SetCommand(std::span<const u8> data) {
LOG_ERROR(Service_HID, "Command not implemented");
return false;
}
diff --git a/src/core/hle/service/hid/hidbus/starlink.h b/src/core/hle/service/hid/hidbus/starlink.h
index 0b1b7ba49..a276aa88f 100644
--- a/src/core/hle/service/hid/hidbus/starlink.h
+++ b/src/core/hle/service/hid/hidbus/starlink.h
@@ -14,8 +14,7 @@ namespace Service::HID {
class Starlink final : public HidbusBase {
public:
- explicit Starlink(Core::HID::HIDCore& hid_core_,
- KernelHelpers::ServiceContext& service_context_);
+ explicit Starlink(Core::System& system_, KernelHelpers::ServiceContext& service_context_);
~Starlink() override;
void OnInit() override;
@@ -29,7 +28,7 @@ public:
u8 GetDeviceId() const override;
// Assigns a command from data
- bool SetCommand(const std::vector<u8>& data) override;
+ bool SetCommand(std::span<const u8> data) override;
// Returns a reply from a command
std::vector<u8> GetReply() const override;
diff --git a/src/core/hle/service/hid/hidbus/stubbed.cpp b/src/core/hle/service/hid/hidbus/stubbed.cpp
index e477443e3..8160b7218 100644
--- a/src/core/hle/service/hid/hidbus/stubbed.cpp
+++ b/src/core/hle/service/hid/hidbus/stubbed.cpp
@@ -8,9 +8,8 @@
namespace Service::HID {
constexpr u8 DEVICE_ID = 0xFF;
-HidbusStubbed::HidbusStubbed(Core::HID::HIDCore& hid_core_,
- KernelHelpers::ServiceContext& service_context_)
- : HidbusBase(service_context_) {}
+HidbusStubbed::HidbusStubbed(Core::System& system_, KernelHelpers::ServiceContext& service_context_)
+ : HidbusBase(system_, service_context_) {}
HidbusStubbed::~HidbusStubbed() = default;
void HidbusStubbed::OnInit() {
@@ -28,7 +27,7 @@ void HidbusStubbed::OnUpdate() {
if (!device_enabled) {
return;
}
- if (!polling_mode_enabled || !is_transfer_memory_set) {
+ if (!polling_mode_enabled || transfer_memory == 0) {
return;
}
@@ -43,7 +42,7 @@ std::vector<u8> HidbusStubbed::GetReply() const {
return {};
}
-bool HidbusStubbed::SetCommand(const std::vector<u8>& data) {
+bool HidbusStubbed::SetCommand(std::span<const u8> data) {
LOG_ERROR(Service_HID, "Command not implemented");
return false;
}
diff --git a/src/core/hle/service/hid/hidbus/stubbed.h b/src/core/hle/service/hid/hidbus/stubbed.h
index 91165ceff..2e58d42fc 100644
--- a/src/core/hle/service/hid/hidbus/stubbed.h
+++ b/src/core/hle/service/hid/hidbus/stubbed.h
@@ -14,8 +14,7 @@ namespace Service::HID {
class HidbusStubbed final : public HidbusBase {
public:
- explicit HidbusStubbed(Core::HID::HIDCore& hid_core_,
- KernelHelpers::ServiceContext& service_context_);
+ explicit HidbusStubbed(Core::System& system_, KernelHelpers::ServiceContext& service_context_);
~HidbusStubbed() override;
void OnInit() override;
@@ -29,7 +28,7 @@ public:
u8 GetDeviceId() const override;
// Assigns a command from data
- bool SetCommand(const std::vector<u8>& data) override;
+ bool SetCommand(std::span<const u8> data) override;
// Returns a reply from a command
std::vector<u8> GetReply() const override;
diff --git a/src/core/hle/service/hid/irs.cpp b/src/core/hle/service/hid/irs.cpp
index 6a3453457..221c33b86 100644
--- a/src/core/hle/service/hid/irs.cpp
+++ b/src/core/hle/service/hid/irs.cpp
@@ -8,7 +8,6 @@
#include "core/core_timing.h"
#include "core/hid/emulated_controller.h"
#include "core/hid/hid_core.h"
-#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/k_shared_memory.h"
#include "core/hle/kernel/k_transfer_memory.h"
#include "core/hle/kernel/kernel.h"
@@ -20,6 +19,7 @@
#include "core/hle/service/hid/irsensor/moment_processor.h"
#include "core/hle/service/hid/irsensor/pointing_processor.h"
#include "core/hle/service/hid/irsensor/tera_plugin_processor.h"
+#include "core/hle/service/ipc_helpers.h"
#include "core/memory.h"
namespace Service::IRS {
@@ -56,7 +56,7 @@ IRS::IRS(Core::System& system_) : ServiceFramework{system_, "irs"} {
}
IRS::~IRS() = default;
-void IRS::ActivateIrsensor(Kernel::HLERequestContext& ctx) {
+void IRS::ActivateIrsensor(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()};
@@ -67,7 +67,7 @@ void IRS::ActivateIrsensor(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void IRS::DeactivateIrsensor(Kernel::HLERequestContext& ctx) {
+void IRS::DeactivateIrsensor(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()};
@@ -78,7 +78,7 @@ void IRS::DeactivateIrsensor(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void IRS::GetIrsensorSharedMemoryHandle(Kernel::HLERequestContext& ctx) {
+void IRS::GetIrsensorSharedMemoryHandle(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()};
@@ -89,7 +89,7 @@ void IRS::GetIrsensorSharedMemoryHandle(Kernel::HLERequestContext& ctx) {
rb.PushCopyObjects(&system.Kernel().GetIrsSharedMem());
}
-void IRS::StopImageProcessor(Kernel::HLERequestContext& ctx) {
+void IRS::StopImageProcessor(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
Core::IrSensor::IrCameraHandle camera_handle;
@@ -108,6 +108,8 @@ void IRS::StopImageProcessor(Kernel::HLERequestContext& ctx) {
auto result = IsIrCameraHandleValid(parameters.camera_handle);
if (result.IsSuccess()) {
// TODO: Stop Image processor
+ npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
+ Common::Input::PollingMode::Active);
result = ResultSuccess;
}
@@ -115,7 +117,7 @@ void IRS::StopImageProcessor(Kernel::HLERequestContext& ctx) {
rb.Push(result);
}
-void IRS::RunMomentProcessor(Kernel::HLERequestContext& ctx) {
+void IRS::RunMomentProcessor(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
Core::IrSensor::IrCameraHandle camera_handle;
@@ -139,13 +141,15 @@ void IRS::RunMomentProcessor(Kernel::HLERequestContext& ctx) {
MakeProcessor<MomentProcessor>(parameters.camera_handle, device);
auto& image_transfer_processor = GetProcessor<MomentProcessor>(parameters.camera_handle);
image_transfer_processor.SetConfig(parameters.processor_config);
+ npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
+ Common::Input::PollingMode::IR);
}
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
}
-void IRS::RunClusteringProcessor(Kernel::HLERequestContext& ctx) {
+void IRS::RunClusteringProcessor(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
Core::IrSensor::IrCameraHandle camera_handle;
@@ -170,13 +174,15 @@ void IRS::RunClusteringProcessor(Kernel::HLERequestContext& ctx) {
auto& image_transfer_processor =
GetProcessor<ClusteringProcessor>(parameters.camera_handle);
image_transfer_processor.SetConfig(parameters.processor_config);
+ npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
+ Common::Input::PollingMode::IR);
}
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
}
-void IRS::RunImageTransferProcessor(Kernel::HLERequestContext& ctx) {
+void IRS::RunImageTransferProcessor(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
Core::IrSensor::IrCameraHandle camera_handle;
@@ -190,8 +196,8 @@ void IRS::RunImageTransferProcessor(Kernel::HLERequestContext& ctx) {
const auto parameters{rp.PopRaw<Parameters>()};
const auto t_mem_handle{ctx.GetCopyHandle(0)};
- auto t_mem =
- system.CurrentProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(t_mem_handle);
+ auto t_mem = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
+ t_mem_handle);
if (t_mem.IsNull()) {
LOG_ERROR(Service_IRS, "t_mem is a nullptr for handle=0x{:08X}", t_mem_handle);
@@ -202,8 +208,6 @@ void IRS::RunImageTransferProcessor(Kernel::HLERequestContext& ctx) {
ASSERT_MSG(t_mem->GetSize() == parameters.transfer_memory_size, "t_mem has incorrect size");
- u8* transfer_memory = system.Memory().GetPointer(t_mem->GetSourceAddress());
-
LOG_INFO(Service_IRS,
"called, npad_type={}, npad_id={}, transfer_memory_size={}, transfer_memory_size={}, "
"applet_resource_user_id={}",
@@ -218,14 +222,16 @@ void IRS::RunImageTransferProcessor(Kernel::HLERequestContext& ctx) {
auto& image_transfer_processor =
GetProcessor<ImageTransferProcessor>(parameters.camera_handle);
image_transfer_processor.SetConfig(parameters.processor_config);
- image_transfer_processor.SetTransferMemoryPointer(transfer_memory);
+ image_transfer_processor.SetTransferMemoryAddress(t_mem->GetSourceAddress());
+ npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
+ Common::Input::PollingMode::IR);
}
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
}
-void IRS::GetImageTransferProcessorState(Kernel::HLERequestContext& ctx) {
+void IRS::GetImageTransferProcessorState(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
Core::IrSensor::IrCameraHandle camera_handle;
@@ -266,7 +272,7 @@ void IRS::GetImageTransferProcessorState(Kernel::HLERequestContext& ctx) {
rb.PushRaw(state);
}
-void IRS::RunTeraPluginProcessor(Kernel::HLERequestContext& ctx) {
+void IRS::RunTeraPluginProcessor(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
Core::IrSensor::IrCameraHandle camera_handle;
@@ -294,13 +300,15 @@ void IRS::RunTeraPluginProcessor(Kernel::HLERequestContext& ctx) {
auto& image_transfer_processor =
GetProcessor<TeraPluginProcessor>(parameters.camera_handle);
image_transfer_processor.SetConfig(parameters.processor_config);
+ npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
+ Common::Input::PollingMode::IR);
}
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
}
-void IRS::GetNpadIrCameraHandle(Kernel::HLERequestContext& ctx) {
+void IRS::GetNpadIrCameraHandle(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto npad_id{rp.PopEnum<Core::HID::NpadIdType>()};
@@ -324,7 +332,7 @@ void IRS::GetNpadIrCameraHandle(Kernel::HLERequestContext& ctx) {
rb.PushRaw(camera_handle);
}
-void IRS::RunPointingProcessor(Kernel::HLERequestContext& ctx) {
+void IRS::RunPointingProcessor(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto camera_handle{rp.PopRaw<Core::IrSensor::IrCameraHandle>()};
const auto processor_config{rp.PopRaw<Core::IrSensor::PackedPointingProcessorConfig>()};
@@ -343,13 +351,15 @@ void IRS::RunPointingProcessor(Kernel::HLERequestContext& ctx) {
MakeProcessor<PointingProcessor>(camera_handle, device);
auto& image_transfer_processor = GetProcessor<PointingProcessor>(camera_handle);
image_transfer_processor.SetConfig(processor_config);
+ npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
+ Common::Input::PollingMode::IR);
}
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
}
-void IRS::SuspendImageProcessor(Kernel::HLERequestContext& ctx) {
+void IRS::SuspendImageProcessor(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
Core::IrSensor::IrCameraHandle camera_handle;
@@ -375,7 +385,7 @@ void IRS::SuspendImageProcessor(Kernel::HLERequestContext& ctx) {
rb.Push(result);
}
-void IRS::CheckFirmwareVersion(Kernel::HLERequestContext& ctx) {
+void IRS::CheckFirmwareVersion(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto camera_handle{rp.PopRaw<Core::IrSensor::IrCameraHandle>()};
const auto mcu_version{rp.PopRaw<Core::IrSensor::PackedMcuVersion>()};
@@ -397,7 +407,7 @@ void IRS::CheckFirmwareVersion(Kernel::HLERequestContext& ctx) {
rb.Push(result);
}
-void IRS::SetFunctionLevel(Kernel::HLERequestContext& ctx) {
+void IRS::SetFunctionLevel(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto camera_handle{rp.PopRaw<Core::IrSensor::IrCameraHandle>()};
const auto function_level{rp.PopRaw<Core::IrSensor::PackedFunctionLevel>()};
@@ -419,7 +429,7 @@ void IRS::SetFunctionLevel(Kernel::HLERequestContext& ctx) {
rb.Push(result);
}
-void IRS::RunImageTransferExProcessor(Kernel::HLERequestContext& ctx) {
+void IRS::RunImageTransferExProcessor(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
Core::IrSensor::IrCameraHandle camera_handle;
@@ -433,10 +443,8 @@ void IRS::RunImageTransferExProcessor(Kernel::HLERequestContext& ctx) {
const auto parameters{rp.PopRaw<Parameters>()};
const auto t_mem_handle{ctx.GetCopyHandle(0)};
- auto t_mem =
- system.CurrentProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(t_mem_handle);
-
- u8* transfer_memory = system.Memory().GetPointer(t_mem->GetSourceAddress());
+ auto t_mem = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
+ t_mem_handle);
LOG_INFO(Service_IRS,
"called, npad_type={}, npad_id={}, transfer_memory_size={}, "
@@ -452,14 +460,16 @@ void IRS::RunImageTransferExProcessor(Kernel::HLERequestContext& ctx) {
auto& image_transfer_processor =
GetProcessor<ImageTransferProcessor>(parameters.camera_handle);
image_transfer_processor.SetConfig(parameters.processor_config);
- image_transfer_processor.SetTransferMemoryPointer(transfer_memory);
+ image_transfer_processor.SetTransferMemoryAddress(t_mem->GetSourceAddress());
+ npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
+ Common::Input::PollingMode::IR);
}
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
}
-void IRS::RunIrLedProcessor(Kernel::HLERequestContext& ctx) {
+void IRS::RunIrLedProcessor(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto camera_handle{rp.PopRaw<Core::IrSensor::IrCameraHandle>()};
const auto processor_config{rp.PopRaw<Core::IrSensor::PackedIrLedProcessorConfig>()};
@@ -479,13 +489,15 @@ void IRS::RunIrLedProcessor(Kernel::HLERequestContext& ctx) {
MakeProcessor<IrLedProcessor>(camera_handle, device);
auto& image_transfer_processor = GetProcessor<IrLedProcessor>(camera_handle);
image_transfer_processor.SetConfig(processor_config);
+ npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
+ Common::Input::PollingMode::IR);
}
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
}
-void IRS::StopImageProcessorAsync(Kernel::HLERequestContext& ctx) {
+void IRS::StopImageProcessorAsync(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
Core::IrSensor::IrCameraHandle camera_handle;
@@ -504,6 +516,8 @@ void IRS::StopImageProcessorAsync(Kernel::HLERequestContext& ctx) {
auto result = IsIrCameraHandleValid(parameters.camera_handle);
if (result.IsSuccess()) {
// TODO: Stop image processor async
+ npad_device->SetPollingMode(Core::HID::EmulatedDeviceIndex::RightIndex,
+ Common::Input::PollingMode::Active);
result = ResultSuccess;
}
@@ -511,7 +525,7 @@ void IRS::StopImageProcessorAsync(Kernel::HLERequestContext& ctx) {
rb.Push(result);
}
-void IRS::ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx) {
+void IRS::ActivateIrsensorWithFunctionLevel(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
Core::IrSensor::PackedFunctionLevel function_level;
diff --git a/src/core/hle/service/hid/irs.h b/src/core/hle/service/hid/irs.h
index 2e6115c73..a8fa19025 100644
--- a/src/core/hle/service/hid/irs.h
+++ b/src/core/hle/service/hid/irs.h
@@ -38,24 +38,24 @@ private:
};
static_assert(sizeof(StatusManager) == 0x8000, "StatusManager is an invalid size");
- void ActivateIrsensor(Kernel::HLERequestContext& ctx);
- void DeactivateIrsensor(Kernel::HLERequestContext& ctx);
- void GetIrsensorSharedMemoryHandle(Kernel::HLERequestContext& ctx);
- void StopImageProcessor(Kernel::HLERequestContext& ctx);
- void RunMomentProcessor(Kernel::HLERequestContext& ctx);
- void RunClusteringProcessor(Kernel::HLERequestContext& ctx);
- void RunImageTransferProcessor(Kernel::HLERequestContext& ctx);
- void GetImageTransferProcessorState(Kernel::HLERequestContext& ctx);
- void RunTeraPluginProcessor(Kernel::HLERequestContext& ctx);
- void GetNpadIrCameraHandle(Kernel::HLERequestContext& ctx);
- void RunPointingProcessor(Kernel::HLERequestContext& ctx);
- void SuspendImageProcessor(Kernel::HLERequestContext& ctx);
- void CheckFirmwareVersion(Kernel::HLERequestContext& ctx);
- void SetFunctionLevel(Kernel::HLERequestContext& ctx);
- void RunImageTransferExProcessor(Kernel::HLERequestContext& ctx);
- void RunIrLedProcessor(Kernel::HLERequestContext& ctx);
- void StopImageProcessorAsync(Kernel::HLERequestContext& ctx);
- void ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx);
+ void ActivateIrsensor(HLERequestContext& ctx);
+ void DeactivateIrsensor(HLERequestContext& ctx);
+ void GetIrsensorSharedMemoryHandle(HLERequestContext& ctx);
+ void StopImageProcessor(HLERequestContext& ctx);
+ void RunMomentProcessor(HLERequestContext& ctx);
+ void RunClusteringProcessor(HLERequestContext& ctx);
+ void RunImageTransferProcessor(HLERequestContext& ctx);
+ void GetImageTransferProcessorState(HLERequestContext& ctx);
+ void RunTeraPluginProcessor(HLERequestContext& ctx);
+ void GetNpadIrCameraHandle(HLERequestContext& ctx);
+ void RunPointingProcessor(HLERequestContext& ctx);
+ void SuspendImageProcessor(HLERequestContext& ctx);
+ void CheckFirmwareVersion(HLERequestContext& ctx);
+ void SetFunctionLevel(HLERequestContext& ctx);
+ void RunImageTransferExProcessor(HLERequestContext& ctx);
+ void RunIrLedProcessor(HLERequestContext& ctx);
+ void StopImageProcessorAsync(HLERequestContext& ctx);
+ void ActivateIrsensorWithFunctionLevel(HLERequestContext& ctx);
Result IsIrCameraHandleValid(const Core::IrSensor::IrCameraHandle& camera_handle) const;
Core::IrSensor::DeviceFormat& GetIrCameraSharedMemoryDeviceEntry(
@@ -80,7 +80,13 @@ private:
LOG_CRITICAL(Service_IRS, "Invalid index {}", index);
return;
}
- processors[index] = std::make_unique<T>(system.HIDCore(), device_state, index);
+
+ if constexpr (std::is_constructible_v<T, Core::System&, Core::IrSensor::DeviceFormat&,
+ std::size_t>) {
+ processors[index] = std::make_unique<T>(system, device_state, index);
+ } else {
+ processors[index] = std::make_unique<T>(system.HIDCore(), device_state, index);
+ }
}
template <typename T>
diff --git a/src/core/hle/service/hid/irsensor/image_transfer_processor.cpp b/src/core/hle/service/hid/irsensor/image_transfer_processor.cpp
index 98f0c579d..803a6277c 100644
--- a/src/core/hle/service/hid/irsensor/image_transfer_processor.cpp
+++ b/src/core/hle/service/hid/irsensor/image_transfer_processor.cpp
@@ -1,16 +1,18 @@
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
+#include "core/core.h"
#include "core/hid/emulated_controller.h"
#include "core/hid/hid_core.h"
#include "core/hle/service/hid/irsensor/image_transfer_processor.h"
+#include "core/memory.h"
namespace Service::IRS {
-ImageTransferProcessor::ImageTransferProcessor(Core::HID::HIDCore& hid_core_,
+ImageTransferProcessor::ImageTransferProcessor(Core::System& system_,
Core::IrSensor::DeviceFormat& device_format,
std::size_t npad_index)
- : device{device_format} {
- npad_device = hid_core_.GetEmulatedControllerByIndex(npad_index);
+ : device{device_format}, system{system_} {
+ npad_device = system.HIDCore().GetEmulatedControllerByIndex(npad_index);
Core::HID::ControllerUpdateCallback engine_callback{
.on_change = [this](Core::HID::ControllerTriggerType type) { OnControllerUpdate(type); },
@@ -43,27 +45,29 @@ void ImageTransferProcessor::OnControllerUpdate(Core::HID::ControllerTriggerType
if (type != Core::HID::ControllerTriggerType::IrSensor) {
return;
}
- if (!is_transfer_memory_set) {
+ if (transfer_memory == 0) {
return;
}
const auto camera_data = npad_device->GetCamera();
- // This indicates how much ambient light is precent
+ // This indicates how much ambient light is present
processor_state.ambient_noise_level = Core::IrSensor::CameraAmbientNoiseLevel::Low;
processor_state.sampling_number = camera_data.sample;
if (camera_data.format != current_config.origin_format) {
LOG_WARNING(Service_IRS, "Wrong Input format {} expected {}", camera_data.format,
current_config.origin_format);
- memset(transfer_memory, 0, GetDataSize(current_config.trimming_format));
+ system.ApplicationMemory().ZeroBlock(transfer_memory,
+ GetDataSize(current_config.trimming_format));
return;
}
if (current_config.origin_format > current_config.trimming_format) {
LOG_WARNING(Service_IRS, "Origin format {} is smaller than trimming format {}",
current_config.origin_format, current_config.trimming_format);
- memset(transfer_memory, 0, GetDataSize(current_config.trimming_format));
+ system.ApplicationMemory().ZeroBlock(transfer_memory,
+ GetDataSize(current_config.trimming_format));
return;
}
@@ -80,7 +84,8 @@ void ImageTransferProcessor::OnControllerUpdate(Core::HID::ControllerTriggerType
"Trimming area ({}, {}, {}, {}) is outside of origin area ({}, {})",
current_config.trimming_start_x, current_config.trimming_start_y,
trimming_width, trimming_height, origin_width, origin_height);
- memset(transfer_memory, 0, GetDataSize(current_config.trimming_format));
+ system.ApplicationMemory().ZeroBlock(transfer_memory,
+ GetDataSize(current_config.trimming_format));
return;
}
@@ -94,7 +99,8 @@ void ImageTransferProcessor::OnControllerUpdate(Core::HID::ControllerTriggerType
}
}
- memcpy(transfer_memory, window_data.data(), GetDataSize(current_config.trimming_format));
+ system.ApplicationMemory().WriteBlock(transfer_memory, window_data.data(),
+ GetDataSize(current_config.trimming_format));
if (!IsProcessorActive()) {
StartProcessor();
@@ -134,8 +140,7 @@ void ImageTransferProcessor::SetConfig(
npad_device->SetCameraFormat(current_config.origin_format);
}
-void ImageTransferProcessor::SetTransferMemoryPointer(u8* t_mem) {
- is_transfer_memory_set = true;
+void ImageTransferProcessor::SetTransferMemoryAddress(Common::ProcessAddress t_mem) {
transfer_memory = t_mem;
}
@@ -143,7 +148,7 @@ Core::IrSensor::ImageTransferProcessorState ImageTransferProcessor::GetState(
std::vector<u8>& data) const {
const auto size = GetDataSize(current_config.trimming_format);
data.resize(size);
- memcpy(data.data(), transfer_memory, size);
+ system.ApplicationMemory().ReadBlock(transfer_memory, data.data(), size);
return processor_state;
}
diff --git a/src/core/hle/service/hid/irsensor/image_transfer_processor.h b/src/core/hle/service/hid/irsensor/image_transfer_processor.h
index 393df492d..7f42d8453 100644
--- a/src/core/hle/service/hid/irsensor/image_transfer_processor.h
+++ b/src/core/hle/service/hid/irsensor/image_transfer_processor.h
@@ -3,10 +3,14 @@
#pragma once
-#include "common/common_types.h"
+#include "common/typed_address.h"
#include "core/hid/irs_types.h"
#include "core/hle/service/hid/irsensor/processor_base.h"
+namespace Core {
+class System;
+}
+
namespace Core::HID {
class EmulatedController;
} // namespace Core::HID
@@ -14,7 +18,7 @@ class EmulatedController;
namespace Service::IRS {
class ImageTransferProcessor final : public ProcessorBase {
public:
- explicit ImageTransferProcessor(Core::HID::HIDCore& hid_core_,
+ explicit ImageTransferProcessor(Core::System& system_,
Core::IrSensor::DeviceFormat& device_format,
std::size_t npad_index);
~ImageTransferProcessor() override;
@@ -33,7 +37,7 @@ public:
void SetConfig(Core::IrSensor::PackedImageTransferProcessorExConfig config);
// Transfer memory where the image data will be stored
- void SetTransferMemoryPointer(u8* t_mem);
+ void SetTransferMemoryAddress(Common::ProcessAddress t_mem);
Core::IrSensor::ImageTransferProcessorState GetState(std::vector<u8>& data) const;
@@ -67,7 +71,7 @@ private:
Core::HID::EmulatedController* npad_device;
int callback_key{};
- u8* transfer_memory = nullptr;
- bool is_transfer_memory_set = false;
+ Core::System& system;
+ Common::ProcessAddress transfer_memory{};
};
} // namespace Service::IRS
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/service/hle_ipc.cpp
index 738b6d0f1..2290df705 100644
--- a/src/core/hle/kernel/hle_ipc.cpp
+++ b/src/core/hle/service/hle_ipc.cpp
@@ -11,8 +11,7 @@
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/logging/log.h"
-#include "core/hle/ipc_helpers.h"
-#include "core/hle/kernel/hle_ipc.h"
+#include "common/scratch_buffer.h"
#include "core/hle/kernel/k_auto_object.h"
#include "core/hle/kernel/k_handle_table.h"
#include "core/hle/kernel/k_process.h"
@@ -20,36 +19,20 @@
#include "core/hle/kernel/k_server_session.h"
#include "core/hle/kernel/k_thread.h"
#include "core/hle/kernel/kernel.h"
-#include "core/hle/kernel/service_thread.h"
+#include "core/hle/service/hle_ipc.h"
+#include "core/hle/service/ipc_helpers.h"
#include "core/memory.h"
-namespace Kernel {
+namespace Service {
-SessionRequestHandler::SessionRequestHandler(KernelCore& kernel_, const char* service_name_,
- ServiceThreadType thread_type)
- : kernel{kernel_}, service_thread{thread_type == ServiceThreadType::CreateNew
- ? kernel.CreateServiceThread(service_name_)
- : kernel.GetDefaultServiceThread()} {}
+SessionRequestHandler::SessionRequestHandler(Kernel::KernelCore& kernel_, const char* service_name_)
+ : kernel{kernel_} {}
-SessionRequestHandler::~SessionRequestHandler() {
- kernel.ReleaseServiceThread(service_thread);
-}
-
-void SessionRequestHandler::AcceptSession(KServerPort* server_port) {
- auto* server_session = server_port->AcceptSession();
- ASSERT(server_session != nullptr);
-
- RegisterSession(server_session, std::make_shared<SessionRequestManager>(kernel));
-}
-
-void SessionRequestHandler::RegisterSession(KServerSession* server_session,
- std::shared_ptr<SessionRequestManager> manager) {
- manager->SetSessionHandler(shared_from_this());
- service_thread.RegisterServerSession(server_session, manager);
- server_session->Close();
-}
+SessionRequestHandler::~SessionRequestHandler() = default;
-SessionRequestManager::SessionRequestManager(KernelCore& kernel_) : kernel{kernel_} {}
+SessionRequestManager::SessionRequestManager(Kernel::KernelCore& kernel_,
+ ServerManager& server_manager_)
+ : kernel{kernel_}, server_manager{server_manager_} {}
SessionRequestManager::~SessionRequestManager() = default;
@@ -68,7 +51,7 @@ bool SessionRequestManager::HasSessionRequestHandler(const HLERequestContext& co
}
}
-Result SessionRequestManager::CompleteSyncRequest(KServerSession* server_session,
+Result SessionRequestManager::CompleteSyncRequest(Kernel::KServerSession* server_session,
HLERequestContext& context) {
Result result = ResultSuccess;
@@ -96,7 +79,7 @@ Result SessionRequestManager::CompleteSyncRequest(KServerSession* server_session
return result;
}
-Result SessionRequestManager::HandleDomainSyncRequest(KServerSession* server_session,
+Result SessionRequestManager::HandleDomainSyncRequest(Kernel::KServerSession* server_session,
HLERequestContext& context) {
if (!context.HasDomainMessageHeader()) {
return ResultSuccess;
@@ -141,16 +124,17 @@ Result SessionRequestManager::HandleDomainSyncRequest(KServerSession* server_ses
return ResultSuccess;
}
-HLERequestContext::HLERequestContext(KernelCore& kernel_, Core::Memory::Memory& memory_,
- KServerSession* server_session_, KThread* thread_)
+HLERequestContext::HLERequestContext(Kernel::KernelCore& kernel_, Core::Memory::Memory& memory_,
+ Kernel::KServerSession* server_session_,
+ Kernel::KThread* thread_)
: server_session(server_session_), thread(thread_), kernel{kernel_}, memory{memory_} {
cmd_buf[0] = 0;
}
HLERequestContext::~HLERequestContext() = default;
-void HLERequestContext::ParseCommandBuffer(const KHandleTable& handle_table, u32_le* src_cmdbuf,
- bool incoming) {
+void HLERequestContext::ParseCommandBuffer(const Kernel::KHandleTable& handle_table,
+ u32_le* src_cmdbuf, bool incoming) {
IPC::RequestParser rp(src_cmdbuf);
command_header = rp.PopRaw<IPC::CommandHeader>();
@@ -270,8 +254,8 @@ void HLERequestContext::ParseCommandBuffer(const KHandleTable& handle_table, u32
rp.Skip(1, false); // The command is actually an u64, but we don't use the high part.
}
-Result HLERequestContext::PopulateFromIncomingCommandBuffer(const KHandleTable& handle_table,
- u32_le* src_cmdbuf) {
+Result HLERequestContext::PopulateFromIncomingCommandBuffer(
+ const Kernel::KHandleTable& handle_table, u32_le* src_cmdbuf) {
ParseCommandBuffer(handle_table, src_cmdbuf, true);
if (command_header->IsCloseCommand()) {
@@ -284,7 +268,7 @@ Result HLERequestContext::PopulateFromIncomingCommandBuffer(const KHandleTable&
return ResultSuccess;
}
-Result HLERequestContext::WriteToOutgoingCommandBuffer(KThread& requesting_thread) {
+Result HLERequestContext::WriteToOutgoingCommandBuffer(Kernel::KThread& requesting_thread) {
auto current_offset = handles_offset;
auto& owner_process = *requesting_thread.GetOwnerProcess();
auto& handle_table = owner_process.GetHandleTable();
@@ -319,13 +303,12 @@ Result HLERequestContext::WriteToOutgoingCommandBuffer(KThread& requesting_threa
}
// Copy the translated command buffer back into the thread's command buffer area.
- memory.WriteBlock(owner_process, requesting_thread.GetTLSAddress(), cmd_buf.data(),
- write_size * sizeof(u32));
+ memory.WriteBlock(requesting_thread.GetTlsAddress(), cmd_buf.data(), write_size * sizeof(u32));
return ResultSuccess;
}
-std::vector<u8> HLERequestContext::ReadBuffer(std::size_t buffer_index) const {
+std::vector<u8> HLERequestContext::ReadBufferCopy(std::size_t buffer_index) const {
const bool is_buffer_a{BufferDescriptorA().size() > buffer_index &&
BufferDescriptorA()[buffer_index].Size()};
if (is_buffer_a) {
@@ -345,6 +328,33 @@ std::vector<u8> HLERequestContext::ReadBuffer(std::size_t buffer_index) const {
}
}
+std::span<const u8> HLERequestContext::ReadBuffer(std::size_t buffer_index) const {
+ static thread_local std::array<Common::ScratchBuffer<u8>, 2> read_buffer_a;
+ static thread_local std::array<Common::ScratchBuffer<u8>, 2> read_buffer_x;
+
+ const bool is_buffer_a{BufferDescriptorA().size() > buffer_index &&
+ BufferDescriptorA()[buffer_index].Size()};
+ if (is_buffer_a) {
+ ASSERT_OR_EXECUTE_MSG(
+ BufferDescriptorA().size() > buffer_index, { return {}; },
+ "BufferDescriptorA invalid buffer_index {}", buffer_index);
+ auto& read_buffer = read_buffer_a[buffer_index];
+ read_buffer.resize_destructive(BufferDescriptorA()[buffer_index].Size());
+ memory.ReadBlock(BufferDescriptorA()[buffer_index].Address(), read_buffer.data(),
+ read_buffer.size());
+ return read_buffer;
+ } else {
+ ASSERT_OR_EXECUTE_MSG(
+ BufferDescriptorX().size() > buffer_index, { return {}; },
+ "BufferDescriptorX invalid buffer_index {}", buffer_index);
+ auto& read_buffer = read_buffer_x[buffer_index];
+ read_buffer.resize_destructive(BufferDescriptorX()[buffer_index].Size());
+ memory.ReadBlock(BufferDescriptorX()[buffer_index].Address(), read_buffer.data(),
+ read_buffer.size());
+ return read_buffer;
+ }
+}
+
std::size_t HLERequestContext::WriteBuffer(const void* buffer, std::size_t size,
std::size_t buffer_index) const {
if (size == 0) {
@@ -518,4 +528,4 @@ std::string HLERequestContext::Description() const {
return s.str();
}
-} // namespace Kernel
+} // namespace Service
diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/service/hle_ipc.h
index e252b5f4b..4bd24c899 100644
--- a/src/core/hle/kernel/hle_ipc.h
+++ b/src/core/hle/service/hle_ipc.h
@@ -7,6 +7,7 @@
#include <functional>
#include <memory>
#include <optional>
+#include <span>
#include <string>
#include <type_traits>
#include <vector>
@@ -30,31 +31,22 @@ class ResponseBuilder;
namespace Service {
class ServiceFrameworkBase;
-}
-
-enum class ServiceThreadType {
- Default,
- CreateNew,
-};
+class ServerManager;
+} // namespace Service
namespace Kernel {
-
-class Domain;
-class HLERequestContext;
class KAutoObject;
class KernelCore;
-class KEvent;
class KHandleTable;
-class KServerPort;
-class KProcess;
class KServerSession;
class KThread;
-class KReadableEvent;
-class KSession;
-class SessionRequestManager;
-class ServiceThread;
+} // namespace Kernel
-enum class ThreadWakeupReason;
+namespace Service {
+
+using Handle = Kernel::Handle;
+
+class HLERequestContext;
/**
* Interface implemented by HLE Session handlers.
@@ -63,8 +55,7 @@ enum class ThreadWakeupReason;
*/
class SessionRequestHandler : public std::enable_shared_from_this<SessionRequestHandler> {
public:
- SessionRequestHandler(KernelCore& kernel_, const char* service_name_,
- ServiceThreadType thread_type);
+ SessionRequestHandler(Kernel::KernelCore& kernel_, const char* service_name_);
virtual ~SessionRequestHandler();
/**
@@ -76,19 +67,10 @@ public:
* @returns Result the result code of the translate operation.
*/
virtual Result HandleSyncRequest(Kernel::KServerSession& session,
- Kernel::HLERequestContext& context) = 0;
-
- void AcceptSession(KServerPort* server_port);
- void RegisterSession(KServerSession* server_session,
- std::shared_ptr<SessionRequestManager> manager);
-
- ServiceThread& GetServiceThread() const {
- return service_thread;
- }
+ HLERequestContext& context) = 0;
protected:
- KernelCore& kernel;
- ServiceThread& service_thread;
+ Kernel::KernelCore& kernel;
};
using SessionRequestHandlerWeakPtr = std::weak_ptr<SessionRequestHandler>;
@@ -101,7 +83,8 @@ using SessionRequestHandlerPtr = std::shared_ptr<SessionRequestHandler>;
*/
class SessionRequestManager final {
public:
- explicit SessionRequestManager(KernelCore& kernel);
+ explicit SessionRequestManager(Kernel::KernelCore& kernel,
+ Service::ServerManager& server_manager);
~SessionRequestManager();
bool IsDomain() const {
@@ -154,48 +137,47 @@ public:
session_handler = std::move(handler);
}
- ServiceThread& GetServiceThread() const {
- return session_handler->GetServiceThread();
+ bool HasSessionRequestHandler(const HLERequestContext& context) const;
+
+ Result HandleDomainSyncRequest(Kernel::KServerSession* server_session,
+ HLERequestContext& context);
+ Result CompleteSyncRequest(Kernel::KServerSession* server_session, HLERequestContext& context);
+
+ Service::ServerManager& GetServerManager() {
+ return server_manager;
}
- bool HasSessionRequestHandler(const HLERequestContext& context) const;
+ // TODO: remove this when sm: is implemented with the proper IUserInterface
+ // abstraction, creating a new C++ handler object for each session:
- Result HandleDomainSyncRequest(KServerSession* server_session, HLERequestContext& context);
- Result CompleteSyncRequest(KServerSession* server_session, HLERequestContext& context);
+ bool GetIsInitializedForSm() const {
+ return is_initialized_for_sm;
+ }
+
+ void SetIsInitializedForSm() {
+ is_initialized_for_sm = true;
+ }
private:
bool convert_to_domain{};
bool is_domain{};
+ bool is_initialized_for_sm{};
SessionRequestHandlerPtr session_handler;
std::vector<SessionRequestHandlerPtr> domain_handlers;
private:
- KernelCore& kernel;
+ Kernel::KernelCore& kernel;
+ Service::ServerManager& server_manager;
};
/**
* Class containing information about an in-flight IPC request being handled by an HLE service
- * implementation. Services should avoid using old global APIs (e.g. Kernel::GetCommandBuffer()) and
- * when possible use the APIs in this class to service the request.
- *
- * HLE handle protocol
- * ===================
- *
- * To avoid needing HLE services to keep a separate handle table, or having to directly modify the
- * requester's table, a tweaked protocol is used to receive and send handles in requests. The kernel
- * will decode the incoming handles into object pointers and insert a id in the buffer where the
- * handle would normally be. The service then calls GetIncomingHandle() with that id to get the
- * pointer to the object. Similarly, instead of inserting a handle into the command buffer, the
- * service calls AddOutgoingHandle() and stores the returned id where the handle would normally go.
- *
- * The end result is similar to just giving services their own real handle tables, but since these
- * ids are local to a specific context, it avoids requiring services to manage handles for objects
- * across multiple calls and ensuring that unneeded handles are cleaned up.
+ * implementation.
*/
class HLERequestContext {
public:
- explicit HLERequestContext(KernelCore& kernel, Core::Memory::Memory& memory,
- KServerSession* session, KThread* thread);
+ explicit HLERequestContext(Kernel::KernelCore& kernel, Core::Memory::Memory& memory,
+ Kernel::KServerSession* session, Kernel::KThread* thread);
~HLERequestContext();
/// Returns a pointer to the IPC command buffer for this request.
@@ -212,10 +194,11 @@ public:
}
/// Populates this context with data from the requesting process/thread.
- Result PopulateFromIncomingCommandBuffer(const KHandleTable& handle_table, u32_le* src_cmdbuf);
+ Result PopulateFromIncomingCommandBuffer(const Kernel::KHandleTable& handle_table,
+ u32_le* src_cmdbuf);
/// Writes data from this context back to the requesting process/thread.
- Result WriteToOutgoingCommandBuffer(KThread& requesting_thread);
+ Result WriteToOutgoingCommandBuffer(Kernel::KThread& requesting_thread);
[[nodiscard]] u32_le GetHipcCommand() const {
return command;
@@ -270,8 +253,11 @@ public:
return domain_message_header.has_value();
}
- /// Helper function to read a buffer using the appropriate buffer descriptor
- [[nodiscard]] std::vector<u8> ReadBuffer(std::size_t buffer_index = 0) const;
+ /// Helper function to get a span of a buffer using the appropriate buffer descriptor
+ [[nodiscard]] std::span<const u8> ReadBuffer(std::size_t buffer_index = 0) const;
+
+ /// Helper function to read a copy of a buffer using the appropriate buffer descriptor
+ [[nodiscard]] std::vector<u8> ReadBufferCopy(std::size_t buffer_index = 0) const;
/// Helper function to write a buffer using the appropriate buffer descriptor
std::size_t WriteBuffer(const void* buffer, std::size_t size,
@@ -339,11 +325,11 @@ public:
return incoming_move_handles.at(index);
}
- void AddMoveObject(KAutoObject* object) {
+ void AddMoveObject(Kernel::KAutoObject* object) {
outgoing_move_objects.emplace_back(object);
}
- void AddCopyObject(KAutoObject* object) {
+ void AddCopyObject(Kernel::KAutoObject* object) {
outgoing_copy_objects.emplace_back(object);
}
@@ -362,7 +348,7 @@ public:
[[nodiscard]] std::string Description() const;
- [[nodiscard]] KThread& GetThread() {
+ [[nodiscard]] Kernel::KThread& GetThread() {
return *thread;
}
@@ -370,20 +356,29 @@ public:
return manager.lock();
}
+ bool GetIsDeferred() const {
+ return is_deferred;
+ }
+
+ void SetIsDeferred(bool is_deferred_ = true) {
+ is_deferred = is_deferred_;
+ }
+
private:
friend class IPC::ResponseBuilder;
- void ParseCommandBuffer(const KHandleTable& handle_table, u32_le* src_cmdbuf, bool incoming);
+ void ParseCommandBuffer(const Kernel::KHandleTable& handle_table, u32_le* src_cmdbuf,
+ bool incoming);
std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf;
Kernel::KServerSession* server_session{};
- KThread* thread;
+ Kernel::KThread* thread;
std::vector<Handle> incoming_move_handles;
std::vector<Handle> incoming_copy_handles;
- std::vector<KAutoObject*> outgoing_move_objects;
- std::vector<KAutoObject*> outgoing_copy_objects;
+ std::vector<Kernel::KAutoObject*> outgoing_move_objects;
+ std::vector<Kernel::KAutoObject*> outgoing_copy_objects;
std::vector<SessionRequestHandlerPtr> outgoing_domain_objects;
std::optional<IPC::CommandHeader> command_header;
@@ -404,9 +399,10 @@ private:
u32 domain_offset{};
std::weak_ptr<SessionRequestManager> manager{};
+ bool is_deferred{false};
- KernelCore& kernel;
+ Kernel::KernelCore& kernel;
Core::Memory::Memory& memory;
};
-} // namespace Kernel
+} // namespace Service
diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/service/ipc_helpers.h
index a86bec252..0e222362e 100644
--- a/src/core/hle/ipc_helpers.h
+++ b/src/core/hle/service/ipc_helpers.h
@@ -10,26 +10,27 @@
#include "common/assert.h"
#include "common/common_types.h"
#include "core/hle/ipc.h"
-#include "core/hle/kernel/hle_ipc.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"
+#include "core/hle/service/hle_ipc.h"
+#include "core/hle/service/server_manager.h"
namespace IPC {
-constexpr Result ERR_REMOTE_PROCESS_DEAD{ErrorModule::HIPC, 301};
+constexpr Result ResultSessionClosed{ErrorModule::HIPC, 301};
class RequestHelperBase {
protected:
- Kernel::HLERequestContext* context = nullptr;
+ Service::HLERequestContext* context = nullptr;
u32* cmdbuf;
u32 index = 0;
public:
explicit RequestHelperBase(u32* command_buffer) : cmdbuf(command_buffer) {}
- explicit RequestHelperBase(Kernel::HLERequestContext& ctx)
+ explicit RequestHelperBase(Service::HLERequestContext& ctx)
: context(&ctx), cmdbuf(ctx.CommandBuffer()) {}
void Skip(u32 size_in_words, bool set_to_null) {
@@ -67,7 +68,7 @@ public:
AlwaysMoveHandles = 1,
};
- explicit ResponseBuilder(Kernel::HLERequestContext& ctx, u32 normal_params_size_,
+ explicit ResponseBuilder(Service::HLERequestContext& ctx, u32 normal_params_size_,
u32 num_handles_to_copy_ = 0, u32 num_objects_to_move_ = 0,
Flags flags = Flags::None)
: RequestHelperBase(ctx), normal_params_size(normal_params_size_),
@@ -145,16 +146,22 @@ public:
template <class T>
void PushIpcInterface(std::shared_ptr<T> iface) {
- if (context->GetManager()->IsDomain()) {
+ auto manager{context->GetManager()};
+
+ if (manager->IsDomain()) {
context->AddDomainObject(std::move(iface));
} else {
- kernel.CurrentProcess()->GetResourceLimit()->Reserve(
+ kernel.ApplicationProcess()->GetResourceLimit()->Reserve(
Kernel::LimitableResource::SessionCountMax, 1);
auto* session = Kernel::KSession::Create(kernel);
- session->Initialize(nullptr, iface->GetServiceName());
- iface->RegisterSession(&session->GetServerSession(),
- std::make_shared<Kernel::SessionRequestManager>(kernel));
+ session->Initialize(nullptr, 0);
+ Kernel::KSession::Register(kernel, session);
+
+ auto next_manager = std::make_shared<Service::SessionRequestManager>(
+ kernel, manager->GetServerManager());
+ next_manager->SetSessionHandler(iface);
+ manager->GetServerManager().RegisterSession(&session->GetServerSession(), next_manager);
context->AddMoveObject(&session->GetClientSession());
}
@@ -341,7 +348,7 @@ class RequestParser : public RequestHelperBase {
public:
explicit RequestParser(u32* command_buffer) : RequestHelperBase(command_buffer) {}
- explicit RequestParser(Kernel::HLERequestContext& ctx) : RequestHelperBase(ctx) {
+ explicit RequestParser(Service::HLERequestContext& ctx) : RequestHelperBase(ctx) {
// TIPC does not have data payload offset
if (!ctx.IsTipc()) {
ASSERT_MSG(ctx.GetDataPayloadOffset(), "context is incomplete");
diff --git a/src/core/hle/service/jit/jit.cpp b/src/core/hle/service/jit/jit.cpp
index 8f2920c51..be996870f 100644
--- a/src/core/hle/service/jit/jit.cpp
+++ b/src/core/hle/service/jit/jit.cpp
@@ -3,12 +3,13 @@
#include "core/arm/symbols.h"
#include "core/core.h"
-#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/k_code_memory.h"
#include "core/hle/kernel/k_transfer_memory.h"
#include "core/hle/result.h"
+#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/jit/jit.h"
#include "core/hle/service/jit/jit_context.h"
+#include "core/hle/service/server_manager.h"
#include "core/hle/service/service.h"
#include "core/memory.h"
@@ -23,8 +24,8 @@ class IJitEnvironment final : public ServiceFramework<IJitEnvironment> {
public:
explicit IJitEnvironment(Core::System& system_, Kernel::KProcess& process_, CodeRange user_rx,
CodeRange user_ro)
- : ServiceFramework{system_, "IJitEnvironment", ServiceThreadType::CreateNew},
- process{&process_}, context{system_.Memory()} {
+ : ServiceFramework{system_, "IJitEnvironment"}, process{&process_},
+ context{system_.ApplicationMemory()} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &IJitEnvironment::GenerateCode, "GenerateCode"},
@@ -43,7 +44,7 @@ public:
configuration.sys_rx_memory = user_rx;
}
- void GenerateCode(Kernel::HLERequestContext& ctx) {
+ void GenerateCode(HLERequestContext& ctx) {
LOG_DEBUG(Service_JIT, "called");
struct InputParameters {
@@ -62,7 +63,7 @@ public:
const auto parameters{rp.PopRaw<InputParameters>()};
// Optional input/output buffers
- std::vector<u8> input_buffer{ctx.CanReadBuffer() ? ctx.ReadBuffer() : std::vector<u8>()};
+ const auto input_buffer{ctx.CanReadBuffer() ? ctx.ReadBuffer() : std::span<const u8>()};
std::vector<u8> output_buffer(ctx.CanWriteBuffer() ? ctx.GetWriteBufferSize() : 0);
// Function call prototype:
@@ -125,14 +126,14 @@ public:
}
};
- void Control(Kernel::HLERequestContext& ctx) {
+ void Control(HLERequestContext& ctx) {
LOG_DEBUG(Service_JIT, "called");
IPC::RequestParser rp{ctx};
const auto command{rp.PopRaw<u64>()};
// Optional input/output buffers
- std::vector<u8> input_buffer{ctx.CanReadBuffer() ? ctx.ReadBuffer() : std::vector<u8>()};
+ const auto input_buffer{ctx.CanReadBuffer() ? ctx.ReadBuffer() : std::span<const u8>()};
std::vector<u8> output_buffer(ctx.CanWriteBuffer() ? ctx.GetWriteBufferSize() : 0);
// Function call prototype:
@@ -170,7 +171,7 @@ public:
}
}
- void LoadPlugin(Kernel::HLERequestContext& ctx) {
+ void LoadPlugin(HLERequestContext& ctx) {
LOG_DEBUG(Service_JIT, "called");
IPC::RequestParser rp{ctx};
@@ -194,7 +195,7 @@ public:
}
// Set up the configuration with the required TransferMemory address
- configuration.transfer_memory.offset = tmem->GetSourceAddress();
+ configuration.transfer_memory.offset = GetInteger(tmem->GetSourceAddress());
configuration.transfer_memory.size = tmem_size;
// Gather up all the callbacks from the loaded plugin
@@ -276,7 +277,7 @@ public:
rb.Push(ResultSuccess);
}
- void GetCodeAddress(Kernel::HLERequestContext& ctx) {
+ void GetCodeAddress(HLERequestContext& ctx) {
LOG_DEBUG(Service_JIT, "called");
IPC::ResponseBuilder rb{ctx, 6};
@@ -332,7 +333,7 @@ public:
RegisterHandlers(functions);
}
- void CreateJitEnvironment(Kernel::HLERequestContext& ctx) {
+ void CreateJitEnvironment(HLERequestContext& ctx) {
LOG_DEBUG(Service_JIT, "called");
struct Parameters {
@@ -353,9 +354,9 @@ public:
return;
}
- // Fetch using the handle table for the current process here,
+ // Fetch using the handle table for the application process here,
// since we are not multiprocess yet.
- const auto& handle_table{system.CurrentProcess()->GetHandleTable()};
+ const auto& handle_table{system.ApplicationProcess()->GetHandleTable()};
auto process{handle_table.GetObject<Kernel::KProcess>(process_handle)};
if (process.IsNull()) {
@@ -382,12 +383,12 @@ public:
}
const CodeRange user_rx{
- .offset = rx_mem->GetSourceAddress(),
+ .offset = GetInteger(rx_mem->GetSourceAddress()),
.size = parameters.rx_size,
};
const CodeRange user_ro{
- .offset = ro_mem->GetSourceAddress(),
+ .offset = GetInteger(ro_mem->GetSourceAddress()),
.size = parameters.ro_size,
};
@@ -397,8 +398,11 @@ public:
}
};
-void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
- std::make_shared<JITU>(system)->InstallAsService(sm);
+void LoopProcess(Core::System& system) {
+ auto server_manager = std::make_unique<ServerManager>(system);
+
+ server_manager->RegisterNamedService("jit:u", std::make_shared<JITU>(system));
+ ServerManager::RunServer(std::move(server_manager));
}
} // namespace Service::JIT
diff --git a/src/core/hle/service/jit/jit.h b/src/core/hle/service/jit/jit.h
index af0f5b4f3..19014c75a 100644
--- a/src/core/hle/service/jit/jit.h
+++ b/src/core/hle/service/jit/jit.h
@@ -7,13 +7,8 @@ namespace Core {
class System;
}
-namespace Service::SM {
-class ServiceManager;
-}
-
namespace Service::JIT {
-/// Registers all JIT services with the specified service manager.
-void InstallInterfaces(SM::ServiceManager& sm, Core::System& system);
+void LoopProcess(Core::System& system);
} // namespace Service::JIT
diff --git a/src/core/hle/service/kernel_helpers.cpp b/src/core/hle/service/kernel_helpers.cpp
index 42991928e..6a313a03b 100644
--- a/src/core/hle/service/kernel_helpers.cpp
+++ b/src/core/hle/service/kernel_helpers.cpp
@@ -15,17 +15,27 @@ namespace Service::KernelHelpers {
ServiceContext::ServiceContext(Core::System& system_, std::string name_)
: kernel(system_.Kernel()) {
+ if (process = Kernel::GetCurrentProcessPointer(kernel); process != nullptr) {
+ return;
+ }
+
// Create the process.
process = Kernel::KProcess::Create(kernel);
ASSERT(Kernel::KProcess::Initialize(process, system_, std::move(name_),
Kernel::KProcess::ProcessType::KernelInternal,
kernel.GetSystemResourceLimit())
.IsSuccess());
+
+ // Register the process.
+ Kernel::KProcess::Register(kernel, process);
+ process_created = true;
}
ServiceContext::~ServiceContext() {
- process->Close();
- process = nullptr;
+ if (process_created) {
+ process->Close();
+ process = nullptr;
+ }
}
Kernel::KEvent* ServiceContext::CreateEvent(std::string&& name) {
diff --git a/src/core/hle/service/kernel_helpers.h b/src/core/hle/service/kernel_helpers.h
index 6415838e5..eca9aefb5 100644
--- a/src/core/hle/service/kernel_helpers.h
+++ b/src/core/hle/service/kernel_helpers.h
@@ -29,6 +29,7 @@ public:
private:
Kernel::KernelCore& kernel;
Kernel::KProcess* process{};
+ bool process_created{false};
};
} // namespace Service::KernelHelpers
diff --git a/src/core/hle/service/lbl/lbl.cpp b/src/core/hle/service/lbl/lbl.cpp
index c8415e0bf..98a79365d 100644
--- a/src/core/hle/service/lbl/lbl.cpp
+++ b/src/core/hle/service/lbl/lbl.cpp
@@ -5,8 +5,9 @@
#include <memory>
#include "common/logging/log.h"
-#include "core/hle/ipc_helpers.h"
+#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/lbl/lbl.h"
+#include "core/hle/service/server_manager.h"
#include "core/hle/service/service.h"
#include "core/hle/service/sm/sm.h"
@@ -59,7 +60,7 @@ private:
On = 1,
};
- void SetCurrentBrightnessSetting(Kernel::HLERequestContext& ctx) {
+ void SetCurrentBrightnessSetting(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
auto brightness = rp.Pop<float>();
@@ -77,7 +78,7 @@ private:
rb.Push(ResultSuccess);
}
- void GetCurrentBrightnessSetting(Kernel::HLERequestContext& ctx) {
+ void GetCurrentBrightnessSetting(HLERequestContext& ctx) {
auto brightness = current_brightness;
if (!std::isfinite(brightness)) {
LOG_ERROR(Service_LBL, "Brightness is infinite!");
@@ -91,7 +92,7 @@ private:
rb.Push(brightness);
}
- void SwitchBacklightOn(Kernel::HLERequestContext& ctx) {
+ void SwitchBacklightOn(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto fade_time = rp.Pop<u64_le>();
LOG_WARNING(Service_LBL, "(STUBBED) called, fade_time={}", fade_time);
@@ -102,7 +103,7 @@ private:
rb.Push(ResultSuccess);
}
- void SwitchBacklightOff(Kernel::HLERequestContext& ctx) {
+ void SwitchBacklightOff(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto fade_time = rp.Pop<u64_le>();
LOG_WARNING(Service_LBL, "(STUBBED) called, fade_time={}", fade_time);
@@ -113,7 +114,7 @@ private:
rb.Push(ResultSuccess);
}
- void GetBacklightSwitchStatus(Kernel::HLERequestContext& ctx) {
+ void GetBacklightSwitchStatus(HLERequestContext& ctx) {
LOG_DEBUG(Service_LBL, "called");
IPC::ResponseBuilder rb{ctx, 3};
@@ -122,7 +123,7 @@ private:
: BacklightSwitchStatus::Off);
}
- void EnableDimming(Kernel::HLERequestContext& ctx) {
+ void EnableDimming(HLERequestContext& ctx) {
LOG_DEBUG(Service_LBL, "called");
dimming = true;
@@ -131,7 +132,7 @@ private:
rb.Push(ResultSuccess);
}
- void DisableDimming(Kernel::HLERequestContext& ctx) {
+ void DisableDimming(HLERequestContext& ctx) {
LOG_DEBUG(Service_LBL, "called");
dimming = false;
@@ -140,7 +141,7 @@ private:
rb.Push(ResultSuccess);
}
- void IsDimmingEnabled(Kernel::HLERequestContext& ctx) {
+ void IsDimmingEnabled(HLERequestContext& ctx) {
LOG_DEBUG(Service_LBL, "called");
IPC::ResponseBuilder rb{ctx, 3};
@@ -148,7 +149,7 @@ private:
rb.Push(dimming);
}
- void EnableAutoBrightnessControl(Kernel::HLERequestContext& ctx) {
+ void EnableAutoBrightnessControl(HLERequestContext& ctx) {
LOG_DEBUG(Service_LBL, "called");
auto_brightness = true;
update_instantly = true;
@@ -157,7 +158,7 @@ private:
rb.Push(ResultSuccess);
}
- void DisableAutoBrightnessControl(Kernel::HLERequestContext& ctx) {
+ void DisableAutoBrightnessControl(HLERequestContext& ctx) {
LOG_DEBUG(Service_LBL, "called");
auto_brightness = false;
@@ -165,7 +166,7 @@ private:
rb.Push(ResultSuccess);
}
- void IsAutoBrightnessControlEnabled(Kernel::HLERequestContext& ctx) {
+ void IsAutoBrightnessControlEnabled(HLERequestContext& ctx) {
LOG_DEBUG(Service_LBL, "called");
IPC::ResponseBuilder rb{ctx, 3};
@@ -173,7 +174,7 @@ private:
rb.Push(auto_brightness);
}
- void SetAmbientLightSensorValue(Kernel::HLERequestContext& ctx) {
+ void SetAmbientLightSensorValue(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto light_value = rp.Pop<float>();
@@ -185,7 +186,7 @@ private:
rb.Push(ResultSuccess);
}
- void GetAmbientLightSensorValue(Kernel::HLERequestContext& ctx) {
+ void GetAmbientLightSensorValue(HLERequestContext& ctx) {
LOG_DEBUG(Service_LBL, "called");
IPC::ResponseBuilder rb{ctx, 3};
@@ -193,7 +194,7 @@ private:
rb.Push(ambient_light_value);
}
- void SetBrightnessReflectionDelayLevel(Kernel::HLERequestContext& ctx) {
+ void SetBrightnessReflectionDelayLevel(HLERequestContext& ctx) {
// This is Intentional, this function does absolutely nothing
LOG_DEBUG(Service_LBL, "called");
@@ -201,7 +202,7 @@ private:
rb.Push(ResultSuccess);
}
- void GetBrightnessReflectionDelayLevel(Kernel::HLERequestContext& ctx) {
+ void GetBrightnessReflectionDelayLevel(HLERequestContext& ctx) {
// This is intentional, the function is hard coded to return 0.0f on hardware
LOG_DEBUG(Service_LBL, "called");
@@ -210,7 +211,7 @@ private:
rb.Push(0.0f);
}
- void SetCurrentBrightnessMapping(Kernel::HLERequestContext& ctx) {
+ void SetCurrentBrightnessMapping(HLERequestContext& ctx) {
// This is Intentional, this function does absolutely nothing
LOG_DEBUG(Service_LBL, "called");
@@ -218,7 +219,7 @@ private:
rb.Push(ResultSuccess);
}
- void GetCurrentBrightnessMapping(Kernel::HLERequestContext& ctx) {
+ void GetCurrentBrightnessMapping(HLERequestContext& ctx) {
// This is Intentional, this function does absolutely nothing
LOG_DEBUG(Service_LBL, "called");
@@ -227,7 +228,7 @@ private:
// This function is suppose to return something but it seems like it doesn't
}
- void SetCurrentAmbientLightSensorMapping(Kernel::HLERequestContext& ctx) {
+ void SetCurrentAmbientLightSensorMapping(HLERequestContext& ctx) {
// This is Intentional, this function does absolutely nothing
LOG_DEBUG(Service_LBL, "called");
@@ -235,7 +236,7 @@ private:
rb.Push(ResultSuccess);
}
- void GetCurrentAmbientLightSensorMapping(Kernel::HLERequestContext& ctx) {
+ void GetCurrentAmbientLightSensorMapping(HLERequestContext& ctx) {
// This is Intentional, this function does absolutely nothing
LOG_DEBUG(Service_LBL, "called");
@@ -244,7 +245,7 @@ private:
// This function is suppose to return something but it seems like it doesn't
}
- void IsAmbientLightSensorAvailable(Kernel::HLERequestContext& ctx) {
+ void IsAmbientLightSensorAvailable(HLERequestContext& ctx) {
LOG_WARNING(Service_LBL, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
@@ -252,7 +253,7 @@ private:
rb.Push(true);
}
- void SetCurrentBrightnessSettingForVrMode(Kernel::HLERequestContext& ctx) {
+ void SetCurrentBrightnessSettingForVrMode(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
auto brightness = rp.Pop<float>();
@@ -269,7 +270,7 @@ private:
rb.Push(ResultSuccess);
}
- void GetCurrentBrightnessSettingForVrMode(Kernel::HLERequestContext& ctx) {
+ void GetCurrentBrightnessSettingForVrMode(HLERequestContext& ctx) {
auto brightness = current_vr_brightness;
if (!std::isfinite(brightness)) {
LOG_ERROR(Service_LBL, "Brightness is infinite!");
@@ -283,7 +284,7 @@ private:
rb.Push(brightness);
}
- void EnableVrMode(Kernel::HLERequestContext& ctx) {
+ void EnableVrMode(HLERequestContext& ctx) {
LOG_DEBUG(Service_LBL, "called");
IPC::ResponseBuilder rb{ctx, 2};
@@ -292,7 +293,7 @@ private:
vr_mode_enabled = true;
}
- void DisableVrMode(Kernel::HLERequestContext& ctx) {
+ void DisableVrMode(HLERequestContext& ctx) {
LOG_DEBUG(Service_LBL, "called");
IPC::ResponseBuilder rb{ctx, 2};
@@ -301,7 +302,7 @@ private:
vr_mode_enabled = false;
}
- void IsVrModeEnabled(Kernel::HLERequestContext& ctx) {
+ void IsVrModeEnabled(HLERequestContext& ctx) {
LOG_DEBUG(Service_LBL, "called");
IPC::ResponseBuilder rb{ctx, 3};
@@ -319,8 +320,11 @@ private:
bool auto_brightness = false; // TODO(ogniK): Move to system settings
};
-void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
- std::make_shared<LBL>(system)->InstallAsService(sm);
+void LoopProcess(Core::System& system) {
+ auto server_manager = std::make_unique<ServerManager>(system);
+
+ server_manager->RegisterNamedService("lbl", std::make_shared<LBL>(system));
+ ServerManager::RunServer(std::move(server_manager));
}
} // namespace Service::LBL
diff --git a/src/core/hle/service/lbl/lbl.h b/src/core/hle/service/lbl/lbl.h
index 6484105c2..e47759c01 100644
--- a/src/core/hle/service/lbl/lbl.h
+++ b/src/core/hle/service/lbl/lbl.h
@@ -7,12 +7,8 @@ namespace Core {
class System;
}
-namespace Service::SM {
-class ServiceManager;
-}
-
namespace Service::LBL {
-void InstallInterfaces(SM::ServiceManager& sm, Core::System& system);
+void LoopProcess(Core::System& system);
} // namespace Service::LBL
diff --git a/src/core/hle/service/ldn/ldn.cpp b/src/core/hle/service/ldn/ldn.cpp
index c49c61cff..9d149a7cd 100644
--- a/src/core/hle/service/ldn/ldn.cpp
+++ b/src/core/hle/service/ldn/ldn.cpp
@@ -8,6 +8,7 @@
#include "core/hle/service/ldn/ldn.h"
#include "core/hle/service/ldn/ldn_results.h"
#include "core/hle/service/ldn/ldn_types.h"
+#include "core/hle/service/server_manager.h"
#include "core/internal_network/network.h"
#include "core/internal_network/network_interface.h"
#include "network/network.h"
@@ -49,7 +50,7 @@ public:
RegisterHandlers(functions);
}
- void CreateMonitorService(Kernel::HLERequestContext& ctx) {
+ void CreateMonitorService(HLERequestContext& ctx) {
LOG_DEBUG(Service_LDN, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -106,7 +107,7 @@ class IUserLocalCommunicationService final
: public ServiceFramework<IUserLocalCommunicationService> {
public:
explicit IUserLocalCommunicationService(Core::System& system_)
- : ServiceFramework{system_, "IUserLocalCommunicationService", ServiceThreadType::CreateNew},
+ : ServiceFramework{system_, "IUserLocalCommunicationService"},
service_context{system, "IUserLocalCommunicationService"},
room_network{system_.GetRoomNetwork()}, lan_discovery{room_network} {
// clang-format off
@@ -168,7 +169,7 @@ public:
state_change_event->Signal();
}
- void GetState(Kernel::HLERequestContext& ctx) {
+ void GetState(HLERequestContext& ctx) {
State state = State::Error;
if (is_initialized) {
@@ -180,7 +181,7 @@ public:
rb.PushEnum(state);
}
- void GetNetworkInfo(Kernel::HLERequestContext& ctx) {
+ void GetNetworkInfo(HLERequestContext& ctx) {
const auto write_buffer_size = ctx.GetWriteBufferSize();
if (write_buffer_size != sizeof(NetworkInfo)) {
@@ -204,7 +205,7 @@ public:
rb.Push(ResultSuccess);
}
- void GetIpv4Address(Kernel::HLERequestContext& ctx) {
+ void GetIpv4Address(HLERequestContext& ctx) {
const auto network_interface = Network::GetSelectedNetworkInterface();
if (!network_interface) {
@@ -233,13 +234,13 @@ public:
rb.PushRaw(subnet_mask);
}
- void GetDisconnectReason(Kernel::HLERequestContext& ctx) {
+ void GetDisconnectReason(HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.PushEnum(lan_discovery.GetDisconnectReason());
}
- void GetSecurityParameter(Kernel::HLERequestContext& ctx) {
+ void GetSecurityParameter(HLERequestContext& ctx) {
SecurityParameter security_parameter{};
NetworkInfo info{};
const Result rc = lan_discovery.GetNetworkInfo(info);
@@ -260,7 +261,7 @@ public:
rb.PushRaw<SecurityParameter>(security_parameter);
}
- void GetNetworkConfig(Kernel::HLERequestContext& ctx) {
+ void GetNetworkConfig(HLERequestContext& ctx) {
NetworkConfig config{};
NetworkInfo info{};
const Result rc = lan_discovery.GetNetworkInfo(info);
@@ -282,7 +283,7 @@ public:
rb.PushRaw<NetworkConfig>(config);
}
- void AttachStateChangeEvent(Kernel::HLERequestContext& ctx) {
+ void AttachStateChangeEvent(HLERequestContext& ctx) {
LOG_INFO(Service_LDN, "called");
IPC::ResponseBuilder rb{ctx, 2, 1};
@@ -290,7 +291,7 @@ public:
rb.PushCopyObjects(state_change_event->GetReadableEvent());
}
- void GetNetworkInfoLatestUpdate(Kernel::HLERequestContext& ctx) {
+ void GetNetworkInfoLatestUpdate(HLERequestContext& ctx) {
const std::size_t network_buffer_size = ctx.GetWriteBufferSize(0);
const std::size_t node_buffer_count = ctx.GetWriteBufferNumElements<NodeLatestUpdate>(1);
@@ -320,15 +321,15 @@ public:
rb.Push(ResultSuccess);
}
- void Scan(Kernel::HLERequestContext& ctx) {
+ void Scan(HLERequestContext& ctx) {
ScanImpl(ctx);
}
- void ScanPrivate(Kernel::HLERequestContext& ctx) {
+ void ScanPrivate(HLERequestContext& ctx) {
ScanImpl(ctx, true);
}
- void ScanImpl(Kernel::HLERequestContext& ctx, bool is_private = false) {
+ void ScanImpl(HLERequestContext& ctx, bool is_private = false) {
IPC::RequestParser rp{ctx};
const auto channel{rp.PopEnum<WifiChannel>()};
const auto scan_filter{rp.PopRaw<ScanFilter>()};
@@ -357,40 +358,40 @@ public:
rb.Push<u32>(count);
}
- void SetWirelessControllerRestriction(Kernel::HLERequestContext& ctx) {
+ void SetWirelessControllerRestriction(HLERequestContext& ctx) {
LOG_WARNING(Service_LDN, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
- void OpenAccessPoint(Kernel::HLERequestContext& ctx) {
+ void OpenAccessPoint(HLERequestContext& ctx) {
LOG_INFO(Service_LDN, "called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(lan_discovery.OpenAccessPoint());
}
- void CloseAccessPoint(Kernel::HLERequestContext& ctx) {
+ void CloseAccessPoint(HLERequestContext& ctx) {
LOG_INFO(Service_LDN, "called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(lan_discovery.CloseAccessPoint());
}
- void CreateNetwork(Kernel::HLERequestContext& ctx) {
+ void CreateNetwork(HLERequestContext& ctx) {
LOG_INFO(Service_LDN, "called");
CreateNetworkImpl(ctx);
}
- void CreateNetworkPrivate(Kernel::HLERequestContext& ctx) {
+ void CreateNetworkPrivate(HLERequestContext& ctx) {
LOG_INFO(Service_LDN, "called");
CreateNetworkImpl(ctx, true);
}
- void CreateNetworkImpl(Kernel::HLERequestContext& ctx, bool is_private = false) {
+ void CreateNetworkImpl(HLERequestContext& ctx, bool is_private = false) {
IPC::RequestParser rp{ctx};
const auto security_config{rp.PopRaw<SecurityConfig>()};
@@ -404,49 +405,49 @@ public:
rb.Push(lan_discovery.CreateNetwork(security_config, user_config, network_Config));
}
- void DestroyNetwork(Kernel::HLERequestContext& ctx) {
+ void DestroyNetwork(HLERequestContext& ctx) {
LOG_INFO(Service_LDN, "called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(lan_discovery.DestroyNetwork());
}
- void SetAdvertiseData(Kernel::HLERequestContext& ctx) {
- std::vector<u8> read_buffer = ctx.ReadBuffer();
+ void SetAdvertiseData(HLERequestContext& ctx) {
+ const auto read_buffer = ctx.ReadBuffer();
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(lan_discovery.SetAdvertiseData(read_buffer));
}
- void SetStationAcceptPolicy(Kernel::HLERequestContext& ctx) {
+ void SetStationAcceptPolicy(HLERequestContext& ctx) {
LOG_WARNING(Service_LDN, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
- void AddAcceptFilterEntry(Kernel::HLERequestContext& ctx) {
+ void AddAcceptFilterEntry(HLERequestContext& ctx) {
LOG_WARNING(Service_LDN, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
- void OpenStation(Kernel::HLERequestContext& ctx) {
+ void OpenStation(HLERequestContext& ctx) {
LOG_INFO(Service_LDN, "called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(lan_discovery.OpenStation());
}
- void CloseStation(Kernel::HLERequestContext& ctx) {
+ void CloseStation(HLERequestContext& ctx) {
LOG_INFO(Service_LDN, "called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(lan_discovery.CloseStation());
}
- void Connect(Kernel::HLERequestContext& ctx) {
+ void Connect(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
SecurityConfig security_config;
@@ -464,7 +465,7 @@ public:
parameters.security_config.passphrase_size,
parameters.security_config.security_mode, parameters.local_communication_version);
- const std::vector<u8> read_buffer = ctx.ReadBuffer();
+ const auto read_buffer = ctx.ReadBuffer();
if (read_buffer.size() != sizeof(NetworkInfo)) {
LOG_ERROR(Frontend, "NetworkInfo doesn't match read_buffer size!");
IPC::ResponseBuilder rb{ctx, 2};
@@ -480,14 +481,14 @@ public:
static_cast<u16>(parameters.local_communication_version)));
}
- void Disconnect(Kernel::HLERequestContext& ctx) {
+ void Disconnect(HLERequestContext& ctx) {
LOG_INFO(Service_LDN, "called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(lan_discovery.Disconnect());
}
- void Initialize(Kernel::HLERequestContext& ctx) {
+ void Initialize(HLERequestContext& ctx) {
const auto rc = InitializeImpl(ctx);
if (rc.IsError()) {
LOG_ERROR(Service_LDN, "Network isn't initialized, rc={}", rc.raw);
@@ -497,7 +498,7 @@ public:
rb.Push(rc);
}
- void Finalize(Kernel::HLERequestContext& ctx) {
+ void Finalize(HLERequestContext& ctx) {
if (auto room_member = room_network.GetRoomMember().lock()) {
room_member->Unbind(ldn_packet_received);
}
@@ -508,7 +509,7 @@ public:
rb.Push(lan_discovery.Finalize());
}
- void Initialize2(Kernel::HLERequestContext& ctx) {
+ void Initialize2(HLERequestContext& ctx) {
const auto rc = InitializeImpl(ctx);
if (rc.IsError()) {
LOG_ERROR(Service_LDN, "Network isn't initialized, rc={}", rc.raw);
@@ -518,7 +519,7 @@ public:
rb.Push(rc);
}
- Result InitializeImpl(Kernel::HLERequestContext& ctx) {
+ Result InitializeImpl(HLERequestContext& ctx) {
const auto network_interface = Network::GetSelectedNetworkInterface();
if (!network_interface) {
LOG_ERROR(Service_LDN, "No network interface is set");
@@ -561,7 +562,7 @@ public:
RegisterHandlers(functions);
}
- void CreateSystemLocalCommunicationService(Kernel::HLERequestContext& ctx) {
+ void CreateSystemLocalCommunicationService(HLERequestContext& ctx) {
LOG_DEBUG(Service_LDN, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -582,7 +583,7 @@ public:
RegisterHandlers(functions);
}
- void CreateUserLocalCommunicationService(Kernel::HLERequestContext& ctx) {
+ void CreateUserLocalCommunicationService(HLERequestContext& ctx) {
LOG_DEBUG(Service_LDN, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -646,7 +647,7 @@ public:
RegisterHandlers(functions);
}
- void Initialize(Kernel::HLERequestContext& ctx) {
+ void Initialize(HLERequestContext& ctx) {
LOG_WARNING(Service_LDN, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
@@ -667,7 +668,7 @@ public:
RegisterHandlers(functions);
}
- void CreateNetworkervice(Kernel::HLERequestContext& ctx) {
+ void CreateNetworkervice(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u64 reserved_input = rp.Pop<u64>();
const u32 input = rp.Pop<u32>();
@@ -680,7 +681,7 @@ public:
rb.PushIpcInterface<INetworkService>(system);
}
- void CreateMonitorService(Kernel::HLERequestContext& ctx) {
+ void CreateMonitorService(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u64 reserved_input = rp.Pop<u64>();
@@ -705,7 +706,7 @@ public:
RegisterHandlers(functions);
}
- void CreateNetworkervice(Kernel::HLERequestContext& ctx) {
+ void CreateNetworkervice(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u64 reserved_input = rp.Pop<u64>();
const u32 input = rp.Pop<u32>();
@@ -718,7 +719,7 @@ public:
rb.PushIpcInterface<INetworkService>(system);
}
- void CreateMonitorService(Kernel::HLERequestContext& ctx) {
+ void CreateMonitorService(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u64 reserved_input = rp.Pop<u64>();
@@ -730,12 +731,15 @@ public:
}
};
-void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
- std::make_shared<LDNM>(system)->InstallAsService(sm);
- std::make_shared<LDNS>(system)->InstallAsService(sm);
- std::make_shared<LDNU>(system)->InstallAsService(sm);
- std::make_shared<LP2PAPP>(system)->InstallAsService(sm);
- std::make_shared<LP2PSYS>(system)->InstallAsService(sm);
+void LoopProcess(Core::System& system) {
+ auto server_manager = std::make_unique<ServerManager>(system);
+
+ server_manager->RegisterNamedService("ldn:m", std::make_shared<LDNM>(system));
+ server_manager->RegisterNamedService("ldn:s", std::make_shared<LDNS>(system));
+ server_manager->RegisterNamedService("ldn:u", std::make_shared<LDNU>(system));
+ server_manager->RegisterNamedService("lp2p:app", std::make_shared<LP2PAPP>(system));
+ server_manager->RegisterNamedService("lp2p:sys", std::make_shared<LP2PSYS>(system));
+ ServerManager::RunServer(std::move(server_manager));
}
} // namespace Service::LDN
diff --git a/src/core/hle/service/ldn/ldn.h b/src/core/hle/service/ldn/ldn.h
index 6afe2ea6f..f4a319168 100644
--- a/src/core/hle/service/ldn/ldn.h
+++ b/src/core/hle/service/ldn/ldn.h
@@ -3,9 +3,9 @@
#pragma once
-#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/k_event.h"
#include "core/hle/result.h"
+#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/sm/sm.h"
@@ -13,13 +13,8 @@ namespace Core {
class System;
}
-namespace Service::SM {
-class ServiceManager;
-}
-
namespace Service::LDN {
-/// Registers all LDN services with the specified service manager.
-void InstallInterfaces(SM::ServiceManager& sm, Core::System& system);
+void LoopProcess(Core::System& system);
} // namespace Service::LDN
diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp
index 652441bc2..c42489ff9 100644
--- a/src/core/hle/service/ldr/ldr.cpp
+++ b/src/core/hle/service/ldr/ldr.cpp
@@ -9,11 +9,12 @@
#include "common/hex_util.h"
#include "common/scope_exit.h"
#include "core/core.h"
-#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/k_page_table.h"
#include "core/hle/kernel/svc_results.h"
#include "core/hle/kernel/svc_types.h"
+#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/ldr/ldr.h"
+#include "core/hle/service/server_manager.h"
#include "core/hle/service/service.h"
#include "core/loader/nro.h"
#include "core/memory.h"
@@ -159,8 +160,7 @@ public:
class RelocatableObject final : public ServiceFramework<RelocatableObject> {
public:
- explicit RelocatableObject(Core::System& system_)
- : ServiceFramework{system_, "ldr:ro", ServiceThreadType::CreateNew} {
+ explicit RelocatableObject(Core::System& system_) : ServiceFramework{system_, "ldr:ro"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &RelocatableObject::LoadModule, "LoadModule"},
@@ -175,7 +175,7 @@ public:
RegisterHandlers(functions);
}
- void RegisterModuleInfo(Kernel::HLERequestContext& ctx) {
+ void RegisterModuleInfo(HLERequestContext& ctx) {
struct Parameters {
u64_le process_id;
u64_le nrr_address;
@@ -225,7 +225,7 @@ public:
// Read NRR data from memory
std::vector<u8> nrr_data(nrr_size);
- system.Memory().ReadBlock(nrr_address, nrr_data.data(), nrr_size);
+ system.ApplicationMemory().ReadBlock(nrr_address, nrr_data.data(), nrr_size);
NRRHeader header;
std::memcpy(&header, nrr_data.data(), sizeof(NRRHeader));
@@ -246,7 +246,7 @@ public:
return;
}
- if (system.GetCurrentProcessProgramID() != header.application_id) {
+ if (system.GetApplicationProcessProgramID() != header.application_id) {
LOG_ERROR(Service_LDR,
"Attempting to load NRR with title ID other than current process. (actual "
"{:016X})!",
@@ -272,7 +272,7 @@ public:
rb.Push(ResultSuccess);
}
- void UnregisterModuleInfo(Kernel::HLERequestContext& ctx) {
+ void UnregisterModuleInfo(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto pid = rp.Pop<u64>();
const auto nrr_address = rp.Pop<VAddr>();
@@ -314,7 +314,7 @@ public:
const auto is_region_available = [&](VAddr addr) {
const auto end_addr = addr + size;
while (addr < end_addr) {
- if (system.Memory().IsValidVirtualAddress(addr)) {
+ if (system.ApplicationMemory().IsValidVirtualAddress(addr)) {
return false;
}
@@ -337,7 +337,7 @@ public:
bool succeeded = false;
const auto map_region_end =
- page_table.GetAliasCodeRegionStart() + page_table.GetAliasCodeRegionSize();
+ GetInteger(page_table.GetAliasCodeRegionStart()) + page_table.GetAliasCodeRegionSize();
while (current_map_addr < map_region_end) {
if (is_region_available(current_map_addr)) {
succeeded = true;
@@ -427,8 +427,8 @@ public:
const VAddr bss_end_addr{
Common::AlignUp(bss_start + nro_header.bss_size, Kernel::PageSize)};
- const auto CopyCode = [this, process](VAddr src_addr, VAddr dst_addr, u64 size) {
- system.Memory().CopyBlock(*process, dst_addr, src_addr, size);
+ const auto CopyCode = [this](VAddr src_addr, VAddr dst_addr, u64 size) {
+ system.ApplicationMemory().CopyBlock(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);
@@ -446,7 +446,7 @@ public:
data_start, bss_end_addr - data_start, Kernel::Svc::MemoryPermission::ReadWrite);
}
- void LoadModule(Kernel::HLERequestContext& ctx) {
+ void LoadModule(HLERequestContext& ctx) {
struct Parameters {
u64_le process_id;
u64_le image_address;
@@ -506,7 +506,7 @@ public:
// Read NRO data from memory
std::vector<u8> nro_data(nro_size);
- system.Memory().ReadBlock(nro_address, nro_data.data(), nro_size);
+ system.ApplicationMemory().ReadBlock(nro_address, nro_data.data(), nro_size);
SHA256Hash hash{};
mbedtls_sha256_ret(nro_data.data(), nro_data.size(), hash.data(), 0);
@@ -542,15 +542,16 @@ public:
}
// Map memory for the NRO
- const auto map_result{MapNro(system.CurrentProcess(), nro_address, nro_size, bss_address,
- bss_size, nro_size + bss_size)};
+ const auto map_result{MapNro(system.ApplicationProcess(), nro_address, nro_size,
+ bss_address, bss_size, nro_size + bss_size)};
if (map_result.Failed()) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(map_result.Code());
}
// Load the NRO into the mapped memory
- if (const auto result{LoadNro(system.CurrentProcess(), header, nro_address, *map_result)};
+ if (const auto result{
+ LoadNro(system.ApplicationProcess(), header, nro_address, *map_result)};
result.IsError()) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(map_result.Code());
@@ -570,7 +571,7 @@ public:
Result UnmapNro(const NROInfo& info) {
// Each region must be unmapped separately to validate memory state
- auto& page_table{system.CurrentProcess()->PageTable()};
+ auto& page_table{system.ApplicationProcess()->PageTable()};
if (info.bss_size != 0) {
CASCADE_CODE(page_table.UnmapCodeMemory(
@@ -591,7 +592,7 @@ public:
return ResultSuccess;
}
- void UnloadModule(Kernel::HLERequestContext& ctx) {
+ void UnloadModule(HLERequestContext& ctx) {
if (!initialized) {
LOG_ERROR(Service_LDR, "LDR:RO not initialized before use!");
IPC::ResponseBuilder rb{ctx, 2};
@@ -637,11 +638,12 @@ public:
rb.Push(result);
}
- void Initialize(Kernel::HLERequestContext& ctx) {
+ void Initialize(HLERequestContext& ctx) {
LOG_WARNING(Service_LDR, "(STUBBED) called");
initialized = true;
- current_map_addr = system.CurrentProcess()->PageTable().GetAliasCodeRegionStart();
+ current_map_addr =
+ GetInteger(system.ApplicationProcess()->PageTable().GetAliasCodeRegionStart());
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
@@ -681,11 +683,15 @@ private:
}
};
-void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
- std::make_shared<DebugMonitor>(system)->InstallAsService(sm);
- std::make_shared<ProcessManager>(system)->InstallAsService(sm);
- std::make_shared<Shell>(system)->InstallAsService(sm);
- std::make_shared<RelocatableObject>(system)->InstallAsService(sm);
+void LoopProcess(Core::System& system) {
+ auto server_manager = std::make_unique<ServerManager>(system);
+
+ server_manager->RegisterNamedService("ldr:dmnt", std::make_shared<DebugMonitor>(system));
+ server_manager->RegisterNamedService("ldr:pm", std::make_shared<ProcessManager>(system));
+ server_manager->RegisterNamedService("ldr:shel", std::make_shared<Shell>(system));
+ server_manager->RegisterNamedService("ldr:ro", std::make_shared<RelocatableObject>(system));
+
+ ServerManager::RunServer(std::move(server_manager));
}
} // namespace Service::LDR
diff --git a/src/core/hle/service/ldr/ldr.h b/src/core/hle/service/ldr/ldr.h
index 25ffd8442..c9281dbfb 100644
--- a/src/core/hle/service/ldr/ldr.h
+++ b/src/core/hle/service/ldr/ldr.h
@@ -7,13 +7,8 @@ namespace Core {
class System;
}
-namespace Service::SM {
-class ServiceManager;
-}
-
namespace Service::LDR {
-/// Registers all LDR services with the specified service manager.
-void InstallInterfaces(SM::ServiceManager& sm, Core::System& system);
+void LoopProcess(Core::System& system);
} // namespace Service::LDR
diff --git a/src/core/hle/service/lm/lm.cpp b/src/core/hle/service/lm/lm.cpp
index ef4b54046..20df00233 100644
--- a/src/core/hle/service/lm/lm.cpp
+++ b/src/core/hle/service/lm/lm.cpp
@@ -8,8 +8,9 @@
#include <boost/container_hash/hash.hpp>
#include "common/logging/log.h"
#include "core/core.h"
-#include "core/hle/ipc_helpers.h"
+#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/lm/lm.h"
+#include "core/hle/service/server_manager.h"
#include "core/hle/service/service.h"
namespace Service::LM {
@@ -92,7 +93,7 @@ public:
}
private:
- void Log(Kernel::HLERequestContext& ctx) {
+ void Log(HLERequestContext& ctx) {
std::size_t offset{};
const auto data = ctx.ReadBuffer();
@@ -147,7 +148,7 @@ private:
}
}
- void SetDestination(Kernel::HLERequestContext& ctx) {
+ void SetDestination(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto log_destination = rp.PopEnum<LogDestination>();
@@ -342,7 +343,7 @@ public:
}
private:
- void OpenLogger(Kernel::HLERequestContext& ctx) {
+ void OpenLogger(HLERequestContext& ctx) {
LOG_DEBUG(Service_LM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -351,8 +352,11 @@ private:
}
};
-void InstallInterfaces(Core::System& system) {
- std::make_shared<LM>(system)->InstallAsService(system.ServiceManager());
+void LoopProcess(Core::System& system) {
+ auto server_manager = std::make_unique<ServerManager>(system);
+
+ server_manager->RegisterNamedService("lm", std::make_shared<LM>(system));
+ ServerManager::RunServer(std::move(server_manager));
}
} // namespace Service::LM
diff --git a/src/core/hle/service/lm/lm.h b/src/core/hle/service/lm/lm.h
index 266019c30..0d7c39cbc 100644
--- a/src/core/hle/service/lm/lm.h
+++ b/src/core/hle/service/lm/lm.h
@@ -9,7 +9,6 @@ class System;
namespace Service::LM {
-/// Registers all LM services with the specified service manager.
-void InstallInterfaces(Core::System& system);
+void LoopProcess(Core::System& system);
} // namespace Service::LM
diff --git a/src/core/hle/service/mig/mig.cpp b/src/core/hle/service/mig/mig.cpp
index b9fe0cecd..082e470ab 100644
--- a/src/core/hle/service/mig/mig.cpp
+++ b/src/core/hle/service/mig/mig.cpp
@@ -4,8 +4,8 @@
#include <memory>
#include "core/hle/service/mig/mig.h"
+#include "core/hle/service/server_manager.h"
#include "core/hle/service/service.h"
-#include "core/hle/service/sm/sm.h"
namespace Service::Migration {
@@ -32,8 +32,11 @@ public:
}
};
-void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
- std::make_shared<MIG_USR>(system)->InstallAsService(sm);
+void LoopProcess(Core::System& system) {
+ auto server_manager = std::make_unique<ServerManager>(system);
+
+ server_manager->RegisterNamedService("mig:user", std::make_shared<MIG_USR>(system));
+ ServerManager::RunServer(std::move(server_manager));
}
} // namespace Service::Migration
diff --git a/src/core/hle/service/mig/mig.h b/src/core/hle/service/mig/mig.h
index f1641a521..c8ed732a5 100644
--- a/src/core/hle/service/mig/mig.h
+++ b/src/core/hle/service/mig/mig.h
@@ -7,12 +7,8 @@ namespace Core {
class System;
}
-namespace Service::SM {
-class ServiceManager;
-}
-
namespace Service::Migration {
-void InstallInterfaces(SM::ServiceManager& sm, Core::System& system);
+void LoopProcess(Core::System& system);
} // namespace Service::Migration
diff --git a/src/core/hle/service/mii/mii.cpp b/src/core/hle/service/mii/mii.cpp
index 390514fdc..5c7adf97d 100644
--- a/src/core/hle/service/mii/mii.cpp
+++ b/src/core/hle/service/mii/mii.cpp
@@ -4,11 +4,11 @@
#include <memory>
#include "common/logging/log.h"
-#include "core/hle/ipc_helpers.h"
+#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/mii/mii.h"
#include "core/hle/service/mii/mii_manager.h"
+#include "core/hle/service/server_manager.h"
#include "core/hle/service/service.h"
-#include "core/hle/service/sm/sm.h"
namespace Service::Mii {
@@ -65,7 +65,7 @@ private:
return out;
}
- void IsUpdated(Kernel::HLERequestContext& ctx) {
+ void IsUpdated(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto source_flag{rp.PopRaw<SourceFlag>()};
@@ -76,7 +76,7 @@ private:
rb.Push(manager.CheckAndResetUpdateCounter(source_flag, current_update_counter));
}
- void IsFullDatabase(Kernel::HLERequestContext& ctx) {
+ void IsFullDatabase(HLERequestContext& ctx) {
LOG_DEBUG(Service_Mii, "called");
IPC::ResponseBuilder rb{ctx, 3};
@@ -84,7 +84,7 @@ private:
rb.Push(manager.IsFullDatabase());
}
- void GetCount(Kernel::HLERequestContext& ctx) {
+ void GetCount(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto source_flag{rp.PopRaw<SourceFlag>()};
@@ -95,7 +95,7 @@ private:
rb.Push<u32>(manager.GetCount(source_flag));
}
- void Get(Kernel::HLERequestContext& ctx) {
+ void Get(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto source_flag{rp.PopRaw<SourceFlag>()};
@@ -117,7 +117,7 @@ private:
rb.Push<u32>(static_cast<u32>(result->size()));
}
- void Get1(Kernel::HLERequestContext& ctx) {
+ void Get1(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto source_flag{rp.PopRaw<SourceFlag>()};
@@ -142,7 +142,7 @@ private:
rb.Push<u32>(static_cast<u32>(result->size()));
}
- void UpdateLatest(Kernel::HLERequestContext& ctx) {
+ void UpdateLatest(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto info{rp.PopRaw<CharInfo>()};
const auto source_flag{rp.PopRaw<SourceFlag>()};
@@ -161,7 +161,7 @@ private:
rb.PushRaw<CharInfo>(*result);
}
- void BuildRandom(Kernel::HLERequestContext& ctx) {
+ void BuildRandom(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto age{rp.PopRaw<Age>()};
@@ -196,7 +196,7 @@ private:
rb.PushRaw<CharInfo>(manager.BuildRandom(age, gender, race));
}
- void BuildDefault(Kernel::HLERequestContext& ctx) {
+ void BuildDefault(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto index{rp.Pop<u32>()};
@@ -215,7 +215,7 @@ private:
rb.PushRaw<CharInfo>(manager.BuildDefault(index));
}
- void GetIndex(Kernel::HLERequestContext& ctx) {
+ void GetIndex(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto info{rp.PopRaw<CharInfo>()};
@@ -227,7 +227,7 @@ private:
rb.Push(index);
}
- void SetInterfaceVersion(Kernel::HLERequestContext& ctx) {
+ void SetInterfaceVersion(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
current_interface_version = rp.PopRaw<u32>();
@@ -239,7 +239,7 @@ private:
rb.Push(ResultSuccess);
}
- void Convert(Kernel::HLERequestContext& ctx) {
+ void Convert(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto mii_v3{rp.PopRaw<Ver3StoreData>()};
@@ -275,7 +275,7 @@ public:
}
private:
- void GetDatabaseService(Kernel::HLERequestContext& ctx) {
+ void GetDatabaseService(HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IDatabaseService>(system);
@@ -310,11 +310,13 @@ public:
}
};
-void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
- std::make_shared<MiiDBModule>(system, "mii:e")->InstallAsService(sm);
- std::make_shared<MiiDBModule>(system, "mii:u")->InstallAsService(sm);
+void LoopProcess(Core::System& system) {
+ auto server_manager = std::make_unique<ServerManager>(system);
- std::make_shared<MiiImg>(system)->InstallAsService(sm);
+ server_manager->RegisterNamedService("mii:e", std::make_shared<MiiDBModule>(system, "mii:e"));
+ server_manager->RegisterNamedService("mii:u", std::make_shared<MiiDBModule>(system, "mii:u"));
+ server_manager->RegisterNamedService("miiimg", std::make_shared<MiiImg>(system));
+ ServerManager::RunServer(std::move(server_manager));
}
} // namespace Service::Mii
diff --git a/src/core/hle/service/mii/mii.h b/src/core/hle/service/mii/mii.h
index 009d80d58..ed4e3f62b 100644
--- a/src/core/hle/service/mii/mii.h
+++ b/src/core/hle/service/mii/mii.h
@@ -7,12 +7,8 @@ namespace Core {
class System;
}
-namespace Service::SM {
-class ServiceManager;
-}
-
namespace Service::Mii {
-void InstallInterfaces(SM::ServiceManager& sm, Core::System& system);
+void LoopProcess(Core::System& system);
} // namespace Service::Mii
diff --git a/src/core/hle/service/mii/mii_manager.cpp b/src/core/hle/service/mii/mii_manager.cpp
index 3a2fe938f..c920650f5 100644
--- a/src/core/hle/service/mii/mii_manager.cpp
+++ b/src/core/hle/service/mii/mii_manager.cpp
@@ -510,7 +510,7 @@ CharInfo MiiManager::ConvertV3ToCharInfo(const Ver3StoreData& mii_v3) const {
return mii;
}
-Ver3StoreData MiiManager::ConvertCharInfoToV3(const CharInfo& mii) const {
+Ver3StoreData MiiManager::BuildFromStoreData(const CharInfo& mii) const {
Service::Mii::MiiManager manager;
Ver3StoreData mii_v3{};
@@ -534,16 +534,13 @@ Ver3StoreData MiiManager::ConvertCharInfoToV3(const CharInfo& mii) const {
mii_v3.region_information.character_set.Assign(mii.font_region);
mii_v3.appearance_bits1.face_shape.Assign(mii.faceline_type);
- mii_v3.appearance_bits1.skin_color.Assign(mii.faceline_color);
mii_v3.appearance_bits2.wrinkles.Assign(mii.faceline_wrinkle);
mii_v3.appearance_bits2.makeup.Assign(mii.faceline_make);
mii_v3.hair_style = mii.hair_type;
- mii_v3.appearance_bits3.hair_color.Assign(mii.hair_color);
mii_v3.appearance_bits3.flip_hair.Assign(mii.hair_flip);
mii_v3.appearance_bits4.eye_type.Assign(mii.eye_type);
- mii_v3.appearance_bits4.eye_color.Assign(mii.eye_color);
mii_v3.appearance_bits4.eye_scale.Assign(mii.eye_scale);
mii_v3.appearance_bits4.eye_vertical_stretch.Assign(mii.eye_aspect);
mii_v3.appearance_bits4.eye_rotation.Assign(mii.eye_rotate);
@@ -551,7 +548,6 @@ Ver3StoreData MiiManager::ConvertCharInfoToV3(const CharInfo& mii) const {
mii_v3.appearance_bits4.eye_y_position.Assign(mii.eye_y);
mii_v3.appearance_bits5.eyebrow_style.Assign(mii.eyebrow_type);
- mii_v3.appearance_bits5.eyebrow_color.Assign(mii.eyebrow_color);
mii_v3.appearance_bits5.eyebrow_scale.Assign(mii.eyebrow_scale);
mii_v3.appearance_bits5.eyebrow_yscale.Assign(mii.eyebrow_aspect);
mii_v3.appearance_bits5.eyebrow_rotation.Assign(mii.eyebrow_rotate);
@@ -563,7 +559,6 @@ Ver3StoreData MiiManager::ConvertCharInfoToV3(const CharInfo& mii) const {
mii_v3.appearance_bits6.nose_y_position.Assign(mii.nose_y);
mii_v3.appearance_bits7.mouth_type.Assign(mii.mouth_type);
- mii_v3.appearance_bits7.mouth_color.Assign(mii.mouth_color);
mii_v3.appearance_bits7.mouth_scale.Assign(mii.mouth_scale);
mii_v3.appearance_bits7.mouth_horizontal_stretch.Assign(mii.mouth_aspect);
mii_v3.appearance_bits8.mouth_y_position.Assign(mii.mouth_y);
@@ -573,10 +568,7 @@ Ver3StoreData MiiManager::ConvertCharInfoToV3(const CharInfo& mii) const {
mii_v3.appearance_bits9.mustache_y_position.Assign(mii.mustache_y);
mii_v3.appearance_bits9.bear_type.Assign(mii.beard_type);
- mii_v3.appearance_bits9.facial_hair_color.Assign(mii.beard_color);
- mii_v3.appearance_bits10.glasses_type.Assign(mii.glasses_type);
- mii_v3.appearance_bits10.glasses_color.Assign(mii.glasses_color);
mii_v3.appearance_bits10.glasses_scale.Assign(mii.glasses_scale);
mii_v3.appearance_bits10.glasses_y_position.Assign(mii.glasses_y);
@@ -585,11 +577,36 @@ Ver3StoreData MiiManager::ConvertCharInfoToV3(const CharInfo& mii) const {
mii_v3.appearance_bits11.mole_x_position.Assign(mii.mole_x);
mii_v3.appearance_bits11.mole_y_position.Assign(mii.mole_y);
+ // These types are converted to V3 from a table
+ mii_v3.appearance_bits1.skin_color.Assign(Ver3FacelineColorTable[mii.faceline_color]);
+ mii_v3.appearance_bits3.hair_color.Assign(Ver3HairColorTable[mii.hair_color]);
+ mii_v3.appearance_bits4.eye_color.Assign(Ver3EyeColorTable[mii.eye_color]);
+ mii_v3.appearance_bits5.eyebrow_color.Assign(Ver3HairColorTable[mii.eyebrow_color]);
+ mii_v3.appearance_bits7.mouth_color.Assign(Ver3MouthlineColorTable[mii.mouth_color]);
+ mii_v3.appearance_bits9.facial_hair_color.Assign(Ver3HairColorTable[mii.beard_color]);
+ mii_v3.appearance_bits10.glasses_color.Assign(Ver3GlassColorTable[mii.glasses_color]);
+ mii_v3.appearance_bits10.glasses_type.Assign(Ver3GlassTypeTable[mii.glasses_type]);
+
+ mii_v3.crc = GenerateCrc16(&mii_v3, sizeof(Ver3StoreData) - sizeof(u16));
+
// TODO: Validate mii_v3 data
return mii_v3;
}
+NfpStoreDataExtension MiiManager::SetFromStoreData(const CharInfo& mii) const {
+ return {
+ .faceline_color = static_cast<u8>(mii.faceline_color & 0xf),
+ .hair_color = static_cast<u8>(mii.hair_color & 0x7f),
+ .eye_color = static_cast<u8>(mii.eyebrow_color & 0x7f),
+ .eyebrow_color = static_cast<u8>(mii.eyebrow_color & 0x7f),
+ .mouth_color = static_cast<u8>(mii.mouth_color & 0x7f),
+ .beard_color = static_cast<u8>(mii.beard_color & 0x7f),
+ .glass_color = static_cast<u8>(mii.glasses_color & 0x7f),
+ .glass_type = static_cast<u8>(mii.glasses_type & 0x1f),
+ };
+}
+
bool MiiManager::ValidateV3Info(const Ver3StoreData& mii_v3) const {
bool is_valid = mii_v3.version == 0 || mii_v3.version == 3;
diff --git a/src/core/hle/service/mii/mii_manager.h b/src/core/hle/service/mii/mii_manager.h
index 83ad3d343..5525fcd1c 100644
--- a/src/core/hle/service/mii/mii_manager.h
+++ b/src/core/hle/service/mii/mii_manager.h
@@ -23,11 +23,16 @@ public:
CharInfo BuildRandom(Age age, Gender gender, Race race);
CharInfo BuildDefault(std::size_t index);
CharInfo ConvertV3ToCharInfo(const Ver3StoreData& mii_v3) const;
- Ver3StoreData ConvertCharInfoToV3(const CharInfo& mii) const;
bool ValidateV3Info(const Ver3StoreData& mii_v3) const;
ResultVal<std::vector<MiiInfoElement>> GetDefault(SourceFlag source_flag);
Result GetIndex(const CharInfo& info, u32& index);
+ // This is nn::mii::detail::Ver::StoreDataRaw::BuildFromStoreData
+ Ver3StoreData BuildFromStoreData(const CharInfo& mii) const;
+
+ // This is nn::mii::detail::NfpStoreDataExtentionRaw::SetFromStoreData
+ NfpStoreDataExtension SetFromStoreData(const CharInfo& mii) const;
+
private:
const Common::UUID user_id{};
u64 update_counter{};
diff --git a/src/core/hle/service/mii/types.h b/src/core/hle/service/mii/types.h
index 9e3247397..c48d08d79 100644
--- a/src/core/hle/service/mii/types.h
+++ b/src/core/hle/service/mii/types.h
@@ -365,10 +365,68 @@ struct Ver3StoreData {
} appearance_bits11;
std::array<u16_le, 0xA> author_name;
- INSERT_PADDING_BYTES(0x4);
+ INSERT_PADDING_BYTES(0x2);
+ u16_be crc;
};
static_assert(sizeof(Ver3StoreData) == 0x60, "Ver3StoreData is an invalid size");
+struct NfpStoreDataExtension {
+ u8 faceline_color;
+ u8 hair_color;
+ u8 eye_color;
+ u8 eyebrow_color;
+ u8 mouth_color;
+ u8 beard_color;
+ u8 glass_color;
+ u8 glass_type;
+};
+static_assert(sizeof(NfpStoreDataExtension) == 0x8, "NfpStoreDataExtension is an invalid size");
+
+constexpr std::array<u8, 0x10> Ver3FacelineColorTable{
+ 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x0, 0x1, 0x5, 0x5,
+};
+
+constexpr std::array<u8, 100> Ver3HairColorTable{
+ 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x0, 0x4, 0x3, 0x5, 0x4, 0x4, 0x6, 0x2, 0x0,
+ 0x6, 0x4, 0x3, 0x2, 0x2, 0x7, 0x3, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2,
+ 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x0, 0x0, 0x4,
+ 0x4, 0x4, 0x4, 0x4, 0x4, 0x0, 0x0, 0x0, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x5, 0x5, 0x5,
+ 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x5, 0x7, 0x5, 0x7, 0x7, 0x7, 0x7, 0x7, 0x6, 0x7,
+ 0x7, 0x7, 0x7, 0x7, 0x3, 0x7, 0x7, 0x7, 0x7, 0x7, 0x0, 0x4, 0x4, 0x4, 0x4,
+};
+
+constexpr std::array<u8, 100> Ver3EyeColorTable{
+ 0x0, 0x2, 0x2, 0x2, 0x1, 0x3, 0x2, 0x3, 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x2, 0x2, 0x4,
+ 0x2, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2,
+ 0x2, 0x2, 0x2, 0x2, 0x0, 0x0, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x1, 0x0, 0x4, 0x4,
+ 0x4, 0x4, 0x4, 0x4, 0x4, 0x0, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5,
+ 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x2, 0x2,
+ 0x3, 0x3, 0x3, 0x3, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1,
+};
+
+constexpr std::array<u8, 100> Ver3MouthlineColorTable{
+ 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x3, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x1, 0x4,
+ 0x4, 0x4, 0x0, 0x1, 0x2, 0x3, 0x4, 0x4, 0x2, 0x3, 0x3, 0x4, 0x4, 0x4, 0x4, 0x1, 0x4,
+ 0x4, 0x2, 0x3, 0x3, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x3, 0x3, 0x3, 0x4, 0x4, 0x4,
+ 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x4, 0x4, 0x4, 0x4, 0x3, 0x3, 0x3, 0x3, 0x4, 0x4, 0x4,
+ 0x4, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x4, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3,
+ 0x3, 0x3, 0x3, 0x3, 0x4, 0x0, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3, 0x3, 0x3, 0x3,
+};
+
+constexpr std::array<u8, 100> Ver3GlassColorTable{
+ 0x0, 0x1, 0x1, 0x1, 0x5, 0x1, 0x1, 0x4, 0x0, 0x5, 0x1, 0x1, 0x3, 0x5, 0x1, 0x2, 0x3,
+ 0x4, 0x5, 0x4, 0x2, 0x2, 0x4, 0x4, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2,
+ 0x2, 0x2, 0x2, 0x2, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3,
+ 0x3, 0x3, 0x3, 0x3, 0x3, 0x0, 0x0, 0x0, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x0, 0x5, 0x5,
+ 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x1, 0x4,
+ 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5,
+};
+
+constexpr std::array<u8, 20> Ver3GlassTypeTable{
+ 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x1,
+ 0x2, 0x1, 0x3, 0x7, 0x7, 0x6, 0x7, 0x8, 0x7, 0x7,
+};
+
struct MiiStoreData {
using Name = std::array<char16_t, 10>;
diff --git a/src/core/hle/service/mm/mm_u.cpp b/src/core/hle/service/mm/mm_u.cpp
index ba8c0e230..6f43b1968 100644
--- a/src/core/hle/service/mm/mm_u.cpp
+++ b/src/core/hle/service/mm/mm_u.cpp
@@ -2,8 +2,9 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/logging/log.h"
-#include "core/hle/ipc_helpers.h"
+#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/mm/mm_u.h"
+#include "core/hle/service/server_manager.h"
#include "core/hle/service/sm/sm.h"
namespace Service::MM {
@@ -28,21 +29,21 @@ public:
}
private:
- void InitializeOld(Kernel::HLERequestContext& ctx) {
+ void InitializeOld(HLERequestContext& ctx) {
LOG_WARNING(Service_MM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
- void FinalizeOld(Kernel::HLERequestContext& ctx) {
+ void FinalizeOld(HLERequestContext& ctx) {
LOG_WARNING(Service_MM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
- void SetAndWaitOld(Kernel::HLERequestContext& ctx) {
+ void SetAndWaitOld(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
min = rp.Pop<u32>();
max = rp.Pop<u32>();
@@ -53,7 +54,7 @@ private:
rb.Push(ResultSuccess);
}
- void GetOld(Kernel::HLERequestContext& ctx) {
+ void GetOld(HLERequestContext& ctx) {
LOG_DEBUG(Service_MM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
@@ -61,7 +62,7 @@ private:
rb.Push(current);
}
- void Initialize(Kernel::HLERequestContext& ctx) {
+ void Initialize(HLERequestContext& ctx) {
LOG_WARNING(Service_MM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
@@ -69,14 +70,14 @@ private:
rb.Push<u32>(id); // Any non zero value
}
- void Finalize(Kernel::HLERequestContext& ctx) {
+ void Finalize(HLERequestContext& ctx) {
LOG_WARNING(Service_MM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
- void SetAndWait(Kernel::HLERequestContext& ctx) {
+ void SetAndWait(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
u32 input_id = rp.Pop<u32>();
min = rp.Pop<u32>();
@@ -89,7 +90,7 @@ private:
rb.Push(ResultSuccess);
}
- void Get(Kernel::HLERequestContext& ctx) {
+ void Get(HLERequestContext& ctx) {
LOG_DEBUG(Service_MM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
@@ -103,8 +104,11 @@ private:
u32 id{1};
};
-void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
- std::make_shared<MM_U>(system)->InstallAsService(service_manager);
+void LoopProcess(Core::System& system) {
+ auto server_manager = std::make_unique<ServerManager>(system);
+
+ server_manager->RegisterNamedService("mm:u", std::make_shared<MM_U>(system));
+ ServerManager::RunServer(std::move(server_manager));
}
} // namespace Service::MM
diff --git a/src/core/hle/service/mm/mm_u.h b/src/core/hle/service/mm/mm_u.h
index b40941e35..43117c9b1 100644
--- a/src/core/hle/service/mm/mm_u.h
+++ b/src/core/hle/service/mm/mm_u.h
@@ -7,13 +7,8 @@ namespace Core {
class System;
}
-namespace Service::SM {
-class ServiceManager;
-}
-
namespace Service::MM {
-/// Registers all MM services with the specified service manager.
-void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system);
+void LoopProcess(Core::System& system);
} // namespace Service::MM
diff --git a/src/core/hle/service/mnpp/mnpp_app.cpp b/src/core/hle/service/mnpp/mnpp_app.cpp
index c3aad5714..b11a92056 100644
--- a/src/core/hle/service/mnpp/mnpp_app.cpp
+++ b/src/core/hle/service/mnpp/mnpp_app.cpp
@@ -2,9 +2,10 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/logging/log.h"
-#include "core/hle/ipc_helpers.h"
+#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/mnpp/mnpp_app.h"
-#include "core/hle/service/sm/sm.h"
+#include "core/hle/service/server_manager.h"
+#include "core/hle/service/service.h"
namespace Service::MNPP {
@@ -22,14 +23,14 @@ public:
}
private:
- void Unknown0(Kernel::HLERequestContext& ctx) {
+ void Unknown0(HLERequestContext& ctx) {
LOG_WARNING(Service_MNPP, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
- void Unknown1(Kernel::HLERequestContext& ctx) {
+ void Unknown1(HLERequestContext& ctx) {
LOG_WARNING(Service_MNPP, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
@@ -37,8 +38,11 @@ private:
}
};
-void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
- std::make_shared<MNPP_APP>(system)->InstallAsService(service_manager);
+void LoopProcess(Core::System& system) {
+ auto server_manager = std::make_unique<ServerManager>(system);
+
+ server_manager->RegisterNamedService("mnpp:app", std::make_shared<MNPP_APP>(system));
+ ServerManager::RunServer(std::move(server_manager));
}
} // namespace Service::MNPP
diff --git a/src/core/hle/service/mnpp/mnpp_app.h b/src/core/hle/service/mnpp/mnpp_app.h
index eec75fe0e..40d0395bd 100644
--- a/src/core/hle/service/mnpp/mnpp_app.h
+++ b/src/core/hle/service/mnpp/mnpp_app.h
@@ -7,13 +7,8 @@ namespace Core {
class System;
}
-namespace Service::SM {
-class ServiceManager;
-}
-
namespace Service::MNPP {
-/// Registers all MNPP services with the specified service manager.
-void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system);
+void LoopProcess(Core::System& system);
} // namespace Service::MNPP
diff --git a/src/core/hle/service/mutex.cpp b/src/core/hle/service/mutex.cpp
new file mode 100644
index 000000000..b0ff71d1b
--- /dev/null
+++ b/src/core/hle/service/mutex.cpp
@@ -0,0 +1,46 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/core.h"
+#include "core/hle/kernel/k_event.h"
+#include "core/hle/kernel/k_synchronization_object.h"
+#include "core/hle/service/mutex.h"
+
+namespace Service {
+
+Mutex::Mutex(Core::System& system) : m_system(system) {
+ m_event = Kernel::KEvent::Create(system.Kernel());
+ m_event->Initialize(nullptr);
+
+ // Register the event.
+ Kernel::KEvent::Register(system.Kernel(), m_event);
+
+ ASSERT(R_SUCCEEDED(m_event->Signal()));
+}
+
+Mutex::~Mutex() {
+ m_event->GetReadableEvent().Close();
+ m_event->Close();
+}
+
+void Mutex::lock() {
+ // Infinitely retry until we successfully clear the event.
+ while (R_FAILED(m_event->GetReadableEvent().Reset())) {
+ s32 index;
+ Kernel::KSynchronizationObject* obj = &m_event->GetReadableEvent();
+
+ // The event was already cleared!
+ // Wait for it to become signaled again.
+ ASSERT(R_SUCCEEDED(
+ Kernel::KSynchronizationObject::Wait(m_system.Kernel(), &index, &obj, 1, -1)));
+ }
+
+ // We successfully cleared the event, and now have exclusive ownership.
+}
+
+void Mutex::unlock() {
+ // Unlock.
+ ASSERT(R_SUCCEEDED(m_event->Signal()));
+}
+
+} // namespace Service
diff --git a/src/core/hle/service/mutex.h b/src/core/hle/service/mutex.h
new file mode 100644
index 000000000..95ac9b117
--- /dev/null
+++ b/src/core/hle/service/mutex.h
@@ -0,0 +1,31 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "common/common_types.h"
+
+namespace Core {
+class System;
+}
+
+namespace Kernel {
+class KEvent;
+}
+
+namespace Service {
+
+class Mutex {
+public:
+ explicit Mutex(Core::System& system);
+ ~Mutex();
+
+ void lock();
+ void unlock();
+
+private:
+ Core::System& m_system;
+ Kernel::KEvent* m_event{};
+};
+
+} // namespace Service
diff --git a/src/core/hle/service/ncm/ncm.cpp b/src/core/hle/service/ncm/ncm.cpp
index 68210a108..650666d6b 100644
--- a/src/core/hle/service/ncm/ncm.cpp
+++ b/src/core/hle/service/ncm/ncm.cpp
@@ -4,10 +4,10 @@
#include <memory>
#include "core/file_sys/romfs_factory.h"
-#include "core/hle/ipc_helpers.h"
+#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/ncm/ncm.h"
+#include "core/hle/service/server_manager.h"
#include "core/hle/service/service.h"
-#include "core/hle/service/sm/sm.h"
namespace Service::NCM {
@@ -124,6 +124,7 @@ public:
{12, nullptr, "InactivateContentMetaDatabase"},
{13, nullptr, "InvalidateRightsIdCache"},
{14, nullptr, "GetMemoryReport"},
+ {15, nullptr, "ActivateFsContentStorage"},
};
// clang-format on
@@ -131,9 +132,12 @@ public:
}
};
-void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
- std::make_shared<LR>(system)->InstallAsService(sm);
- std::make_shared<NCM>(system)->InstallAsService(sm);
+void LoopProcess(Core::System& system) {
+ auto server_manager = std::make_unique<ServerManager>(system);
+
+ server_manager->RegisterNamedService("lr", std::make_shared<LR>(system));
+ server_manager->RegisterNamedService("ncm", std::make_shared<NCM>(system));
+ ServerManager::RunServer(std::move(server_manager));
}
} // namespace Service::NCM
diff --git a/src/core/hle/service/ncm/ncm.h b/src/core/hle/service/ncm/ncm.h
index de3971437..b78efdcd7 100644
--- a/src/core/hle/service/ncm/ncm.h
+++ b/src/core/hle/service/ncm/ncm.h
@@ -7,12 +7,8 @@ namespace Core {
class System;
}
-namespace Service::SM {
-class ServiceManager;
-}
-
namespace Service::NCM {
-void InstallInterfaces(SM::ServiceManager& sm, Core::System& system);
+void LoopProcess(Core::System& system);
} // namespace Service::NCM
diff --git a/src/core/hle/service/nfp/amiibo_crypto.cpp b/src/core/hle/service/nfc/common/amiibo_crypto.cpp
index ffb2f959c..bc232c334 100644
--- a/src/core/hle/service/nfp/amiibo_crypto.cpp
+++ b/src/core/hle/service/nfc/common/amiibo_crypto.cpp
@@ -12,7 +12,7 @@
#include "common/fs/fs.h"
#include "common/fs/path_util.h"
#include "common/logging/log.h"
-#include "core/hle/service/nfp/amiibo_crypto.h"
+#include "core/hle/service/nfc/common/amiibo_crypto.h"
namespace Service::NFP::AmiiboCrypto {
@@ -36,12 +36,12 @@ bool IsAmiiboValid(const EncryptedNTAG215File& ntag_file) {
// Validate UUID
constexpr u8 CT = 0x88; // As defined in `ISO / IEC 14443 - 3`
- if ((CT ^ ntag_file.uuid.uid[0] ^ ntag_file.uuid.uid[1] ^ ntag_file.uuid.uid[2]) !=
- ntag_file.uuid.uid[3]) {
+ if ((CT ^ ntag_file.uuid.part1[0] ^ ntag_file.uuid.part1[1] ^ ntag_file.uuid.part1[2]) !=
+ ntag_file.uuid.crc_check1) {
return false;
}
- if ((ntag_file.uuid.uid[4] ^ ntag_file.uuid.uid[5] ^ ntag_file.uuid.uid[6] ^
- ntag_file.uuid.nintendo_id) != ntag_file.uuid.lock_bytes[0]) {
+ if ((ntag_file.uuid.part2[0] ^ ntag_file.uuid.part2[1] ^ ntag_file.uuid.part2[2] ^
+ ntag_file.uuid.nintendo_id) != ntag_file.uuid_crc_check2) {
return false;
}
@@ -52,10 +52,7 @@ bool IsAmiiboValid(const EncryptedNTAG215File& ntag_file) {
if (ntag_file.compability_container != 0xEEFF10F1U) {
return false;
}
- if (amiibo_data.constant_value != 0xA5) {
- return false;
- }
- if (amiibo_data.model_info.tag_type != PackedTagType::Type2) {
+ if (amiibo_data.model_info.tag_type != NFC::PackedTagType::Type2) {
return false;
}
if ((ntag_file.dynamic_lock & 0xFFFFFF) != 0x0F0001U) {
@@ -70,26 +67,34 @@ bool IsAmiiboValid(const EncryptedNTAG215File& ntag_file) {
return true;
}
+bool IsAmiiboValid(const NTAG215File& ntag_file) {
+ return IsAmiiboValid(EncodedDataToNfcData(ntag_file));
+}
+
NTAG215File NfcDataToEncodedData(const EncryptedNTAG215File& nfc_data) {
NTAG215File encoded_data{};
- encoded_data.uid = nfc_data.uuid.uid;
- encoded_data.nintendo_id = nfc_data.uuid.nintendo_id;
+ encoded_data.uid = nfc_data.uuid;
+ encoded_data.uid_crc_check2 = nfc_data.uuid_crc_check2;
+ encoded_data.internal_number = nfc_data.internal_number;
encoded_data.static_lock = nfc_data.static_lock;
encoded_data.compability_container = nfc_data.compability_container;
encoded_data.hmac_data = nfc_data.user_memory.hmac_data;
encoded_data.constant_value = nfc_data.user_memory.constant_value;
encoded_data.write_counter = nfc_data.user_memory.write_counter;
+ encoded_data.amiibo_version = nfc_data.user_memory.amiibo_version;
encoded_data.settings = nfc_data.user_memory.settings;
encoded_data.owner_mii = nfc_data.user_memory.owner_mii;
- encoded_data.title_id = nfc_data.user_memory.title_id;
- encoded_data.applicaton_write_counter = nfc_data.user_memory.applicaton_write_counter;
+ encoded_data.application_id = nfc_data.user_memory.application_id;
+ encoded_data.application_write_counter = nfc_data.user_memory.application_write_counter;
encoded_data.application_area_id = nfc_data.user_memory.application_area_id;
+ encoded_data.application_id_byte = nfc_data.user_memory.application_id_byte;
encoded_data.unknown = nfc_data.user_memory.unknown;
+ encoded_data.mii_extension = nfc_data.user_memory.mii_extension;
encoded_data.unknown2 = nfc_data.user_memory.unknown2;
+ encoded_data.register_info_crc = nfc_data.user_memory.register_info_crc;
encoded_data.application_area = nfc_data.user_memory.application_area;
encoded_data.hmac_tag = nfc_data.user_memory.hmac_tag;
- encoded_data.lock_bytes = nfc_data.uuid.lock_bytes;
encoded_data.model_info = nfc_data.user_memory.model_info;
encoded_data.keygen_salt = nfc_data.user_memory.keygen_salt;
encoded_data.dynamic_lock = nfc_data.dynamic_lock;
@@ -103,21 +108,25 @@ NTAG215File NfcDataToEncodedData(const EncryptedNTAG215File& nfc_data) {
EncryptedNTAG215File EncodedDataToNfcData(const NTAG215File& encoded_data) {
EncryptedNTAG215File nfc_data{};
- nfc_data.uuid.uid = encoded_data.uid;
- nfc_data.uuid.nintendo_id = encoded_data.nintendo_id;
- nfc_data.uuid.lock_bytes = encoded_data.lock_bytes;
+ nfc_data.uuid = encoded_data.uid;
+ nfc_data.uuid_crc_check2 = encoded_data.uid_crc_check2;
+ nfc_data.internal_number = encoded_data.internal_number;
nfc_data.static_lock = encoded_data.static_lock;
nfc_data.compability_container = encoded_data.compability_container;
nfc_data.user_memory.hmac_data = encoded_data.hmac_data;
nfc_data.user_memory.constant_value = encoded_data.constant_value;
nfc_data.user_memory.write_counter = encoded_data.write_counter;
+ nfc_data.user_memory.amiibo_version = encoded_data.amiibo_version;
nfc_data.user_memory.settings = encoded_data.settings;
nfc_data.user_memory.owner_mii = encoded_data.owner_mii;
- nfc_data.user_memory.title_id = encoded_data.title_id;
- nfc_data.user_memory.applicaton_write_counter = encoded_data.applicaton_write_counter;
+ nfc_data.user_memory.application_id = encoded_data.application_id;
+ nfc_data.user_memory.application_write_counter = encoded_data.application_write_counter;
nfc_data.user_memory.application_area_id = encoded_data.application_area_id;
+ nfc_data.user_memory.application_id_byte = encoded_data.application_id_byte;
nfc_data.user_memory.unknown = encoded_data.unknown;
+ nfc_data.user_memory.mii_extension = encoded_data.mii_extension;
nfc_data.user_memory.unknown2 = encoded_data.unknown2;
+ nfc_data.user_memory.register_info_crc = encoded_data.register_info_crc;
nfc_data.user_memory.application_area = encoded_data.application_area;
nfc_data.user_memory.hmac_tag = encoded_data.hmac_tag;
nfc_data.user_memory.model_info = encoded_data.model_info;
@@ -130,23 +139,12 @@ EncryptedNTAG215File EncodedDataToNfcData(const NTAG215File& encoded_data) {
return nfc_data;
}
-u32 GetTagPassword(const TagUuid& uuid) {
- // Verifiy that the generated password is correct
- u32 password = 0xAA ^ (uuid.uid[1] ^ uuid.uid[3]);
- password &= (0x55 ^ (uuid.uid[2] ^ uuid.uid[4])) << 8;
- password &= (0xAA ^ (uuid.uid[3] ^ uuid.uid[5])) << 16;
- password &= (0x55 ^ (uuid.uid[4] ^ uuid.uid[6])) << 24;
- return password;
-}
-
HashSeed GetSeed(const NTAG215File& data) {
HashSeed seed{
.magic = data.write_counter,
.padding = {},
.uid_1 = data.uid,
- .nintendo_id_1 = data.nintendo_id,
.uid_2 = data.uid,
- .nintendo_id_2 = data.nintendo_id,
.keygen_salt = data.keygen_salt,
};
@@ -168,10 +166,11 @@ std::vector<u8> GenerateInternalKey(const InternalKey& key, const HashSeed& seed
output.insert(output.end(), key.magic_bytes.begin(),
key.magic_bytes.begin() + key.magic_length);
- output.insert(output.end(), seed.uid_1.begin(), seed.uid_1.end());
- output.emplace_back(seed.nintendo_id_1);
- output.insert(output.end(), seed.uid_2.begin(), seed.uid_2.end());
- output.emplace_back(seed.nintendo_id_2);
+ std::array<u8, sizeof(NFP::TagUuid)> seed_uuid{};
+ memcpy(seed_uuid.data(), &seed.uid_1, sizeof(NFP::TagUuid));
+ output.insert(output.end(), seed_uuid.begin(), seed_uuid.end());
+ memcpy(seed_uuid.data(), &seed.uid_2, sizeof(NFP::TagUuid));
+ output.insert(output.end(), seed_uuid.begin(), seed_uuid.end());
for (std::size_t i = 0; i < sizeof(seed.keygen_salt); i++) {
output.emplace_back(static_cast<u8>(seed.keygen_salt[i] ^ key.xor_pad[i]));
@@ -255,8 +254,8 @@ void Cipher(const DerivedKeys& keys, const NTAG215File& in_data, NTAG215File& ou
// Copy the rest of the data directly
out_data.uid = in_data.uid;
- out_data.nintendo_id = in_data.nintendo_id;
- out_data.lock_bytes = in_data.lock_bytes;
+ out_data.uid_crc_check2 = in_data.uid_crc_check2;
+ out_data.internal_number = in_data.internal_number;
out_data.static_lock = in_data.static_lock;
out_data.compability_container = in_data.compability_container;
diff --git a/src/core/hle/service/nfp/amiibo_crypto.h b/src/core/hle/service/nfc/common/amiibo_crypto.h
index 1fa61174e..6a3e0841e 100644
--- a/src/core/hle/service/nfp/amiibo_crypto.h
+++ b/src/core/hle/service/nfc/common/amiibo_crypto.h
@@ -24,10 +24,8 @@ using DrgbOutput = std::array<u8, 0x20>;
struct HashSeed {
u16_be magic;
std::array<u8, 0xE> padding;
- UniqueSerialNumber uid_1;
- u8 nintendo_id_1;
- UniqueSerialNumber uid_2;
- u8 nintendo_id_2;
+ TagUuid uid_1;
+ TagUuid uid_2;
std::array<u8, 0x20> keygen_salt;
};
static_assert(sizeof(HashSeed) == 0x40, "HashSeed is an invalid size");
@@ -60,15 +58,15 @@ static_assert(sizeof(DerivedKeys) == 0x30, "DerivedKeys is an invalid size");
/// Validates that the amiibo file is not corrupted
bool IsAmiiboValid(const EncryptedNTAG215File& ntag_file);
+/// Validates that the amiibo file is not corrupted
+bool IsAmiiboValid(const NTAG215File& ntag_file);
+
/// Converts from encrypted file format to encoded file format
NTAG215File NfcDataToEncodedData(const EncryptedNTAG215File& nfc_data);
/// Converts from encoded file format to encrypted file format
EncryptedNTAG215File EncodedDataToNfcData(const NTAG215File& encoded_data);
-/// Returns password needed to allow write access to protected memory
-u32 GetTagPassword(const TagUuid& uuid);
-
// Generates Seed needed for key derivation
HashSeed GetSeed(const NTAG215File& data);
@@ -94,7 +92,7 @@ bool LoadKeys(InternalKey& locked_secret, InternalKey& unfixed_info);
/// Returns true if key_retail.bin exist
bool IsKeyAvailable();
-/// Decodes encripted amiibo data returns true if output is valid
+/// Decodes encrypted amiibo data returns true if output is valid
bool DecodeAmiibo(const EncryptedNTAG215File& encrypted_tag_data, NTAG215File& tag_data);
/// Encodes plain amiibo data returns true if output is valid
diff --git a/src/core/hle/service/nfc/common/device.cpp b/src/core/hle/service/nfc/common/device.cpp
new file mode 100644
index 000000000..5bf289818
--- /dev/null
+++ b/src/core/hle/service/nfc/common/device.cpp
@@ -0,0 +1,1483 @@
+// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4701) // Potentially uninitialized local variable 'result' used
+#endif
+
+#include <boost/crc.hpp>
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+#include <fmt/format.h>
+
+#include "common/fs/file.h"
+#include "common/fs/fs.h"
+#include "common/fs/path_util.h"
+#include "common/input.h"
+#include "common/logging/log.h"
+#include "common/string_util.h"
+#include "common/tiny_mt.h"
+#include "core/core.h"
+#include "core/hid/emulated_controller.h"
+#include "core/hid/hid_core.h"
+#include "core/hid/hid_types.h"
+#include "core/hle/kernel/k_event.h"
+#include "core/hle/service/ipc_helpers.h"
+#include "core/hle/service/mii/mii_manager.h"
+#include "core/hle/service/mii/types.h"
+#include "core/hle/service/nfc/common/amiibo_crypto.h"
+#include "core/hle/service/nfc/common/device.h"
+#include "core/hle/service/nfc/mifare_result.h"
+#include "core/hle/service/nfc/nfc_result.h"
+#include "core/hle/service/time/time_manager.h"
+#include "core/hle/service/time/time_zone_content_manager.h"
+#include "core/hle/service/time/time_zone_types.h"
+
+namespace Service::NFC {
+NfcDevice::NfcDevice(Core::HID::NpadIdType npad_id_, Core::System& system_,
+ KernelHelpers::ServiceContext& service_context_,
+ Kernel::KEvent* availability_change_event_)
+ : npad_id{npad_id_}, system{system_}, service_context{service_context_},
+ availability_change_event{availability_change_event_} {
+ activate_event = service_context.CreateEvent("NFC:ActivateEvent");
+ deactivate_event = service_context.CreateEvent("NFC:DeactivateEvent");
+ npad_device = system.HIDCore().GetEmulatedController(npad_id);
+
+ Core::HID::ControllerUpdateCallback engine_callback{
+ .on_change = [this](Core::HID::ControllerTriggerType type) { NpadUpdate(type); },
+ .is_npad_service = false,
+ };
+ is_controller_set = true;
+ callback_key = npad_device->SetCallback(engine_callback);
+}
+
+NfcDevice::~NfcDevice() {
+ service_context.CloseEvent(activate_event);
+ service_context.CloseEvent(deactivate_event);
+ if (!is_controller_set) {
+ return;
+ }
+ npad_device->DeleteCallback(callback_key);
+ is_controller_set = false;
+};
+
+void NfcDevice::NpadUpdate(Core::HID::ControllerTriggerType type) {
+ if (!is_initalized) {
+ return;
+ }
+
+ if (type == Core::HID::ControllerTriggerType::Connected) {
+ Initialize();
+ availability_change_event->Signal();
+ return;
+ }
+
+ if (type == Core::HID::ControllerTriggerType::Disconnected) {
+ device_state = DeviceState::Unavailable;
+ availability_change_event->Signal();
+ return;
+ }
+
+ if (type != Core::HID::ControllerTriggerType::Nfc) {
+ return;
+ }
+
+ if (!npad_device->IsConnected()) {
+ return;
+ }
+
+ const auto nfc_status = npad_device->GetNfc();
+ switch (nfc_status.state) {
+ case Common::Input::NfcState::NewAmiibo:
+ LoadNfcTag(nfc_status.protocol, nfc_status.tag_type, nfc_status.uuid_length,
+ nfc_status.uuid);
+ break;
+ case Common::Input::NfcState::AmiiboRemoved:
+ if (device_state == DeviceState::Initialized || device_state == DeviceState::TagRemoved) {
+ break;
+ }
+ if (device_state != DeviceState::SearchingForTag) {
+ CloseNfcTag();
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+bool NfcDevice::LoadNfcTag(u8 protocol, u8 tag_type, u8 uuid_length, UniqueSerialNumber uuid) {
+ if (device_state != DeviceState::SearchingForTag) {
+ LOG_ERROR(Service_NFC, "Game is not looking for nfc tag, current state {}", device_state);
+ return false;
+ }
+
+ if ((protocol & static_cast<u8>(allowed_protocols)) == 0) {
+ LOG_ERROR(Service_NFC, "Protocol not supported {}", protocol);
+ return false;
+ }
+
+ real_tag_info = {
+ .uuid = uuid,
+ .uuid_length = uuid_length,
+ .protocol = static_cast<NfcProtocol>(protocol),
+ .tag_type = static_cast<TagType>(tag_type),
+ };
+
+ device_state = DeviceState::TagFound;
+ deactivate_event->GetReadableEvent().Clear();
+ activate_event->Signal();
+ return true;
+}
+
+bool NfcDevice::LoadAmiiboData() {
+ std::vector<u8> data{};
+
+ if (!npad_device->ReadAmiiboData(data)) {
+ return false;
+ }
+
+ if (data.size() < sizeof(NFP::EncryptedNTAG215File)) {
+ LOG_ERROR(Service_NFC, "Not an amiibo, size={}", data.size());
+ return false;
+ }
+
+ memcpy(&tag_data, data.data(), sizeof(NFP::EncryptedNTAG215File));
+ is_plain_amiibo = NFP::AmiiboCrypto::IsAmiiboValid(tag_data);
+ is_write_protected = false;
+
+ // Fallback for plain amiibos
+ if (is_plain_amiibo) {
+ LOG_INFO(Service_NFP, "Using plain amiibo");
+ encrypted_tag_data = NFP::AmiiboCrypto::EncodedDataToNfcData(tag_data);
+ return true;
+ }
+
+ // Fallback for encrypted amiibos without keys
+ if (!NFP::AmiiboCrypto::IsKeyAvailable()) {
+ LOG_INFO(Service_NFC, "Loading amiibo without keys");
+ memcpy(&encrypted_tag_data, data.data(), sizeof(NFP::EncryptedNTAG215File));
+ BuildAmiiboWithoutKeys(tag_data, encrypted_tag_data);
+ is_plain_amiibo = true;
+ is_write_protected = true;
+ return true;
+ }
+
+ LOG_INFO(Service_NFP, "Using encrypted amiibo");
+ tag_data = {};
+ memcpy(&encrypted_tag_data, data.data(), sizeof(NFP::EncryptedNTAG215File));
+ return true;
+}
+
+void NfcDevice::CloseNfcTag() {
+ LOG_INFO(Service_NFC, "Remove nfc tag");
+
+ if (device_state == DeviceState::TagMounted) {
+ Unmount();
+ }
+
+ device_state = DeviceState::TagRemoved;
+ encrypted_tag_data = {};
+ tag_data = {};
+ activate_event->GetReadableEvent().Clear();
+ deactivate_event->Signal();
+}
+
+Kernel::KReadableEvent& NfcDevice::GetActivateEvent() const {
+ return activate_event->GetReadableEvent();
+}
+
+Kernel::KReadableEvent& NfcDevice::GetDeactivateEvent() const {
+ return deactivate_event->GetReadableEvent();
+}
+
+void NfcDevice::Initialize() {
+ device_state = npad_device->HasNfc() ? DeviceState::Initialized : DeviceState::Unavailable;
+ encrypted_tag_data = {};
+ tag_data = {};
+
+ if (device_state != DeviceState::Initialized) {
+ return;
+ }
+
+ is_initalized = npad_device->AddNfcHandle();
+}
+
+void NfcDevice::Finalize() {
+ if (device_state == DeviceState::TagMounted) {
+ Unmount();
+ }
+ if (device_state == DeviceState::SearchingForTag || device_state == DeviceState::TagRemoved) {
+ StopDetection();
+ }
+
+ if (device_state != DeviceState::Unavailable) {
+ npad_device->RemoveNfcHandle();
+ }
+
+ device_state = DeviceState::Unavailable;
+ is_initalized = false;
+}
+
+Result NfcDevice::StartDetection(NfcProtocol allowed_protocol) {
+ if (device_state != DeviceState::Initialized && device_state != DeviceState::TagRemoved) {
+ LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
+ return ResultWrongDeviceState;
+ }
+
+ if (!npad_device->StartNfcPolling()) {
+ LOG_ERROR(Service_NFC, "Nfc polling not supported");
+ return ResultNfcDisabled;
+ }
+
+ device_state = DeviceState::SearchingForTag;
+ allowed_protocols = allowed_protocol;
+ return ResultSuccess;
+}
+
+Result NfcDevice::StopDetection() {
+ if (device_state == DeviceState::Initialized) {
+ return ResultSuccess;
+ }
+
+ if (device_state == DeviceState::TagFound || device_state == DeviceState::TagMounted) {
+ CloseNfcTag();
+ }
+
+ if (device_state == DeviceState::SearchingForTag || device_state == DeviceState::TagRemoved) {
+ npad_device->StopNfcPolling();
+ device_state = DeviceState::Initialized;
+ return ResultSuccess;
+ }
+
+ LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
+ return ResultWrongDeviceState;
+}
+
+Result NfcDevice::GetTagInfo(NFP::TagInfo& tag_info) const {
+ if (device_state != DeviceState::TagFound && device_state != DeviceState::TagMounted) {
+ LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
+ if (device_state == DeviceState::TagRemoved) {
+ return ResultTagRemoved;
+ }
+ return ResultWrongDeviceState;
+ }
+
+ tag_info = real_tag_info;
+
+ // Generate random UUID to bypass amiibo load limits
+ if (real_tag_info.tag_type == TagType::Type2 && Settings::values.random_amiibo_id) {
+ Common::TinyMT rng{};
+ rng.Initialize(static_cast<u32>(GetCurrentPosixTime()));
+ rng.GenerateRandomBytes(tag_info.uuid.data(), tag_info.uuid_length);
+ }
+
+ return ResultSuccess;
+}
+
+Result NfcDevice::ReadMifare(std::span<const MifareReadBlockParameter> parameters,
+ std::span<MifareReadBlockData> read_block_data) const {
+ if (device_state != DeviceState::TagFound && device_state != DeviceState::TagMounted) {
+ LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
+ if (device_state == DeviceState::TagRemoved) {
+ return ResultTagRemoved;
+ }
+ return ResultWrongDeviceState;
+ }
+
+ Result result = ResultSuccess;
+
+ TagInfo tag_info{};
+ result = GetTagInfo(tag_info);
+
+ if (result.IsError()) {
+ return result;
+ }
+
+ if (tag_info.protocol != NfcProtocol::TypeA || tag_info.tag_type != TagType::Mifare) {
+ return ResultInvalidTagType;
+ }
+
+ if (parameters.size() == 0) {
+ return ResultInvalidArgument;
+ }
+
+ Common::Input::MifareRequest request{};
+ Common::Input::MifareRequest out_data{};
+ const auto unknown = parameters[0].sector_key.unknown;
+ for (std::size_t i = 0; i < parameters.size(); i++) {
+ if (unknown != parameters[i].sector_key.unknown) {
+ return ResultInvalidArgument;
+ }
+ }
+
+ for (std::size_t i = 0; i < parameters.size(); i++) {
+ if (parameters[i].sector_key.command == MifareCmd::None) {
+ continue;
+ }
+ request.data[i].command = static_cast<u8>(parameters[i].sector_key.command);
+ request.data[i].sector = parameters[i].sector_number;
+ memcpy(request.data[i].key.data(), parameters[i].sector_key.sector_key.data(),
+ sizeof(KeyData));
+ }
+
+ if (!npad_device->ReadMifareData(request, out_data)) {
+ return ResultMifareError288;
+ }
+
+ for (std::size_t i = 0; i < read_block_data.size(); i++) {
+ if (static_cast<MifareCmd>(out_data.data[i].command) == MifareCmd::None) {
+ continue;
+ }
+
+ read_block_data[i] = {
+ .data = out_data.data[i].data,
+ .sector_number = out_data.data[i].sector,
+ };
+ }
+
+ return ResultSuccess;
+}
+
+Result NfcDevice::WriteMifare(std::span<const MifareWriteBlockParameter> parameters) {
+ Result result = ResultSuccess;
+
+ TagInfo tag_info{};
+ result = GetTagInfo(tag_info);
+
+ if (result.IsError()) {
+ return result;
+ }
+
+ if (tag_info.protocol != NfcProtocol::TypeA || tag_info.tag_type != TagType::Mifare) {
+ return ResultInvalidTagType;
+ }
+
+ if (parameters.size() == 0) {
+ return ResultInvalidArgument;
+ }
+
+ const auto unknown = parameters[0].sector_key.unknown;
+ for (std::size_t i = 0; i < parameters.size(); i++) {
+ if (unknown != parameters[i].sector_key.unknown) {
+ return ResultInvalidArgument;
+ }
+ }
+
+ Common::Input::MifareRequest request{};
+ for (std::size_t i = 0; i < parameters.size(); i++) {
+ if (parameters[i].sector_key.command == MifareCmd::None) {
+ continue;
+ }
+ request.data[i].command = static_cast<u8>(parameters[i].sector_key.command);
+ request.data[i].sector = parameters[i].sector_number;
+ memcpy(request.data[i].key.data(), parameters[i].sector_key.sector_key.data(),
+ sizeof(KeyData));
+ memcpy(request.data[i].data.data(), parameters[i].data.data(), sizeof(KeyData));
+ }
+
+ if (!npad_device->WriteMifareData(request)) {
+ return ResultMifareError288;
+ }
+
+ return result;
+}
+
+Result NfcDevice::SendCommandByPassThrough(const Time::Clock::TimeSpanType& timeout,
+ std::span<const u8> command_data,
+ std::span<u8> out_data) {
+ // Not implemented
+ return ResultSuccess;
+}
+
+Result NfcDevice::Mount(NFP::ModelType model_type, NFP::MountTarget mount_target_) {
+ if (device_state != DeviceState::TagFound) {
+ LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
+ return ResultWrongDeviceState;
+ }
+
+ if (!LoadAmiiboData()) {
+ LOG_ERROR(Service_NFP, "Not an amiibo");
+ return ResultInvalidTagType;
+ }
+
+ if (!NFP::AmiiboCrypto::IsAmiiboValid(encrypted_tag_data)) {
+ LOG_ERROR(Service_NFP, "Not an amiibo");
+ return ResultInvalidTagType;
+ }
+
+ // The loaded amiibo is not encrypted
+ if (is_plain_amiibo) {
+ std::vector<u8> data(sizeof(NFP::NTAG215File));
+ memcpy(data.data(), &tag_data, sizeof(tag_data));
+ WriteBackupData(tag_data.uid, data);
+
+ device_state = DeviceState::TagMounted;
+ mount_target = mount_target_;
+ return ResultSuccess;
+ }
+
+ if (!NFP::AmiiboCrypto::DecodeAmiibo(encrypted_tag_data, tag_data)) {
+ bool has_backup = HasBackup(encrypted_tag_data.uuid).IsSuccess();
+ LOG_ERROR(Service_NFP, "Can't decode amiibo, has_backup= {}", has_backup);
+ return has_backup ? ResultCorruptedDataWithBackup : ResultCorruptedData;
+ }
+
+ std::vector<u8> data(sizeof(NFP::EncryptedNTAG215File));
+ memcpy(data.data(), &encrypted_tag_data, sizeof(encrypted_tag_data));
+ WriteBackupData(encrypted_tag_data.uuid, data);
+
+ device_state = DeviceState::TagMounted;
+ mount_target = mount_target_;
+ return ResultSuccess;
+}
+
+Result NfcDevice::Unmount() {
+ if (device_state != DeviceState::TagMounted) {
+ LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
+ if (device_state == DeviceState::TagRemoved) {
+ return ResultTagRemoved;
+ }
+ return ResultWrongDeviceState;
+ }
+
+ // Save data before unloading the amiibo
+ if (is_data_moddified) {
+ Flush();
+ }
+
+ device_state = DeviceState::TagFound;
+ mount_target = NFP::MountTarget::None;
+ is_app_area_open = false;
+
+ return ResultSuccess;
+}
+
+Result NfcDevice::Flush() {
+ if (device_state != DeviceState::TagMounted) {
+ LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
+ if (device_state == DeviceState::TagRemoved) {
+ return ResultTagRemoved;
+ }
+ return ResultWrongDeviceState;
+ }
+
+ if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
+ LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
+ return ResultWrongDeviceState;
+ }
+
+ auto& settings = tag_data.settings;
+
+ const auto& current_date = GetAmiiboDate(GetCurrentPosixTime());
+ if (settings.write_date.raw_date != current_date.raw_date) {
+ settings.write_date = current_date;
+ UpdateSettingsCrc();
+ }
+
+ tag_data.write_counter++;
+
+ const auto result = FlushWithBreak(NFP::BreakType::Normal);
+
+ is_data_moddified = false;
+
+ return result;
+}
+
+Result NfcDevice::FlushDebug() {
+ if (device_state != DeviceState::TagMounted) {
+ LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
+ if (device_state == DeviceState::TagRemoved) {
+ return ResultTagRemoved;
+ }
+ return ResultWrongDeviceState;
+ }
+
+ if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
+ LOG_ERROR(Service_NFC, "Amiibo is read only", device_state);
+ return ResultWrongDeviceState;
+ }
+
+ tag_data.write_counter++;
+
+ const auto result = FlushWithBreak(NFP::BreakType::Normal);
+
+ is_data_moddified = false;
+
+ return result;
+}
+
+Result NfcDevice::FlushWithBreak(NFP::BreakType break_type) {
+ if (break_type != NFP::BreakType::Normal) {
+ LOG_ERROR(Service_NFC, "Break type not implemented {}", break_type);
+ return ResultWrongDeviceState;
+ }
+
+ if (is_write_protected) {
+ LOG_ERROR(Service_NFP, "No keys available skipping write request");
+ return ResultSuccess;
+ }
+
+ std::vector<u8> data(sizeof(NFP::EncryptedNTAG215File));
+ if (is_plain_amiibo) {
+ memcpy(data.data(), &tag_data, sizeof(tag_data));
+ WriteBackupData(tag_data.uid, data);
+ } else {
+ if (!NFP::AmiiboCrypto::EncodeAmiibo(tag_data, encrypted_tag_data)) {
+ LOG_ERROR(Service_NFP, "Failed to encode data");
+ return ResultWriteAmiiboFailed;
+ }
+
+ memcpy(data.data(), &encrypted_tag_data, sizeof(encrypted_tag_data));
+ WriteBackupData(encrypted_tag_data.uuid, data);
+ }
+
+ if (!npad_device->WriteNfc(data)) {
+ LOG_ERROR(Service_NFP, "Error writing to file");
+ return ResultWriteAmiiboFailed;
+ }
+
+ return ResultSuccess;
+}
+
+Result NfcDevice::Restore() {
+ if (device_state != DeviceState::TagFound) {
+ LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
+ if (device_state == DeviceState::TagRemoved) {
+ return ResultTagRemoved;
+ }
+ return ResultWrongDeviceState;
+ }
+
+ NFC::TagInfo tag_info{};
+ std::array<u8, sizeof(NFP::EncryptedNTAG215File)> data{};
+ Result result = GetTagInfo(tag_info);
+
+ if (result.IsError()) {
+ return result;
+ }
+
+ result = ReadBackupData(tag_info.uuid, tag_info.uuid_length, data);
+
+ if (result.IsError()) {
+ return result;
+ }
+
+ NFP::NTAG215File temporary_tag_data{};
+ NFP::EncryptedNTAG215File temporary_encrypted_tag_data{};
+
+ // Fallback for encrypted amiibos without keys
+ if (is_write_protected) {
+ return ResultWriteAmiiboFailed;
+ }
+
+ // Fallback for plain amiibos
+ if (is_plain_amiibo) {
+ LOG_INFO(Service_NFP, "Restoring backup of plain amiibo");
+ memcpy(&temporary_tag_data, data.data(), sizeof(NFP::EncryptedNTAG215File));
+ temporary_encrypted_tag_data = NFP::AmiiboCrypto::EncodedDataToNfcData(temporary_tag_data);
+ }
+
+ if (!is_plain_amiibo) {
+ LOG_INFO(Service_NFP, "Restoring backup of encrypted amiibo");
+ temporary_tag_data = {};
+ memcpy(&temporary_encrypted_tag_data, data.data(), sizeof(NFP::EncryptedNTAG215File));
+ }
+
+ if (!NFP::AmiiboCrypto::IsAmiiboValid(temporary_encrypted_tag_data)) {
+ return ResultInvalidTagType;
+ }
+
+ if (!is_plain_amiibo) {
+ if (!NFP::AmiiboCrypto::DecodeAmiibo(temporary_encrypted_tag_data, temporary_tag_data)) {
+ LOG_ERROR(Service_NFP, "Can't decode amiibo");
+ return ResultCorruptedData;
+ }
+ }
+
+ // Overwrite tag contents with backup and mount the tag
+ tag_data = temporary_tag_data;
+ encrypted_tag_data = temporary_encrypted_tag_data;
+ device_state = DeviceState::TagMounted;
+ mount_target = NFP::MountTarget::All;
+ is_data_moddified = true;
+
+ return ResultSuccess;
+}
+
+Result NfcDevice::GetCommonInfo(NFP::CommonInfo& common_info) const {
+ if (device_state != DeviceState::TagMounted) {
+ LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
+ if (device_state == DeviceState::TagRemoved) {
+ return ResultTagRemoved;
+ }
+ return ResultWrongDeviceState;
+ }
+
+ if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
+ LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
+ return ResultWrongDeviceState;
+ }
+
+ const auto& settings = tag_data.settings;
+
+ // TODO: Validate this data
+ common_info = {
+ .last_write_date = settings.write_date.GetWriteDate(),
+ .write_counter = tag_data.application_write_counter,
+ .version = tag_data.amiibo_version,
+ .application_area_size = sizeof(NFP::ApplicationArea),
+ };
+ return ResultSuccess;
+}
+
+Result NfcDevice::GetModelInfo(NFP::ModelInfo& model_info) const {
+ if (device_state != DeviceState::TagMounted) {
+ LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
+ if (device_state == DeviceState::TagRemoved) {
+ return ResultTagRemoved;
+ }
+ return ResultWrongDeviceState;
+ }
+
+ const auto& model_info_data = encrypted_tag_data.user_memory.model_info;
+
+ model_info = {
+ .character_id = model_info_data.character_id,
+ .character_variant = model_info_data.character_variant,
+ .amiibo_type = model_info_data.amiibo_type,
+ .model_number = model_info_data.model_number,
+ .series = model_info_data.series,
+ };
+ return ResultSuccess;
+}
+
+Result NfcDevice::GetRegisterInfo(NFP::RegisterInfo& register_info) const {
+ if (device_state != DeviceState::TagMounted) {
+ LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
+ if (device_state == DeviceState::TagRemoved) {
+ return ResultTagRemoved;
+ }
+ return ResultWrongDeviceState;
+ }
+
+ if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
+ LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
+ return ResultWrongDeviceState;
+ }
+
+ if (tag_data.settings.settings.amiibo_initialized == 0) {
+ return ResultRegistrationIsNotInitialized;
+ }
+
+ Service::Mii::MiiManager manager;
+ const auto& settings = tag_data.settings;
+
+ // TODO: Validate this data
+ register_info = {
+ .mii_char_info = manager.ConvertV3ToCharInfo(tag_data.owner_mii),
+ .creation_date = settings.init_date.GetWriteDate(),
+ .amiibo_name = GetAmiiboName(settings),
+ .font_region = settings.settings.font_region,
+ };
+
+ return ResultSuccess;
+}
+
+Result NfcDevice::GetRegisterInfoPrivate(NFP::RegisterInfoPrivate& register_info) const {
+ if (device_state != DeviceState::TagMounted) {
+ LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
+ if (device_state == DeviceState::TagRemoved) {
+ return ResultTagRemoved;
+ }
+ return ResultWrongDeviceState;
+ }
+
+ if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
+ LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
+ return ResultWrongDeviceState;
+ }
+
+ if (tag_data.settings.settings.amiibo_initialized == 0) {
+ return ResultRegistrationIsNotInitialized;
+ }
+
+ Service::Mii::MiiManager manager;
+ const auto& settings = tag_data.settings;
+
+ // TODO: Validate and complete this data
+ register_info = {
+ .mii_store_data = {},
+ .creation_date = settings.init_date.GetWriteDate(),
+ .amiibo_name = GetAmiiboName(settings),
+ .font_region = settings.settings.font_region,
+ };
+
+ return ResultSuccess;
+}
+
+Result NfcDevice::GetAdminInfo(NFP::AdminInfo& admin_info) const {
+ if (device_state != DeviceState::TagMounted) {
+ LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
+ if (device_state == DeviceState::TagRemoved) {
+ return ResultTagRemoved;
+ }
+ return ResultWrongDeviceState;
+ }
+
+ if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
+ LOG_ERROR(Service_NFC, "Amiibo is read only", device_state);
+ return ResultWrongDeviceState;
+ }
+
+ u8 flags = static_cast<u8>(tag_data.settings.settings.raw >> 0x4);
+ if (tag_data.settings.settings.amiibo_initialized == 0) {
+ flags = flags & 0xfe;
+ }
+
+ u64 application_id = 0;
+ u32 application_area_id = 0;
+ NFP::AppAreaVersion app_area_version = NFP::AppAreaVersion::NotSet;
+ if (tag_data.settings.settings.appdata_initialized != 0) {
+ application_id = tag_data.application_id;
+ app_area_version = static_cast<NFP::AppAreaVersion>(
+ application_id >> NFP::application_id_version_offset & 0xf);
+
+ // Restore application id to original value
+ if (application_id >> 0x38 != 0) {
+ const u8 application_byte = tag_data.application_id_byte & 0xf;
+ application_id =
+ RemoveVersionByte(application_id) |
+ (static_cast<u64>(application_byte) << NFP::application_id_version_offset);
+ }
+
+ application_area_id = tag_data.application_area_id;
+ }
+
+ // TODO: Validate this data
+ admin_info = {
+ .application_id = application_id,
+ .application_area_id = application_area_id,
+ .crc_change_counter = tag_data.settings.crc_counter,
+ .flags = flags,
+ .tag_type = PackedTagType::Type2,
+ .app_area_version = app_area_version,
+ };
+
+ return ResultSuccess;
+}
+
+Result NfcDevice::DeleteRegisterInfo() {
+ if (device_state != DeviceState::TagMounted) {
+ LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
+ if (device_state == DeviceState::TagRemoved) {
+ return ResultTagRemoved;
+ }
+ return ResultWrongDeviceState;
+ }
+
+ if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
+ LOG_ERROR(Service_NFC, "Amiibo is read only", device_state);
+ return ResultWrongDeviceState;
+ }
+
+ if (tag_data.settings.settings.amiibo_initialized == 0) {
+ return ResultRegistrationIsNotInitialized;
+ }
+
+ Common::TinyMT rng{};
+ rng.Initialize(static_cast<u32>(GetCurrentPosixTime()));
+ rng.GenerateRandomBytes(&tag_data.owner_mii, sizeof(tag_data.owner_mii));
+ rng.GenerateRandomBytes(&tag_data.settings.amiibo_name, sizeof(tag_data.settings.amiibo_name));
+ rng.GenerateRandomBytes(&tag_data.unknown, sizeof(u8));
+ rng.GenerateRandomBytes(&tag_data.unknown2[0], sizeof(u32));
+ rng.GenerateRandomBytes(&tag_data.unknown2[1], sizeof(u32));
+ rng.GenerateRandomBytes(&tag_data.register_info_crc, sizeof(u32));
+ rng.GenerateRandomBytes(&tag_data.settings.init_date, sizeof(u32));
+ tag_data.settings.settings.font_region.Assign(0);
+ tag_data.settings.settings.amiibo_initialized.Assign(0);
+
+ return Flush();
+}
+
+Result NfcDevice::SetRegisterInfoPrivate(const NFP::RegisterInfoPrivate& register_info) {
+ if (device_state != DeviceState::TagMounted) {
+ LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
+ if (device_state == DeviceState::TagRemoved) {
+ return ResultTagRemoved;
+ }
+ return ResultWrongDeviceState;
+ }
+
+ if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
+ LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
+ return ResultWrongDeviceState;
+ }
+
+ Service::Mii::MiiManager manager;
+ const auto mii = manager.BuildDefault(0);
+ auto& settings = tag_data.settings;
+
+ if (tag_data.settings.settings.amiibo_initialized == 0) {
+ settings.init_date = GetAmiiboDate(GetCurrentPosixTime());
+ settings.write_date.raw_date = 0;
+ }
+
+ SetAmiiboName(settings, register_info.amiibo_name);
+ tag_data.owner_mii = manager.BuildFromStoreData(mii);
+ tag_data.mii_extension = manager.SetFromStoreData(mii);
+ tag_data.unknown = 0;
+ tag_data.unknown2 = {};
+ settings.country_code_id = 0;
+ settings.settings.font_region.Assign(0);
+ settings.settings.amiibo_initialized.Assign(1);
+
+ UpdateRegisterInfoCrc();
+
+ return Flush();
+}
+
+Result NfcDevice::RestoreAmiibo() {
+ if (device_state != DeviceState::TagMounted) {
+ LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
+ if (device_state == DeviceState::TagRemoved) {
+ return ResultTagRemoved;
+ }
+ return ResultWrongDeviceState;
+ }
+
+ if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
+ LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
+ return ResultWrongDeviceState;
+ }
+
+ // TODO: Load amiibo from backup on system
+ LOG_ERROR(Service_NFP, "Not Implemented");
+ return ResultSuccess;
+}
+
+Result NfcDevice::Format() {
+ auto result1 = DeleteApplicationArea();
+ auto result2 = DeleteRegisterInfo();
+
+ if (result1.IsError()) {
+ return result1;
+ }
+
+ if (result2.IsError()) {
+ return result2;
+ }
+
+ return Flush();
+}
+
+Result NfcDevice::OpenApplicationArea(u32 access_id) {
+ if (device_state != DeviceState::TagMounted) {
+ LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
+ if (device_state == DeviceState::TagRemoved) {
+ return ResultTagRemoved;
+ }
+ return ResultWrongDeviceState;
+ }
+
+ if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
+ LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
+ return ResultWrongDeviceState;
+ }
+
+ if (tag_data.settings.settings.appdata_initialized.Value() == 0) {
+ LOG_WARNING(Service_NFP, "Application area is not initialized");
+ return ResultApplicationAreaIsNotInitialized;
+ }
+
+ if (tag_data.application_area_id != access_id) {
+ LOG_WARNING(Service_NFP, "Wrong application area id");
+ return ResultWrongApplicationAreaId;
+ }
+
+ is_app_area_open = true;
+
+ return ResultSuccess;
+}
+
+Result NfcDevice::GetApplicationAreaId(u32& application_area_id) const {
+ application_area_id = {};
+
+ if (device_state != DeviceState::TagMounted) {
+ LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
+ if (device_state == DeviceState::TagRemoved) {
+ return ResultTagRemoved;
+ }
+ return ResultWrongDeviceState;
+ }
+
+ if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
+ LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
+ return ResultWrongDeviceState;
+ }
+
+ if (tag_data.settings.settings.appdata_initialized.Value() == 0) {
+ LOG_WARNING(Service_NFP, "Application area is not initialized");
+ return ResultApplicationAreaIsNotInitialized;
+ }
+
+ application_area_id = tag_data.application_area_id;
+
+ return ResultSuccess;
+}
+
+Result NfcDevice::GetApplicationArea(std::span<u8> data) const {
+ if (device_state != DeviceState::TagMounted) {
+ LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
+ if (device_state == DeviceState::TagRemoved) {
+ return ResultTagRemoved;
+ }
+ return ResultWrongDeviceState;
+ }
+
+ if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
+ LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
+ return ResultWrongDeviceState;
+ }
+
+ if (!is_app_area_open) {
+ LOG_ERROR(Service_NFP, "Application area is not open");
+ return ResultWrongDeviceState;
+ }
+
+ if (tag_data.settings.settings.appdata_initialized.Value() == 0) {
+ LOG_ERROR(Service_NFP, "Application area is not initialized");
+ return ResultApplicationAreaIsNotInitialized;
+ }
+
+ memcpy(data.data(), tag_data.application_area.data(),
+ std::min(data.size(), sizeof(NFP::ApplicationArea)));
+
+ return ResultSuccess;
+}
+
+Result NfcDevice::SetApplicationArea(std::span<const u8> data) {
+ if (device_state != DeviceState::TagMounted) {
+ LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
+ if (device_state == DeviceState::TagRemoved) {
+ return ResultTagRemoved;
+ }
+ return ResultWrongDeviceState;
+ }
+
+ if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
+ LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
+ return ResultWrongDeviceState;
+ }
+
+ if (!is_app_area_open) {
+ LOG_ERROR(Service_NFP, "Application area is not open");
+ return ResultWrongDeviceState;
+ }
+
+ if (tag_data.settings.settings.appdata_initialized.Value() == 0) {
+ LOG_ERROR(Service_NFP, "Application area is not initialized");
+ return ResultApplicationAreaIsNotInitialized;
+ }
+
+ if (data.size() > sizeof(NFP::ApplicationArea)) {
+ LOG_ERROR(Service_NFP, "Wrong data size {}", data.size());
+ return ResultUnknown;
+ }
+
+ Common::TinyMT rng{};
+ rng.Initialize(static_cast<u32>(GetCurrentPosixTime()));
+ std::memcpy(tag_data.application_area.data(), data.data(), data.size());
+ // Fill remaining data with random numbers
+ rng.GenerateRandomBytes(tag_data.application_area.data() + data.size(),
+ sizeof(NFP::ApplicationArea) - data.size());
+
+ if (tag_data.application_write_counter != NFP::counter_limit) {
+ tag_data.application_write_counter++;
+ }
+
+ is_data_moddified = true;
+
+ return ResultSuccess;
+}
+
+Result NfcDevice::CreateApplicationArea(u32 access_id, std::span<const u8> data) {
+ if (device_state != DeviceState::TagMounted) {
+ LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
+ if (device_state == DeviceState::TagRemoved) {
+ return ResultTagRemoved;
+ }
+ return ResultWrongDeviceState;
+ }
+
+ if (tag_data.settings.settings.appdata_initialized.Value() != 0) {
+ LOG_ERROR(Service_NFP, "Application area already exist");
+ return ResultApplicationAreaExist;
+ }
+
+ return RecreateApplicationArea(access_id, data);
+}
+
+Result NfcDevice::RecreateApplicationArea(u32 access_id, std::span<const u8> data) {
+ if (device_state != DeviceState::TagMounted) {
+ LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
+ if (device_state == DeviceState::TagRemoved) {
+ return ResultTagRemoved;
+ }
+ return ResultWrongDeviceState;
+ }
+
+ if (is_app_area_open) {
+ LOG_ERROR(Service_NFP, "Application area is open");
+ return ResultWrongDeviceState;
+ }
+
+ if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
+ LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
+ return ResultWrongDeviceState;
+ }
+
+ if (data.size() > sizeof(NFP::ApplicationArea)) {
+ LOG_ERROR(Service_NFP, "Wrong data size {}", data.size());
+ return ResultWrongApplicationAreaSize;
+ }
+
+ Common::TinyMT rng{};
+ rng.Initialize(static_cast<u32>(GetCurrentPosixTime()));
+ std::memcpy(tag_data.application_area.data(), data.data(), data.size());
+ // Fill remaining data with random numbers
+ rng.GenerateRandomBytes(tag_data.application_area.data() + data.size(),
+ sizeof(NFP::ApplicationArea) - data.size());
+
+ if (tag_data.application_write_counter != NFP::counter_limit) {
+ tag_data.application_write_counter++;
+ }
+
+ const u64 application_id = system.GetApplicationProcessProgramID();
+
+ tag_data.application_id_byte =
+ static_cast<u8>(application_id >> NFP::application_id_version_offset & 0xf);
+ tag_data.application_id =
+ RemoveVersionByte(application_id) | (static_cast<u64>(NFP::AppAreaVersion::NintendoSwitch)
+ << NFP::application_id_version_offset);
+ tag_data.settings.settings.appdata_initialized.Assign(1);
+ tag_data.application_area_id = access_id;
+ tag_data.unknown = {};
+ tag_data.unknown2 = {};
+
+ UpdateRegisterInfoCrc();
+
+ return Flush();
+}
+
+Result NfcDevice::DeleteApplicationArea() {
+ if (device_state != DeviceState::TagMounted) {
+ LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
+ if (device_state == DeviceState::TagRemoved) {
+ return ResultTagRemoved;
+ }
+ return ResultWrongDeviceState;
+ }
+
+ if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
+ LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
+ return ResultWrongDeviceState;
+ }
+
+ if (tag_data.settings.settings.appdata_initialized == 0) {
+ return ResultApplicationAreaIsNotInitialized;
+ }
+
+ if (tag_data.application_write_counter != NFP::counter_limit) {
+ tag_data.application_write_counter++;
+ }
+
+ Common::TinyMT rng{};
+ rng.Initialize(static_cast<u32>(GetCurrentPosixTime()));
+ rng.GenerateRandomBytes(tag_data.application_area.data(), sizeof(NFP::ApplicationArea));
+ rng.GenerateRandomBytes(&tag_data.application_id, sizeof(u64));
+ rng.GenerateRandomBytes(&tag_data.application_area_id, sizeof(u32));
+ rng.GenerateRandomBytes(&tag_data.application_id_byte, sizeof(u8));
+ tag_data.settings.settings.appdata_initialized.Assign(0);
+ tag_data.unknown = {};
+ tag_data.unknown2 = {};
+ is_app_area_open = false;
+
+ UpdateRegisterInfoCrc();
+
+ return Flush();
+}
+
+Result NfcDevice::ExistsApplicationArea(bool& has_application_area) const {
+ if (device_state != DeviceState::TagMounted) {
+ LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
+ if (device_state == DeviceState::TagRemoved) {
+ return ResultTagRemoved;
+ }
+ return ResultWrongDeviceState;
+ }
+
+ if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
+ LOG_ERROR(Service_NFC, "Amiibo is read only", device_state);
+ return ResultWrongDeviceState;
+ }
+
+ has_application_area = tag_data.settings.settings.appdata_initialized.Value() != 0;
+
+ return ResultSuccess;
+}
+
+Result NfcDevice::GetAll(NFP::NfpData& data) const {
+ if (device_state != DeviceState::TagMounted) {
+ LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
+ if (device_state == DeviceState::TagRemoved) {
+ return ResultTagRemoved;
+ }
+ return ResultWrongDeviceState;
+ }
+
+ if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
+ LOG_ERROR(Service_NFC, "Amiibo is read only", device_state);
+ return ResultWrongDeviceState;
+ }
+
+ NFP::CommonInfo common_info{};
+ const u64 application_id = tag_data.application_id;
+
+ GetCommonInfo(common_info);
+
+ data = {
+ .magic = tag_data.constant_value,
+ .write_counter = tag_data.write_counter,
+ .settings_crc = tag_data.settings.crc,
+ .common_info = common_info,
+ .mii_char_info = tag_data.owner_mii,
+ .mii_store_data_extension = tag_data.mii_extension,
+ .creation_date = tag_data.settings.init_date.GetWriteDate(),
+ .amiibo_name = tag_data.settings.amiibo_name,
+ .amiibo_name_null_terminated = 0,
+ .settings = tag_data.settings.settings,
+ .unknown1 = tag_data.unknown,
+ .register_info_crc = tag_data.register_info_crc,
+ .unknown2 = tag_data.unknown2,
+ .application_id = application_id,
+ .access_id = tag_data.application_area_id,
+ .settings_crc_counter = tag_data.settings.crc_counter,
+ .font_region = tag_data.settings.settings.font_region,
+ .tag_type = PackedTagType::Type2,
+ .console_type = static_cast<NFP::AppAreaVersion>(
+ application_id >> NFP::application_id_version_offset & 0xf),
+ .application_id_byte = tag_data.application_id_byte,
+ .application_area = tag_data.application_area,
+ };
+
+ return ResultSuccess;
+}
+
+Result NfcDevice::SetAll(const NFP::NfpData& data) {
+ if (device_state != DeviceState::TagMounted) {
+ LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
+ if (device_state == DeviceState::TagRemoved) {
+ return ResultTagRemoved;
+ }
+ return ResultWrongDeviceState;
+ }
+
+ if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
+ LOG_ERROR(Service_NFC, "Amiibo is read only", device_state);
+ return ResultWrongDeviceState;
+ }
+
+ tag_data.constant_value = data.magic;
+ tag_data.write_counter = data.write_counter;
+ tag_data.settings.crc = data.settings_crc;
+ tag_data.settings.write_date.SetWriteDate(data.common_info.last_write_date);
+ tag_data.write_counter = data.common_info.write_counter;
+ tag_data.amiibo_version = data.common_info.version;
+ tag_data.owner_mii = data.mii_char_info;
+ tag_data.mii_extension = data.mii_store_data_extension;
+ tag_data.settings.init_date.SetWriteDate(data.creation_date);
+ tag_data.settings.amiibo_name = data.amiibo_name;
+ tag_data.settings.settings = data.settings;
+ tag_data.unknown = data.unknown1;
+ tag_data.register_info_crc = data.register_info_crc;
+ tag_data.unknown2 = data.unknown2;
+ tag_data.application_id = data.application_id;
+ tag_data.application_area_id = data.access_id;
+ tag_data.settings.crc_counter = data.settings_crc_counter;
+ tag_data.settings.settings.font_region.Assign(data.font_region);
+ tag_data.application_id_byte = data.application_id_byte;
+ tag_data.application_area = data.application_area;
+
+ return ResultSuccess;
+}
+
+Result NfcDevice::BreakTag(NFP::BreakType break_type) {
+ if (device_state != DeviceState::TagMounted) {
+ LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
+ if (device_state == DeviceState::TagRemoved) {
+ return ResultTagRemoved;
+ }
+ return ResultWrongDeviceState;
+ }
+
+ if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
+ LOG_ERROR(Service_NFC, "Amiibo is read only", device_state);
+ return ResultWrongDeviceState;
+ }
+
+ // TODO: Complete this implementation
+
+ return FlushWithBreak(break_type);
+}
+
+Result NfcDevice::HasBackup(const UniqueSerialNumber& uid, std::size_t uuid_size) const {
+ ASSERT_MSG(uuid_size < sizeof(UniqueSerialNumber), "Invalid UUID size");
+ constexpr auto backup_dir = "backup";
+ const auto yuzu_amiibo_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::AmiiboDir);
+ const auto file_name =
+ fmt::format("{0:02x}.bin", fmt::join(uid.begin(), uid.begin() + uuid_size, ""));
+
+ if (!Common::FS::Exists(yuzu_amiibo_dir / backup_dir / file_name)) {
+ return ResultUnableToAccessBackupFile;
+ }
+
+ return ResultSuccess;
+}
+
+Result NfcDevice::HasBackup(const NFP::TagUuid& tag_uid) const {
+ UniqueSerialNumber uuid{};
+ memcpy(uuid.data(), &tag_uid, sizeof(NFP::TagUuid));
+ return HasBackup(uuid, sizeof(NFP::TagUuid));
+}
+
+Result NfcDevice::ReadBackupData(const UniqueSerialNumber& uid, std::size_t uuid_size,
+ std::span<u8> data) const {
+ ASSERT_MSG(uuid_size < sizeof(UniqueSerialNumber), "Invalid UUID size");
+ constexpr auto backup_dir = "backup";
+ const auto yuzu_amiibo_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::AmiiboDir);
+ const auto file_name =
+ fmt::format("{0:02x}.bin", fmt::join(uid.begin(), uid.begin() + uuid_size, ""));
+
+ const Common::FS::IOFile keys_file{yuzu_amiibo_dir / backup_dir / file_name,
+ Common::FS::FileAccessMode::Read,
+ Common::FS::FileType::BinaryFile};
+
+ if (!keys_file.IsOpen()) {
+ LOG_ERROR(Service_NFP, "Failed to open amiibo backup");
+ return ResultUnableToAccessBackupFile;
+ }
+
+ if (keys_file.Read(data) != data.size()) {
+ LOG_ERROR(Service_NFP, "Failed to read amiibo backup");
+ return ResultUnableToAccessBackupFile;
+ }
+
+ return ResultSuccess;
+}
+
+Result NfcDevice::ReadBackupData(const NFP::TagUuid& tag_uid, std::span<u8> data) const {
+ UniqueSerialNumber uuid{};
+ memcpy(uuid.data(), &tag_uid, sizeof(NFP::TagUuid));
+ return ReadBackupData(uuid, sizeof(NFP::TagUuid), data);
+}
+
+Result NfcDevice::WriteBackupData(const UniqueSerialNumber& uid, std::size_t uuid_size,
+ std::span<const u8> data) {
+ ASSERT_MSG(uuid_size < sizeof(UniqueSerialNumber), "Invalid UUID size");
+ constexpr auto backup_dir = "backup";
+ const auto yuzu_amiibo_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::AmiiboDir);
+ const auto file_name =
+ fmt::format("{0:02x}.bin", fmt::join(uid.begin(), uid.begin() + uuid_size, ""));
+
+ if (HasBackup(uid, uuid_size).IsError()) {
+ if (!Common::FS::CreateDir(yuzu_amiibo_dir / backup_dir)) {
+ return ResultBackupPathAlreadyExist;
+ }
+
+ if (!Common::FS::NewFile(yuzu_amiibo_dir / backup_dir / file_name)) {
+ return ResultBackupPathAlreadyExist;
+ }
+ }
+
+ const Common::FS::IOFile keys_file{yuzu_amiibo_dir / backup_dir / file_name,
+ Common::FS::FileAccessMode::ReadWrite,
+ Common::FS::FileType::BinaryFile};
+
+ if (!keys_file.IsOpen()) {
+ LOG_ERROR(Service_NFP, "Failed to open amiibo backup");
+ return ResultUnableToAccessBackupFile;
+ }
+
+ if (keys_file.Write(data) != data.size()) {
+ LOG_ERROR(Service_NFP, "Failed to write amiibo backup");
+ return ResultUnableToAccessBackupFile;
+ }
+
+ return ResultSuccess;
+}
+
+Result NfcDevice::WriteBackupData(const NFP::TagUuid& tag_uid, std::span<const u8> data) {
+ UniqueSerialNumber uuid{};
+ memcpy(uuid.data(), &tag_uid, sizeof(NFP::TagUuid));
+ return WriteBackupData(uuid, sizeof(NFP::TagUuid), data);
+}
+
+Result NfcDevice::WriteNtf(std::span<const u8> data) {
+ if (device_state != DeviceState::TagMounted) {
+ LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
+ if (device_state == DeviceState::TagRemoved) {
+ return ResultTagRemoved;
+ }
+ return ResultWrongDeviceState;
+ }
+
+ if (mount_target == NFP::MountTarget::None || mount_target == NFP::MountTarget::Rom) {
+ LOG_ERROR(Service_NFC, "Amiibo is read only", device_state);
+ return ResultWrongDeviceState;
+ }
+
+ // Not implemented
+
+ return ResultSuccess;
+}
+
+NFP::AmiiboName NfcDevice::GetAmiiboName(const NFP::AmiiboSettings& settings) const {
+ std::array<char16_t, NFP::amiibo_name_length> settings_amiibo_name{};
+ NFP::AmiiboName amiibo_name{};
+
+ // Convert from big endian to little endian
+ for (std::size_t i = 0; i < NFP::amiibo_name_length; i++) {
+ settings_amiibo_name[i] = static_cast<u16>(settings.amiibo_name[i]);
+ }
+
+ // Convert from utf16 to utf8
+ const auto amiibo_name_utf8 = Common::UTF16ToUTF8(settings_amiibo_name.data());
+ memcpy(amiibo_name.data(), amiibo_name_utf8.data(), amiibo_name_utf8.size());
+
+ return amiibo_name;
+}
+
+void NfcDevice::SetAmiiboName(NFP::AmiiboSettings& settings,
+ const NFP::AmiiboName& amiibo_name) const {
+ std::array<char16_t, NFP::amiibo_name_length> settings_amiibo_name{};
+
+ // Convert from utf8 to utf16
+ const auto amiibo_name_utf16 = Common::UTF8ToUTF16(amiibo_name.data());
+ memcpy(settings_amiibo_name.data(), amiibo_name_utf16.data(),
+ amiibo_name_utf16.size() * sizeof(char16_t));
+
+ // Convert from little endian to big endian
+ for (std::size_t i = 0; i < NFP::amiibo_name_length; i++) {
+ settings.amiibo_name[i] = static_cast<u16_be>(settings_amiibo_name[i]);
+ }
+}
+
+NFP::AmiiboDate NfcDevice::GetAmiiboDate(s64 posix_time) const {
+ const auto& time_zone_manager =
+ system.GetTimeManager().GetTimeZoneContentManager().GetTimeZoneManager();
+ Time::TimeZone::CalendarInfo calendar_info{};
+ NFP::AmiiboDate amiibo_date{};
+
+ amiibo_date.SetYear(2000);
+ amiibo_date.SetMonth(1);
+ amiibo_date.SetDay(1);
+
+ if (time_zone_manager.ToCalendarTime({}, posix_time, calendar_info) == ResultSuccess) {
+ amiibo_date.SetYear(calendar_info.time.year);
+ amiibo_date.SetMonth(calendar_info.time.month);
+ amiibo_date.SetDay(calendar_info.time.day);
+ }
+
+ return amiibo_date;
+}
+
+u64 NfcDevice::GetCurrentPosixTime() const {
+ auto& standard_steady_clock{system.GetTimeManager().GetStandardSteadyClockCore()};
+ return standard_steady_clock.GetCurrentTimePoint(system).time_point;
+}
+
+u64 NfcDevice::RemoveVersionByte(u64 application_id) const {
+ return application_id & ~(0xfULL << NFP::application_id_version_offset);
+}
+
+void NfcDevice::UpdateSettingsCrc() {
+ auto& settings = tag_data.settings;
+
+ if (settings.crc_counter != NFP::counter_limit) {
+ settings.crc_counter++;
+ }
+
+ // TODO: this reads data from a global, find what it is
+ std::array<u8, 8> unknown_input{};
+ boost::crc_32_type crc;
+ crc.process_bytes(&unknown_input, sizeof(unknown_input));
+ settings.crc = crc.checksum();
+}
+
+void NfcDevice::UpdateRegisterInfoCrc() {
+#pragma pack(push, 1)
+ struct CrcData {
+ Mii::Ver3StoreData mii;
+ u8 application_id_byte;
+ u8 unknown;
+ Mii::NfpStoreDataExtension mii_extension;
+ std::array<u32, 0x5> unknown2;
+ };
+ static_assert(sizeof(CrcData) == 0x7e, "CrcData is an invalid size");
+#pragma pack(pop)
+
+ const CrcData crc_data{
+ .mii = tag_data.owner_mii,
+ .application_id_byte = tag_data.application_id_byte,
+ .unknown = tag_data.unknown,
+ .mii_extension = tag_data.mii_extension,
+ .unknown2 = tag_data.unknown2,
+ };
+
+ boost::crc_32_type crc;
+ crc.process_bytes(&crc_data, sizeof(CrcData));
+ tag_data.register_info_crc = crc.checksum();
+}
+
+void NfcDevice::BuildAmiiboWithoutKeys(NFP::NTAG215File& stubbed_tag_data,
+ const NFP::EncryptedNTAG215File& encrypted_file) const {
+ Service::Mii::MiiManager manager;
+ auto& settings = stubbed_tag_data.settings;
+
+ stubbed_tag_data = NFP::AmiiboCrypto::NfcDataToEncodedData(encrypted_file);
+
+ // Common info
+ stubbed_tag_data.write_counter = 0;
+ stubbed_tag_data.amiibo_version = 0;
+ settings.write_date = GetAmiiboDate(GetCurrentPosixTime());
+
+ // Register info
+ SetAmiiboName(settings, {'y', 'u', 'z', 'u', 'A', 'm', 'i', 'i', 'b', 'o'});
+ settings.settings.font_region.Assign(0);
+ settings.init_date = GetAmiiboDate(GetCurrentPosixTime());
+ stubbed_tag_data.owner_mii = manager.BuildFromStoreData(manager.BuildDefault(0));
+
+ // Admin info
+ settings.settings.amiibo_initialized.Assign(1);
+ settings.settings.appdata_initialized.Assign(0);
+}
+
+u64 NfcDevice::GetHandle() const {
+ // Generate a handle based of the npad id
+ return static_cast<u64>(npad_id);
+}
+
+DeviceState NfcDevice::GetCurrentState() const {
+ return device_state;
+}
+
+Result NfcDevice::GetNpadId(Core::HID::NpadIdType& out_npad_id) const {
+ out_npad_id = npad_id;
+ return ResultSuccess;
+}
+
+} // namespace Service::NFC
diff --git a/src/core/hle/service/nfc/common/device.h b/src/core/hle/service/nfc/common/device.h
new file mode 100644
index 000000000..0ed1ff34c
--- /dev/null
+++ b/src/core/hle/service/nfc/common/device.h
@@ -0,0 +1,146 @@
+// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include <span>
+
+#include "common/common_types.h"
+#include "core/hle/service/kernel_helpers.h"
+#include "core/hle/service/nfc/mifare_types.h"
+#include "core/hle/service/nfc/nfc_types.h"
+#include "core/hle/service/nfp/nfp_types.h"
+#include "core/hle/service/service.h"
+#include "core/hle/service/time/clock_types.h"
+
+namespace Kernel {
+class KEvent;
+class KReadableEvent;
+} // namespace Kernel
+
+namespace Core {
+class System;
+} // namespace Core
+
+namespace Core::HID {
+class EmulatedController;
+enum class ControllerTriggerType;
+enum class NpadIdType : u32;
+} // namespace Core::HID
+
+namespace Service::NFC {
+class NfcDevice {
+public:
+ NfcDevice(Core::HID::NpadIdType npad_id_, Core::System& system_,
+ KernelHelpers::ServiceContext& service_context_,
+ Kernel::KEvent* availability_change_event_);
+ ~NfcDevice();
+
+ void Initialize();
+ void Finalize();
+
+ Result StartDetection(NfcProtocol allowed_protocol);
+ Result StopDetection();
+
+ Result GetTagInfo(TagInfo& tag_info) const;
+
+ Result ReadMifare(std::span<const MifareReadBlockParameter> parameters,
+ std::span<MifareReadBlockData> read_block_data) const;
+
+ Result WriteMifare(std::span<const MifareWriteBlockParameter> parameters);
+
+ Result SendCommandByPassThrough(const Time::Clock::TimeSpanType& timeout,
+ std::span<const u8> command_data, std::span<u8> out_data);
+
+ Result Mount(NFP::ModelType model_type, NFP::MountTarget mount_target);
+ Result Unmount();
+
+ Result Flush();
+ Result FlushDebug();
+ Result FlushWithBreak(NFP::BreakType break_type);
+ Result Restore();
+
+ Result GetCommonInfo(NFP::CommonInfo& common_info) const;
+ Result GetModelInfo(NFP::ModelInfo& model_info) const;
+ Result GetRegisterInfo(NFP::RegisterInfo& register_info) const;
+ Result GetRegisterInfoPrivate(NFP::RegisterInfoPrivate& register_info) const;
+ Result GetAdminInfo(NFP::AdminInfo& admin_info) const;
+
+ Result DeleteRegisterInfo();
+ Result SetRegisterInfoPrivate(const NFP::RegisterInfoPrivate& register_info);
+ Result RestoreAmiibo();
+ Result Format();
+
+ Result OpenApplicationArea(u32 access_id);
+ Result GetApplicationAreaId(u32& application_area_id) const;
+ Result GetApplicationArea(std::span<u8> data) const;
+ Result SetApplicationArea(std::span<const u8> data);
+ Result CreateApplicationArea(u32 access_id, std::span<const u8> data);
+ Result RecreateApplicationArea(u32 access_id, std::span<const u8> data);
+ Result DeleteApplicationArea();
+ Result ExistsApplicationArea(bool& has_application_area) const;
+
+ Result GetAll(NFP::NfpData& data) const;
+ Result SetAll(const NFP::NfpData& data);
+ Result BreakTag(NFP::BreakType break_type);
+ Result HasBackup(const UniqueSerialNumber& uid, std::size_t uuid_size) const;
+ Result HasBackup(const NFP::TagUuid& tag_uid) const;
+ Result ReadBackupData(const UniqueSerialNumber& uid, std::size_t uuid_size,
+ std::span<u8> data) const;
+ Result ReadBackupData(const NFP::TagUuid& tag_uid, std::span<u8> data) const;
+ Result WriteBackupData(const UniqueSerialNumber& uid, std::size_t uuid_size,
+ std::span<const u8> data);
+ Result WriteBackupData(const NFP::TagUuid& tag_uid, std::span<const u8> data);
+ Result WriteNtf(std::span<const u8> data);
+
+ u64 GetHandle() const;
+ DeviceState GetCurrentState() const;
+ Result GetNpadId(Core::HID::NpadIdType& out_npad_id) const;
+
+ Kernel::KReadableEvent& GetActivateEvent() const;
+ Kernel::KReadableEvent& GetDeactivateEvent() const;
+
+private:
+ void NpadUpdate(Core::HID::ControllerTriggerType type);
+ bool LoadNfcTag(u8 protocol, u8 tag_type, u8 uuid_length, UniqueSerialNumber uuid);
+ bool LoadAmiiboData();
+ void CloseNfcTag();
+
+ NFP::AmiiboName GetAmiiboName(const NFP::AmiiboSettings& settings) const;
+ void SetAmiiboName(NFP::AmiiboSettings& settings, const NFP::AmiiboName& amiibo_name) const;
+ NFP::AmiiboDate GetAmiiboDate(s64 posix_time) const;
+ u64 GetCurrentPosixTime() const;
+ u64 RemoveVersionByte(u64 application_id) const;
+ void UpdateSettingsCrc();
+ void UpdateRegisterInfoCrc();
+
+ void BuildAmiiboWithoutKeys(NFP::NTAG215File& stubbed_tag_data,
+ const NFP::EncryptedNTAG215File& encrypted_file) const;
+
+ bool is_controller_set{};
+ int callback_key;
+ const Core::HID::NpadIdType npad_id;
+ Core::System& system;
+ Core::HID::EmulatedController* npad_device = nullptr;
+ KernelHelpers::ServiceContext& service_context;
+ Kernel::KEvent* activate_event = nullptr;
+ Kernel::KEvent* deactivate_event = nullptr;
+ Kernel::KEvent* availability_change_event = nullptr;
+
+ bool is_initalized{};
+ NfcProtocol allowed_protocols{};
+ DeviceState device_state{DeviceState::Unavailable};
+
+ // NFP data
+ bool is_data_moddified{};
+ bool is_app_area_open{};
+ bool is_plain_amiibo{};
+ bool is_write_protected{};
+ NFP::MountTarget mount_target{NFP::MountTarget::None};
+
+ TagInfo real_tag_info{};
+ NFP::NTAG215File tag_data{};
+ NFP::EncryptedNTAG215File encrypted_tag_data{};
+};
+
+} // namespace Service::NFC
diff --git a/src/core/hle/service/nfc/common/device_manager.cpp b/src/core/hle/service/nfc/common/device_manager.cpp
new file mode 100644
index 000000000..562f3a28e
--- /dev/null
+++ b/src/core/hle/service/nfc/common/device_manager.cpp
@@ -0,0 +1,708 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "common/logging/log.h"
+#include "core/core.h"
+#include "core/hid/hid_types.h"
+#include "core/hle/kernel/k_event.h"
+#include "core/hle/service/ipc_helpers.h"
+#include "core/hle/service/nfc/common/device.h"
+#include "core/hle/service/nfc/common/device_manager.h"
+#include "core/hle/service/nfc/nfc_result.h"
+#include "core/hle/service/time/clock_types.h"
+
+namespace Service::NFC {
+
+DeviceManager::DeviceManager(Core::System& system_, KernelHelpers::ServiceContext& service_context_)
+ : system{system_}, service_context{service_context_} {
+
+ availability_change_event =
+ service_context.CreateEvent("Nfc:DeviceManager:AvailabilityChangeEvent");
+
+ for (u32 device_index = 0; device_index < devices.size(); device_index++) {
+ devices[device_index] =
+ std::make_shared<NfcDevice>(Core::HID::IndexToNpadIdType(device_index), system,
+ service_context, availability_change_event);
+ }
+
+ is_initialized = false;
+}
+
+DeviceManager ::~DeviceManager() {
+ if (is_initialized) {
+ Finalize();
+ }
+ service_context.CloseEvent(availability_change_event);
+}
+
+Result DeviceManager::Initialize() {
+ for (auto& device : devices) {
+ device->Initialize();
+ }
+ is_initialized = true;
+ return ResultSuccess;
+}
+
+Result DeviceManager::Finalize() {
+ for (auto& device : devices) {
+ device->Finalize();
+ }
+ is_initialized = false;
+ return ResultSuccess;
+}
+
+Result DeviceManager::ListDevices(std::vector<u64>& nfp_devices,
+ std::size_t max_allowed_devices) const {
+ for (auto& device : devices) {
+ if (nfp_devices.size() >= max_allowed_devices) {
+ continue;
+ }
+ if (device->GetCurrentState() != DeviceState::Unavailable) {
+ nfp_devices.push_back(device->GetHandle());
+ }
+ }
+
+ if (nfp_devices.empty()) {
+ return ResultDeviceNotFound;
+ }
+
+ return ResultSuccess;
+}
+
+DeviceState DeviceManager::GetDeviceState(u64 device_handle) const {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ const auto result = GetDeviceFromHandle(device_handle, device, false);
+
+ if (result.IsSuccess()) {
+ return device->GetCurrentState();
+ }
+
+ return DeviceState::Unavailable;
+}
+
+Result DeviceManager::GetNpadId(u64 device_handle, Core::HID::NpadIdType& npad_id) const {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ auto result = GetDeviceHandle(device_handle, device);
+
+ if (result.IsSuccess()) {
+ result = device->GetNpadId(npad_id);
+ result = VerifyDeviceResult(device, result);
+ }
+
+ return result;
+}
+
+Kernel::KReadableEvent& DeviceManager::AttachAvailabilityChangeEvent() const {
+ return availability_change_event->GetReadableEvent();
+}
+
+Result DeviceManager::StartDetection(u64 device_handle, NfcProtocol tag_protocol) {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ auto result = GetDeviceHandle(device_handle, device);
+
+ if (result.IsSuccess()) {
+ result = device->StartDetection(tag_protocol);
+ result = VerifyDeviceResult(device, result);
+ }
+
+ return result;
+}
+
+Result DeviceManager::StopDetection(u64 device_handle) {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ auto result = GetDeviceHandle(device_handle, device);
+
+ if (result.IsSuccess()) {
+ result = device->StopDetection();
+ result = VerifyDeviceResult(device, result);
+ }
+
+ return result;
+}
+
+Result DeviceManager::GetTagInfo(u64 device_handle, TagInfo& tag_info) const {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ auto result = GetDeviceHandle(device_handle, device);
+
+ if (result.IsSuccess()) {
+ result = device->GetTagInfo(tag_info);
+ result = VerifyDeviceResult(device, result);
+ }
+
+ return result;
+}
+
+Kernel::KReadableEvent& DeviceManager::AttachActivateEvent(u64 device_handle) const {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ GetDeviceFromHandle(device_handle, device, false);
+
+ // TODO: Return proper error code on failure
+ return device->GetActivateEvent();
+}
+
+Kernel::KReadableEvent& DeviceManager::AttachDeactivateEvent(u64 device_handle) const {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ GetDeviceFromHandle(device_handle, device, false);
+
+ // TODO: Return proper error code on failure
+ return device->GetDeactivateEvent();
+}
+
+Result DeviceManager::ReadMifare(u64 device_handle,
+ std::span<const MifareReadBlockParameter> read_parameters,
+ std::span<MifareReadBlockData> read_data) {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ auto result = GetDeviceHandle(device_handle, device);
+
+ if (result.IsSuccess()) {
+ result = device->ReadMifare(read_parameters, read_data);
+ result = VerifyDeviceResult(device, result);
+ }
+
+ return result;
+}
+
+Result DeviceManager::WriteMifare(u64 device_handle,
+ std::span<const MifareWriteBlockParameter> write_parameters) {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ auto result = GetDeviceHandle(device_handle, device);
+
+ if (result.IsSuccess()) {
+ result = device->WriteMifare(write_parameters);
+ result = VerifyDeviceResult(device, result);
+ }
+
+ return result;
+}
+
+Result DeviceManager::SendCommandByPassThrough(u64 device_handle,
+ const Time::Clock::TimeSpanType& timeout,
+ std::span<const u8> command_data,
+ std::span<u8> out_data) {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ auto result = GetDeviceHandle(device_handle, device);
+
+ if (result.IsSuccess()) {
+ result = device->SendCommandByPassThrough(timeout, command_data, out_data);
+ result = VerifyDeviceResult(device, result);
+ }
+
+ return result;
+}
+
+Result DeviceManager::Mount(u64 device_handle, NFP::ModelType model_type,
+ NFP::MountTarget mount_target) {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ auto result = GetDeviceHandle(device_handle, device);
+
+ if (result.IsSuccess()) {
+ result = device->Mount(model_type, mount_target);
+ result = VerifyDeviceResult(device, result);
+ }
+
+ return result;
+}
+
+Result DeviceManager::Unmount(u64 device_handle) {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ auto result = GetDeviceHandle(device_handle, device);
+
+ if (result.IsSuccess()) {
+ result = device->Unmount();
+ result = VerifyDeviceResult(device, result);
+ }
+
+ return result;
+}
+
+Result DeviceManager::OpenApplicationArea(u64 device_handle, u32 access_id) {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ auto result = GetDeviceHandle(device_handle, device);
+
+ if (result.IsSuccess()) {
+ result = device->OpenApplicationArea(access_id);
+ result = VerifyDeviceResult(device, result);
+ }
+
+ return result;
+}
+
+Result DeviceManager::GetApplicationArea(u64 device_handle, std::span<u8> data) const {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ auto result = GetDeviceHandle(device_handle, device);
+
+ if (result.IsSuccess()) {
+ result = device->GetApplicationArea(data);
+ result = VerifyDeviceResult(device, result);
+ }
+
+ return result;
+}
+
+Result DeviceManager::SetApplicationArea(u64 device_handle, std::span<const u8> data) {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ auto result = GetDeviceHandle(device_handle, device);
+
+ if (result.IsSuccess()) {
+ result = device->SetApplicationArea(data);
+ result = VerifyDeviceResult(device, result);
+ }
+
+ return result;
+}
+
+Result DeviceManager::Flush(u64 device_handle) {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ auto result = GetDeviceHandle(device_handle, device);
+
+ if (result.IsSuccess()) {
+ result = device->Flush();
+ result = VerifyDeviceResult(device, result);
+ }
+
+ return result;
+}
+
+Result DeviceManager::Restore(u64 device_handle) {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ auto result = GetDeviceHandle(device_handle, device);
+
+ if (result.IsSuccess()) {
+ result = device->Restore();
+ result = VerifyDeviceResult(device, result);
+ }
+
+ return result;
+}
+
+Result DeviceManager::CreateApplicationArea(u64 device_handle, u32 access_id,
+ std::span<const u8> data) {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ auto result = GetDeviceHandle(device_handle, device);
+
+ if (result.IsSuccess()) {
+ result = device->CreateApplicationArea(access_id, data);
+ result = VerifyDeviceResult(device, result);
+ }
+
+ return result;
+}
+
+Result DeviceManager::GetRegisterInfo(u64 device_handle, NFP::RegisterInfo& register_info) const {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ auto result = GetDeviceHandle(device_handle, device);
+
+ if (result.IsSuccess()) {
+ result = device->GetRegisterInfo(register_info);
+ result = VerifyDeviceResult(device, result);
+ }
+
+ return result;
+}
+
+Result DeviceManager::GetCommonInfo(u64 device_handle, NFP::CommonInfo& common_info) const {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ auto result = GetDeviceHandle(device_handle, device);
+
+ if (result.IsSuccess()) {
+ result = device->GetCommonInfo(common_info);
+ result = VerifyDeviceResult(device, result);
+ }
+
+ return result;
+}
+
+Result DeviceManager::GetModelInfo(u64 device_handle, NFP::ModelInfo& model_info) const {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ auto result = GetDeviceHandle(device_handle, device);
+
+ if (result.IsSuccess()) {
+ result = device->GetModelInfo(model_info);
+ result = VerifyDeviceResult(device, result);
+ }
+
+ return result;
+}
+
+u32 DeviceManager::GetApplicationAreaSize() const {
+ return sizeof(NFP::ApplicationArea);
+}
+
+Result DeviceManager::RecreateApplicationArea(u64 device_handle, u32 access_id,
+ std::span<const u8> data) {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ auto result = GetDeviceHandle(device_handle, device);
+
+ if (result.IsSuccess()) {
+ result = device->RecreateApplicationArea(access_id, data);
+ result = VerifyDeviceResult(device, result);
+ }
+
+ return result;
+}
+
+Result DeviceManager::Format(u64 device_handle) {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ auto result = GetDeviceHandle(device_handle, device);
+
+ if (result.IsSuccess()) {
+ result = device->Format();
+ result = VerifyDeviceResult(device, result);
+ }
+
+ return result;
+}
+
+Result DeviceManager::GetAdminInfo(u64 device_handle, NFP::AdminInfo& admin_info) const {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ auto result = GetDeviceHandle(device_handle, device);
+
+ if (result.IsSuccess()) {
+ result = device->GetAdminInfo(admin_info);
+ result = VerifyDeviceResult(device, result);
+ }
+
+ return result;
+}
+
+Result DeviceManager::GetRegisterInfoPrivate(u64 device_handle,
+ NFP::RegisterInfoPrivate& register_info) const {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ auto result = GetDeviceHandle(device_handle, device);
+
+ if (result.IsSuccess()) {
+ result = device->GetRegisterInfoPrivate(register_info);
+ result = VerifyDeviceResult(device, result);
+ }
+
+ return result;
+}
+
+Result DeviceManager::SetRegisterInfoPrivate(u64 device_handle,
+ const NFP::RegisterInfoPrivate& register_info) {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ auto result = GetDeviceHandle(device_handle, device);
+
+ if (result.IsSuccess()) {
+ result = device->SetRegisterInfoPrivate(register_info);
+ result = VerifyDeviceResult(device, result);
+ }
+
+ return result;
+}
+
+Result DeviceManager::DeleteRegisterInfo(u64 device_handle) {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ auto result = GetDeviceHandle(device_handle, device);
+
+ if (result.IsSuccess()) {
+ result = device->DeleteRegisterInfo();
+ result = VerifyDeviceResult(device, result);
+ }
+
+ return result;
+}
+
+Result DeviceManager::DeleteApplicationArea(u64 device_handle) {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ auto result = GetDeviceHandle(device_handle, device);
+
+ if (result.IsSuccess()) {
+ result = device->DeleteApplicationArea();
+ result = VerifyDeviceResult(device, result);
+ }
+
+ return result;
+}
+
+Result DeviceManager::ExistsApplicationArea(u64 device_handle, bool& has_application_area) const {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ auto result = GetDeviceHandle(device_handle, device);
+
+ if (result.IsSuccess()) {
+ result = device->ExistsApplicationArea(has_application_area);
+ result = VerifyDeviceResult(device, result);
+ }
+
+ return result;
+}
+
+Result DeviceManager::GetAll(u64 device_handle, NFP::NfpData& nfp_data) const {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ auto result = GetDeviceHandle(device_handle, device);
+
+ if (result.IsSuccess()) {
+ result = device->GetAll(nfp_data);
+ result = VerifyDeviceResult(device, result);
+ }
+
+ return result;
+}
+
+Result DeviceManager::SetAll(u64 device_handle, const NFP::NfpData& nfp_data) {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ auto result = GetDeviceHandle(device_handle, device);
+
+ if (result.IsSuccess()) {
+ result = device->SetAll(nfp_data);
+ result = VerifyDeviceResult(device, result);
+ }
+
+ return result;
+}
+
+Result DeviceManager::FlushDebug(u64 device_handle) {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ auto result = GetDeviceHandle(device_handle, device);
+
+ if (result.IsSuccess()) {
+ result = device->FlushDebug();
+ result = VerifyDeviceResult(device, result);
+ }
+
+ return result;
+}
+
+Result DeviceManager::BreakTag(u64 device_handle, NFP::BreakType break_type) {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ auto result = GetDeviceHandle(device_handle, device);
+
+ if (result.IsSuccess()) {
+ result = device->BreakTag(break_type);
+ result = VerifyDeviceResult(device, result);
+ }
+
+ return result;
+}
+
+Result DeviceManager::ReadBackupData(u64 device_handle, std::span<u8> data) const {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ auto result = GetDeviceHandle(device_handle, device);
+ NFC::TagInfo tag_info{};
+
+ if (result.IsSuccess()) {
+ result = device->GetTagInfo(tag_info);
+ }
+
+ if (result.IsSuccess()) {
+ result = device->ReadBackupData(tag_info.uuid, tag_info.uuid_length, data);
+ result = VerifyDeviceResult(device, result);
+ }
+
+ return result;
+}
+
+Result DeviceManager::WriteBackupData(u64 device_handle, std::span<const u8> data) {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ auto result = GetDeviceHandle(device_handle, device);
+ NFC::TagInfo tag_info{};
+
+ if (result.IsSuccess()) {
+ result = device->GetTagInfo(tag_info);
+ }
+
+ if (result.IsSuccess()) {
+ result = device->WriteBackupData(tag_info.uuid, tag_info.uuid_length, data);
+ result = VerifyDeviceResult(device, result);
+ }
+
+ return result;
+}
+
+Result DeviceManager::WriteNtf(u64 device_handle, NFP::WriteType, std::span<const u8> data) {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ auto result = GetDeviceHandle(device_handle, device);
+
+ if (result.IsSuccess()) {
+ result = device->WriteNtf(data);
+ result = VerifyDeviceResult(device, result);
+ }
+
+ return result;
+}
+
+Result DeviceManager::GetDeviceFromHandle(u64 handle, std::shared_ptr<NfcDevice>& nfc_device,
+ bool check_state) const {
+ if (check_state) {
+ const Result is_parameter_set = IsNfcParameterSet();
+ if (is_parameter_set.IsError()) {
+ return is_parameter_set;
+ }
+ const Result is_enabled = IsNfcEnabled();
+ if (is_enabled.IsError()) {
+ return is_enabled;
+ }
+ const Result is_nfc_initialized = IsNfcInitialized();
+ if (is_nfc_initialized.IsError()) {
+ return is_nfc_initialized;
+ }
+ }
+
+ for (auto& device : devices) {
+ if (device->GetHandle() == handle) {
+ nfc_device = device;
+ return ResultSuccess;
+ }
+ }
+
+ return ResultDeviceNotFound;
+}
+
+std::optional<std::shared_ptr<NfcDevice>> DeviceManager::GetNfcDevice(u64 handle) {
+ for (auto& device : devices) {
+ if (device->GetHandle() == handle) {
+ return device;
+ }
+ }
+ return std::nullopt;
+}
+
+const std::optional<std::shared_ptr<NfcDevice>> DeviceManager::GetNfcDevice(u64 handle) const {
+ for (auto& device : devices) {
+ if (device->GetHandle() == handle) {
+ return device;
+ }
+ }
+ return std::nullopt;
+}
+
+Result DeviceManager::GetDeviceHandle(u64 handle, std::shared_ptr<NfcDevice>& device) const {
+ const auto result = GetDeviceFromHandle(handle, device, true);
+ if (result.IsError()) {
+ return result;
+ }
+ return CheckDeviceState(device);
+}
+
+Result DeviceManager::VerifyDeviceResult(std::shared_ptr<NfcDevice> device,
+ Result operation_result) const {
+ if (operation_result.IsSuccess()) {
+ return operation_result;
+ }
+
+ const Result is_parameter_set = IsNfcParameterSet();
+ if (is_parameter_set.IsError()) {
+ return is_parameter_set;
+ }
+ const Result is_enabled = IsNfcEnabled();
+ if (is_enabled.IsError()) {
+ return is_enabled;
+ }
+ const Result is_nfc_initialized = IsNfcInitialized();
+ if (is_nfc_initialized.IsError()) {
+ return is_nfc_initialized;
+ }
+ const Result device_state = CheckDeviceState(device);
+ if (device_state.IsError()) {
+ return device_state;
+ }
+
+ return operation_result;
+}
+
+Result DeviceManager::CheckDeviceState(std::shared_ptr<NfcDevice> device) const {
+ if (device == nullptr) {
+ return ResultInvalidArgument;
+ }
+
+ return ResultSuccess;
+}
+
+Result DeviceManager::IsNfcEnabled() const {
+ // TODO: This calls nn::settings::detail::GetNfcEnableFlag
+ const bool is_enabled = true;
+ if (!is_enabled) {
+ return ResultNfcDisabled;
+ }
+ return ResultSuccess;
+}
+
+Result DeviceManager::IsNfcParameterSet() const {
+ // TODO: This calls checks against a bool on offset 0x450
+ const bool is_set = true;
+ if (!is_set) {
+ return ResultUnknown76;
+ }
+ return ResultSuccess;
+}
+
+Result DeviceManager::IsNfcInitialized() const {
+ if (!is_initialized) {
+ return ResultNfcNotInitialized;
+ }
+ return ResultSuccess;
+}
+
+} // namespace Service::NFC
diff --git a/src/core/hle/service/nfc/common/device_manager.h b/src/core/hle/service/nfc/common/device_manager.h
new file mode 100644
index 000000000..c61ba0cf3
--- /dev/null
+++ b/src/core/hle/service/nfc/common/device_manager.h
@@ -0,0 +1,100 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#pragma once
+
+#include <array>
+#include <memory>
+#include <optional>
+#include <span>
+
+#include "core/hid/hid_types.h"
+#include "core/hle/service/kernel_helpers.h"
+#include "core/hle/service/nfc/mifare_types.h"
+#include "core/hle/service/nfc/nfc_types.h"
+#include "core/hle/service/nfp/nfp_types.h"
+#include "core/hle/service/service.h"
+#include "core/hle/service/time/clock_types.h"
+
+namespace Service::NFC {
+class NfcDevice;
+
+class DeviceManager {
+public:
+ explicit DeviceManager(Core::System& system_, KernelHelpers::ServiceContext& service_context_);
+ ~DeviceManager();
+
+ // Nfc device manager
+ Result Initialize();
+ Result Finalize();
+ Result ListDevices(std::vector<u64>& nfp_devices, std::size_t max_allowed_devices) const;
+ DeviceState GetDeviceState(u64 device_handle) const;
+ Result GetNpadId(u64 device_handle, Core::HID::NpadIdType& npad_id) const;
+ Kernel::KReadableEvent& AttachAvailabilityChangeEvent() const;
+ Result StartDetection(u64 device_handle, NfcProtocol tag_protocol);
+ Result StopDetection(u64 device_handle);
+ Result GetTagInfo(u64 device_handle, NFP::TagInfo& tag_info) const;
+ Kernel::KReadableEvent& AttachActivateEvent(u64 device_handle) const;
+ Kernel::KReadableEvent& AttachDeactivateEvent(u64 device_handle) const;
+ Result ReadMifare(u64 device_handle,
+ const std::span<const MifareReadBlockParameter> read_parameters,
+ std::span<MifareReadBlockData> read_data);
+ Result WriteMifare(u64 device_handle,
+ std::span<const MifareWriteBlockParameter> write_parameters);
+ Result SendCommandByPassThrough(u64 device_handle, const Time::Clock::TimeSpanType& timeout,
+ std::span<const u8> command_data, std::span<u8> out_data);
+
+ // Nfp device manager
+ Result Mount(u64 device_handle, NFP::ModelType model_type, NFP::MountTarget mount_target);
+ Result Unmount(u64 device_handle);
+ Result OpenApplicationArea(u64 device_handle, u32 access_id);
+ Result GetApplicationArea(u64 device_handle, std::span<u8> data) const;
+ Result SetApplicationArea(u64 device_handle, std::span<const u8> data);
+ Result Flush(u64 device_handle);
+ Result Restore(u64 device_handle);
+ Result CreateApplicationArea(u64 device_handle, u32 access_id, std::span<const u8> data);
+ Result GetRegisterInfo(u64 device_handle, NFP::RegisterInfo& register_info) const;
+ Result GetCommonInfo(u64 device_handle, NFP::CommonInfo& common_info) const;
+ Result GetModelInfo(u64 device_handle, NFP::ModelInfo& model_info) const;
+ u32 GetApplicationAreaSize() const;
+ Result RecreateApplicationArea(u64 device_handle, u32 access_id, std::span<const u8> data);
+ Result Format(u64 device_handle);
+ Result GetAdminInfo(u64 device_handle, NFP::AdminInfo& admin_info) const;
+ Result GetRegisterInfoPrivate(u64 device_handle, NFP::RegisterInfoPrivate& register_info) const;
+ Result SetRegisterInfoPrivate(u64 device_handle, const NFP::RegisterInfoPrivate& register_info);
+ Result DeleteRegisterInfo(u64 device_handle);
+ Result DeleteApplicationArea(u64 device_handle);
+ Result ExistsApplicationArea(u64 device_handle, bool& has_application_area) const;
+ Result GetAll(u64 device_handle, NFP::NfpData& nfp_data) const;
+ Result SetAll(u64 device_handle, const NFP::NfpData& nfp_data);
+ Result FlushDebug(u64 device_handle);
+ Result BreakTag(u64 device_handle, NFP::BreakType break_type);
+ Result ReadBackupData(u64 device_handle, std::span<u8> data) const;
+ Result WriteBackupData(u64 device_handle, std::span<const u8> data);
+ Result WriteNtf(u64 device_handle, NFP::WriteType, std::span<const u8> data);
+
+private:
+ Result IsNfcEnabled() const;
+ Result IsNfcParameterSet() const;
+ Result IsNfcInitialized() const;
+
+ Result GetDeviceFromHandle(u64 handle, std::shared_ptr<NfcDevice>& device,
+ bool check_state) const;
+
+ Result GetDeviceHandle(u64 handle, std::shared_ptr<NfcDevice>& device) const;
+ Result VerifyDeviceResult(std::shared_ptr<NfcDevice> device, Result operation_result) const;
+ Result CheckDeviceState(std::shared_ptr<NfcDevice> device) const;
+
+ std::optional<std::shared_ptr<NfcDevice>> GetNfcDevice(u64 handle);
+ const std::optional<std::shared_ptr<NfcDevice>> GetNfcDevice(u64 handle) const;
+
+ bool is_initialized = false;
+ mutable std::mutex mutex;
+ std::array<std::shared_ptr<NfcDevice>, 10> devices{};
+
+ Core::System& system;
+ KernelHelpers::ServiceContext service_context;
+ Kernel::KEvent* availability_change_event;
+};
+
+} // namespace Service::NFC
diff --git a/src/core/hle/service/nfc/mifare_result.h b/src/core/hle/service/nfc/mifare_result.h
new file mode 100644
index 000000000..16a9171e6
--- /dev/null
+++ b/src/core/hle/service/nfc/mifare_result.h
@@ -0,0 +1,17 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#pragma once
+
+#include "core/hle/result.h"
+
+namespace Service::NFC::Mifare {
+
+constexpr Result ResultDeviceNotFound(ErrorModule::NFCMifare, 64);
+constexpr Result ResultInvalidArgument(ErrorModule::NFCMifare, 65);
+constexpr Result ResultWrongDeviceState(ErrorModule::NFCMifare, 73);
+constexpr Result ResultNfcDisabled(ErrorModule::NFCMifare, 80);
+constexpr Result ResultTagRemoved(ErrorModule::NFCMifare, 97);
+constexpr Result ResultNotAMifare(ErrorModule::NFCMifare, 288);
+
+} // namespace Service::NFC::Mifare
diff --git a/src/core/hle/service/nfc/mifare_types.h b/src/core/hle/service/nfc/mifare_types.h
new file mode 100644
index 000000000..467937399
--- /dev/null
+++ b/src/core/hle/service/nfc/mifare_types.h
@@ -0,0 +1,64 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#pragma once
+
+#include <array>
+
+#include "common/common_funcs.h"
+#include "common/common_types.h"
+
+namespace Service::NFC {
+
+enum class MifareCmd : u8 {
+ None = 0x00,
+ Read = 0x30,
+ AuthA = 0x60,
+ AuthB = 0x61,
+ Write = 0xA0,
+ Transfer = 0xB0,
+ Decrement = 0xC0,
+ Increment = 0xC1,
+ Store = 0xC2
+};
+
+using DataBlock = std::array<u8, 0x10>;
+using KeyData = std::array<u8, 0x6>;
+
+struct SectorKey {
+ MifareCmd command;
+ u8 unknown; // Usually 1
+ INSERT_PADDING_BYTES(0x6);
+ KeyData sector_key;
+ INSERT_PADDING_BYTES(0x2);
+};
+static_assert(sizeof(SectorKey) == 0x10, "SectorKey is an invalid size");
+
+// This is nn::nfc::MifareReadBlockParameter
+struct MifareReadBlockParameter {
+ u8 sector_number{};
+ INSERT_PADDING_BYTES(0x7);
+ SectorKey sector_key{};
+};
+static_assert(sizeof(MifareReadBlockParameter) == 0x18,
+ "MifareReadBlockParameter is an invalid size");
+
+// This is nn::nfc::MifareReadBlockData
+struct MifareReadBlockData {
+ DataBlock data{};
+ u8 sector_number{};
+ INSERT_PADDING_BYTES(0x7);
+};
+static_assert(sizeof(MifareReadBlockData) == 0x18, "MifareReadBlockData is an invalid size");
+
+// This is nn::nfc::MifareWriteBlockParameter
+struct MifareWriteBlockParameter {
+ DataBlock data;
+ u8 sector_number;
+ INSERT_PADDING_BYTES(0x7);
+ SectorKey sector_key;
+};
+static_assert(sizeof(MifareWriteBlockParameter) == 0x28,
+ "MifareWriteBlockParameter is an invalid size");
+
+} // namespace Service::NFC
diff --git a/src/core/hle/service/nfc/mifare_user.cpp b/src/core/hle/service/nfc/mifare_user.cpp
deleted file mode 100644
index 51523a3ae..000000000
--- a/src/core/hle/service/nfc/mifare_user.cpp
+++ /dev/null
@@ -1,400 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#include "common/logging/log.h"
-#include "core/core.h"
-#include "core/hid/hid_types.h"
-#include "core/hle/ipc_helpers.h"
-#include "core/hle/kernel/k_event.h"
-#include "core/hle/service/nfc/mifare_user.h"
-#include "core/hle/service/nfc/nfc_device.h"
-#include "core/hle/service/nfc/nfc_result.h"
-
-namespace Service::NFC {
-
-MFIUser::MFIUser(Core::System& system_)
- : ServiceFramework{system_, "NFC::MFIUser"}, service_context{system_, service_name} {
- static const FunctionInfo functions[] = {
- {0, &MFIUser::Initialize, "Initialize"},
- {1, &MFIUser::Finalize, "Finalize"},
- {2, &MFIUser::ListDevices, "ListDevices"},
- {3, &MFIUser::StartDetection, "StartDetection"},
- {4, &MFIUser::StopDetection, "StopDetection"},
- {5, &MFIUser::Read, "Read"},
- {6, &MFIUser::Write, "Write"},
- {7, &MFIUser::GetTagInfo, "GetTagInfo"},
- {8, &MFIUser::GetActivateEventHandle, "GetActivateEventHandle"},
- {9, &MFIUser::GetDeactivateEventHandle, "GetDeactivateEventHandle"},
- {10, &MFIUser::GetState, "GetState"},
- {11, &MFIUser::GetDeviceState, "GetDeviceState"},
- {12, &MFIUser::GetNpadId, "GetNpadId"},
- {13, &MFIUser::GetAvailabilityChangeEventHandle, "GetAvailabilityChangeEventHandle"},
- };
- RegisterHandlers(functions);
-
- availability_change_event = service_context.CreateEvent("MFIUser:AvailabilityChangeEvent");
-
- for (u32 device_index = 0; device_index < 10; device_index++) {
- devices[device_index] =
- std::make_shared<NfcDevice>(Core::HID::IndexToNpadIdType(device_index), system,
- service_context, availability_change_event);
- }
-}
-
-MFIUser ::~MFIUser() {
- availability_change_event->Close();
-}
-
-void MFIUser::Initialize(Kernel::HLERequestContext& ctx) {
- LOG_INFO(Service_NFC, "called");
-
- state = State::Initialized;
-
- for (auto& device : devices) {
- device->Initialize();
- }
-
- IPC::ResponseBuilder rb{ctx, 2, 0};
- rb.Push(ResultSuccess);
-}
-
-void MFIUser::Finalize(Kernel::HLERequestContext& ctx) {
- LOG_INFO(Service_NFC, "called");
-
- state = State::NonInitialized;
-
- for (auto& device : devices) {
- device->Finalize();
- }
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void MFIUser::ListDevices(Kernel::HLERequestContext& ctx) {
- LOG_DEBUG(Service_NFC, "called");
-
- if (state == State::NonInitialized) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(MifareNfcDisabled);
- return;
- }
-
- if (!ctx.CanWriteBuffer()) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(MifareInvalidArgument);
- return;
- }
-
- if (ctx.GetWriteBufferSize() == 0) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(MifareInvalidArgument);
- return;
- }
-
- std::vector<u64> nfp_devices;
- const std::size_t max_allowed_devices = ctx.GetWriteBufferNumElements<u64>();
-
- for (const auto& device : devices) {
- if (nfp_devices.size() >= max_allowed_devices) {
- continue;
- }
- if (device->GetCurrentState() != NFP::DeviceState::Unavailable) {
- nfp_devices.push_back(device->GetHandle());
- }
- }
-
- if (nfp_devices.empty()) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(MifareDeviceNotFound);
- return;
- }
-
- ctx.WriteBuffer(nfp_devices);
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push(static_cast<s32>(nfp_devices.size()));
-}
-
-void MFIUser::StartDetection(Kernel::HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto device_handle{rp.Pop<u64>()};
- LOG_INFO(Service_NFC, "called, device_handle={}", device_handle);
-
- if (state == State::NonInitialized) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(MifareNfcDisabled);
- return;
- }
-
- auto device = GetNfcDevice(device_handle);
-
- if (!device.has_value()) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(MifareDeviceNotFound);
- return;
- }
-
- const auto result = device.value()->StartDetection(NFP::TagProtocol::All);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
-}
-
-void MFIUser::StopDetection(Kernel::HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto device_handle{rp.Pop<u64>()};
- LOG_INFO(Service_NFC, "called, device_handle={}", device_handle);
-
- if (state == State::NonInitialized) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(MifareNfcDisabled);
- return;
- }
-
- auto device = GetNfcDevice(device_handle);
-
- if (!device.has_value()) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(MifareDeviceNotFound);
- return;
- }
-
- const auto result = device.value()->StopDetection();
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
-}
-
-void MFIUser::Read(Kernel::HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto device_handle{rp.Pop<u64>()};
- const auto buffer{ctx.ReadBuffer()};
- const auto number_of_commands{ctx.GetReadBufferNumElements<NFP::MifareReadBlockParameter>()};
- std::vector<NFP::MifareReadBlockParameter> read_commands(number_of_commands);
-
- memcpy(read_commands.data(), buffer.data(),
- number_of_commands * sizeof(NFP::MifareReadBlockParameter));
-
- LOG_INFO(Service_NFC, "(STUBBED) called, device_handle={}, read_commands_size={}",
- device_handle, number_of_commands);
-
- if (state == State::NonInitialized) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(MifareNfcDisabled);
- return;
- }
-
- auto device = GetNfcDevice(device_handle);
-
- if (!device.has_value()) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(MifareDeviceNotFound);
- return;
- }
-
- Result result = ResultSuccess;
- std::vector<NFP::MifareReadBlockData> out_data(number_of_commands);
- for (std::size_t i = 0; i < number_of_commands; i++) {
- result = device.value()->MifareRead(read_commands[i], out_data[i]);
- if (result.IsError()) {
- break;
- }
- }
-
- ctx.WriteBuffer(out_data);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
-}
-
-void MFIUser::Write(Kernel::HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto device_handle{rp.Pop<u64>()};
- const auto buffer{ctx.ReadBuffer()};
- const auto number_of_commands{ctx.GetReadBufferNumElements<NFP::MifareWriteBlockParameter>()};
- std::vector<NFP::MifareWriteBlockParameter> write_commands(number_of_commands);
-
- memcpy(write_commands.data(), buffer.data(),
- number_of_commands * sizeof(NFP::MifareWriteBlockParameter));
-
- LOG_INFO(Service_NFC, "(STUBBED) called, device_handle={}, write_commands_size={}",
- device_handle, number_of_commands);
-
- if (state == State::NonInitialized) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(MifareNfcDisabled);
- return;
- }
-
- auto device = GetNfcDevice(device_handle);
-
- if (!device.has_value()) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(MifareDeviceNotFound);
- return;
- }
-
- Result result = ResultSuccess;
- std::vector<NFP::MifareReadBlockData> out_data(number_of_commands);
- for (std::size_t i = 0; i < number_of_commands; i++) {
- result = device.value()->MifareWrite(write_commands[i]);
- if (result.IsError()) {
- break;
- }
- }
-
- if (result.IsSuccess()) {
- result = device.value()->Flush();
- }
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
-}
-
-void MFIUser::GetTagInfo(Kernel::HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto device_handle{rp.Pop<u64>()};
- LOG_INFO(Service_NFC, "called, device_handle={}", device_handle);
-
- if (state == State::NonInitialized) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(MifareNfcDisabled);
- return;
- }
-
- auto device = GetNfcDevice(device_handle);
-
- if (!device.has_value()) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(MifareDeviceNotFound);
- return;
- }
-
- NFP::TagInfo tag_info{};
- const auto result = device.value()->GetTagInfo(tag_info, true);
- ctx.WriteBuffer(tag_info);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
-}
-
-void MFIUser::GetActivateEventHandle(Kernel::HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto device_handle{rp.Pop<u64>()};
- LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
-
- if (state == State::NonInitialized) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(MifareNfcDisabled);
- return;
- }
-
- auto device = GetNfcDevice(device_handle);
-
- if (!device.has_value()) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(MifareDeviceNotFound);
- return;
- }
-
- IPC::ResponseBuilder rb{ctx, 2, 1};
- rb.Push(ResultSuccess);
- rb.PushCopyObjects(device.value()->GetActivateEvent());
-}
-
-void MFIUser::GetDeactivateEventHandle(Kernel::HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto device_handle{rp.Pop<u64>()};
- LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
-
- if (state == State::NonInitialized) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(MifareNfcDisabled);
- return;
- }
-
- auto device = GetNfcDevice(device_handle);
-
- if (!device.has_value()) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(MifareDeviceNotFound);
- return;
- }
-
- IPC::ResponseBuilder rb{ctx, 2, 1};
- rb.Push(ResultSuccess);
- rb.PushCopyObjects(device.value()->GetDeactivateEvent());
-}
-
-void MFIUser::GetState(Kernel::HLERequestContext& ctx) {
- LOG_DEBUG(Service_NFC, "called");
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.PushEnum(state);
-}
-
-void MFIUser::GetDeviceState(Kernel::HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto device_handle{rp.Pop<u64>()};
- LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
-
- auto device = GetNfcDevice(device_handle);
-
- if (!device.has_value()) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(MifareDeviceNotFound);
- return;
- }
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.PushEnum(device.value()->GetCurrentState());
-}
-
-void MFIUser::GetNpadId(Kernel::HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto device_handle{rp.Pop<u64>()};
- LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
-
- if (state == State::NonInitialized) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(MifareNfcDisabled);
- return;
- }
-
- auto device = GetNfcDevice(device_handle);
-
- if (!device.has_value()) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(MifareDeviceNotFound);
- return;
- }
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.PushEnum(device.value()->GetNpadId());
-}
-
-void MFIUser::GetAvailabilityChangeEventHandle(Kernel::HLERequestContext& ctx) {
- LOG_INFO(Service_NFC, "called");
-
- if (state == State::NonInitialized) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(MifareNfcDisabled);
- return;
- }
-
- IPC::ResponseBuilder rb{ctx, 2, 1};
- rb.Push(ResultSuccess);
- rb.PushCopyObjects(availability_change_event->GetReadableEvent());
-}
-
-std::optional<std::shared_ptr<NfcDevice>> MFIUser::GetNfcDevice(u64 handle) {
- for (auto& device : devices) {
- if (device->GetHandle() == handle) {
- return device;
- }
- }
- return std::nullopt;
-}
-
-} // namespace Service::NFC
diff --git a/src/core/hle/service/nfc/mifare_user.h b/src/core/hle/service/nfc/mifare_user.h
deleted file mode 100644
index 0e0638cb6..000000000
--- a/src/core/hle/service/nfc/mifare_user.h
+++ /dev/null
@@ -1,52 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#pragma once
-
-#include <array>
-#include <memory>
-#include <optional>
-
-#include "core/hle/service/kernel_helpers.h"
-#include "core/hle/service/service.h"
-
-namespace Service::NFC {
-class NfcDevice;
-
-class MFIUser final : public ServiceFramework<MFIUser> {
-public:
- explicit MFIUser(Core::System& system_);
- ~MFIUser();
-
-private:
- enum class State : u32 {
- NonInitialized,
- Initialized,
- };
-
- void Initialize(Kernel::HLERequestContext& ctx);
- void Finalize(Kernel::HLERequestContext& ctx);
- void ListDevices(Kernel::HLERequestContext& ctx);
- void StartDetection(Kernel::HLERequestContext& ctx);
- void StopDetection(Kernel::HLERequestContext& ctx);
- void Read(Kernel::HLERequestContext& ctx);
- void Write(Kernel::HLERequestContext& ctx);
- void GetTagInfo(Kernel::HLERequestContext& ctx);
- void GetActivateEventHandle(Kernel::HLERequestContext& ctx);
- void GetDeactivateEventHandle(Kernel::HLERequestContext& ctx);
- void GetState(Kernel::HLERequestContext& ctx);
- void GetDeviceState(Kernel::HLERequestContext& ctx);
- void GetNpadId(Kernel::HLERequestContext& ctx);
- void GetAvailabilityChangeEventHandle(Kernel::HLERequestContext& ctx);
-
- std::optional<std::shared_ptr<NfcDevice>> GetNfcDevice(u64 handle);
-
- KernelHelpers::ServiceContext service_context;
-
- std::array<std::shared_ptr<NfcDevice>, 10> devices{};
-
- State state{State::NonInitialized};
- Kernel::KEvent* availability_change_event;
-};
-
-} // namespace Service::NFC
diff --git a/src/core/hle/service/nfc/nfc.cpp b/src/core/hle/service/nfc/nfc.cpp
index b17b18ab9..30ae989b9 100644
--- a/src/core/hle/service/nfc/nfc.cpp
+++ b/src/core/hle/service/nfc/nfc.cpp
@@ -5,15 +5,116 @@
#include "common/logging/log.h"
#include "common/settings.h"
-#include "core/hle/ipc_helpers.h"
-#include "core/hle/service/nfc/mifare_user.h"
+#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/nfc/nfc.h"
-#include "core/hle/service/nfc/nfc_user.h"
+#include "core/hle/service/nfc/nfc_interface.h"
+#include "core/hle/service/server_manager.h"
#include "core/hle/service/service.h"
-#include "core/hle/service/sm/sm.h"
namespace Service::NFC {
+class IUser final : public NfcInterface {
+public:
+ explicit IUser(Core::System& system_) : NfcInterface(system_, "NFC::IUser", BackendType::Nfc) {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, &NfcInterface::Initialize, "InitializeOld"},
+ {1, &NfcInterface::Finalize, "FinalizeOld"},
+ {2, &NfcInterface::GetState, "GetStateOld"},
+ {3, &NfcInterface::IsNfcEnabled, "IsNfcEnabledOld"},
+ {400, &NfcInterface::Initialize, "Initialize"},
+ {401, &NfcInterface::Finalize, "Finalize"},
+ {402, &NfcInterface::GetState, "GetState"},
+ {403, &NfcInterface::IsNfcEnabled, "IsNfcEnabled"},
+ {404, &NfcInterface::ListDevices, "ListDevices"},
+ {405, &NfcInterface::GetDeviceState, "GetDeviceState"},
+ {406, &NfcInterface::GetNpadId, "GetNpadId"},
+ {407, &NfcInterface::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"},
+ {408, &NfcInterface::StartDetection, "StartDetection"},
+ {409, &NfcInterface::StopDetection, "StopDetection"},
+ {410, &NfcInterface::GetTagInfo, "GetTagInfo"},
+ {411, &NfcInterface::AttachActivateEvent, "AttachActivateEvent"},
+ {412, &NfcInterface::AttachDeactivateEvent, "AttachDeactivateEvent"},
+ {1000, &NfcInterface::ReadMifare, "ReadMifare"},
+ {1001, &NfcInterface::WriteMifare ,"WriteMifare"},
+ {1300, &NfcInterface::SendCommandByPassThrough, "SendCommandByPassThrough"},
+ {1301, nullptr, "KeepPassThroughSession"},
+ {1302, nullptr, "ReleasePassThroughSession"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+class ISystem final : public NfcInterface {
+public:
+ explicit ISystem(Core::System& system_)
+ : NfcInterface{system_, "NFC::ISystem", BackendType::Nfc} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, &NfcInterface::Initialize, "InitializeOld"},
+ {1, &NfcInterface::Finalize, "FinalizeOld"},
+ {2, &NfcInterface::GetState, "GetStateOld"},
+ {3, &NfcInterface::IsNfcEnabled, "IsNfcEnabledOld"},
+ {100, nullptr, "SetNfcEnabledOld"},
+ {400, &NfcInterface::Initialize, "Initialize"},
+ {401, &NfcInterface::Finalize, "Finalize"},
+ {402, &NfcInterface::GetState, "GetState"},
+ {403, &NfcInterface::IsNfcEnabled, "IsNfcEnabled"},
+ {404, &NfcInterface::ListDevices, "ListDevices"},
+ {405, &NfcInterface::GetDeviceState, "GetDeviceState"},
+ {406, &NfcInterface::GetNpadId, "GetNpadId"},
+ {407, &NfcInterface::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"},
+ {408, &NfcInterface::StartDetection, "StartDetection"},
+ {409, &NfcInterface::StopDetection, "StopDetection"},
+ {410, &NfcInterface::GetTagInfo, "GetTagInfo"},
+ {411, &NfcInterface::AttachActivateEvent, "AttachActivateEvent"},
+ {412, &NfcInterface::AttachDeactivateEvent, "AttachDeactivateEvent"},
+ {500, nullptr, "SetNfcEnabled"},
+ {510, nullptr, "OutputTestWave"},
+ {1000, &NfcInterface::ReadMifare, "ReadMifare"},
+ {1001, &NfcInterface::WriteMifare, "WriteMifare"},
+ {1300, &NfcInterface::SendCommandByPassThrough, "SendCommandByPassThrough"},
+ {1301, nullptr, "KeepPassThroughSession"},
+ {1302, nullptr, "ReleasePassThroughSession"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+// MFInterface has an unique interface but it's identical to NfcInterface so we can keep the code
+// simpler
+using MFInterface = NfcInterface;
+class MFIUser final : public MFInterface {
+public:
+ explicit MFIUser(Core::System& system_)
+ : MFInterface{system_, "NFC::MFInterface", BackendType::Mifare} {
+ // clang-format off
+ static const FunctionInfoTyped<MFIUser> functions[] = {
+ {0, &MFIUser::Initialize, "Initialize"},
+ {1, &MFIUser::Finalize, "Finalize"},
+ {2, &MFIUser::ListDevices, "ListDevices"},
+ {3, &MFIUser::StartDetection, "StartDetection"},
+ {4, &MFIUser::StopDetection, "StopDetection"},
+ {5, &MFIUser::ReadMifare, "Read"},
+ {6, &MFIUser::WriteMifare, "Write"},
+ {7, &MFIUser::GetTagInfo, "GetTagInfo"},
+ {8, &MFIUser::AttachActivateEvent, "GetActivateEventHandle"},
+ {9, &MFIUser::AttachDeactivateEvent, "GetDeactivateEventHandle"},
+ {10, &MFIUser::GetState, "GetState"},
+ {11, &MFIUser::GetDeviceState, "GetDeviceState"},
+ {12, &MFIUser::GetNpadId, "GetNpadId"},
+ {13, &MFIUser::AttachAvailabilityChangeEvent, "GetAvailabilityChangeEventHandle"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
class IAm final : public ServiceFramework<IAm> {
public:
explicit IAm(Core::System& system_) : ServiceFramework{system_, "NFC::IAm"} {
@@ -34,7 +135,7 @@ public:
explicit NFC_AM(Core::System& system_) : ServiceFramework{system_, "nfc:am"} {
// clang-format off
static const FunctionInfo functions[] = {
- {0, &NFC_AM::CreateAmInterface, "CreateAmInterface"},
+ {0, &NFC_AM::CreateAmNfcInterface, "CreateAmNfcInterface"},
};
// clang-format on
@@ -42,7 +143,7 @@ public:
}
private:
- void CreateAmInterface(Kernel::HLERequestContext& ctx) {
+ void CreateAmNfcInterface(HLERequestContext& ctx) {
LOG_DEBUG(Service_NFC, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -56,7 +157,7 @@ public:
explicit NFC_MF_U(Core::System& system_) : ServiceFramework{system_, "nfc:mf:u"} {
// clang-format off
static const FunctionInfo functions[] = {
- {0, &NFC_MF_U::CreateUserInterface, "CreateUserInterface"},
+ {0, &NFC_MF_U::CreateUserNfcInterface, "CreateUserNfcInterface"},
};
// clang-format on
@@ -64,7 +165,7 @@ public:
}
private:
- void CreateUserInterface(Kernel::HLERequestContext& ctx) {
+ void CreateUserNfcInterface(HLERequestContext& ctx) {
LOG_DEBUG(Service_NFC, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -78,7 +179,7 @@ public:
explicit NFC_U(Core::System& system_) : ServiceFramework{system_, "nfc:user"} {
// clang-format off
static const FunctionInfo functions[] = {
- {0, &NFC_U::CreateUserInterface, "CreateUserInterface"},
+ {0, &NFC_U::CreateUserNfcInterface, "CreateUserNfcInterface"},
};
// clang-format on
@@ -86,7 +187,7 @@ public:
}
private:
- void CreateUserInterface(Kernel::HLERequestContext& ctx) {
+ void CreateUserNfcInterface(HLERequestContext& ctx) {
LOG_DEBUG(Service_NFC, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -95,49 +196,12 @@ private:
}
};
-class ISystem final : public ServiceFramework<ISystem> {
-public:
- explicit ISystem(Core::System& system_) : ServiceFramework{system_, "ISystem"} {
- // clang-format off
- static const FunctionInfo functions[] = {
- {0, nullptr, "Initialize"},
- {1, nullptr, "Finalize"},
- {2, nullptr, "GetStateOld"},
- {3, nullptr, "IsNfcEnabledOld"},
- {100, nullptr, "SetNfcEnabledOld"},
- {400, nullptr, "InitializeSystem"},
- {401, nullptr, "FinalizeSystem"},
- {402, nullptr, "GetState"},
- {403, nullptr, "IsNfcEnabled"},
- {404, nullptr, "ListDevices"},
- {405, nullptr, "GetDeviceState"},
- {406, nullptr, "GetNpadId"},
- {407, nullptr, "AttachAvailabilityChangeEvent"},
- {408, nullptr, "StartDetection"},
- {409, nullptr, "StopDetection"},
- {410, nullptr, "GetTagInfo"},
- {411, nullptr, "AttachActivateEvent"},
- {412, nullptr, "AttachDeactivateEvent"},
- {500, nullptr, "SetNfcEnabled"},
- {510, nullptr, "OutputTestWave"},
- {1000, nullptr, "ReadMifare"},
- {1001, nullptr, "WriteMifare"},
- {1300, nullptr, "SendCommandByPassThrough"},
- {1301, nullptr, "KeepPassThroughSession"},
- {1302, nullptr, "ReleasePassThroughSession"},
- };
- // clang-format on
-
- RegisterHandlers(functions);
- }
-};
-
class NFC_SYS final : public ServiceFramework<NFC_SYS> {
public:
explicit NFC_SYS(Core::System& system_) : ServiceFramework{system_, "nfc:sys"} {
// clang-format off
static const FunctionInfo functions[] = {
- {0, &NFC_SYS::CreateSystemInterface, "CreateSystemInterface"},
+ {0, &NFC_SYS::CreateSystemNfcInterface, "CreateSystemNfcInterface"},
};
// clang-format on
@@ -145,7 +209,7 @@ public:
}
private:
- void CreateSystemInterface(Kernel::HLERequestContext& ctx) {
+ void CreateSystemNfcInterface(HLERequestContext& ctx) {
LOG_DEBUG(Service_NFC, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -154,11 +218,15 @@ private:
}
};
-void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
- std::make_shared<NFC_AM>(system)->InstallAsService(sm);
- std::make_shared<NFC_MF_U>(system)->InstallAsService(sm);
- std::make_shared<NFC_U>(system)->InstallAsService(sm);
- std::make_shared<NFC_SYS>(system)->InstallAsService(sm);
+void LoopProcess(Core::System& system) {
+ auto server_manager = std::make_unique<ServerManager>(system);
+
+ server_manager->RegisterNamedService("nfc:am", std::make_shared<NFC_AM>(system));
+ server_manager->RegisterNamedService("nfc:mf:u", std::make_shared<NFC_MF_U>(system));
+ server_manager->RegisterNamedService("nfc:user", std::make_shared<NFC_U>(system));
+ server_manager->RegisterNamedService("nfc:sys", std::make_shared<NFC_SYS>(system));
+
+ ServerManager::RunServer(std::move(server_manager));
}
} // namespace Service::NFC
diff --git a/src/core/hle/service/nfc/nfc.h b/src/core/hle/service/nfc/nfc.h
index 0107b696c..d15955b75 100644
--- a/src/core/hle/service/nfc/nfc.h
+++ b/src/core/hle/service/nfc/nfc.h
@@ -7,12 +7,8 @@ namespace Core {
class System;
}
-namespace Service::SM {
-class ServiceManager;
-}
-
namespace Service::NFC {
-void InstallInterfaces(SM::ServiceManager& sm, Core::System& system);
+void LoopProcess(Core::System& system);
} // namespace Service::NFC
diff --git a/src/core/hle/service/nfc/nfc_device.cpp b/src/core/hle/service/nfc/nfc_device.cpp
deleted file mode 100644
index 78578f723..000000000
--- a/src/core/hle/service/nfc/nfc_device.cpp
+++ /dev/null
@@ -1,273 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#include "common/input.h"
-#include "common/logging/log.h"
-#include "core/core.h"
-#include "core/hid/emulated_controller.h"
-#include "core/hid/hid_core.h"
-#include "core/hid/hid_types.h"
-#include "core/hle/ipc_helpers.h"
-#include "core/hle/kernel/k_event.h"
-#include "core/hle/service/nfc/nfc_device.h"
-#include "core/hle/service/nfc/nfc_result.h"
-#include "core/hle/service/nfc/nfc_user.h"
-
-namespace Service::NFC {
-NfcDevice::NfcDevice(Core::HID::NpadIdType npad_id_, Core::System& system_,
- KernelHelpers::ServiceContext& service_context_,
- Kernel::KEvent* availability_change_event_)
- : npad_id{npad_id_}, system{system_}, service_context{service_context_},
- availability_change_event{availability_change_event_} {
- activate_event = service_context.CreateEvent("IUser:NFCActivateEvent");
- deactivate_event = service_context.CreateEvent("IUser:NFCDeactivateEvent");
- npad_device = system.HIDCore().GetEmulatedController(npad_id);
-
- Core::HID::ControllerUpdateCallback engine_callback{
- .on_change = [this](Core::HID::ControllerTriggerType type) { NpadUpdate(type); },
- .is_npad_service = false,
- };
- is_controller_set = true;
- callback_key = npad_device->SetCallback(engine_callback);
-}
-
-NfcDevice::~NfcDevice() {
- activate_event->Close();
- deactivate_event->Close();
- if (!is_controller_set) {
- return;
- }
- npad_device->DeleteCallback(callback_key);
- is_controller_set = false;
-};
-
-void NfcDevice::NpadUpdate(Core::HID::ControllerTriggerType type) {
- if (type == Core::HID::ControllerTriggerType::Connected ||
- type == Core::HID::ControllerTriggerType::Disconnected) {
- availability_change_event->Signal();
- return;
- }
-
- if (type != Core::HID::ControllerTriggerType::Nfc) {
- return;
- }
-
- if (!npad_device->IsConnected()) {
- return;
- }
-
- const auto nfc_status = npad_device->GetNfc();
- switch (nfc_status.state) {
- case Common::Input::NfcState::NewAmiibo:
- LoadNfcTag(nfc_status.data);
- break;
- case Common::Input::NfcState::AmiiboRemoved:
- if (device_state != NFP::DeviceState::SearchingForTag) {
- CloseNfcTag();
- }
- break;
- default:
- break;
- }
-}
-
-bool NfcDevice::LoadNfcTag(std::span<const u8> data) {
- if (device_state != NFP::DeviceState::SearchingForTag) {
- LOG_ERROR(Service_NFC, "Game is not looking for nfc tag, current state {}", device_state);
- return false;
- }
-
- if (data.size() < sizeof(NFP::EncryptedNTAG215File)) {
- LOG_ERROR(Service_NFC, "Not an amiibo, size={}", data.size());
- return false;
- }
-
- tag_data.resize(data.size());
- memcpy(tag_data.data(), data.data(), data.size());
- memcpy(&encrypted_tag_data, data.data(), sizeof(NFP::EncryptedNTAG215File));
-
- device_state = NFP::DeviceState::TagFound;
- deactivate_event->GetReadableEvent().Clear();
- activate_event->Signal();
- return true;
-}
-
-void NfcDevice::CloseNfcTag() {
- LOG_INFO(Service_NFC, "Remove nfc tag");
-
- device_state = NFP::DeviceState::TagRemoved;
- encrypted_tag_data = {};
- activate_event->GetReadableEvent().Clear();
- deactivate_event->Signal();
-}
-
-Kernel::KReadableEvent& NfcDevice::GetActivateEvent() const {
- return activate_event->GetReadableEvent();
-}
-
-Kernel::KReadableEvent& NfcDevice::GetDeactivateEvent() const {
- return deactivate_event->GetReadableEvent();
-}
-
-void NfcDevice::Initialize() {
- device_state =
- npad_device->HasNfc() ? NFP::DeviceState::Initialized : NFP::DeviceState::Unavailable;
- encrypted_tag_data = {};
-}
-
-void NfcDevice::Finalize() {
- if (device_state == NFP::DeviceState::SearchingForTag ||
- device_state == NFP::DeviceState::TagRemoved) {
- StopDetection();
- }
- device_state = NFP::DeviceState::Unavailable;
-}
-
-Result NfcDevice::StartDetection(NFP::TagProtocol allowed_protocol) {
- if (device_state != NFP::DeviceState::Initialized &&
- device_state != NFP::DeviceState::TagRemoved) {
- LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
- return WrongDeviceState;
- }
-
- if (!npad_device->SetPollingMode(Common::Input::PollingMode::NFC)) {
- LOG_ERROR(Service_NFC, "Nfc not supported");
- return NfcDisabled;
- }
-
- device_state = NFP::DeviceState::SearchingForTag;
- allowed_protocols = allowed_protocol;
- return ResultSuccess;
-}
-
-Result NfcDevice::StopDetection() {
- npad_device->SetPollingMode(Common::Input::PollingMode::Active);
-
- if (device_state == NFP::DeviceState::Initialized) {
- return ResultSuccess;
- }
-
- if (device_state == NFP::DeviceState::TagFound ||
- device_state == NFP::DeviceState::TagMounted) {
- CloseNfcTag();
- return ResultSuccess;
- }
- if (device_state == NFP::DeviceState::SearchingForTag ||
- device_state == NFP::DeviceState::TagRemoved) {
- device_state = NFP::DeviceState::Initialized;
- return ResultSuccess;
- }
-
- LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
- return WrongDeviceState;
-}
-
-Result NfcDevice::Flush() {
- if (device_state != NFP::DeviceState::TagFound &&
- device_state != NFP::DeviceState::TagMounted) {
- LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
- if (device_state == NFP::DeviceState::TagRemoved) {
- return TagRemoved;
- }
- return WrongDeviceState;
- }
-
- if (!npad_device->WriteNfc(tag_data)) {
- LOG_ERROR(Service_NFP, "Error writing to file");
- return MifareReadError;
- }
-
- return ResultSuccess;
-}
-
-Result NfcDevice::GetTagInfo(NFP::TagInfo& tag_info, bool is_mifare) const {
- if (device_state != NFP::DeviceState::TagFound &&
- device_state != NFP::DeviceState::TagMounted) {
- LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
- if (device_state == NFP::DeviceState::TagRemoved) {
- return TagRemoved;
- }
- return WrongDeviceState;
- }
-
- if (is_mifare) {
- tag_info = {
- .uuid = encrypted_tag_data.uuid.uid,
- .uuid_length = static_cast<u8>(encrypted_tag_data.uuid.uid.size()),
- .protocol = NFP::TagProtocol::TypeA,
- .tag_type = NFP::TagType::Type4,
- };
- return ResultSuccess;
- }
-
- // Protocol and tag type may change here
- tag_info = {
- .uuid = encrypted_tag_data.uuid.uid,
- .uuid_length = static_cast<u8>(encrypted_tag_data.uuid.uid.size()),
- .protocol = NFP::TagProtocol::TypeA,
- .tag_type = NFP::TagType::Type2,
- };
-
- return ResultSuccess;
-}
-
-Result NfcDevice::MifareRead(const NFP::MifareReadBlockParameter& parameter,
- NFP::MifareReadBlockData& read_block_data) {
- const std::size_t sector_index = parameter.sector_number * sizeof(NFP::DataBlock);
- read_block_data.sector_number = parameter.sector_number;
-
- if (device_state != NFP::DeviceState::TagFound &&
- device_state != NFP::DeviceState::TagMounted) {
- LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
- if (device_state == NFP::DeviceState::TagRemoved) {
- return TagRemoved;
- }
- return WrongDeviceState;
- }
-
- if (tag_data.size() < sector_index + sizeof(NFP::DataBlock)) {
- return MifareReadError;
- }
-
- // TODO: Use parameter.sector_key to read encrypted data
- memcpy(read_block_data.data.data(), tag_data.data() + sector_index, sizeof(NFP::DataBlock));
-
- return ResultSuccess;
-}
-
-Result NfcDevice::MifareWrite(const NFP::MifareWriteBlockParameter& parameter) {
- const std::size_t sector_index = parameter.sector_number * sizeof(NFP::DataBlock);
-
- if (device_state != NFP::DeviceState::TagFound &&
- device_state != NFP::DeviceState::TagMounted) {
- LOG_ERROR(Service_NFC, "Wrong device state {}", device_state);
- if (device_state == NFP::DeviceState::TagRemoved) {
- return TagRemoved;
- }
- return WrongDeviceState;
- }
-
- if (tag_data.size() < sector_index + sizeof(NFP::DataBlock)) {
- return MifareReadError;
- }
-
- // TODO: Use parameter.sector_key to encrypt the data
- memcpy(tag_data.data() + sector_index, parameter.data.data(), sizeof(NFP::DataBlock));
-
- return ResultSuccess;
-}
-
-u64 NfcDevice::GetHandle() const {
- // Generate a handle based of the npad id
- return static_cast<u64>(npad_id);
-}
-
-NFP::DeviceState NfcDevice::GetCurrentState() const {
- return device_state;
-}
-
-Core::HID::NpadIdType NfcDevice::GetNpadId() const {
- return npad_id;
-}
-
-} // namespace Service::NFC
diff --git a/src/core/hle/service/nfc/nfc_device.h b/src/core/hle/service/nfc/nfc_device.h
deleted file mode 100644
index a6e114d36..000000000
--- a/src/core/hle/service/nfc/nfc_device.h
+++ /dev/null
@@ -1,77 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#pragma once
-
-#include "common/common_types.h"
-#include "core/hle/service/kernel_helpers.h"
-#include "core/hle/service/nfp/nfp_types.h"
-#include "core/hle/service/service.h"
-
-namespace Kernel {
-class KEvent;
-class KReadableEvent;
-} // namespace Kernel
-
-namespace Core {
-class System;
-} // namespace Core
-
-namespace Core::HID {
-class EmulatedController;
-enum class ControllerTriggerType;
-enum class NpadIdType : u32;
-} // namespace Core::HID
-
-namespace Service::NFC {
-class NfcDevice {
-public:
- NfcDevice(Core::HID::NpadIdType npad_id_, Core::System& system_,
- KernelHelpers::ServiceContext& service_context_,
- Kernel::KEvent* availability_change_event_);
- ~NfcDevice();
-
- void Initialize();
- void Finalize();
-
- Result StartDetection(NFP::TagProtocol allowed_protocol);
- Result StopDetection();
- Result Flush();
-
- Result GetTagInfo(NFP::TagInfo& tag_info, bool is_mifare) const;
-
- Result MifareRead(const NFP::MifareReadBlockParameter& parameter,
- NFP::MifareReadBlockData& read_block_data);
-
- Result MifareWrite(const NFP::MifareWriteBlockParameter& parameter);
-
- u64 GetHandle() const;
- NFP::DeviceState GetCurrentState() const;
- Core::HID::NpadIdType GetNpadId() const;
-
- Kernel::KReadableEvent& GetActivateEvent() const;
- Kernel::KReadableEvent& GetDeactivateEvent() const;
-
-private:
- void NpadUpdate(Core::HID::ControllerTriggerType type);
- bool LoadNfcTag(std::span<const u8> data);
- void CloseNfcTag();
-
- bool is_controller_set{};
- int callback_key;
- const Core::HID::NpadIdType npad_id;
- Core::System& system;
- Core::HID::EmulatedController* npad_device = nullptr;
- KernelHelpers::ServiceContext& service_context;
- Kernel::KEvent* activate_event = nullptr;
- Kernel::KEvent* deactivate_event = nullptr;
- Kernel::KEvent* availability_change_event = nullptr;
-
- NFP::TagProtocol allowed_protocols{};
- NFP::DeviceState device_state{NFP::DeviceState::Unavailable};
-
- NFP::EncryptedNTAG215File encrypted_tag_data{};
- std::vector<u8> tag_data{};
-};
-
-} // namespace Service::NFC
diff --git a/src/core/hle/service/nfc/nfc_interface.cpp b/src/core/hle/service/nfc/nfc_interface.cpp
new file mode 100644
index 000000000..e7ca7582e
--- /dev/null
+++ b/src/core/hle/service/nfc/nfc_interface.cpp
@@ -0,0 +1,394 @@
+// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "common/logging/log.h"
+#include "core/core.h"
+#include "core/hid/hid_types.h"
+#include "core/hle/kernel/k_event.h"
+#include "core/hle/service/ipc_helpers.h"
+#include "core/hle/service/nfc/common/device.h"
+#include "core/hle/service/nfc/common/device_manager.h"
+#include "core/hle/service/nfc/mifare_result.h"
+#include "core/hle/service/nfc/mifare_types.h"
+#include "core/hle/service/nfc/nfc_interface.h"
+#include "core/hle/service/nfc/nfc_result.h"
+#include "core/hle/service/nfc/nfc_types.h"
+#include "core/hle/service/nfp/nfp_result.h"
+#include "core/hle/service/time/clock_types.h"
+
+namespace Service::NFC {
+
+NfcInterface::NfcInterface(Core::System& system_, const char* name, BackendType service_backend)
+ : ServiceFramework{system_, name}, service_context{system_, service_name},
+ backend_type{service_backend} {}
+
+NfcInterface ::~NfcInterface() = default;
+
+void NfcInterface::Initialize(HLERequestContext& ctx) {
+ LOG_INFO(Service_NFC, "called");
+
+ auto manager = GetManager();
+ auto result = manager->Initialize();
+
+ if (result.IsSuccess()) {
+ state = State::Initialized;
+ } else {
+ manager->Finalize();
+ }
+
+ IPC::ResponseBuilder rb{ctx, 2, 0};
+ rb.Push(result);
+}
+
+void NfcInterface::Finalize(HLERequestContext& ctx) {
+ LOG_INFO(Service_NFC, "called");
+
+ if (state != State::NonInitialized) {
+ if (GetBackendType() != BackendType::None) {
+ GetManager()->Finalize();
+ }
+ device_manager = nullptr;
+ state = State::NonInitialized;
+ }
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void NfcInterface::GetState(HLERequestContext& ctx) {
+ LOG_DEBUG(Service_NFC, "called");
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.PushEnum(state);
+}
+
+void NfcInterface::IsNfcEnabled(HLERequestContext& ctx) {
+ LOG_DEBUG(Service_NFC, "called");
+
+ // TODO: This calls nn::settings::detail::GetNfcEnableFlag
+ const bool is_enabled = true;
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.Push(is_enabled);
+}
+
+void NfcInterface::ListDevices(HLERequestContext& ctx) {
+ std::vector<u64> nfp_devices;
+ const std::size_t max_allowed_devices = ctx.GetWriteBufferNumElements<u64>();
+ LOG_DEBUG(Service_NFC, "called");
+
+ auto result = GetManager()->ListDevices(nfp_devices, max_allowed_devices);
+ result = TranslateResultToServiceError(result);
+
+ if (result.IsError()) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+ return;
+ }
+
+ ctx.WriteBuffer(nfp_devices);
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.Push(static_cast<s32>(nfp_devices.size()));
+}
+
+void NfcInterface::GetDeviceState(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto device_handle{rp.Pop<u64>()};
+ LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
+
+ const auto device_state = GetManager()->GetDeviceState(device_handle);
+
+ if (device_state > DeviceState::Finalized) {
+ ASSERT_MSG(false, "Invalid device state");
+ }
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.PushEnum(device_state);
+}
+
+void NfcInterface::GetNpadId(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto device_handle{rp.Pop<u64>()};
+ LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
+
+ Core::HID::NpadIdType npad_id{};
+ auto result = GetManager()->GetNpadId(device_handle, npad_id);
+ result = TranslateResultToServiceError(result);
+
+ if (result.IsError()) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+ return;
+ }
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.PushEnum(npad_id);
+}
+
+void NfcInterface::AttachAvailabilityChangeEvent(HLERequestContext& ctx) {
+ LOG_INFO(Service_NFC, "called");
+
+ IPC::ResponseBuilder rb{ctx, 2, 1};
+ rb.Push(ResultSuccess);
+ rb.PushCopyObjects(GetManager()->AttachAvailabilityChangeEvent());
+}
+
+void NfcInterface::StartDetection(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto device_handle{rp.Pop<u64>()};
+ auto tag_protocol{NfcProtocol::All};
+
+ if (backend_type == BackendType::Nfc) {
+ tag_protocol = rp.PopEnum<NfcProtocol>();
+ }
+
+ LOG_INFO(Service_NFC, "called, device_handle={}, nfp_protocol={}", device_handle, tag_protocol);
+ auto result = GetManager()->StartDetection(device_handle, tag_protocol);
+ result = TranslateResultToServiceError(result);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+}
+
+void NfcInterface::StopDetection(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto device_handle{rp.Pop<u64>()};
+ LOG_INFO(Service_NFC, "called, device_handle={}", device_handle);
+
+ auto result = GetManager()->StopDetection(device_handle);
+ result = TranslateResultToServiceError(result);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+}
+
+void NfcInterface::GetTagInfo(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto device_handle{rp.Pop<u64>()};
+ LOG_INFO(Service_NFC, "called, device_handle={}", device_handle);
+
+ TagInfo tag_info{};
+ auto result = GetManager()->GetTagInfo(device_handle, tag_info);
+ result = TranslateResultToServiceError(result);
+
+ if (result.IsSuccess()) {
+ ctx.WriteBuffer(tag_info);
+ }
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+}
+
+void NfcInterface::AttachActivateEvent(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto device_handle{rp.Pop<u64>()};
+ LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
+
+ IPC::ResponseBuilder rb{ctx, 2, 1};
+ rb.Push(ResultSuccess);
+ rb.PushCopyObjects(GetManager()->AttachActivateEvent(device_handle));
+}
+
+void NfcInterface::AttachDeactivateEvent(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto device_handle{rp.Pop<u64>()};
+ LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
+
+ IPC::ResponseBuilder rb{ctx, 2, 1};
+ rb.Push(ResultSuccess);
+ rb.PushCopyObjects(GetManager()->AttachDeactivateEvent(device_handle));
+}
+
+void NfcInterface::ReadMifare(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto device_handle{rp.Pop<u64>()};
+ const auto buffer{ctx.ReadBuffer()};
+ const auto number_of_commands{ctx.GetReadBufferNumElements<MifareReadBlockParameter>()};
+ std::vector<MifareReadBlockParameter> read_commands(number_of_commands);
+
+ memcpy(read_commands.data(), buffer.data(),
+ number_of_commands * sizeof(MifareReadBlockParameter));
+
+ LOG_INFO(Service_NFC, "called, device_handle={}, read_commands_size={}", device_handle,
+ number_of_commands);
+
+ std::vector<MifareReadBlockData> out_data(number_of_commands);
+ auto result = GetManager()->ReadMifare(device_handle, read_commands, out_data);
+ result = TranslateResultToServiceError(result);
+
+ if (result.IsSuccess()) {
+ ctx.WriteBuffer(out_data);
+ }
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+}
+
+void NfcInterface::WriteMifare(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto device_handle{rp.Pop<u64>()};
+ const auto buffer{ctx.ReadBuffer()};
+ const auto number_of_commands{ctx.GetReadBufferNumElements<MifareWriteBlockParameter>()};
+ std::vector<MifareWriteBlockParameter> write_commands(number_of_commands);
+
+ memcpy(write_commands.data(), buffer.data(),
+ number_of_commands * sizeof(MifareWriteBlockParameter));
+
+ LOG_INFO(Service_NFC, "(STUBBED) called, device_handle={}, write_commands_size={}",
+ device_handle, number_of_commands);
+
+ auto result = GetManager()->WriteMifare(device_handle, write_commands);
+ result = TranslateResultToServiceError(result);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+}
+
+void NfcInterface::SendCommandByPassThrough(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto device_handle{rp.Pop<u64>()};
+ const auto timeout{rp.PopRaw<Time::Clock::TimeSpanType>()};
+ const auto command_data{ctx.ReadBuffer()};
+ LOG_INFO(Service_NFC, "(STUBBED) called, device_handle={}, timeout={}, data_size={}",
+ device_handle, timeout.ToSeconds(), command_data.size());
+
+ std::vector<u8> out_data(1);
+ auto result =
+ GetManager()->SendCommandByPassThrough(device_handle, timeout, command_data, out_data);
+ result = TranslateResultToServiceError(result);
+
+ if (result.IsError()) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+ return;
+ }
+
+ ctx.WriteBuffer(out_data);
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.Push(static_cast<u32>(out_data.size()));
+}
+
+std::shared_ptr<DeviceManager> NfcInterface::GetManager() {
+ if (device_manager == nullptr) {
+ device_manager = std::make_shared<DeviceManager>(system, service_context);
+ }
+ return device_manager;
+}
+
+BackendType NfcInterface::GetBackendType() const {
+ return backend_type;
+}
+
+Result NfcInterface::TranslateResultToServiceError(Result result) const {
+ const auto backend = GetBackendType();
+
+ if (result.IsSuccess()) {
+ return result;
+ }
+
+ if (result.module != ErrorModule::NFC) {
+ return result;
+ }
+
+ switch (backend) {
+ case BackendType::Mifare:
+ return TranslateResultToNfp(result);
+ case BackendType::Nfp: {
+ return TranslateResultToNfp(result);
+ }
+ default:
+ if (result != ResultBackupPathAlreadyExist) {
+ return result;
+ }
+ return ResultUnknown74;
+ }
+}
+
+Result NfcInterface::TranslateResultToNfp(Result result) const {
+ if (result == ResultDeviceNotFound) {
+ return NFP::ResultDeviceNotFound;
+ }
+ if (result == ResultInvalidArgument) {
+ return NFP::ResultInvalidArgument;
+ }
+ if (result == ResultWrongApplicationAreaSize) {
+ return NFP::ResultWrongApplicationAreaSize;
+ }
+ if (result == ResultWrongDeviceState) {
+ return NFP::ResultWrongDeviceState;
+ }
+ if (result == ResultUnknown74) {
+ return NFP::ResultUnknown74;
+ }
+ if (result == ResultNfcDisabled) {
+ return NFP::ResultNfcDisabled;
+ }
+ if (result == ResultNfcNotInitialized) {
+ return NFP::ResultNfcDisabled;
+ }
+ if (result == ResultWriteAmiiboFailed) {
+ return NFP::ResultWriteAmiiboFailed;
+ }
+ if (result == ResultTagRemoved) {
+ return NFP::ResultTagRemoved;
+ }
+ if (result == ResultRegistrationIsNotInitialized) {
+ return NFP::ResultRegistrationIsNotInitialized;
+ }
+ if (result == ResultApplicationAreaIsNotInitialized) {
+ return NFP::ResultApplicationAreaIsNotInitialized;
+ }
+ if (result == ResultCorruptedDataWithBackup) {
+ return NFP::ResultCorruptedDataWithBackup;
+ }
+ if (result == ResultCorruptedData) {
+ return NFP::ResultCorruptedData;
+ }
+ if (result == ResultWrongApplicationAreaId) {
+ return NFP::ResultWrongApplicationAreaId;
+ }
+ if (result == ResultApplicationAreaExist) {
+ return NFP::ResultApplicationAreaExist;
+ }
+ if (result == ResultInvalidTagType) {
+ return NFP::ResultNotAnAmiibo;
+ }
+ if (result == ResultUnableToAccessBackupFile) {
+ return NFP::ResultUnableToAccessBackupFile;
+ }
+ LOG_WARNING(Service_NFC, "Result conversion not handled");
+ return result;
+}
+
+Result NfcInterface::TranslateResultToMifare(Result result) const {
+ if (result == ResultDeviceNotFound) {
+ return Mifare::ResultDeviceNotFound;
+ }
+ if (result == ResultInvalidArgument) {
+ return Mifare::ResultInvalidArgument;
+ }
+ if (result == ResultWrongDeviceState) {
+ return Mifare::ResultWrongDeviceState;
+ }
+ if (result == ResultNfcDisabled) {
+ return Mifare::ResultNfcDisabled;
+ }
+ if (result == ResultTagRemoved) {
+ return Mifare::ResultTagRemoved;
+ }
+ if (result == ResultInvalidTagType) {
+ return Mifare::ResultNotAMifare;
+ }
+ LOG_WARNING(Service_NFC, "Result conversion not handled");
+ return result;
+}
+
+} // namespace Service::NFC
diff --git a/src/core/hle/service/nfc/nfc_interface.h b/src/core/hle/service/nfc/nfc_interface.h
new file mode 100644
index 000000000..08be174d8
--- /dev/null
+++ b/src/core/hle/service/nfc/nfc_interface.h
@@ -0,0 +1,49 @@
+// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "core/hle/service/kernel_helpers.h"
+#include "core/hle/service/nfc/nfc_types.h"
+#include "core/hle/service/service.h"
+
+namespace Service::NFC {
+class DeviceManager;
+
+class NfcInterface : public ServiceFramework<NfcInterface> {
+public:
+ explicit NfcInterface(Core::System& system_, const char* name, BackendType service_backend);
+ ~NfcInterface();
+
+ void Initialize(HLERequestContext& ctx);
+ void Finalize(HLERequestContext& ctx);
+ void GetState(HLERequestContext& ctx);
+ void IsNfcEnabled(HLERequestContext& ctx);
+ void ListDevices(HLERequestContext& ctx);
+ void GetDeviceState(HLERequestContext& ctx);
+ void GetNpadId(HLERequestContext& ctx);
+ void AttachAvailabilityChangeEvent(HLERequestContext& ctx);
+ void StartDetection(HLERequestContext& ctx);
+ void StopDetection(HLERequestContext& ctx);
+ void GetTagInfo(HLERequestContext& ctx);
+ void AttachActivateEvent(HLERequestContext& ctx);
+ void AttachDeactivateEvent(HLERequestContext& ctx);
+ void ReadMifare(HLERequestContext& ctx);
+ void WriteMifare(HLERequestContext& ctx);
+ void SendCommandByPassThrough(HLERequestContext& ctx);
+
+protected:
+ std::shared_ptr<DeviceManager> GetManager();
+ BackendType GetBackendType() const;
+ Result TranslateResultToServiceError(Result result) const;
+ Result TranslateResultToNfp(Result result) const;
+ Result TranslateResultToMifare(Result result) const;
+
+ KernelHelpers::ServiceContext service_context;
+
+ BackendType backend_type;
+ State state{State::NonInitialized};
+ std::shared_ptr<DeviceManager> device_manager = nullptr;
+};
+
+} // namespace Service::NFC
diff --git a/src/core/hle/service/nfc/nfc_result.h b/src/core/hle/service/nfc/nfc_result.h
index 146b8ba61..715c0e80c 100644
--- a/src/core/hle/service/nfc/nfc_result.h
+++ b/src/core/hle/service/nfc/nfc_result.h
@@ -1,5 +1,5 @@
-// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
@@ -7,17 +7,25 @@
namespace Service::NFC {
-constexpr Result DeviceNotFound(ErrorModule::NFC, 64);
-constexpr Result InvalidArgument(ErrorModule::NFC, 65);
-constexpr Result WrongDeviceState(ErrorModule::NFC, 73);
-constexpr Result NfcDisabled(ErrorModule::NFC, 80);
-constexpr Result TagRemoved(ErrorModule::NFC, 97);
-
-constexpr Result MifareDeviceNotFound(ErrorModule::NFCMifare, 64);
-constexpr Result MifareInvalidArgument(ErrorModule::NFCMifare, 65);
-constexpr Result MifareWrongDeviceState(ErrorModule::NFCMifare, 73);
-constexpr Result MifareNfcDisabled(ErrorModule::NFCMifare, 80);
-constexpr Result MifareTagRemoved(ErrorModule::NFCMifare, 97);
-constexpr Result MifareReadError(ErrorModule::NFCMifare, 288);
+constexpr Result ResultDeviceNotFound(ErrorModule::NFC, 64);
+constexpr Result ResultInvalidArgument(ErrorModule::NFC, 65);
+constexpr Result ResultWrongApplicationAreaSize(ErrorModule::NFC, 68);
+constexpr Result ResultWrongDeviceState(ErrorModule::NFC, 73);
+constexpr Result ResultUnknown74(ErrorModule::NFC, 74);
+constexpr Result ResultUnknown76(ErrorModule::NFC, 76);
+constexpr Result ResultNfcNotInitialized(ErrorModule::NFC, 77);
+constexpr Result ResultNfcDisabled(ErrorModule::NFC, 80);
+constexpr Result ResultWriteAmiiboFailed(ErrorModule::NFC, 88);
+constexpr Result ResultTagRemoved(ErrorModule::NFC, 97);
+constexpr Result ResultUnableToAccessBackupFile(ErrorModule::NFC, 113);
+constexpr Result ResultRegistrationIsNotInitialized(ErrorModule::NFC, 120);
+constexpr Result ResultApplicationAreaIsNotInitialized(ErrorModule::NFC, 128);
+constexpr Result ResultCorruptedDataWithBackup(ErrorModule::NFC, 136);
+constexpr Result ResultCorruptedData(ErrorModule::NFC, 144);
+constexpr Result ResultWrongApplicationAreaId(ErrorModule::NFC, 152);
+constexpr Result ResultApplicationAreaExist(ErrorModule::NFC, 168);
+constexpr Result ResultInvalidTagType(ErrorModule::NFC, 178);
+constexpr Result ResultBackupPathAlreadyExist(ErrorModule::NFC, 216);
+constexpr Result ResultMifareError288(ErrorModule::NFC, 288);
} // namespace Service::NFC
diff --git a/src/core/hle/service/nfc/nfc_types.h b/src/core/hle/service/nfc/nfc_types.h
new file mode 100644
index 000000000..68e724442
--- /dev/null
+++ b/src/core/hle/service/nfc/nfc_types.h
@@ -0,0 +1,91 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#pragma once
+
+#include <array>
+
+#include "common/common_funcs.h"
+#include "common/common_types.h"
+
+namespace Service::NFC {
+enum class BackendType : u32 {
+ None,
+ Nfc,
+ Nfp,
+ Mifare,
+};
+
+// This is nn::nfc::DeviceState
+enum class DeviceState : u32 {
+ Initialized,
+ SearchingForTag,
+ TagFound,
+ TagRemoved,
+ TagMounted,
+ Unavailable,
+ Finalized,
+};
+
+// This is nn::nfc::State
+enum class State : u32 {
+ NonInitialized,
+ Initialized,
+};
+
+// This is nn::nfc::TagType
+enum class TagType : u32 {
+ None = 0,
+ Type1 = 1U << 0, // ISO14443A RW. Topaz
+ Type2 = 1U << 1, // ISO14443A RW. Ultralight, NTAGX, ST25TN
+ Type3 = 1U << 2, // ISO14443A RW/RO. Sony FeliCa
+ Type4A = 1U << 3, // ISO14443A RW/RO. DESFire
+ Type4B = 1U << 4, // ISO14443B RW/RO. DESFire
+ Type5 = 1U << 5, // ISO15693 RW/RO. SLI, SLIX, ST25TV
+ Mifare = 1U << 6, // Mifare classic. Skylanders
+ All = 0xFFFFFFFF,
+};
+
+enum class PackedTagType : u8 {
+ None = 0,
+ Type1 = 1U << 0, // ISO14443A RW. Topaz
+ Type2 = 1U << 1, // ISO14443A RW. Ultralight, NTAGX, ST25TN
+ Type3 = 1U << 2, // ISO14443A RW/RO. Sony FeliCa
+ Type4A = 1U << 3, // ISO14443A RW/RO. DESFire
+ Type4B = 1U << 4, // ISO14443B RW/RO. DESFire
+ Type5 = 1U << 5, // ISO15693 RW/RO. SLI, SLIX, ST25TV
+ Mifare = 1U << 6, // Mifare classic. Skylanders
+ All = 0xFF,
+};
+
+// This is nn::nfc::NfcProtocol
+enum class NfcProtocol : u32 {
+ None,
+ TypeA = 1U << 0, // ISO14443A
+ TypeB = 1U << 1, // ISO14443B
+ TypeF = 1U << 2, // Sony FeliCa
+ All = 0xFFFFFFFFU,
+};
+
+// this is nn::nfc::TestWaveType
+enum class TestWaveType : u32 {
+ Unknown,
+};
+
+using UniqueSerialNumber = std::array<u8, 10>;
+
+// This is nn::nfc::DeviceHandle
+using DeviceHandle = u64;
+
+// This is nn::nfc::TagInfo
+struct TagInfo {
+ UniqueSerialNumber uuid;
+ u8 uuid_length;
+ INSERT_PADDING_BYTES(0x15);
+ NfcProtocol protocol;
+ TagType tag_type;
+ INSERT_PADDING_BYTES(0x30);
+};
+static_assert(sizeof(TagInfo) == 0x58, "TagInfo is an invalid size");
+
+} // namespace Service::NFC
diff --git a/src/core/hle/service/nfc/nfc_user.cpp b/src/core/hle/service/nfc/nfc_user.cpp
deleted file mode 100644
index 89aa6b3f5..000000000
--- a/src/core/hle/service/nfc/nfc_user.cpp
+++ /dev/null
@@ -1,365 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#include "common/logging/log.h"
-#include "core/core.h"
-#include "core/hid/hid_types.h"
-#include "core/hle/ipc_helpers.h"
-#include "core/hle/kernel/k_event.h"
-#include "core/hle/service/nfc/nfc_device.h"
-#include "core/hle/service/nfc/nfc_result.h"
-#include "core/hle/service/nfc/nfc_user.h"
-#include "core/hle/service/time/clock_types.h"
-
-namespace Service::NFC {
-
-IUser::IUser(Core::System& system_)
- : ServiceFramework{system_, "NFC::IUser"}, service_context{system_, service_name} {
- static const FunctionInfo functions[] = {
- {0, &IUser::Initialize, "InitializeOld"},
- {1, &IUser::Finalize, "FinalizeOld"},
- {2, &IUser::GetState, "GetStateOld"},
- {3, &IUser::IsNfcEnabled, "IsNfcEnabledOld"},
- {400, &IUser::Initialize, "Initialize"},
- {401, &IUser::Finalize, "Finalize"},
- {402, &IUser::GetState, "GetState"},
- {403, &IUser::IsNfcEnabled, "IsNfcEnabled"},
- {404, &IUser::ListDevices, "ListDevices"},
- {405, &IUser::GetDeviceState, "GetDeviceState"},
- {406, &IUser::GetNpadId, "GetNpadId"},
- {407, &IUser::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"},
- {408, &IUser::StartDetection, "StartDetection"},
- {409, &IUser::StopDetection, "StopDetection"},
- {410, &IUser::GetTagInfo, "GetTagInfo"},
- {411, &IUser::AttachActivateEvent, "AttachActivateEvent"},
- {412, &IUser::AttachDeactivateEvent, "AttachDeactivateEvent"},
- {1000, nullptr, "ReadMifare"},
- {1001, nullptr, "WriteMifare"},
- {1300, &IUser::SendCommandByPassThrough, "SendCommandByPassThrough"},
- {1301, nullptr, "KeepPassThroughSession"},
- {1302, nullptr, "ReleasePassThroughSession"},
- };
- RegisterHandlers(functions);
-
- availability_change_event = service_context.CreateEvent("IUser:AvailabilityChangeEvent");
-
- for (u32 device_index = 0; device_index < 10; device_index++) {
- devices[device_index] =
- std::make_shared<NfcDevice>(Core::HID::IndexToNpadIdType(device_index), system,
- service_context, availability_change_event);
- }
-}
-
-IUser ::~IUser() {
- availability_change_event->Close();
-}
-
-void IUser::Initialize(Kernel::HLERequestContext& ctx) {
- LOG_INFO(Service_NFC, "called");
-
- state = State::Initialized;
-
- for (auto& device : devices) {
- device->Initialize();
- }
-
- IPC::ResponseBuilder rb{ctx, 2, 0};
- rb.Push(ResultSuccess);
-}
-
-void IUser::Finalize(Kernel::HLERequestContext& ctx) {
- LOG_INFO(Service_NFC, "called");
-
- state = State::NonInitialized;
-
- for (auto& device : devices) {
- device->Finalize();
- }
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void IUser::GetState(Kernel::HLERequestContext& ctx) {
- LOG_DEBUG(Service_NFC, "called");
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.PushEnum(state);
-}
-
-void IUser::IsNfcEnabled(Kernel::HLERequestContext& ctx) {
- LOG_DEBUG(Service_NFC, "called");
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push(state != State::NonInitialized);
-}
-
-void IUser::ListDevices(Kernel::HLERequestContext& ctx) {
- LOG_DEBUG(Service_NFC, "called");
-
- if (state == State::NonInitialized) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(NfcDisabled);
- return;
- }
-
- if (!ctx.CanWriteBuffer()) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(InvalidArgument);
- return;
- }
-
- if (ctx.GetWriteBufferSize() == 0) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(InvalidArgument);
- return;
- }
-
- std::vector<u64> nfp_devices;
- const std::size_t max_allowed_devices = ctx.GetWriteBufferNumElements<u64>();
-
- for (auto& device : devices) {
- if (nfp_devices.size() >= max_allowed_devices) {
- continue;
- }
- if (device->GetCurrentState() != NFP::DeviceState::Unavailable) {
- nfp_devices.push_back(device->GetHandle());
- }
- }
-
- if (nfp_devices.empty()) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(DeviceNotFound);
- return;
- }
-
- ctx.WriteBuffer(nfp_devices);
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push(static_cast<s32>(nfp_devices.size()));
-}
-
-void IUser::GetDeviceState(Kernel::HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto device_handle{rp.Pop<u64>()};
- LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
-
- auto device = GetNfcDevice(device_handle);
-
- if (!device.has_value()) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(DeviceNotFound);
- return;
- }
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.PushEnum(device.value()->GetCurrentState());
-}
-
-void IUser::GetNpadId(Kernel::HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto device_handle{rp.Pop<u64>()};
- LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
-
- if (state == State::NonInitialized) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(NfcDisabled);
- return;
- }
-
- auto device = GetNfcDevice(device_handle);
-
- if (!device.has_value()) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(DeviceNotFound);
- return;
- }
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.PushEnum(device.value()->GetNpadId());
-}
-
-void IUser::AttachAvailabilityChangeEvent(Kernel::HLERequestContext& ctx) {
- LOG_INFO(Service_NFC, "called");
-
- if (state == State::NonInitialized) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(NfcDisabled);
- return;
- }
-
- IPC::ResponseBuilder rb{ctx, 2, 1};
- rb.Push(ResultSuccess);
- rb.PushCopyObjects(availability_change_event->GetReadableEvent());
-}
-
-void IUser::StartDetection(Kernel::HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto device_handle{rp.Pop<u64>()};
- const auto nfp_protocol{rp.PopEnum<NFP::TagProtocol>()};
- LOG_INFO(Service_NFC, "called, device_handle={}, nfp_protocol={}", device_handle, nfp_protocol);
-
- if (state == State::NonInitialized) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(NfcDisabled);
- return;
- }
-
- auto device = GetNfcDevice(device_handle);
-
- if (!device.has_value()) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(DeviceNotFound);
- return;
- }
-
- const auto result = device.value()->StartDetection(nfp_protocol);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
-}
-
-void IUser::StopDetection(Kernel::HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto device_handle{rp.Pop<u64>()};
- LOG_INFO(Service_NFC, "called, device_handle={}", device_handle);
-
- if (state == State::NonInitialized) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(NfcDisabled);
- return;
- }
-
- auto device = GetNfcDevice(device_handle);
-
- if (!device.has_value()) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(DeviceNotFound);
- return;
- }
-
- const auto result = device.value()->StopDetection();
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
-}
-
-void IUser::GetTagInfo(Kernel::HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto device_handle{rp.Pop<u64>()};
- LOG_INFO(Service_NFC, "called, device_handle={}", device_handle);
-
- if (state == State::NonInitialized) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(NfcDisabled);
- return;
- }
-
- auto device = GetNfcDevice(device_handle);
-
- if (!device.has_value()) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(DeviceNotFound);
- return;
- }
-
- NFP::TagInfo tag_info{};
- const auto result = device.value()->GetTagInfo(tag_info, false);
- ctx.WriteBuffer(tag_info);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
-}
-
-void IUser::AttachActivateEvent(Kernel::HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto device_handle{rp.Pop<u64>()};
- LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
-
- if (state == State::NonInitialized) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(NfcDisabled);
- return;
- }
-
- auto device = GetNfcDevice(device_handle);
-
- if (!device.has_value()) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(DeviceNotFound);
- return;
- }
-
- IPC::ResponseBuilder rb{ctx, 2, 1};
- rb.Push(ResultSuccess);
- rb.PushCopyObjects(device.value()->GetActivateEvent());
-}
-
-void IUser::AttachDeactivateEvent(Kernel::HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto device_handle{rp.Pop<u64>()};
- LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle);
-
- if (state == State::NonInitialized) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(NfcDisabled);
- return;
- }
-
- auto device = GetNfcDevice(device_handle);
-
- if (!device.has_value()) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(DeviceNotFound);
- return;
- }
-
- IPC::ResponseBuilder rb{ctx, 2, 1};
- rb.Push(ResultSuccess);
- rb.PushCopyObjects(device.value()->GetDeactivateEvent());
-}
-
-void IUser::SendCommandByPassThrough(Kernel::HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto device_handle{rp.Pop<u64>()};
- const auto timeout{rp.PopRaw<Time::Clock::TimeSpanType>()};
- const auto command_data{ctx.ReadBuffer()};
-
- LOG_INFO(Service_NFC, "(STUBBED) called, device_handle={}, timeout={}, data_size={}",
- device_handle, timeout.ToSeconds(), command_data.size());
-
- if (state == State::NonInitialized) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(NfcDisabled);
- return;
- }
-
- auto device = GetNfcDevice(device_handle);
-
- if (!device.has_value()) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(DeviceNotFound);
- return;
- }
-
- std::vector<u8> out_data(1);
- // TODO: Request data from nfc device
- ctx.WriteBuffer(out_data);
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push(static_cast<u32>(out_data.size()));
-}
-
-std::optional<std::shared_ptr<NfcDevice>> IUser::GetNfcDevice(u64 handle) {
- for (auto& device : devices) {
- if (device->GetHandle() == handle) {
- return device;
- }
- }
- return std::nullopt;
-}
-
-} // namespace Service::NFC
diff --git a/src/core/hle/service/nfc/nfc_user.h b/src/core/hle/service/nfc/nfc_user.h
deleted file mode 100644
index a5a4f12f9..000000000
--- a/src/core/hle/service/nfc/nfc_user.h
+++ /dev/null
@@ -1,52 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#pragma once
-
-#include <array>
-#include <memory>
-#include <optional>
-
-#include "core/hle/service/kernel_helpers.h"
-#include "core/hle/service/service.h"
-
-namespace Service::NFC {
-class NfcDevice;
-
-class IUser final : public ServiceFramework<IUser> {
-public:
- explicit IUser(Core::System& system_);
- ~IUser();
-
-private:
- enum class State : u32 {
- NonInitialized,
- Initialized,
- };
-
- void Initialize(Kernel::HLERequestContext& ctx);
- void Finalize(Kernel::HLERequestContext& ctx);
- void GetState(Kernel::HLERequestContext& ctx);
- void IsNfcEnabled(Kernel::HLERequestContext& ctx);
- void ListDevices(Kernel::HLERequestContext& ctx);
- void GetDeviceState(Kernel::HLERequestContext& ctx);
- void GetNpadId(Kernel::HLERequestContext& ctx);
- void AttachAvailabilityChangeEvent(Kernel::HLERequestContext& ctx);
- void StartDetection(Kernel::HLERequestContext& ctx);
- void StopDetection(Kernel::HLERequestContext& ctx);
- void GetTagInfo(Kernel::HLERequestContext& ctx);
- void AttachActivateEvent(Kernel::HLERequestContext& ctx);
- void AttachDeactivateEvent(Kernel::HLERequestContext& ctx);
- void SendCommandByPassThrough(Kernel::HLERequestContext& ctx);
-
- std::optional<std::shared_ptr<NfcDevice>> GetNfcDevice(u64 handle);
-
- KernelHelpers::ServiceContext service_context;
-
- std::array<std::shared_ptr<NfcDevice>, 10> devices{};
-
- State state{State::NonInitialized};
- Kernel::KEvent* availability_change_event;
-};
-
-} // namespace Service::NFC
diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp
index 0cb55ca49..2eeabc138 100644
--- a/src/core/hle/service/nfp/nfp.cpp
+++ b/src/core/hle/service/nfp/nfp.cpp
@@ -2,12 +2,140 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/logging/log.h"
-#include "core/hle/ipc_helpers.h"
+#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/nfp/nfp.h"
-#include "core/hle/service/nfp/nfp_user.h"
+#include "core/hle/service/nfp/nfp_interface.h"
+#include "core/hle/service/server_manager.h"
namespace Service::NFP {
+class IUser final : public Interface {
+public:
+ explicit IUser(Core::System& system_) : Interface(system_, "NFP:IUser") {
+ // clang-format off
+ static const FunctionInfoTyped<IUser> functions[] = {
+ {0, &IUser::Initialize, "Initialize"},
+ {1, &IUser::Finalize, "Finalize"},
+ {2, &IUser::ListDevices, "ListDevices"},
+ {3, &IUser::StartDetection, "StartDetection"},
+ {4, &IUser::StopDetection, "StopDetection"},
+ {5, &IUser::Mount, "Mount"},
+ {6, &IUser::Unmount, "Unmount"},
+ {7, &IUser::OpenApplicationArea, "OpenApplicationArea"},
+ {8, &IUser::GetApplicationArea, "GetApplicationArea"},
+ {9, &IUser::SetApplicationArea, "SetApplicationArea"},
+ {10, &IUser::Flush, "Flush"},
+ {11, &IUser::Restore, "Restore"},
+ {12, &IUser::CreateApplicationArea, "CreateApplicationArea"},
+ {13, &IUser::GetTagInfo, "GetTagInfo"},
+ {14, &IUser::GetRegisterInfo, "GetRegisterInfo"},
+ {15, &IUser::GetCommonInfo, "GetCommonInfo"},
+ {16, &IUser::GetModelInfo, "GetModelInfo"},
+ {17, &IUser::AttachActivateEvent, "AttachActivateEvent"},
+ {18, &IUser::AttachDeactivateEvent, "AttachDeactivateEvent"},
+ {19, &IUser::GetState, "GetState"},
+ {20, &IUser::GetDeviceState, "GetDeviceState"},
+ {21, &IUser::GetNpadId, "GetNpadId"},
+ {22, &IUser::GetApplicationAreaSize, "GetApplicationAreaSize"},
+ {23, &IUser::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"},
+ {24, &IUser::RecreateApplicationArea, "RecreateApplicationArea"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+class ISystem final : public Interface {
+public:
+ explicit ISystem(Core::System& system_) : Interface(system_, "NFP:ISystem") {
+ // clang-format off
+ static const FunctionInfoTyped<ISystem> functions[] = {
+ {0, &ISystem::InitializeSystem, "InitializeSystem"},
+ {1, &ISystem::FinalizeSystem, "FinalizeSystem"},
+ {2, &ISystem::ListDevices, "ListDevices"},
+ {3, &ISystem::StartDetection, "StartDetection"},
+ {4, &ISystem::StopDetection, "StopDetection"},
+ {5, &ISystem::Mount, "Mount"},
+ {6, &ISystem::Unmount, "Unmount"},
+ {10, &ISystem::Flush, "Flush"},
+ {11, &ISystem::Restore, "Restore"},
+ {12, &ISystem::CreateApplicationArea, "CreateApplicationArea"},
+ {13, &ISystem::GetTagInfo, "GetTagInfo"},
+ {14, &ISystem::GetRegisterInfo, "GetRegisterInfo"},
+ {15, &ISystem::GetCommonInfo, "GetCommonInfo"},
+ {16, &ISystem::GetModelInfo, "GetModelInfo"},
+ {17, &ISystem::AttachActivateEvent, "AttachActivateEvent"},
+ {18, &ISystem::AttachDeactivateEvent, "AttachDeactivateEvent"},
+ {19, &ISystem::GetState, "GetState"},
+ {20, &ISystem::GetDeviceState, "GetDeviceState"},
+ {21, &ISystem::GetNpadId, "GetNpadId"},
+ {23, &ISystem::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"},
+ {100, &ISystem::Format, "Format"},
+ {101, &ISystem::GetAdminInfo, "GetAdminInfo"},
+ {102, &ISystem::GetRegisterInfoPrivate, "GetRegisterInfoPrivate"},
+ {103, &ISystem::SetRegisterInfoPrivate, "SetRegisterInfoPrivate"},
+ {104, &ISystem::DeleteRegisterInfo, "DeleteRegisterInfo"},
+ {105, &ISystem::DeleteApplicationArea, "DeleteApplicationArea"},
+ {106, &ISystem::ExistsApplicationArea, "ExistsApplicationArea"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
+class IDebug final : public Interface {
+public:
+ explicit IDebug(Core::System& system_) : Interface(system_, "NFP:IDebug") {
+ // clang-format off
+ static const FunctionInfoTyped<IDebug> functions[] = {
+ {0, &IDebug::InitializeDebug, "InitializeDebug"},
+ {1, &IDebug::FinalizeDebug, "FinalizeDebug"},
+ {2, &IDebug::ListDevices, "ListDevices"},
+ {3, &IDebug::StartDetection, "StartDetection"},
+ {4, &IDebug::StopDetection, "StopDetection"},
+ {5, &IDebug::Mount, "Mount"},
+ {6, &IDebug::Unmount, "Unmount"},
+ {7, &IDebug::OpenApplicationArea, "OpenApplicationArea"},
+ {8, &IDebug::GetApplicationArea, "GetApplicationArea"},
+ {9, &IDebug::SetApplicationArea, "SetApplicationArea"},
+ {10, &IDebug::Flush, "Flush"},
+ {11, &IDebug::Restore, "Restore"},
+ {12, &IDebug::CreateApplicationArea, "CreateApplicationArea"},
+ {13, &IDebug::GetTagInfo, "GetTagInfo"},
+ {14, &IDebug::GetRegisterInfo, "GetRegisterInfo"},
+ {15, &IDebug::GetCommonInfo, "GetCommonInfo"},
+ {16, &IDebug::GetModelInfo, "GetModelInfo"},
+ {17, &IDebug::AttachActivateEvent, "AttachActivateEvent"},
+ {18, &IDebug::AttachDeactivateEvent, "AttachDeactivateEvent"},
+ {19, &IDebug::GetState, "GetState"},
+ {20, &IDebug::GetDeviceState, "GetDeviceState"},
+ {21, &IDebug::GetNpadId, "GetNpadId"},
+ {22, &IDebug::GetApplicationAreaSize, "GetApplicationAreaSize"},
+ {23, &IDebug::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"},
+ {24, &IDebug::RecreateApplicationArea, "RecreateApplicationArea"},
+ {100, &IDebug::Format, "Format"},
+ {101, &IDebug::GetAdminInfo, "GetAdminInfo"},
+ {102, &IDebug::GetRegisterInfoPrivate, "GetRegisterInfoPrivate"},
+ {103, &IDebug::SetRegisterInfoPrivate, "SetRegisterInfoPrivate"},
+ {104, &IDebug::DeleteRegisterInfo, "DeleteRegisterInfo"},
+ {105, &IDebug::DeleteApplicationArea, "DeleteApplicationArea"},
+ {106, &IDebug::ExistsApplicationArea, "ExistsApplicationArea"},
+ {200, &IDebug::GetAll, "GetAll"},
+ {201, &IDebug::SetAll, "SetAll"},
+ {202, &IDebug::FlushDebug, "FlushDebug"},
+ {203, &IDebug::BreakTag, "BreakTag"},
+ {204, &IDebug::ReadBackupData, "ReadBackupData"},
+ {205, &IDebug::WriteBackupData, "WriteBackupData"},
+ {206, &IDebug::WriteNtf, "WriteNtf"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
class IUserManager final : public ServiceFramework<IUserManager> {
public:
explicit IUserManager(Core::System& system_) : ServiceFramework{system_, "nfp:user"} {
@@ -21,23 +149,66 @@ public:
}
private:
- void CreateUserInterface(Kernel::HLERequestContext& ctx) {
+ void CreateUserInterface(HLERequestContext& ctx) {
LOG_DEBUG(Service_NFP, "called");
- if (user_interface == nullptr) {
- user_interface = std::make_shared<IUser>(system);
- }
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ rb.Push(ResultSuccess);
+ rb.PushIpcInterface<IUser>(system);
+ }
+};
+
+class ISystemManager final : public ServiceFramework<ISystemManager> {
+public:
+ explicit ISystemManager(Core::System& system_) : ServiceFramework{system_, "nfp:sys"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, &ISystemManager::CreateSystemInterface, "CreateSystemInterface"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+
+private:
+ void CreateSystemInterface(HLERequestContext& ctx) {
+ LOG_DEBUG(Service_NFP, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
- rb.PushIpcInterface<IUser>(user_interface);
+ rb.PushIpcInterface<ISystem>(system);
+ }
+};
+
+class IDebugManager final : public ServiceFramework<IDebugManager> {
+public:
+ explicit IDebugManager(Core::System& system_) : ServiceFramework{system_, "nfp:dbg"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, &IDebugManager::CreateDebugInterface, "CreateDebugInterface"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
}
- std::shared_ptr<IUser> user_interface;
+private:
+ void CreateDebugInterface(HLERequestContext& ctx) {
+ LOG_DEBUG(Service_NFP, "called");
+
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ rb.Push(ResultSuccess);
+ rb.PushIpcInterface<IDebug>(system);
+ }
};
-void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
- std::make_shared<IUserManager>(system)->InstallAsService(service_manager);
+void LoopProcess(Core::System& system) {
+ auto server_manager = std::make_unique<ServerManager>(system);
+
+ server_manager->RegisterNamedService("nfp:user", std::make_shared<IUserManager>(system));
+ server_manager->RegisterNamedService("nfp:sys", std::make_shared<ISystemManager>(system));
+ server_manager->RegisterNamedService("nfp:dbg", std::make_shared<IDebugManager>(system));
+ ServerManager::RunServer(std::move(server_manager));
}
} // namespace Service::NFP
diff --git a/src/core/hle/service/nfp/nfp.h b/src/core/hle/service/nfp/nfp.h
index a25c362b8..a5aac710b 100644
--- a/src/core/hle/service/nfp/nfp.h
+++ b/src/core/hle/service/nfp/nfp.h
@@ -7,6 +7,6 @@
namespace Service::NFP {
-void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system);
+void LoopProcess(Core::System& system);
} // namespace Service::NFP
diff --git a/src/core/hle/service/nfp/nfp_device.cpp b/src/core/hle/service/nfp/nfp_device.cpp
deleted file mode 100644
index c860fd1a1..000000000
--- a/src/core/hle/service/nfp/nfp_device.cpp
+++ /dev/null
@@ -1,719 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#include <array>
-
-#include "common/input.h"
-#include "common/logging/log.h"
-#include "common/string_util.h"
-#include "common/tiny_mt.h"
-#include "core/core.h"
-#include "core/hid/emulated_controller.h"
-#include "core/hid/hid_core.h"
-#include "core/hid/hid_types.h"
-#include "core/hle/ipc_helpers.h"
-#include "core/hle/kernel/k_event.h"
-#include "core/hle/service/mii/mii_manager.h"
-#include "core/hle/service/mii/types.h"
-#include "core/hle/service/nfp/amiibo_crypto.h"
-#include "core/hle/service/nfp/nfp_device.h"
-#include "core/hle/service/nfp/nfp_result.h"
-#include "core/hle/service/nfp/nfp_user.h"
-#include "core/hle/service/time/time_manager.h"
-#include "core/hle/service/time/time_zone_content_manager.h"
-#include "core/hle/service/time/time_zone_types.h"
-
-namespace Service::NFP {
-NfpDevice::NfpDevice(Core::HID::NpadIdType npad_id_, Core::System& system_,
- KernelHelpers::ServiceContext& service_context_,
- Kernel::KEvent* availability_change_event_)
- : npad_id{npad_id_}, system{system_}, service_context{service_context_},
- availability_change_event{availability_change_event_} {
- activate_event = service_context.CreateEvent("IUser:NFPActivateEvent");
- deactivate_event = service_context.CreateEvent("IUser:NFPDeactivateEvent");
- npad_device = system.HIDCore().GetEmulatedController(npad_id);
-
- Core::HID::ControllerUpdateCallback engine_callback{
- .on_change = [this](Core::HID::ControllerTriggerType type) { NpadUpdate(type); },
- .is_npad_service = false,
- };
- is_controller_set = true;
- callback_key = npad_device->SetCallback(engine_callback);
-
- auto& standard_steady_clock{system.GetTimeManager().GetStandardSteadyClockCore()};
- current_posix_time = standard_steady_clock.GetCurrentTimePoint(system).time_point;
-}
-
-NfpDevice::~NfpDevice() {
- activate_event->Close();
- deactivate_event->Close();
- if (!is_controller_set) {
- return;
- }
- npad_device->DeleteCallback(callback_key);
- is_controller_set = false;
-};
-
-void NfpDevice::NpadUpdate(Core::HID::ControllerTriggerType type) {
- if (type == Core::HID::ControllerTriggerType::Connected ||
- type == Core::HID::ControllerTriggerType::Disconnected) {
- availability_change_event->Signal();
- return;
- }
-
- if (type != Core::HID::ControllerTriggerType::Nfc) {
- return;
- }
-
- if (!npad_device->IsConnected()) {
- return;
- }
-
- const auto nfc_status = npad_device->GetNfc();
- switch (nfc_status.state) {
- case Common::Input::NfcState::NewAmiibo:
- LoadAmiibo(nfc_status.data);
- break;
- case Common::Input::NfcState::AmiiboRemoved:
- if (device_state == DeviceState::Initialized || device_state == DeviceState::TagRemoved) {
- break;
- }
- if (device_state != DeviceState::SearchingForTag) {
- CloseAmiibo();
- }
- break;
- default:
- break;
- }
-}
-
-bool NfpDevice::LoadAmiibo(std::span<const u8> data) {
- if (device_state != DeviceState::SearchingForTag) {
- LOG_ERROR(Service_NFP, "Game is not looking for amiibos, current state {}", device_state);
- return false;
- }
-
- if (data.size() != sizeof(EncryptedNTAG215File)) {
- LOG_ERROR(Service_NFP, "Not an amiibo, size={}", data.size());
- return false;
- }
-
- // TODO: Filter by allowed_protocols here
-
- memcpy(&encrypted_tag_data, data.data(), sizeof(EncryptedNTAG215File));
-
- device_state = DeviceState::TagFound;
- deactivate_event->GetReadableEvent().Clear();
- activate_event->Signal();
- return true;
-}
-
-void NfpDevice::CloseAmiibo() {
- LOG_INFO(Service_NFP, "Remove amiibo");
-
- if (device_state == DeviceState::TagMounted) {
- Unmount();
- }
-
- device_state = DeviceState::TagRemoved;
- encrypted_tag_data = {};
- tag_data = {};
- activate_event->GetReadableEvent().Clear();
- deactivate_event->Signal();
-}
-
-Kernel::KReadableEvent& NfpDevice::GetActivateEvent() const {
- return activate_event->GetReadableEvent();
-}
-
-Kernel::KReadableEvent& NfpDevice::GetDeactivateEvent() const {
- return deactivate_event->GetReadableEvent();
-}
-
-void NfpDevice::Initialize() {
- device_state = npad_device->HasNfc() ? DeviceState::Initialized : DeviceState::Unavailable;
- encrypted_tag_data = {};
- tag_data = {};
-}
-
-void NfpDevice::Finalize() {
- if (device_state == DeviceState::TagMounted) {
- Unmount();
- }
- if (device_state == DeviceState::SearchingForTag || device_state == DeviceState::TagRemoved) {
- StopDetection();
- }
- device_state = DeviceState::Unavailable;
-}
-
-Result NfpDevice::StartDetection(TagProtocol allowed_protocol) {
- if (device_state != DeviceState::Initialized && device_state != DeviceState::TagRemoved) {
- LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
- return WrongDeviceState;
- }
-
- if (!npad_device->SetPollingMode(Common::Input::PollingMode::NFC)) {
- LOG_ERROR(Service_NFP, "Nfc not supported");
- return NfcDisabled;
- }
-
- device_state = DeviceState::SearchingForTag;
- allowed_protocols = allowed_protocol;
- return ResultSuccess;
-}
-
-Result NfpDevice::StopDetection() {
- npad_device->SetPollingMode(Common::Input::PollingMode::Active);
-
- if (device_state == DeviceState::Initialized) {
- return ResultSuccess;
- }
-
- if (device_state == DeviceState::TagFound || device_state == DeviceState::TagMounted) {
- CloseAmiibo();
- return ResultSuccess;
- }
- if (device_state == DeviceState::SearchingForTag || device_state == DeviceState::TagRemoved) {
- device_state = DeviceState::Initialized;
- return ResultSuccess;
- }
-
- LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
- return WrongDeviceState;
-}
-
-Result NfpDevice::Flush() {
- if (device_state != DeviceState::TagMounted) {
- LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
- if (device_state == DeviceState::TagRemoved) {
- return TagRemoved;
- }
- return WrongDeviceState;
- }
-
- if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) {
- LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
- return WrongDeviceState;
- }
-
- auto& settings = tag_data.settings;
-
- const auto& current_date = GetAmiiboDate(current_posix_time);
- if (settings.write_date.raw_date != current_date.raw_date) {
- settings.write_date = current_date;
- settings.crc_counter++;
- // TODO: Find how to calculate the crc check
- // settings.crc = CalculateCRC(settings);
- }
-
- tag_data.write_counter++;
-
- if (!AmiiboCrypto::EncodeAmiibo(tag_data, encrypted_tag_data)) {
- LOG_ERROR(Service_NFP, "Failed to encode data");
- return WriteAmiiboFailed;
- }
-
- std::vector<u8> data(sizeof(encrypted_tag_data));
- memcpy(data.data(), &encrypted_tag_data, sizeof(encrypted_tag_data));
-
- if (!npad_device->WriteNfc(data)) {
- LOG_ERROR(Service_NFP, "Error writing to file");
- return WriteAmiiboFailed;
- }
-
- is_data_moddified = false;
-
- return ResultSuccess;
-}
-
-Result NfpDevice::Mount(MountTarget mount_target_) {
- if (device_state != DeviceState::TagFound) {
- LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
- return WrongDeviceState;
- }
-
- if (!AmiiboCrypto::IsAmiiboValid(encrypted_tag_data)) {
- LOG_ERROR(Service_NFP, "Not an amiibo");
- return NotAnAmiibo;
- }
-
- // Mark amiibos as read only when keys are missing
- if (!AmiiboCrypto::IsKeyAvailable()) {
- LOG_ERROR(Service_NFP, "No keys detected");
- device_state = DeviceState::TagMounted;
- mount_target = MountTarget::Rom;
- return ResultSuccess;
- }
-
- if (!AmiiboCrypto::DecodeAmiibo(encrypted_tag_data, tag_data)) {
- LOG_ERROR(Service_NFP, "Can't decode amiibo {}", device_state);
- return CorruptedData;
- }
-
- device_state = DeviceState::TagMounted;
- mount_target = mount_target_;
- return ResultSuccess;
-}
-
-Result NfpDevice::Unmount() {
- if (device_state != DeviceState::TagMounted) {
- LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
- if (device_state == DeviceState::TagRemoved) {
- return TagRemoved;
- }
- return WrongDeviceState;
- }
-
- // Save data before unloading the amiibo
- if (is_data_moddified) {
- Flush();
- }
-
- device_state = DeviceState::TagFound;
- mount_target = MountTarget::None;
- is_app_area_open = false;
-
- return ResultSuccess;
-}
-
-Result NfpDevice::GetTagInfo(TagInfo& tag_info) const {
- if (device_state != DeviceState::TagFound && device_state != DeviceState::TagMounted) {
- LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
- if (device_state == DeviceState::TagRemoved) {
- return TagRemoved;
- }
- return WrongDeviceState;
- }
-
- tag_info = {
- .uuid = encrypted_tag_data.uuid.uid,
- .uuid_length = static_cast<u8>(encrypted_tag_data.uuid.uid.size()),
- .protocol = TagProtocol::TypeA,
- .tag_type = TagType::Type2,
- };
-
- return ResultSuccess;
-}
-
-Result NfpDevice::GetCommonInfo(CommonInfo& common_info) const {
- if (device_state != DeviceState::TagMounted) {
- LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
- if (device_state == DeviceState::TagRemoved) {
- return TagRemoved;
- }
- return WrongDeviceState;
- }
-
- if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) {
- LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
- return WrongDeviceState;
- }
-
- const auto& settings = tag_data.settings;
-
- // TODO: Validate this data
- common_info = {
- .last_write_date = settings.write_date.GetWriteDate(),
- .write_counter = tag_data.write_counter,
- .version = 0,
- .application_area_size = sizeof(ApplicationArea),
- };
- return ResultSuccess;
-}
-
-Result NfpDevice::GetModelInfo(ModelInfo& model_info) const {
- if (device_state != DeviceState::TagMounted) {
- LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
- if (device_state == DeviceState::TagRemoved) {
- return TagRemoved;
- }
- return WrongDeviceState;
- }
-
- const auto& model_info_data = encrypted_tag_data.user_memory.model_info;
- model_info = {
- .character_id = model_info_data.character_id,
- .character_variant = model_info_data.character_variant,
- .amiibo_type = model_info_data.amiibo_type,
- .model_number = model_info_data.model_number,
- .series = model_info_data.series,
- };
- return ResultSuccess;
-}
-
-Result NfpDevice::GetRegisterInfo(RegisterInfo& register_info) const {
- if (device_state != DeviceState::TagMounted) {
- LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
- if (device_state == DeviceState::TagRemoved) {
- return TagRemoved;
- }
- return WrongDeviceState;
- }
-
- if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) {
- LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
- return WrongDeviceState;
- }
-
- if (tag_data.settings.settings.amiibo_initialized == 0) {
- return RegistrationIsNotInitialized;
- }
-
- Service::Mii::MiiManager manager;
- const auto& settings = tag_data.settings;
-
- // TODO: Validate this data
- register_info = {
- .mii_char_info = manager.ConvertV3ToCharInfo(tag_data.owner_mii),
- .creation_date = settings.init_date.GetWriteDate(),
- .amiibo_name = GetAmiiboName(settings),
- .font_region = {},
- };
-
- return ResultSuccess;
-}
-
-Result NfpDevice::SetNicknameAndOwner(const AmiiboName& amiibo_name) {
- if (device_state != DeviceState::TagMounted) {
- LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
- if (device_state == DeviceState::TagRemoved) {
- return TagRemoved;
- }
- return WrongDeviceState;
- }
-
- if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) {
- LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
- return WrongDeviceState;
- }
-
- Service::Mii::MiiManager manager;
- auto& settings = tag_data.settings;
-
- settings.init_date = GetAmiiboDate(current_posix_time);
- settings.write_date = GetAmiiboDate(current_posix_time);
- settings.crc_counter++;
- // TODO: Find how to calculate the crc check
- // settings.crc = CalculateCRC(settings);
-
- SetAmiiboName(settings, amiibo_name);
- tag_data.owner_mii = manager.ConvertCharInfoToV3(manager.BuildDefault(0));
- settings.settings.amiibo_initialized.Assign(1);
-
- return Flush();
-}
-
-Result NfpDevice::RestoreAmiibo() {
- if (device_state != DeviceState::TagMounted) {
- LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
- if (device_state == DeviceState::TagRemoved) {
- return TagRemoved;
- }
- return WrongDeviceState;
- }
-
- if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) {
- LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
- return WrongDeviceState;
- }
-
- // TODO: Load amiibo from backup on system
- LOG_ERROR(Service_NFP, "Not Implemented");
- return ResultSuccess;
-}
-
-Result NfpDevice::DeleteAllData() {
- const auto result = DeleteApplicationArea();
- if (result.IsError()) {
- return result;
- }
-
- if (device_state != DeviceState::TagMounted) {
- LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
- if (device_state == DeviceState::TagRemoved) {
- return TagRemoved;
- }
- return WrongDeviceState;
- }
-
- Common::TinyMT rng{};
- rng.GenerateRandomBytes(&tag_data.owner_mii, sizeof(tag_data.owner_mii));
- tag_data.settings.settings.amiibo_initialized.Assign(0);
-
- return Flush();
-}
-
-Result NfpDevice::OpenApplicationArea(u32 access_id) {
- if (device_state != DeviceState::TagMounted) {
- LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
- if (device_state == DeviceState::TagRemoved) {
- return TagRemoved;
- }
- return WrongDeviceState;
- }
-
- if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) {
- LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
- return WrongDeviceState;
- }
-
- if (tag_data.settings.settings.appdata_initialized.Value() == 0) {
- LOG_WARNING(Service_NFP, "Application area is not initialized");
- return ApplicationAreaIsNotInitialized;
- }
-
- if (tag_data.application_area_id != access_id) {
- LOG_WARNING(Service_NFP, "Wrong application area id");
- return WrongApplicationAreaId;
- }
-
- is_app_area_open = true;
-
- return ResultSuccess;
-}
-
-Result NfpDevice::GetApplicationAreaId(u32& application_area_id) const {
- application_area_id = {};
-
- if (device_state != DeviceState::TagMounted) {
- LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
- if (device_state == DeviceState::TagRemoved) {
- return TagRemoved;
- }
- return WrongDeviceState;
- }
-
- if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) {
- LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
- return WrongDeviceState;
- }
-
- if (tag_data.settings.settings.appdata_initialized.Value() == 0) {
- LOG_WARNING(Service_NFP, "Application area is not initialized");
- return ApplicationAreaIsNotInitialized;
- }
-
- application_area_id = tag_data.application_area_id;
-
- return ResultSuccess;
-}
-
-Result NfpDevice::GetApplicationArea(std::vector<u8>& data) const {
- if (device_state != DeviceState::TagMounted) {
- LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
- if (device_state == DeviceState::TagRemoved) {
- return TagRemoved;
- }
- return WrongDeviceState;
- }
-
- if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) {
- LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
- return WrongDeviceState;
- }
-
- if (!is_app_area_open) {
- LOG_ERROR(Service_NFP, "Application area is not open");
- return WrongDeviceState;
- }
-
- if (tag_data.settings.settings.appdata_initialized.Value() == 0) {
- LOG_ERROR(Service_NFP, "Application area is not initialized");
- return ApplicationAreaIsNotInitialized;
- }
-
- if (data.size() > sizeof(ApplicationArea)) {
- data.resize(sizeof(ApplicationArea));
- }
-
- memcpy(data.data(), tag_data.application_area.data(), data.size());
-
- return ResultSuccess;
-}
-
-Result NfpDevice::SetApplicationArea(std::span<const u8> data) {
- if (device_state != DeviceState::TagMounted) {
- LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
- if (device_state == DeviceState::TagRemoved) {
- return TagRemoved;
- }
- return WrongDeviceState;
- }
-
- if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) {
- LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
- return WrongDeviceState;
- }
-
- if (!is_app_area_open) {
- LOG_ERROR(Service_NFP, "Application area is not open");
- return WrongDeviceState;
- }
-
- if (tag_data.settings.settings.appdata_initialized.Value() == 0) {
- LOG_ERROR(Service_NFP, "Application area is not initialized");
- return ApplicationAreaIsNotInitialized;
- }
-
- if (data.size() > sizeof(ApplicationArea)) {
- LOG_ERROR(Service_NFP, "Wrong data size {}", data.size());
- return ResultUnknown;
- }
-
- Common::TinyMT rng{};
- std::memcpy(tag_data.application_area.data(), data.data(), data.size());
- // Fill remaining data with random numbers
- rng.GenerateRandomBytes(tag_data.application_area.data() + data.size(),
- sizeof(ApplicationArea) - data.size());
-
- tag_data.applicaton_write_counter++;
- is_data_moddified = true;
-
- return ResultSuccess;
-}
-
-Result NfpDevice::CreateApplicationArea(u32 access_id, std::span<const u8> data) {
- if (device_state != DeviceState::TagMounted) {
- LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
- if (device_state == DeviceState::TagRemoved) {
- return TagRemoved;
- }
- return WrongDeviceState;
- }
-
- if (tag_data.settings.settings.appdata_initialized.Value() != 0) {
- LOG_ERROR(Service_NFP, "Application area already exist");
- return ApplicationAreaExist;
- }
-
- return RecreateApplicationArea(access_id, data);
-}
-
-Result NfpDevice::RecreateApplicationArea(u32 access_id, std::span<const u8> data) {
- if (device_state != DeviceState::TagMounted) {
- LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
- if (device_state == DeviceState::TagRemoved) {
- return TagRemoved;
- }
- return WrongDeviceState;
- }
-
- if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) {
- LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
- return WrongDeviceState;
- }
-
- if (data.size() > sizeof(ApplicationArea)) {
- LOG_ERROR(Service_NFP, "Wrong data size {}", data.size());
- return WrongApplicationAreaSize;
- }
-
- Common::TinyMT rng{};
- std::memcpy(tag_data.application_area.data(), data.data(), data.size());
- // Fill remaining data with random numbers
- rng.GenerateRandomBytes(tag_data.application_area.data() + data.size(),
- sizeof(ApplicationArea) - data.size());
-
- // TODO: Investigate why the title id needs to be moddified
- tag_data.title_id = system.GetCurrentProcessProgramID();
- tag_data.title_id = tag_data.title_id | 0x30000000ULL;
- tag_data.settings.settings.appdata_initialized.Assign(1);
- tag_data.application_area_id = access_id;
- tag_data.applicaton_write_counter++;
- tag_data.unknown = {};
-
- return Flush();
-}
-
-Result NfpDevice::DeleteApplicationArea() {
- if (device_state != DeviceState::TagMounted) {
- LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
- if (device_state == DeviceState::TagRemoved) {
- return TagRemoved;
- }
- return WrongDeviceState;
- }
-
- if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) {
- LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
- return WrongDeviceState;
- }
-
- Common::TinyMT rng{};
- rng.GenerateRandomBytes(tag_data.application_area.data(), sizeof(ApplicationArea));
- rng.GenerateRandomBytes(&tag_data.title_id, sizeof(u64));
- rng.GenerateRandomBytes(&tag_data.application_area_id, sizeof(u32));
- tag_data.settings.settings.appdata_initialized.Assign(0);
- tag_data.applicaton_write_counter++;
- tag_data.unknown = {};
-
- return Flush();
-}
-
-u64 NfpDevice::GetHandle() const {
- // Generate a handle based of the npad id
- return static_cast<u64>(npad_id);
-}
-
-u32 NfpDevice::GetApplicationAreaSize() const {
- return sizeof(ApplicationArea);
-}
-
-DeviceState NfpDevice::GetCurrentState() const {
- return device_state;
-}
-
-Core::HID::NpadIdType NfpDevice::GetNpadId() const {
- return npad_id;
-}
-
-AmiiboName NfpDevice::GetAmiiboName(const AmiiboSettings& settings) const {
- std::array<char16_t, amiibo_name_length> settings_amiibo_name{};
- AmiiboName amiibo_name{};
-
- // Convert from big endian to little endian
- for (std::size_t i = 0; i < amiibo_name_length; i++) {
- settings_amiibo_name[i] = static_cast<u16>(settings.amiibo_name[i]);
- }
-
- // Convert from utf16 to utf8
- const auto amiibo_name_utf8 = Common::UTF16ToUTF8(settings_amiibo_name.data());
- memcpy(amiibo_name.data(), amiibo_name_utf8.data(), amiibo_name_utf8.size());
-
- return amiibo_name;
-}
-
-void NfpDevice::SetAmiiboName(AmiiboSettings& settings, const AmiiboName& amiibo_name) {
- std::array<char16_t, amiibo_name_length> settings_amiibo_name{};
-
- // Convert from utf8 to utf16
- const auto amiibo_name_utf16 = Common::UTF8ToUTF16(amiibo_name.data());
- memcpy(settings_amiibo_name.data(), amiibo_name_utf16.data(),
- amiibo_name_utf16.size() * sizeof(char16_t));
-
- // Convert from little endian to big endian
- for (std::size_t i = 0; i < amiibo_name_length; i++) {
- settings.amiibo_name[i] = static_cast<u16_be>(settings_amiibo_name[i]);
- }
-}
-
-AmiiboDate NfpDevice::GetAmiiboDate(s64 posix_time) const {
- const auto& time_zone_manager =
- system.GetTimeManager().GetTimeZoneContentManager().GetTimeZoneManager();
- Time::TimeZone::CalendarInfo calendar_info{};
- AmiiboDate amiibo_date{};
-
- amiibo_date.SetYear(2000);
- amiibo_date.SetMonth(1);
- amiibo_date.SetDay(1);
-
- if (time_zone_manager.ToCalendarTime({}, posix_time, calendar_info) == ResultSuccess) {
- amiibo_date.SetYear(calendar_info.time.year);
- amiibo_date.SetMonth(calendar_info.time.month);
- amiibo_date.SetDay(calendar_info.time.day);
- }
-
- return amiibo_date;
-}
-
-} // namespace Service::NFP
diff --git a/src/core/hle/service/nfp/nfp_device.h b/src/core/hle/service/nfp/nfp_device.h
deleted file mode 100644
index b6a46f2ac..000000000
--- a/src/core/hle/service/nfp/nfp_device.h
+++ /dev/null
@@ -1,101 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#pragma once
-
-#include <span>
-#include <vector>
-
-#include "common/common_types.h"
-#include "core/hle/service/kernel_helpers.h"
-#include "core/hle/service/nfp/nfp_types.h"
-#include "core/hle/service/service.h"
-
-namespace Kernel {
-class KEvent;
-class KReadableEvent;
-} // namespace Kernel
-
-namespace Core {
-class System;
-} // namespace Core
-
-namespace Core::HID {
-class EmulatedController;
-enum class ControllerTriggerType;
-enum class NpadIdType : u32;
-} // namespace Core::HID
-
-namespace Service::NFP {
-class NfpDevice {
-public:
- NfpDevice(Core::HID::NpadIdType npad_id_, Core::System& system_,
- KernelHelpers::ServiceContext& service_context_,
- Kernel::KEvent* availability_change_event_);
- ~NfpDevice();
-
- void Initialize();
- void Finalize();
-
- Result StartDetection(TagProtocol allowed_protocol);
- Result StopDetection();
- Result Mount(MountTarget mount_target);
- Result Unmount();
- Result Flush();
-
- Result GetTagInfo(TagInfo& tag_info) const;
- Result GetCommonInfo(CommonInfo& common_info) const;
- Result GetModelInfo(ModelInfo& model_info) const;
- Result GetRegisterInfo(RegisterInfo& register_info) const;
-
- Result SetNicknameAndOwner(const AmiiboName& amiibo_name);
- Result RestoreAmiibo();
- Result DeleteAllData();
-
- Result OpenApplicationArea(u32 access_id);
- Result GetApplicationAreaId(u32& application_area_id) const;
- Result GetApplicationArea(std::vector<u8>& data) const;
- Result SetApplicationArea(std::span<const u8> data);
- Result CreateApplicationArea(u32 access_id, std::span<const u8> data);
- Result RecreateApplicationArea(u32 access_id, std::span<const u8> data);
- Result DeleteApplicationArea();
-
- u64 GetHandle() const;
- u32 GetApplicationAreaSize() const;
- DeviceState GetCurrentState() const;
- Core::HID::NpadIdType GetNpadId() const;
-
- Kernel::KReadableEvent& GetActivateEvent() const;
- Kernel::KReadableEvent& GetDeactivateEvent() const;
-
-private:
- void NpadUpdate(Core::HID::ControllerTriggerType type);
- bool LoadAmiibo(std::span<const u8> data);
- void CloseAmiibo();
-
- AmiiboName GetAmiiboName(const AmiiboSettings& settings) const;
- void SetAmiiboName(AmiiboSettings& settings, const AmiiboName& amiibo_name);
- AmiiboDate GetAmiiboDate(s64 posix_time) const;
-
- bool is_controller_set{};
- int callback_key;
- const Core::HID::NpadIdType npad_id;
- Core::System& system;
- Core::HID::EmulatedController* npad_device = nullptr;
- KernelHelpers::ServiceContext& service_context;
- Kernel::KEvent* activate_event = nullptr;
- Kernel::KEvent* deactivate_event = nullptr;
- Kernel::KEvent* availability_change_event = nullptr;
-
- bool is_data_moddified{};
- bool is_app_area_open{};
- TagProtocol allowed_protocols{};
- s64 current_posix_time{};
- MountTarget mount_target{MountTarget::None};
- DeviceState device_state{DeviceState::Unavailable};
-
- NTAG215File tag_data{};
- EncryptedNTAG215File encrypted_tag_data{};
-};
-
-} // namespace Service::NFP
diff --git a/src/core/hle/service/nfp/nfp_interface.cpp b/src/core/hle/service/nfp/nfp_interface.cpp
new file mode 100644
index 000000000..34ef9d82d
--- /dev/null
+++ b/src/core/hle/service/nfp/nfp_interface.cpp
@@ -0,0 +1,438 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "common/logging/log.h"
+#include "core/core.h"
+#include "core/hid/hid_types.h"
+#include "core/hle/kernel/k_event.h"
+#include "core/hle/service/ipc_helpers.h"
+#include "core/hle/service/nfc/common/device.h"
+#include "core/hle/service/nfc/common/device_manager.h"
+#include "core/hle/service/nfc/nfc_types.h"
+#include "core/hle/service/nfp/nfp_interface.h"
+#include "core/hle/service/nfp/nfp_result.h"
+#include "core/hle/service/nfp/nfp_types.h"
+
+namespace Service::NFP {
+
+Interface::Interface(Core::System& system_, const char* name)
+ : NfcInterface{system_, name, NFC::BackendType::Nfp} {}
+
+Interface::~Interface() = default;
+
+void Interface::InitializeSystem(HLERequestContext& ctx) {
+ Initialize(ctx);
+}
+
+void Interface::InitializeDebug(HLERequestContext& ctx) {
+ Initialize(ctx);
+}
+
+void Interface::FinalizeSystem(HLERequestContext& ctx) {
+ Finalize(ctx);
+}
+
+void Interface::FinalizeDebug(HLERequestContext& ctx) {
+ Finalize(ctx);
+}
+
+void Interface::Mount(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto device_handle{rp.Pop<u64>()};
+ const auto model_type{rp.PopEnum<ModelType>()};
+ const auto mount_target{rp.PopEnum<MountTarget>()};
+ LOG_INFO(Service_NFP, "called, device_handle={}, model_type={}, mount_target={}", device_handle,
+ model_type, mount_target);
+
+ auto result = GetManager()->Mount(device_handle, model_type, mount_target);
+ result = TranslateResultToServiceError(result);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+}
+
+void Interface::Unmount(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto device_handle{rp.Pop<u64>()};
+ LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
+
+ auto result = GetManager()->Unmount(device_handle);
+ result = TranslateResultToServiceError(result);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+}
+
+void Interface::OpenApplicationArea(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto device_handle{rp.Pop<u64>()};
+ const auto access_id{rp.Pop<u32>()};
+ LOG_INFO(Service_NFP, "called, device_handle={}, access_id={}", device_handle, access_id);
+
+ auto result = GetManager()->OpenApplicationArea(device_handle, access_id);
+ result = TranslateResultToServiceError(result);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+}
+
+void Interface::GetApplicationArea(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto device_handle{rp.Pop<u64>()};
+ const auto data_size = ctx.GetWriteBufferSize();
+ LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
+
+ std::vector<u8> data(data_size);
+ auto result = GetManager()->GetApplicationArea(device_handle, data);
+ result = TranslateResultToServiceError(result);
+
+ if (result.IsError()) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+ return;
+ }
+
+ ctx.WriteBuffer(data);
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(result);
+ rb.Push(static_cast<u32>(data_size));
+}
+
+void Interface::SetApplicationArea(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto device_handle{rp.Pop<u64>()};
+ const auto data{ctx.ReadBuffer()};
+ LOG_INFO(Service_NFP, "called, device_handle={}, data_size={}", device_handle, data.size());
+
+ auto result = GetManager()->SetApplicationArea(device_handle, data);
+ result = TranslateResultToServiceError(result);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+}
+
+void Interface::Flush(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto device_handle{rp.Pop<u64>()};
+ LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
+
+ auto result = GetManager()->Flush(device_handle);
+ result = TranslateResultToServiceError(result);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+}
+
+void Interface::Restore(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto device_handle{rp.Pop<u64>()};
+ LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
+
+ auto result = GetManager()->Restore(device_handle);
+ result = TranslateResultToServiceError(result);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+}
+
+void Interface::CreateApplicationArea(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto device_handle{rp.Pop<u64>()};
+ const auto access_id{rp.Pop<u32>()};
+ const auto data{ctx.ReadBuffer()};
+ LOG_INFO(Service_NFP, "called, device_handle={}, data_size={}, access_id={}", device_handle,
+ access_id, data.size());
+
+ auto result = GetManager()->CreateApplicationArea(device_handle, access_id, data);
+ result = TranslateResultToServiceError(result);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+}
+
+void Interface::GetRegisterInfo(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto device_handle{rp.Pop<u64>()};
+ LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
+
+ RegisterInfo register_info{};
+ auto result = GetManager()->GetRegisterInfo(device_handle, register_info);
+ result = TranslateResultToServiceError(result);
+
+ if (result.IsSuccess()) {
+ ctx.WriteBuffer(register_info);
+ }
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+}
+
+void Interface::GetCommonInfo(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto device_handle{rp.Pop<u64>()};
+ LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
+
+ CommonInfo common_info{};
+ auto result = GetManager()->GetCommonInfo(device_handle, common_info);
+ result = TranslateResultToServiceError(result);
+
+ if (result.IsSuccess()) {
+ ctx.WriteBuffer(common_info);
+ }
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+}
+
+void Interface::GetModelInfo(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto device_handle{rp.Pop<u64>()};
+ LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
+
+ ModelInfo model_info{};
+ auto result = GetManager()->GetModelInfo(device_handle, model_info);
+ result = TranslateResultToServiceError(result);
+
+ if (result.IsSuccess()) {
+ ctx.WriteBuffer(model_info);
+ }
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+}
+
+void Interface::GetApplicationAreaSize(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto device_handle{rp.Pop<u64>()};
+ LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle);
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.Push(GetManager()->GetApplicationAreaSize());
+}
+
+void Interface::RecreateApplicationArea(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto device_handle{rp.Pop<u64>()};
+ const auto access_id{rp.Pop<u32>()};
+ const auto data{ctx.ReadBuffer()};
+ LOG_INFO(Service_NFP, "called, device_handle={}, data_size={}, access_id={}", device_handle,
+ access_id, data.size());
+
+ auto result = GetManager()->RecreateApplicationArea(device_handle, access_id, data);
+ result = TranslateResultToServiceError(result);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+}
+
+void Interface::Format(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto device_handle{rp.Pop<u64>()};
+ LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
+
+ auto result = GetManager()->Format(device_handle);
+ result = TranslateResultToServiceError(result);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+}
+
+void Interface::GetAdminInfo(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto device_handle{rp.Pop<u64>()};
+ LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
+
+ AdminInfo admin_info{};
+ auto result = GetManager()->GetAdminInfo(device_handle, admin_info);
+ result = TranslateResultToServiceError(result);
+
+ if (result.IsSuccess()) {
+ ctx.WriteBuffer(admin_info);
+ }
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+}
+
+void Interface::GetRegisterInfoPrivate(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto device_handle{rp.Pop<u64>()};
+ LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
+
+ RegisterInfoPrivate register_info{};
+ auto result = GetManager()->GetRegisterInfoPrivate(device_handle, register_info);
+ result = TranslateResultToServiceError(result);
+
+ if (result.IsSuccess()) {
+ ctx.WriteBuffer(register_info);
+ }
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+}
+
+void Interface::SetRegisterInfoPrivate(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto device_handle{rp.Pop<u64>()};
+ const auto register_info_buffer{ctx.ReadBuffer()};
+ LOG_INFO(Service_NFP, "called, device_handle={}, buffer_size={}", device_handle,
+ register_info_buffer.size());
+
+ RegisterInfoPrivate register_info{};
+ memcpy(&register_info, register_info_buffer.data(), sizeof(RegisterInfoPrivate));
+ auto result = GetManager()->SetRegisterInfoPrivate(device_handle, register_info);
+ result = TranslateResultToServiceError(result);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+}
+
+void Interface::DeleteRegisterInfo(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto device_handle{rp.Pop<u64>()};
+ LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
+
+ auto result = GetManager()->DeleteRegisterInfo(device_handle);
+ result = TranslateResultToServiceError(result);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+}
+
+void Interface::DeleteApplicationArea(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto device_handle{rp.Pop<u64>()};
+ LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
+
+ auto result = GetManager()->DeleteApplicationArea(device_handle);
+ result = TranslateResultToServiceError(result);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+}
+
+void Interface::ExistsApplicationArea(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto device_handle{rp.Pop<u64>()};
+ LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
+
+ bool has_application_area = false;
+ auto result = GetManager()->ExistsApplicationArea(device_handle, has_application_area);
+ result = TranslateResultToServiceError(result);
+
+ if (result.IsError()) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+ return;
+ }
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(result);
+ rb.Push(has_application_area);
+}
+
+void Interface::GetAll(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto device_handle{rp.Pop<u64>()};
+ LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
+
+ NfpData nfp_data{};
+ auto result = GetManager()->GetAll(device_handle, nfp_data);
+ result = TranslateResultToServiceError(result);
+
+ if (result.IsSuccess()) {
+ ctx.WriteBuffer(nfp_data);
+ }
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+}
+
+void Interface::SetAll(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto device_handle{rp.Pop<u64>()};
+ const auto nfp_data_buffer{ctx.ReadBuffer()};
+
+ LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
+
+ NfpData nfp_data{};
+ memcpy(&nfp_data, nfp_data_buffer.data(), sizeof(NfpData));
+ auto result = GetManager()->SetAll(device_handle, nfp_data);
+ result = TranslateResultToServiceError(result);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+}
+
+void Interface::FlushDebug(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto device_handle{rp.Pop<u64>()};
+ LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
+
+ auto result = GetManager()->FlushDebug(device_handle);
+ result = TranslateResultToServiceError(result);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+}
+
+void Interface::BreakTag(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto device_handle{rp.Pop<u64>()};
+ const auto break_type{rp.PopEnum<BreakType>()};
+ LOG_WARNING(Service_NFP, "(STUBBED) called, device_handle={}, break_type={}", device_handle,
+ break_type);
+
+ auto result = GetManager()->BreakTag(device_handle, break_type);
+ result = TranslateResultToServiceError(result);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+}
+
+void Interface::ReadBackupData(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto device_handle{rp.Pop<u64>()};
+ LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
+
+ std::vector<u8> backup_data{};
+ auto result = GetManager()->ReadBackupData(device_handle, backup_data);
+ result = TranslateResultToServiceError(result);
+
+ if (result.IsSuccess()) {
+ ctx.WriteBuffer(backup_data);
+ }
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+}
+
+void Interface::WriteBackupData(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto device_handle{rp.Pop<u64>()};
+ const auto backup_data_buffer{ctx.ReadBuffer()};
+ LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
+
+ auto result = GetManager()->WriteBackupData(device_handle, backup_data_buffer);
+ result = TranslateResultToServiceError(result);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+}
+
+void Interface::WriteNtf(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto device_handle{rp.Pop<u64>()};
+ const auto write_type{rp.PopEnum<WriteType>()};
+ const auto ntf_data_buffer{ctx.ReadBuffer()};
+ LOG_WARNING(Service_NFP, "(STUBBED) called, device_handle={}", device_handle);
+
+ auto result = GetManager()->WriteNtf(device_handle, write_type, ntf_data_buffer);
+ result = TranslateResultToServiceError(result);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+}
+
+} // namespace Service::NFP
diff --git a/src/core/hle/service/nfp/nfp_interface.h b/src/core/hle/service/nfp/nfp_interface.h
new file mode 100644
index 000000000..fa985b068
--- /dev/null
+++ b/src/core/hle/service/nfp/nfp_interface.h
@@ -0,0 +1,50 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "core/hle/service/kernel_helpers.h"
+#include "core/hle/service/nfc/nfc_interface.h"
+#include "core/hle/service/service.h"
+
+namespace Service::NFP {
+
+class Interface : public NFC::NfcInterface {
+public:
+ explicit Interface(Core::System& system_, const char* name);
+ ~Interface() override;
+
+ void InitializeSystem(HLERequestContext& ctx);
+ void InitializeDebug(HLERequestContext& ctx);
+ void FinalizeSystem(HLERequestContext& ctx);
+ void FinalizeDebug(HLERequestContext& ctx);
+ void Mount(HLERequestContext& ctx);
+ void Unmount(HLERequestContext& ctx);
+ void OpenApplicationArea(HLERequestContext& ctx);
+ void GetApplicationArea(HLERequestContext& ctx);
+ void SetApplicationArea(HLERequestContext& ctx);
+ void Flush(HLERequestContext& ctx);
+ void Restore(HLERequestContext& ctx);
+ void CreateApplicationArea(HLERequestContext& ctx);
+ void GetRegisterInfo(HLERequestContext& ctx);
+ void GetCommonInfo(HLERequestContext& ctx);
+ void GetModelInfo(HLERequestContext& ctx);
+ void GetApplicationAreaSize(HLERequestContext& ctx);
+ void RecreateApplicationArea(HLERequestContext& ctx);
+ void Format(HLERequestContext& ctx);
+ void GetAdminInfo(HLERequestContext& ctx);
+ void GetRegisterInfoPrivate(HLERequestContext& ctx);
+ void SetRegisterInfoPrivate(HLERequestContext& ctx);
+ void DeleteRegisterInfo(HLERequestContext& ctx);
+ void DeleteApplicationArea(HLERequestContext& ctx);
+ void ExistsApplicationArea(HLERequestContext& ctx);
+ void GetAll(HLERequestContext& ctx);
+ void SetAll(HLERequestContext& ctx);
+ void FlushDebug(HLERequestContext& ctx);
+ void BreakTag(HLERequestContext& ctx);
+ void ReadBackupData(HLERequestContext& ctx);
+ void WriteBackupData(HLERequestContext& ctx);
+ void WriteNtf(HLERequestContext& ctx);
+};
+
+} // namespace Service::NFP
diff --git a/src/core/hle/service/nfp/nfp_result.h b/src/core/hle/service/nfp/nfp_result.h
index d8e4cf094..618533843 100644
--- a/src/core/hle/service/nfp/nfp_result.h
+++ b/src/core/hle/service/nfp/nfp_result.h
@@ -1,5 +1,5 @@
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-3.0-or-later
+// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
@@ -7,18 +7,21 @@
namespace Service::NFP {
-constexpr Result DeviceNotFound(ErrorModule::NFP, 64);
-constexpr Result InvalidArgument(ErrorModule::NFP, 65);
-constexpr Result WrongApplicationAreaSize(ErrorModule::NFP, 68);
-constexpr Result WrongDeviceState(ErrorModule::NFP, 73);
-constexpr Result NfcDisabled(ErrorModule::NFP, 80);
-constexpr Result WriteAmiiboFailed(ErrorModule::NFP, 88);
-constexpr Result TagRemoved(ErrorModule::NFP, 97);
-constexpr Result RegistrationIsNotInitialized(ErrorModule::NFP, 120);
-constexpr Result ApplicationAreaIsNotInitialized(ErrorModule::NFP, 128);
-constexpr Result CorruptedData(ErrorModule::NFP, 144);
-constexpr Result WrongApplicationAreaId(ErrorModule::NFP, 152);
-constexpr Result ApplicationAreaExist(ErrorModule::NFP, 168);
-constexpr Result NotAnAmiibo(ErrorModule::NFP, 178);
+constexpr Result ResultDeviceNotFound(ErrorModule::NFP, 64);
+constexpr Result ResultInvalidArgument(ErrorModule::NFP, 65);
+constexpr Result ResultWrongApplicationAreaSize(ErrorModule::NFP, 68);
+constexpr Result ResultWrongDeviceState(ErrorModule::NFP, 73);
+constexpr Result ResultUnknown74(ErrorModule::NFC, 74);
+constexpr Result ResultNfcDisabled(ErrorModule::NFP, 80);
+constexpr Result ResultWriteAmiiboFailed(ErrorModule::NFP, 88);
+constexpr Result ResultTagRemoved(ErrorModule::NFP, 97);
+constexpr Result ResultRegistrationIsNotInitialized(ErrorModule::NFP, 120);
+constexpr Result ResultApplicationAreaIsNotInitialized(ErrorModule::NFP, 128);
+constexpr Result ResultCorruptedDataWithBackup(ErrorModule::NFP, 136);
+constexpr Result ResultCorruptedData(ErrorModule::NFP, 144);
+constexpr Result ResultWrongApplicationAreaId(ErrorModule::NFP, 152);
+constexpr Result ResultApplicationAreaExist(ErrorModule::NFP, 168);
+constexpr Result ResultNotAnAmiibo(ErrorModule::NFP, 178);
+constexpr Result ResultUnableToAccessBackupFile(ErrorModule::NFP, 200);
} // namespace Service::NFP
diff --git a/src/core/hle/service/nfp/nfp_types.h b/src/core/hle/service/nfp/nfp_types.h
index fc228c2b2..aed12a7f8 100644
--- a/src/core/hle/service/nfp/nfp_types.h
+++ b/src/core/hle/service/nfp/nfp_types.h
@@ -7,30 +7,19 @@
#include "common/swap.h"
#include "core/hle/service/mii/types.h"
+#include "core/hle/service/nfc/nfc_types.h"
namespace Service::NFP {
static constexpr std::size_t amiibo_name_length = 0xA;
+static constexpr std::size_t application_id_version_offset = 0x1c;
+static constexpr std::size_t counter_limit = 0xffff;
-enum class ServiceType : u32 {
- User,
- Debug,
- System,
-};
-
-enum class DeviceState : u32 {
- Initialized,
- SearchingForTag,
- TagFound,
- TagRemoved,
- TagMounted,
- Unavailable,
- Finalized,
-};
-
+// This is nn::nfp::ModelType
enum class ModelType : u32 {
Amiibo,
};
+// This is nn::nfp::MountTarget
enum class MountTarget : u32 {
None,
Rom,
@@ -70,33 +59,23 @@ enum class AmiiboSeries : u8 {
Diablo,
};
-enum class TagType : u32 {
- None,
- Type1, // ISO14443A RW 96-2k bytes 106kbit/s
- Type2, // ISO14443A RW/RO 540 bytes 106kbit/s
- Type3, // Sony Felica RW/RO 2k bytes 212kbit/s
- Type4, // ISO14443A RW/RO 4k-32k bytes 424kbit/s
- Type5, // ISO15693 RW/RO 540 bytes 106kbit/s
+enum class AppAreaVersion : u8 {
+ Nintendo3DS = 0,
+ NintendoWiiU = 1,
+ Nintendo3DSv2 = 2,
+ NintendoSwitch = 3,
+ NotSet = 0xFF,
};
-enum class PackedTagType : u8 {
- None,
- Type1, // ISO14443A RW 96-2k bytes 106kbit/s
- Type2, // ISO14443A RW/RO 540 bytes 106kbit/s
- Type3, // Sony Felica RW/RO 2k bytes 212kbit/s
- Type4, // ISO14443A RW/RO 4k-32k bytes 424kbit/s
- Type5, // ISO15693 RW/RO 540 bytes 106kbit/s
+enum class BreakType : u32 {
+ Normal,
+ Unknown1,
+ Unknown2,
};
-// Verify this enum. It might be completely wrong default protocol is 0x48
-enum class TagProtocol : u32 {
- None,
- TypeA = 1U << 0, // ISO14443A
- TypeB = 1U << 1, // ISO14443B
- TypeF = 1U << 2, // Sony Felica
- Unknown1 = 1U << 3,
- Unknown2 = 1U << 5,
- All = 0xFFFFFFFFU,
+enum class WriteType : u32 {
+ Unknown0,
+ Unknown1,
};
enum class CabinetMode : u8 {
@@ -106,31 +85,28 @@ enum class CabinetMode : u8 {
StartFormatter,
};
-enum class MifareCmd : u8 {
- AuthA = 0x60,
- AuthB = 0x61,
- Read = 0x30,
- Write = 0xA0,
- Transfer = 0xB0,
- Decrement = 0xC0,
- Increment = 0xC1,
- Store = 0xC2
-};
-
-using UniqueSerialNumber = std::array<u8, 7>;
-using LockBytes = std::array<u8, 2>;
+using UuidPart = std::array<u8, 3>;
using HashData = std::array<u8, 0x20>;
using ApplicationArea = std::array<u8, 0xD8>;
using AmiiboName = std::array<char, (amiibo_name_length * 4) + 1>;
-using DataBlock = std::array<u8, 0x10>;
-using KeyData = std::array<u8, 0x6>;
+
+// This is nn::nfp::TagInfo
+using TagInfo = NFC::TagInfo;
+
+struct NtagTagUuid {
+ UuidPart part1;
+ UuidPart part2;
+ u8 nintendo_id;
+};
+static_assert(sizeof(NtagTagUuid) == 7, "NtagTagUuid is an invalid size");
struct TagUuid {
- UniqueSerialNumber uid;
+ UuidPart part1;
+ u8 crc_check1;
+ UuidPart part2;
u8 nintendo_id;
- LockBytes lock_bytes;
};
-static_assert(sizeof(TagUuid) == 10, "TagUuid is an invalid size");
+static_assert(sizeof(TagUuid) == 8, "TagUuid is an invalid size");
struct WriteDate {
u16 year;
@@ -171,6 +147,12 @@ struct AmiiboDate {
};
}
+ void SetWriteDate(const WriteDate& write_date) {
+ SetYear(write_date.year);
+ SetMonth(write_date.month);
+ SetDay(write_date.day);
+ }
+
void SetYear(u16 year) {
const u16 year_converted = static_cast<u16>((year - 2000) << 9);
raw_date = Common::swap16((GetValue() & ~0xFE00) | year_converted);
@@ -197,6 +179,7 @@ struct Settings {
union {
u8 raw{};
+ BitField<0, 4, u8> font_region;
BitField<4, 1, u8> amiibo_initialized;
BitField<5, 1, u8> appdata_initialized;
};
@@ -220,7 +203,7 @@ struct AmiiboModelInfo {
AmiiboType amiibo_type;
u16_be model_number;
AmiiboSeries series;
- PackedTagType tag_type;
+ NFC::PackedTagType tag_type;
INSERT_PADDING_BYTES(0x4); // Unknown
};
static_assert(sizeof(AmiiboModelInfo) == 0xC, "AmiiboModelInfo is an invalid size");
@@ -236,41 +219,47 @@ static_assert(sizeof(NTAG215Password) == 0x8, "NTAG215Password is an invalid siz
struct EncryptedAmiiboFile {
u8 constant_value; // Must be A5
u16_be write_counter; // Number of times the amiibo has been written?
- INSERT_PADDING_BYTES(0x1); // Unknown 1
+ u8 amiibo_version; // Amiibo file version
AmiiboSettings settings; // Encrypted amiibo settings
HashData hmac_tag; // Hash
AmiiboModelInfo model_info; // Encrypted amiibo model info
HashData keygen_salt; // Salt
HashData hmac_data; // Hash
Service::Mii::Ver3StoreData owner_mii; // Encrypted Mii data
- u64_be title_id; // Encrypted Game id
- u16_be applicaton_write_counter; // Encrypted Counter
+ u64_be application_id; // Encrypted Game id
+ u16_be application_write_counter; // Encrypted Counter
u32_be application_area_id; // Encrypted Game id
- std::array<u8, 0x2> unknown;
- std::array<u32, 0x8> unknown2;
+ u8 application_id_byte;
+ u8 unknown;
+ Service::Mii::NfpStoreDataExtension mii_extension;
+ std::array<u32, 0x5> unknown2;
+ u32_be register_info_crc;
ApplicationArea application_area; // Encrypted Game data
};
static_assert(sizeof(EncryptedAmiiboFile) == 0x1F8, "AmiiboFile is an invalid size");
struct NTAG215File {
- LockBytes lock_bytes; // Tag UUID
+ u8 uid_crc_check2;
+ u8 internal_number;
u16 static_lock; // Set defined pages as read only
u32 compability_container; // Defines available memory
HashData hmac_data; // Hash
u8 constant_value; // Must be A5
u16_be write_counter; // Number of times the amiibo has been written?
- INSERT_PADDING_BYTES(0x1); // Unknown 1
+ u8 amiibo_version; // Amiibo file version
AmiiboSettings settings;
- Service::Mii::Ver3StoreData owner_mii; // Encrypted Mii data
- u64_be title_id;
- u16_be applicaton_write_counter; // Encrypted Counter
+ Service::Mii::Ver3StoreData owner_mii; // Mii data
+ u64_be application_id; // Game id
+ u16_be application_write_counter; // Counter
u32_be application_area_id;
- std::array<u8, 0x2> unknown;
- std::array<u32, 0x8> unknown2;
+ u8 application_id_byte;
+ u8 unknown;
+ Service::Mii::NfpStoreDataExtension mii_extension;
+ std::array<u32, 0x5> unknown2;
+ u32_be register_info_crc;
ApplicationArea application_area; // Encrypted Game data
HashData hmac_tag; // Hash
- UniqueSerialNumber uid; // Unique serial number
- u8 nintendo_id; // Tag UUID
+ TagUuid uid;
AmiiboModelInfo model_info;
HashData keygen_salt; // Salt
u32 dynamic_lock; // Dynamic lock
@@ -283,7 +272,9 @@ static_assert(std::is_trivially_copyable_v<NTAG215File>, "NTAG215File must be tr
#pragma pack()
struct EncryptedNTAG215File {
- TagUuid uuid; // Unique serial number
+ TagUuid uuid;
+ u8 uuid_crc_check2;
+ u8 internal_number;
u16 static_lock; // Set defined pages as read only
u32 compability_container; // Defines available memory
EncryptedAmiiboFile user_memory; // Writable data
@@ -292,21 +283,12 @@ struct EncryptedNTAG215File {
u32 CFG1; // Defines number of verification attempts
NTAG215Password password; // Password data
};
-static_assert(sizeof(EncryptedNTAG215File) == 0x21C, "EncryptedNTAG215File is an invalid size");
+static_assert(sizeof(EncryptedNTAG215File) == sizeof(NTAG215File),
+ "EncryptedNTAG215File is an invalid size");
static_assert(std::is_trivially_copyable_v<EncryptedNTAG215File>,
"EncryptedNTAG215File must be trivially copyable.");
-struct TagInfo {
- UniqueSerialNumber uuid;
- INSERT_PADDING_BYTES(0x3);
- u8 uuid_length;
- INSERT_PADDING_BYTES(0x15);
- TagProtocol protocol;
- TagType tag_type;
- INSERT_PADDING_BYTES(0x30);
-};
-static_assert(sizeof(TagInfo) == 0x58, "TagInfo is an invalid size");
-
+// This is nn::nfp::CommonInfo
struct CommonInfo {
WriteDate last_write_date;
u16 write_counter;
@@ -317,6 +299,7 @@ struct CommonInfo {
};
static_assert(sizeof(CommonInfo) == 0x40, "CommonInfo is an invalid size");
+// This is nn::nfp::ModelInfo
struct ModelInfo {
u16 character_id;
u8 character_variant;
@@ -327,6 +310,7 @@ struct ModelInfo {
};
static_assert(sizeof(ModelInfo) == 0x40, "ModelInfo is an invalid size");
+// This is nn::nfp::RegisterInfo
struct RegisterInfo {
Service::Mii::CharInfo mii_char_info;
WriteDate creation_date;
@@ -336,37 +320,60 @@ struct RegisterInfo {
};
static_assert(sizeof(RegisterInfo) == 0x100, "RegisterInfo is an invalid size");
-struct SectorKey {
- MifareCmd command;
- u8 unknown; // Usually 1
- INSERT_PADDING_BYTES(0x6);
- KeyData sector_key;
- INSERT_PADDING_BYTES(0x2);
-};
-static_assert(sizeof(SectorKey) == 0x10, "SectorKey is an invalid size");
-
-struct MifareReadBlockParameter {
- u8 sector_number;
- INSERT_PADDING_BYTES(0x7);
- SectorKey sector_key;
+// This is nn::nfp::RegisterInfoPrivate
+struct RegisterInfoPrivate {
+ Service::Mii::MiiStoreData mii_store_data;
+ WriteDate creation_date;
+ AmiiboName amiibo_name;
+ u8 font_region;
+ INSERT_PADDING_BYTES(0x8E);
};
-static_assert(sizeof(MifareReadBlockParameter) == 0x18,
- "MifareReadBlockParameter is an invalid size");
-
-struct MifareReadBlockData {
- DataBlock data;
- u8 sector_number;
+static_assert(sizeof(RegisterInfoPrivate) == 0x100, "RegisterInfoPrivate is an invalid size");
+
+// This is nn::nfp::AdminInfo
+struct AdminInfo {
+ u64 application_id;
+ u32 application_area_id;
+ u16 crc_change_counter;
+ u8 flags;
+ NFC::PackedTagType tag_type;
+ AppAreaVersion app_area_version;
INSERT_PADDING_BYTES(0x7);
+ INSERT_PADDING_BYTES(0x28);
};
-static_assert(sizeof(MifareReadBlockData) == 0x18, "MifareReadBlockData is an invalid size");
+static_assert(sizeof(AdminInfo) == 0x40, "AdminInfo is an invalid size");
-struct MifareWriteBlockParameter {
- DataBlock data;
- u8 sector_number;
- INSERT_PADDING_BYTES(0x7);
- SectorKey sector_key;
+#pragma pack(1)
+// This is nn::nfp::NfpData
+struct NfpData {
+ u8 magic;
+ INSERT_PADDING_BYTES(0x1);
+ u8 write_counter;
+ INSERT_PADDING_BYTES(0x1);
+ u32 settings_crc;
+ INSERT_PADDING_BYTES(0x38);
+ CommonInfo common_info;
+ Service::Mii::Ver3StoreData mii_char_info;
+ Service::Mii::NfpStoreDataExtension mii_store_data_extension;
+ WriteDate creation_date;
+ std::array<u16_be, amiibo_name_length> amiibo_name;
+ u16 amiibo_name_null_terminated;
+ Settings settings;
+ u8 unknown1;
+ u32 register_info_crc;
+ std::array<u32, 5> unknown2;
+ INSERT_PADDING_BYTES(0x64);
+ u64 application_id;
+ u32 access_id;
+ u16 settings_crc_counter;
+ u8 font_region;
+ NFC::PackedTagType tag_type;
+ AppAreaVersion console_type;
+ u8 application_id_byte;
+ INSERT_PADDING_BYTES(0x2E);
+ ApplicationArea application_area;
};
-static_assert(sizeof(MifareWriteBlockParameter) == 0x28,
- "MifareWriteBlockParameter is an invalid size");
+static_assert(sizeof(NfpData) == 0x298, "NfpData is an invalid size");
+#pragma pack()
} // namespace Service::NFP
diff --git a/src/core/hle/service/nfp/nfp_user.cpp b/src/core/hle/service/nfp/nfp_user.cpp
deleted file mode 100644
index a4d3d1bc7..000000000
--- a/src/core/hle/service/nfp/nfp_user.cpp
+++ /dev/null
@@ -1,672 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#include "common/logging/log.h"
-#include "core/core.h"
-#include "core/hid/hid_types.h"
-#include "core/hle/ipc_helpers.h"
-#include "core/hle/kernel/k_event.h"
-#include "core/hle/service/nfp/nfp_device.h"
-#include "core/hle/service/nfp/nfp_result.h"
-#include "core/hle/service/nfp/nfp_user.h"
-
-namespace Service::NFP {
-
-IUser::IUser(Core::System& system_)
- : ServiceFramework{system_, "NFP::IUser"}, service_context{system_, service_name} {
- static const FunctionInfo functions[] = {
- {0, &IUser::Initialize, "Initialize"},
- {1, &IUser::Finalize, "Finalize"},
- {2, &IUser::ListDevices, "ListDevices"},
- {3, &IUser::StartDetection, "StartDetection"},
- {4, &IUser::StopDetection, "StopDetection"},
- {5, &IUser::Mount, "Mount"},
- {6, &IUser::Unmount, "Unmount"},
- {7, &IUser::OpenApplicationArea, "OpenApplicationArea"},
- {8, &IUser::GetApplicationArea, "GetApplicationArea"},
- {9, &IUser::SetApplicationArea, "SetApplicationArea"},
- {10, &IUser::Flush, "Flush"},
- {11, &IUser::Restore, "Restore"},
- {12, &IUser::CreateApplicationArea, "CreateApplicationArea"},
- {13, &IUser::GetTagInfo, "GetTagInfo"},
- {14, &IUser::GetRegisterInfo, "GetRegisterInfo"},
- {15, &IUser::GetCommonInfo, "GetCommonInfo"},
- {16, &IUser::GetModelInfo, "GetModelInfo"},
- {17, &IUser::AttachActivateEvent, "AttachActivateEvent"},
- {18, &IUser::AttachDeactivateEvent, "AttachDeactivateEvent"},
- {19, &IUser::GetState, "GetState"},
- {20, &IUser::GetDeviceState, "GetDeviceState"},
- {21, &IUser::GetNpadId, "GetNpadId"},
- {22, &IUser::GetApplicationAreaSize, "GetApplicationAreaSize"},
- {23, &IUser::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"},
- {24, &IUser::RecreateApplicationArea, "RecreateApplicationArea"},
- };
- RegisterHandlers(functions);
-
- availability_change_event = service_context.CreateEvent("IUser:AvailabilityChangeEvent");
-
- for (u32 device_index = 0; device_index < 10; device_index++) {
- devices[device_index] =
- std::make_shared<NfpDevice>(Core::HID::IndexToNpadIdType(device_index), system,
- service_context, availability_change_event);
- }
-}
-
-IUser ::~IUser() {
- availability_change_event->Close();
-}
-
-void IUser::Initialize(Kernel::HLERequestContext& ctx) {
- LOG_INFO(Service_NFP, "called");
-
- state = State::Initialized;
-
- for (auto& device : devices) {
- device->Initialize();
- }
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void IUser::Finalize(Kernel::HLERequestContext& ctx) {
- LOG_INFO(Service_NFP, "called");
-
- state = State::NonInitialized;
-
- for (auto& device : devices) {
- device->Finalize();
- }
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void IUser::ListDevices(Kernel::HLERequestContext& ctx) {
- LOG_DEBUG(Service_NFP, "called");
-
- if (state == State::NonInitialized) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(NfcDisabled);
- return;
- }
-
- if (!ctx.CanWriteBuffer()) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(InvalidArgument);
- return;
- }
-
- if (ctx.GetWriteBufferSize() == 0) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(InvalidArgument);
- return;
- }
-
- std::vector<u64> nfp_devices;
- const std::size_t max_allowed_devices = ctx.GetWriteBufferNumElements<u64>();
-
- for (const auto& device : devices) {
- if (nfp_devices.size() >= max_allowed_devices) {
- continue;
- }
- if (device->GetCurrentState() != DeviceState::Unavailable) {
- nfp_devices.push_back(device->GetHandle());
- }
- }
-
- if (nfp_devices.empty()) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(DeviceNotFound);
- return;
- }
-
- ctx.WriteBuffer(nfp_devices);
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push(static_cast<s32>(nfp_devices.size()));
-}
-
-void IUser::StartDetection(Kernel::HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto device_handle{rp.Pop<u64>()};
- const auto nfp_protocol{rp.PopEnum<TagProtocol>()};
- LOG_INFO(Service_NFP, "called, device_handle={}, nfp_protocol={}", device_handle, nfp_protocol);
-
- if (state == State::NonInitialized) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(NfcDisabled);
- return;
- }
-
- auto device = GetNfpDevice(device_handle);
-
- if (!device.has_value()) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(DeviceNotFound);
- return;
- }
-
- const auto result = device.value()->StartDetection(nfp_protocol);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
-}
-
-void IUser::StopDetection(Kernel::HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto device_handle{rp.Pop<u64>()};
- LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
-
- if (state == State::NonInitialized) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(NfcDisabled);
- return;
- }
-
- auto device = GetNfpDevice(device_handle);
-
- if (!device.has_value()) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(DeviceNotFound);
- return;
- }
-
- const auto result = device.value()->StopDetection();
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
-}
-
-void IUser::Mount(Kernel::HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto device_handle{rp.Pop<u64>()};
- const auto model_type{rp.PopEnum<ModelType>()};
- const auto mount_target{rp.PopEnum<MountTarget>()};
- LOG_INFO(Service_NFP, "called, device_handle={}, model_type={}, mount_target={}", device_handle,
- model_type, mount_target);
-
- if (state == State::NonInitialized) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(NfcDisabled);
- return;
- }
-
- auto device = GetNfpDevice(device_handle);
-
- if (!device.has_value()) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(DeviceNotFound);
- return;
- }
-
- const auto result = device.value()->Mount(mount_target);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
-}
-
-void IUser::Unmount(Kernel::HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto device_handle{rp.Pop<u64>()};
- LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
-
- if (state == State::NonInitialized) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(NfcDisabled);
- return;
- }
-
- auto device = GetNfpDevice(device_handle);
-
- if (!device.has_value()) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(DeviceNotFound);
- return;
- }
-
- const auto result = device.value()->Unmount();
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
-}
-
-void IUser::OpenApplicationArea(Kernel::HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto device_handle{rp.Pop<u64>()};
- const auto access_id{rp.Pop<u32>()};
- LOG_INFO(Service_NFP, "called, device_handle={}, access_id={}", device_handle, access_id);
-
- if (state == State::NonInitialized) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(NfcDisabled);
- return;
- }
-
- auto device = GetNfpDevice(device_handle);
-
- if (!device.has_value()) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(DeviceNotFound);
- return;
- }
-
- const auto result = device.value()->OpenApplicationArea(access_id);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
-}
-
-void IUser::GetApplicationArea(Kernel::HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto device_handle{rp.Pop<u64>()};
- const auto data_size = ctx.GetWriteBufferSize();
- LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
-
- if (state == State::NonInitialized) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(NfcDisabled);
- return;
- }
-
- if (!ctx.CanWriteBuffer()) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(InvalidArgument);
- return;
- }
-
- auto device = GetNfpDevice(device_handle);
-
- if (!device.has_value()) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(DeviceNotFound);
- return;
- }
-
- std::vector<u8> data(data_size);
- const auto result = device.value()->GetApplicationArea(data);
- ctx.WriteBuffer(data);
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(result);
- rb.Push(static_cast<u32>(data_size));
-}
-
-void IUser::SetApplicationArea(Kernel::HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto device_handle{rp.Pop<u64>()};
- const auto data{ctx.ReadBuffer()};
- LOG_INFO(Service_NFP, "called, device_handle={}, data_size={}", device_handle, data.size());
-
- if (state == State::NonInitialized) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(NfcDisabled);
- return;
- }
-
- if (!ctx.CanReadBuffer()) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(InvalidArgument);
- return;
- }
-
- auto device = GetNfpDevice(device_handle);
-
- if (!device.has_value()) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(DeviceNotFound);
- return;
- }
-
- const auto result = device.value()->SetApplicationArea(data);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
-}
-
-void IUser::Flush(Kernel::HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto device_handle{rp.Pop<u64>()};
- LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
-
- if (state == State::NonInitialized) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(NfcDisabled);
- return;
- }
-
- auto device = GetNfpDevice(device_handle);
-
- if (!device.has_value()) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(DeviceNotFound);
- return;
- }
-
- const auto result = device.value()->Flush();
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
-}
-
-void IUser::Restore(Kernel::HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto device_handle{rp.Pop<u64>()};
- LOG_WARNING(Service_NFP, "(STUBBED) called, device_handle={}", device_handle);
-
- if (state == State::NonInitialized) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(NfcDisabled);
- return;
- }
-
- auto device = GetNfpDevice(device_handle);
-
- if (!device.has_value()) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(DeviceNotFound);
- return;
- }
-
- const auto result = device.value()->RestoreAmiibo();
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
-}
-
-void IUser::CreateApplicationArea(Kernel::HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto device_handle{rp.Pop<u64>()};
- const auto access_id{rp.Pop<u32>()};
- const auto data{ctx.ReadBuffer()};
- LOG_INFO(Service_NFP, "called, device_handle={}, data_size={}, access_id={}", device_handle,
- access_id, data.size());
-
- if (state == State::NonInitialized) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(NfcDisabled);
- return;
- }
-
- if (!ctx.CanReadBuffer()) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(InvalidArgument);
- return;
- }
-
- auto device = GetNfpDevice(device_handle);
-
- if (!device.has_value()) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(DeviceNotFound);
- return;
- }
-
- const auto result = device.value()->CreateApplicationArea(access_id, data);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
-}
-
-void IUser::GetTagInfo(Kernel::HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto device_handle{rp.Pop<u64>()};
- LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
-
- if (state == State::NonInitialized) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(NfcDisabled);
- return;
- }
-
- auto device = GetNfpDevice(device_handle);
-
- if (!device.has_value()) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(DeviceNotFound);
- return;
- }
-
- TagInfo tag_info{};
- const auto result = device.value()->GetTagInfo(tag_info);
- ctx.WriteBuffer(tag_info);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
-}
-
-void IUser::GetRegisterInfo(Kernel::HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto device_handle{rp.Pop<u64>()};
- LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
-
- if (state == State::NonInitialized) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(NfcDisabled);
- return;
- }
-
- auto device = GetNfpDevice(device_handle);
-
- if (!device.has_value()) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(DeviceNotFound);
- return;
- }
-
- RegisterInfo register_info{};
- const auto result = device.value()->GetRegisterInfo(register_info);
- ctx.WriteBuffer(register_info);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
-}
-
-void IUser::GetCommonInfo(Kernel::HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto device_handle{rp.Pop<u64>()};
- LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
-
- if (state == State::NonInitialized) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(NfcDisabled);
- return;
- }
-
- auto device = GetNfpDevice(device_handle);
-
- if (!device.has_value()) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(DeviceNotFound);
- return;
- }
-
- CommonInfo common_info{};
- const auto result = device.value()->GetCommonInfo(common_info);
- ctx.WriteBuffer(common_info);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
-}
-
-void IUser::GetModelInfo(Kernel::HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto device_handle{rp.Pop<u64>()};
- LOG_INFO(Service_NFP, "called, device_handle={}", device_handle);
-
- if (state == State::NonInitialized) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(NfcDisabled);
- return;
- }
-
- auto device = GetNfpDevice(device_handle);
-
- if (!device.has_value()) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(DeviceNotFound);
- return;
- }
-
- ModelInfo model_info{};
- const auto result = device.value()->GetModelInfo(model_info);
- ctx.WriteBuffer(model_info);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
-}
-
-void IUser::AttachActivateEvent(Kernel::HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto device_handle{rp.Pop<u64>()};
- LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle);
-
- if (state == State::NonInitialized) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(NfcDisabled);
- return;
- }
-
- auto device = GetNfpDevice(device_handle);
-
- if (!device.has_value()) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(DeviceNotFound);
- return;
- }
-
- IPC::ResponseBuilder rb{ctx, 2, 1};
- rb.Push(ResultSuccess);
- rb.PushCopyObjects(device.value()->GetActivateEvent());
-}
-
-void IUser::AttachDeactivateEvent(Kernel::HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto device_handle{rp.Pop<u64>()};
- LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle);
-
- if (state == State::NonInitialized) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(NfcDisabled);
- return;
- }
-
- auto device = GetNfpDevice(device_handle);
-
- if (!device.has_value()) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(DeviceNotFound);
- return;
- }
-
- IPC::ResponseBuilder rb{ctx, 2, 1};
- rb.Push(ResultSuccess);
- rb.PushCopyObjects(device.value()->GetDeactivateEvent());
-}
-
-void IUser::GetState(Kernel::HLERequestContext& ctx) {
- LOG_DEBUG(Service_NFP, "called");
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.PushEnum(state);
-}
-
-void IUser::GetDeviceState(Kernel::HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto device_handle{rp.Pop<u64>()};
- LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle);
-
- auto device = GetNfpDevice(device_handle);
-
- if (!device.has_value()) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(DeviceNotFound);
- return;
- }
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.PushEnum(device.value()->GetCurrentState());
-}
-
-void IUser::GetNpadId(Kernel::HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto device_handle{rp.Pop<u64>()};
- LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle);
-
- if (state == State::NonInitialized) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(NfcDisabled);
- return;
- }
-
- auto device = GetNfpDevice(device_handle);
-
- if (!device.has_value()) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(DeviceNotFound);
- return;
- }
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.PushEnum(device.value()->GetNpadId());
-}
-
-void IUser::GetApplicationAreaSize(Kernel::HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto device_handle{rp.Pop<u64>()};
- LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle);
-
- auto device = GetNfpDevice(device_handle);
-
- if (!device.has_value()) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(DeviceNotFound);
- return;
- }
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push(device.value()->GetApplicationAreaSize());
-}
-
-void IUser::AttachAvailabilityChangeEvent(Kernel::HLERequestContext& ctx) {
- LOG_INFO(Service_NFP, "called");
-
- if (state == State::NonInitialized) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(NfcDisabled);
- return;
- }
-
- IPC::ResponseBuilder rb{ctx, 2, 1};
- rb.Push(ResultSuccess);
- rb.PushCopyObjects(availability_change_event->GetReadableEvent());
-}
-
-void IUser::RecreateApplicationArea(Kernel::HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto device_handle{rp.Pop<u64>()};
- const auto access_id{rp.Pop<u32>()};
- const auto data{ctx.ReadBuffer()};
- LOG_INFO(Service_NFP, "called, device_handle={}, data_size={}, access_id={}", device_handle,
- access_id, data.size());
-
- if (state == State::NonInitialized) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(NfcDisabled);
- return;
- }
-
- auto device = GetNfpDevice(device_handle);
-
- if (!device.has_value()) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(DeviceNotFound);
- return;
- }
-
- const auto result = device.value()->RecreateApplicationArea(access_id, data);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
-}
-
-std::optional<std::shared_ptr<NfpDevice>> IUser::GetNfpDevice(u64 handle) {
- for (auto& device : devices) {
- if (device->GetHandle() == handle) {
- return device;
- }
- }
- return std::nullopt;
-}
-
-} // namespace Service::NFP
diff --git a/src/core/hle/service/nfp/nfp_user.h b/src/core/hle/service/nfp/nfp_user.h
deleted file mode 100644
index 7e9a90af8..000000000
--- a/src/core/hle/service/nfp/nfp_user.h
+++ /dev/null
@@ -1,63 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#pragma once
-
-#include <array>
-#include <memory>
-#include <optional>
-
-#include "core/hle/service/kernel_helpers.h"
-#include "core/hle/service/service.h"
-
-namespace Service::NFP {
-class NfpDevice;
-
-class IUser final : public ServiceFramework<IUser> {
-public:
- explicit IUser(Core::System& system_);
- ~IUser();
-
-private:
- enum class State : u32 {
- NonInitialized,
- Initialized,
- };
-
- void Initialize(Kernel::HLERequestContext& ctx);
- void Finalize(Kernel::HLERequestContext& ctx);
- void ListDevices(Kernel::HLERequestContext& ctx);
- void StartDetection(Kernel::HLERequestContext& ctx);
- void StopDetection(Kernel::HLERequestContext& ctx);
- void Mount(Kernel::HLERequestContext& ctx);
- void Unmount(Kernel::HLERequestContext& ctx);
- void OpenApplicationArea(Kernel::HLERequestContext& ctx);
- void GetApplicationArea(Kernel::HLERequestContext& ctx);
- void SetApplicationArea(Kernel::HLERequestContext& ctx);
- void Flush(Kernel::HLERequestContext& ctx);
- void Restore(Kernel::HLERequestContext& ctx);
- void CreateApplicationArea(Kernel::HLERequestContext& ctx);
- void GetTagInfo(Kernel::HLERequestContext& ctx);
- void GetRegisterInfo(Kernel::HLERequestContext& ctx);
- void GetCommonInfo(Kernel::HLERequestContext& ctx);
- void GetModelInfo(Kernel::HLERequestContext& ctx);
- void AttachActivateEvent(Kernel::HLERequestContext& ctx);
- void AttachDeactivateEvent(Kernel::HLERequestContext& ctx);
- void GetState(Kernel::HLERequestContext& ctx);
- void GetDeviceState(Kernel::HLERequestContext& ctx);
- void GetNpadId(Kernel::HLERequestContext& ctx);
- void GetApplicationAreaSize(Kernel::HLERequestContext& ctx);
- void AttachAvailabilityChangeEvent(Kernel::HLERequestContext& ctx);
- void RecreateApplicationArea(Kernel::HLERequestContext& ctx);
-
- std::optional<std::shared_ptr<NfpDevice>> GetNfpDevice(u64 handle);
-
- KernelHelpers::ServiceContext service_context;
-
- std::array<std::shared_ptr<NfpDevice>, 10> devices{};
-
- State state{State::NonInitialized};
- Kernel::KEvent* availability_change_event;
-};
-
-} // namespace Service::NFP
diff --git a/src/core/hle/service/ngct/ngct.cpp b/src/core/hle/service/ngct/ngct.cpp
index 8af8a835d..493c80ed2 100644
--- a/src/core/hle/service/ngct/ngct.cpp
+++ b/src/core/hle/service/ngct/ngct.cpp
@@ -3,8 +3,9 @@
#include "common/string_util.h"
#include "core/core.h"
-#include "core/hle/ipc_helpers.h"
+#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/ngct/ngct.h"
+#include "core/hle/service/server_manager.h"
#include "core/hle/service/service.h"
namespace Service::NGCT {
@@ -23,7 +24,7 @@ public:
}
private:
- void Match(Kernel::HLERequestContext& ctx) {
+ void Match(HLERequestContext& ctx) {
const auto buffer = ctx.ReadBuffer();
const auto text = Common::StringFromFixedZeroTerminatedBuffer(
reinterpret_cast<const char*>(buffer.data()), buffer.size());
@@ -36,7 +37,7 @@ private:
rb.Push(false);
}
- void Filter(Kernel::HLERequestContext& ctx) {
+ void Filter(HLERequestContext& ctx) {
const auto buffer = ctx.ReadBuffer();
const auto text = Common::StringFromFixedZeroTerminatedBuffer(
reinterpret_cast<const char*>(buffer.data()), buffer.size());
@@ -51,8 +52,11 @@ private:
}
};
-void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
- std::make_shared<IService>(system)->InstallAsService(system.ServiceManager());
+void LoopProcess(Core::System& system) {
+ auto server_manager = std::make_unique<ServerManager>(system);
+
+ server_manager->RegisterNamedService("ngct:u", std::make_shared<IService>(system));
+ ServerManager::RunServer(std::move(server_manager));
}
} // namespace Service::NGCT
diff --git a/src/core/hle/service/ngct/ngct.h b/src/core/hle/service/ngct/ngct.h
index 370bd4a25..27c34dad4 100644
--- a/src/core/hle/service/ngct/ngct.h
+++ b/src/core/hle/service/ngct/ngct.h
@@ -7,13 +7,8 @@ namespace Core {
class System;
}
-namespace Service::SM {
-class ServiceManager;
-}
-
namespace Service::NGCT {
-/// Registers all NGCT services with the specified service manager.
-void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system);
+void LoopProcess(Core::System& system);
} // namespace Service::NGCT
diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp
index 5d32adf64..91d42853e 100644
--- a/src/core/hle/service/nifm/nifm.cpp
+++ b/src/core/hle/service/nifm/nifm.cpp
@@ -2,10 +2,11 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/core.h"
-#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/k_event.h"
+#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/nifm/nifm.h"
+#include "core/hle/service/server_manager.h"
namespace {
@@ -216,8 +217,8 @@ public:
}
private:
- void Submit(Kernel::HLERequestContext& ctx) {
- LOG_WARNING(Service_NIFM, "(STUBBED) called");
+ void Submit(HLERequestContext& ctx) {
+ LOG_DEBUG(Service_NIFM, "(STUBBED) called");
if (state == RequestState::NotSubmitted) {
UpdateState(RequestState::OnHold);
@@ -227,16 +228,16 @@ private:
rb.Push(ResultSuccess);
}
- void GetRequestState(Kernel::HLERequestContext& ctx) {
- LOG_WARNING(Service_NIFM, "(STUBBED) called");
+ void GetRequestState(HLERequestContext& ctx) {
+ LOG_DEBUG(Service_NIFM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.PushEnum(state);
}
- void GetResult(Kernel::HLERequestContext& ctx) {
- LOG_WARNING(Service_NIFM, "(STUBBED) called");
+ void GetResult(HLERequestContext& ctx) {
+ LOG_DEBUG(Service_NIFM, "(STUBBED) called");
const auto result = [this] {
const auto has_connection = Network::GetHostIPv4Address().has_value();
@@ -260,7 +261,7 @@ private:
rb.Push(result);
}
- void GetSystemEventReadableHandles(Kernel::HLERequestContext& ctx) {
+ void GetSystemEventReadableHandles(HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2, 2};
@@ -268,21 +269,21 @@ private:
rb.PushCopyObjects(event1->GetReadableEvent(), event2->GetReadableEvent());
}
- void Cancel(Kernel::HLERequestContext& ctx) {
+ void Cancel(HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
- void SetConnectionConfirmationOption(Kernel::HLERequestContext& ctx) {
+ void SetConnectionConfirmationOption(HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
- void GetAppletInfo(Kernel::HLERequestContext& ctx) {
+ void GetAppletInfo(HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
std::vector<u8> out_buffer(ctx.GetWriteBufferSize());
@@ -321,7 +322,7 @@ public:
}
};
-void IGeneralService::GetClientId(Kernel::HLERequestContext& ctx) {
+void IGeneralService::GetClientId(HLERequestContext& ctx) {
static constexpr u32 client_id = 1;
LOG_WARNING(Service_NIFM, "(STUBBED) called");
@@ -330,7 +331,7 @@ void IGeneralService::GetClientId(Kernel::HLERequestContext& ctx) {
rb.Push<u64>(client_id); // Client ID needs to be non zero otherwise it's considered invalid
}
-void IGeneralService::CreateScanRequest(Kernel::HLERequestContext& ctx) {
+void IGeneralService::CreateScanRequest(HLERequestContext& ctx) {
LOG_DEBUG(Service_NIFM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -339,7 +340,7 @@ void IGeneralService::CreateScanRequest(Kernel::HLERequestContext& ctx) {
rb.PushIpcInterface<IScanRequest>(system);
}
-void IGeneralService::CreateRequest(Kernel::HLERequestContext& ctx) {
+void IGeneralService::CreateRequest(HLERequestContext& ctx) {
LOG_DEBUG(Service_NIFM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -348,7 +349,7 @@ void IGeneralService::CreateRequest(Kernel::HLERequestContext& ctx) {
rb.PushIpcInterface<IRequest>(system);
}
-void IGeneralService::GetCurrentNetworkProfile(Kernel::HLERequestContext& ctx) {
+void IGeneralService::GetCurrentNetworkProfile(HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
const auto net_iface = Network::GetSelectedNetworkInterface();
@@ -407,14 +408,14 @@ void IGeneralService::GetCurrentNetworkProfile(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void IGeneralService::RemoveNetworkProfile(Kernel::HLERequestContext& ctx) {
+void IGeneralService::RemoveNetworkProfile(HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
-void IGeneralService::GetCurrentIpAddress(Kernel::HLERequestContext& ctx) {
+void IGeneralService::GetCurrentIpAddress(HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
auto ipv4 = Network::GetHostIPv4Address();
@@ -435,7 +436,7 @@ void IGeneralService::GetCurrentIpAddress(Kernel::HLERequestContext& ctx) {
rb.PushRaw(*ipv4);
}
-void IGeneralService::CreateTemporaryNetworkProfile(Kernel::HLERequestContext& ctx) {
+void IGeneralService::CreateTemporaryNetworkProfile(HLERequestContext& ctx) {
LOG_DEBUG(Service_NIFM, "called");
ASSERT_MSG(ctx.GetReadBufferSize() == 0x17c, "SfNetworkProfileData is not the correct size");
@@ -450,7 +451,7 @@ void IGeneralService::CreateTemporaryNetworkProfile(Kernel::HLERequestContext& c
rb.PushRaw<u128>(uuid);
}
-void IGeneralService::GetCurrentIpConfigInfo(Kernel::HLERequestContext& ctx) {
+void IGeneralService::GetCurrentIpConfigInfo(HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
struct IpConfigInfo {
@@ -494,7 +495,7 @@ void IGeneralService::GetCurrentIpConfigInfo(Kernel::HLERequestContext& ctx) {
rb.PushRaw<IpConfigInfo>(ip_config_info);
}
-void IGeneralService::IsWirelessCommunicationEnabled(Kernel::HLERequestContext& ctx) {
+void IGeneralService::IsWirelessCommunicationEnabled(HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
@@ -502,7 +503,7 @@ void IGeneralService::IsWirelessCommunicationEnabled(Kernel::HLERequestContext&
rb.Push<u8>(1);
}
-void IGeneralService::GetInternetConnectionStatus(Kernel::HLERequestContext& ctx) {
+void IGeneralService::GetInternetConnectionStatus(HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
struct Output {
@@ -519,7 +520,7 @@ void IGeneralService::GetInternetConnectionStatus(Kernel::HLERequestContext& ctx
rb.PushRaw(out);
}
-void IGeneralService::IsEthernetCommunicationEnabled(Kernel::HLERequestContext& ctx) {
+void IGeneralService::IsEthernetCommunicationEnabled(HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
@@ -531,7 +532,7 @@ void IGeneralService::IsEthernetCommunicationEnabled(Kernel::HLERequestContext&
}
}
-void IGeneralService::IsAnyInternetRequestAccepted(Kernel::HLERequestContext& ctx) {
+void IGeneralService::IsAnyInternetRequestAccepted(HLERequestContext& ctx) {
LOG_ERROR(Service_NIFM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
@@ -609,7 +610,7 @@ public:
}
private:
- void CreateGeneralServiceOld(Kernel::HLERequestContext& ctx) {
+ void CreateGeneralServiceOld(HLERequestContext& ctx) {
LOG_DEBUG(Service_NIFM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -617,7 +618,7 @@ private:
rb.PushIpcInterface<IGeneralService>(system);
}
- void CreateGeneralService(Kernel::HLERequestContext& ctx) {
+ void CreateGeneralService(HLERequestContext& ctx) {
LOG_DEBUG(Service_NIFM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -626,10 +627,16 @@ private:
}
};
-void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
- std::make_shared<NetworkInterface>("nifm:a", system)->InstallAsService(service_manager);
- std::make_shared<NetworkInterface>("nifm:s", system)->InstallAsService(service_manager);
- std::make_shared<NetworkInterface>("nifm:u", system)->InstallAsService(service_manager);
+void LoopProcess(Core::System& system) {
+ auto server_manager = std::make_unique<ServerManager>(system);
+
+ server_manager->RegisterNamedService("nifm:a",
+ std::make_shared<NetworkInterface>("nifm:a", system));
+ server_manager->RegisterNamedService("nifm:s",
+ std::make_shared<NetworkInterface>("nifm:s", system));
+ server_manager->RegisterNamedService("nifm:u",
+ std::make_shared<NetworkInterface>("nifm:u", system));
+ ServerManager::RunServer(std::move(server_manager));
}
} // namespace Service::NIFM
diff --git a/src/core/hle/service/nifm/nifm.h b/src/core/hle/service/nifm/nifm.h
index 48161be28..9b20e6823 100644
--- a/src/core/hle/service/nifm/nifm.h
+++ b/src/core/hle/service/nifm/nifm.h
@@ -12,14 +12,9 @@ namespace Core {
class System;
}
-namespace Service::SM {
-class ServiceManager;
-}
-
namespace Service::NIFM {
-/// Registers all NIFM services with the specified service manager.
-void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system);
+void LoopProcess(Core::System& system);
class IGeneralService final : public ServiceFramework<IGeneralService> {
public:
@@ -27,18 +22,18 @@ public:
~IGeneralService() override;
private:
- void GetClientId(Kernel::HLERequestContext& ctx);
- void CreateScanRequest(Kernel::HLERequestContext& ctx);
- void CreateRequest(Kernel::HLERequestContext& ctx);
- void GetCurrentNetworkProfile(Kernel::HLERequestContext& ctx);
- void RemoveNetworkProfile(Kernel::HLERequestContext& ctx);
- void GetCurrentIpAddress(Kernel::HLERequestContext& ctx);
- void CreateTemporaryNetworkProfile(Kernel::HLERequestContext& ctx);
- void GetCurrentIpConfigInfo(Kernel::HLERequestContext& ctx);
- void IsWirelessCommunicationEnabled(Kernel::HLERequestContext& ctx);
- void GetInternetConnectionStatus(Kernel::HLERequestContext& ctx);
- void IsEthernetCommunicationEnabled(Kernel::HLERequestContext& ctx);
- void IsAnyInternetRequestAccepted(Kernel::HLERequestContext& ctx);
+ void GetClientId(HLERequestContext& ctx);
+ void CreateScanRequest(HLERequestContext& ctx);
+ void CreateRequest(HLERequestContext& ctx);
+ void GetCurrentNetworkProfile(HLERequestContext& ctx);
+ void RemoveNetworkProfile(HLERequestContext& ctx);
+ void GetCurrentIpAddress(HLERequestContext& ctx);
+ void CreateTemporaryNetworkProfile(HLERequestContext& ctx);
+ void GetCurrentIpConfigInfo(HLERequestContext& ctx);
+ void IsWirelessCommunicationEnabled(HLERequestContext& ctx);
+ void GetInternetConnectionStatus(HLERequestContext& ctx);
+ void IsEthernetCommunicationEnabled(HLERequestContext& ctx);
+ void IsAnyInternetRequestAccepted(HLERequestContext& ctx);
Network::RoomNetwork& network;
};
diff --git a/src/core/hle/service/nim/nim.cpp b/src/core/hle/service/nim/nim.cpp
index 5a8a91e0b..42de87f9a 100644
--- a/src/core/hle/service/nim/nim.cpp
+++ b/src/core/hle/service/nim/nim.cpp
@@ -4,12 +4,12 @@
#include <chrono>
#include <ctime>
#include "core/core.h"
-#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/k_event.h"
+#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/nim/nim.h"
+#include "core/hle/service/server_manager.h"
#include "core/hle/service/service.h"
-#include "core/hle/service/sm/sm.h"
namespace Service::NIM {
@@ -46,7 +46,7 @@ public:
}
private:
- void CreateAsyncInterface(Kernel::HLERequestContext& ctx) {
+ void CreateAsyncInterface(HLERequestContext& ctx) {
LOG_WARNING(Service_NIM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
@@ -68,7 +68,7 @@ public:
}
private:
- void CreateAccessorInterface(Kernel::HLERequestContext& ctx) {
+ void CreateAccessorInterface(HLERequestContext& ctx) {
LOG_WARNING(Service_NIM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
@@ -239,14 +239,14 @@ public:
}
private:
- void CreateServerInterface(Kernel::HLERequestContext& ctx) {
+ void CreateServerInterface(HLERequestContext& ctx) {
LOG_WARNING(Service_NIM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IShopServiceAccessServer>(system);
}
- void IsLargeResourceAvailable(Kernel::HLERequestContext& ctx) {
+ void IsLargeResourceAvailable(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto unknown{rp.Pop<u64>()};
@@ -325,7 +325,7 @@ public:
}
private:
- void StartTask(Kernel::HLERequestContext& ctx) {
+ void StartTask(HLERequestContext& ctx) {
// No need to connect to the internet, just finish the task straight away.
LOG_DEBUG(Service_NIM, "called");
finished_event->Signal();
@@ -333,7 +333,7 @@ private:
rb.Push(ResultSuccess);
}
- void GetFinishNotificationEvent(Kernel::HLERequestContext& ctx) {
+ void GetFinishNotificationEvent(HLERequestContext& ctx) {
LOG_DEBUG(Service_NIM, "called");
IPC::ResponseBuilder rb{ctx, 2, 1};
@@ -341,21 +341,21 @@ private:
rb.PushCopyObjects(finished_event->GetReadableEvent());
}
- void GetResult(Kernel::HLERequestContext& ctx) {
+ void GetResult(HLERequestContext& ctx) {
LOG_DEBUG(Service_NIM, "called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
- void Cancel(Kernel::HLERequestContext& ctx) {
+ void Cancel(HLERequestContext& ctx) {
LOG_DEBUG(Service_NIM, "called");
finished_event->Clear();
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
- void IsProcessing(Kernel::HLERequestContext& ctx) {
+ void IsProcessing(HLERequestContext& ctx) {
LOG_DEBUG(Service_NIM, "called");
IPC::ResponseBuilder rb{ctx, 3};
@@ -363,7 +363,7 @@ private:
rb.PushRaw<u32>(0); // We instantly process the request
}
- void GetServerTime(Kernel::HLERequestContext& ctx) {
+ void GetServerTime(HLERequestContext& ctx) {
LOG_DEBUG(Service_NIM, "called");
const s64 server_time{std::chrono::duration_cast<std::chrono::seconds>(
@@ -394,7 +394,7 @@ public:
}
private:
- void OpenEnsureNetworkClockAvailabilityService(Kernel::HLERequestContext& ctx) {
+ void OpenEnsureNetworkClockAvailabilityService(HLERequestContext& ctx) {
LOG_DEBUG(Service_NIM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -403,14 +403,14 @@ private:
}
// TODO(ogniK): Do we need these?
- void SuspendAutonomicTimeCorrection(Kernel::HLERequestContext& ctx) {
+ void SuspendAutonomicTimeCorrection(HLERequestContext& ctx) {
LOG_WARNING(Service_NIM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
- void ResumeAutonomicTimeCorrection(Kernel::HLERequestContext& ctx) {
+ void ResumeAutonomicTimeCorrection(HLERequestContext& ctx) {
LOG_WARNING(Service_NIM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
@@ -418,11 +418,14 @@ private:
}
};
-void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
- std::make_shared<NIM>(system)->InstallAsService(sm);
- std::make_shared<NIM_ECA>(system)->InstallAsService(sm);
- std::make_shared<NIM_SHP>(system)->InstallAsService(sm);
- std::make_shared<NTC>(system)->InstallAsService(sm);
+void LoopProcess(Core::System& system) {
+ auto server_manager = std::make_unique<ServerManager>(system);
+
+ server_manager->RegisterNamedService("nim", std::make_shared<NIM>(system));
+ server_manager->RegisterNamedService("nim:eca", std::make_shared<NIM_ECA>(system));
+ server_manager->RegisterNamedService("nim:shp", std::make_shared<NIM_SHP>(system));
+ server_manager->RegisterNamedService("ntc", std::make_shared<NTC>(system));
+ ServerManager::RunServer(std::move(server_manager));
}
} // namespace Service::NIM
diff --git a/src/core/hle/service/nim/nim.h b/src/core/hle/service/nim/nim.h
index 8f6ff28e8..e7d599908 100644
--- a/src/core/hle/service/nim/nim.h
+++ b/src/core/hle/service/nim/nim.h
@@ -7,12 +7,8 @@ namespace Core {
class System;
}
-namespace Service::SM {
-class ServiceManager;
-}
-
namespace Service::NIM {
-void InstallInterfaces(SM::ServiceManager& sm, Core::System& system);
+void LoopProcess(Core::System& system);
} // namespace Service::NIM
diff --git a/src/core/hle/service/npns/npns.cpp b/src/core/hle/service/npns/npns.cpp
index 8133711c2..a162e5c54 100644
--- a/src/core/hle/service/npns/npns.cpp
+++ b/src/core/hle/service/npns/npns.cpp
@@ -4,8 +4,8 @@
#include <memory>
#include "core/hle/service/npns/npns.h"
+#include "core/hle/service/server_manager.h"
#include "core/hle/service/service.h"
-#include "core/hle/service/sm/sm.h"
namespace Service::NPNS {
@@ -94,9 +94,12 @@ public:
}
};
-void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
- std::make_shared<NPNS_S>(system)->InstallAsService(sm);
- std::make_shared<NPNS_U>(system)->InstallAsService(sm);
+void LoopProcess(Core::System& system) {
+ auto server_manager = std::make_unique<ServerManager>(system);
+
+ server_manager->RegisterNamedService("npns:s", std::make_shared<NPNS_S>(system));
+ server_manager->RegisterNamedService("npns:u", std::make_shared<NPNS_U>(system));
+ ServerManager::RunServer(std::move(server_manager));
}
} // namespace Service::NPNS
diff --git a/src/core/hle/service/npns/npns.h b/src/core/hle/service/npns/npns.h
index 84e6ec437..0019fca76 100644
--- a/src/core/hle/service/npns/npns.h
+++ b/src/core/hle/service/npns/npns.h
@@ -7,12 +7,8 @@ namespace Core {
class System;
}
-namespace Service::SM {
-class ServiceManager;
-}
-
namespace Service::NPNS {
-void InstallInterfaces(SM::ServiceManager& sm, Core::System& system);
+void LoopProcess(Core::System& system);
} // namespace Service::NPNS
diff --git a/src/core/hle/service/ns/errors.h b/src/core/hle/service/ns/errors.h
index 8a7621798..16d2ea6f7 100644
--- a/src/core/hle/service/ns/errors.h
+++ b/src/core/hle/service/ns/errors.h
@@ -7,5 +7,6 @@
namespace Service::NS {
-constexpr Result ERR_APPLICATION_LANGUAGE_NOT_FOUND{ErrorModule::NS, 300};
-} \ No newline at end of file
+constexpr Result ResultApplicationLanguageNotFound{ErrorModule::NS, 300};
+
+}
diff --git a/src/core/hle/service/ns/iplatform_service_manager.cpp b/src/core/hle/service/ns/iplatform_service_manager.cpp
index 1fab2f0dd..6c2f5e70b 100644
--- a/src/core/hle/service/ns/iplatform_service_manager.cpp
+++ b/src/core/hle/service/ns/iplatform_service_manager.cpp
@@ -15,11 +15,11 @@
#include "core/file_sys/registered_cache.h"
#include "core/file_sys/romfs.h"
#include "core/file_sys/system_archive/system_archive.h"
-#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/k_shared_memory.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/physical_memory.h"
#include "core/hle/service/filesystem/filesystem.h"
+#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/ns/iplatform_service_manager.h"
namespace Service::NS {
@@ -119,7 +119,7 @@ struct IPlatformServiceManager::Impl {
break;
}
- // Derive key withing inverse xor
+ // Derive key within inverse xor
const u32 KEY = GetU32Swapped(input.data() + cur_offset) ^ EXPECTED_MAGIC;
const u32 SIZE = GetU32Swapped(input.data() + cur_offset + 4) ^ KEY;
shared_font_regions.push_back(FontRegion{cur_offset + 8, SIZE});
@@ -208,7 +208,7 @@ IPlatformServiceManager::IPlatformServiceManager(Core::System& system_, const ch
IPlatformServiceManager::~IPlatformServiceManager() = default;
-void IPlatformServiceManager::RequestLoad(Kernel::HLERequestContext& ctx) {
+void IPlatformServiceManager::RequestLoad(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u32 shared_font_type{rp.Pop<u32>()};
// Games don't call this so all fonts should be loaded
@@ -218,7 +218,7 @@ void IPlatformServiceManager::RequestLoad(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void IPlatformServiceManager::GetLoadState(Kernel::HLERequestContext& ctx) {
+void IPlatformServiceManager::GetLoadState(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u32 font_id{rp.Pop<u32>()};
LOG_DEBUG(Service_NS, "called, font_id={}", font_id);
@@ -228,7 +228,7 @@ void IPlatformServiceManager::GetLoadState(Kernel::HLERequestContext& ctx) {
rb.Push<u32>(static_cast<u32>(LoadState::Done));
}
-void IPlatformServiceManager::GetSize(Kernel::HLERequestContext& ctx) {
+void IPlatformServiceManager::GetSize(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u32 font_id{rp.Pop<u32>()};
LOG_DEBUG(Service_NS, "called, font_id={}", font_id);
@@ -238,7 +238,7 @@ void IPlatformServiceManager::GetSize(Kernel::HLERequestContext& ctx) {
rb.Push<u32>(impl->GetSharedFontRegion(font_id).size);
}
-void IPlatformServiceManager::GetSharedMemoryAddressOffset(Kernel::HLERequestContext& ctx) {
+void IPlatformServiceManager::GetSharedMemoryAddressOffset(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u32 font_id{rp.Pop<u32>()};
LOG_DEBUG(Service_NS, "called, font_id={}", font_id);
@@ -248,7 +248,7 @@ void IPlatformServiceManager::GetSharedMemoryAddressOffset(Kernel::HLERequestCon
rb.Push<u32>(impl->GetSharedFontRegion(font_id).offset);
}
-void IPlatformServiceManager::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) {
+void IPlatformServiceManager::GetSharedMemoryNativeHandle(HLERequestContext& ctx) {
// Map backing memory for the font data
LOG_DEBUG(Service_NS, "called");
@@ -261,7 +261,7 @@ void IPlatformServiceManager::GetSharedMemoryNativeHandle(Kernel::HLERequestCont
rb.PushCopyObjects(&kernel.GetFontSharedMem());
}
-void IPlatformServiceManager::GetSharedFontInOrderOfPriority(Kernel::HLERequestContext& ctx) {
+void IPlatformServiceManager::GetSharedFontInOrderOfPriority(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u64 language_code{rp.Pop<u64>()}; // TODO(ogniK): Find out what this is used for
LOG_DEBUG(Service_NS, "called, language_code={:X}", language_code);
diff --git a/src/core/hle/service/ns/iplatform_service_manager.h b/src/core/hle/service/ns/iplatform_service_manager.h
index ed6eda89f..03071e02b 100644
--- a/src/core/hle/service/ns/iplatform_service_manager.h
+++ b/src/core/hle/service/ns/iplatform_service_manager.h
@@ -42,12 +42,12 @@ public:
~IPlatformServiceManager() override;
private:
- void RequestLoad(Kernel::HLERequestContext& ctx);
- void GetLoadState(Kernel::HLERequestContext& ctx);
- void GetSize(Kernel::HLERequestContext& ctx);
- void GetSharedMemoryAddressOffset(Kernel::HLERequestContext& ctx);
- void GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx);
- void GetSharedFontInOrderOfPriority(Kernel::HLERequestContext& ctx);
+ void RequestLoad(HLERequestContext& ctx);
+ void GetLoadState(HLERequestContext& ctx);
+ void GetSize(HLERequestContext& ctx);
+ void GetSharedMemoryAddressOffset(HLERequestContext& ctx);
+ void GetSharedMemoryNativeHandle(HLERequestContext& ctx);
+ void GetSharedFontInOrderOfPriority(HLERequestContext& ctx);
struct Impl;
std::unique_ptr<Impl> impl;
diff --git a/src/core/hle/service/ns/ns.cpp b/src/core/hle/service/ns/ns.cpp
index f59a1a63d..376067a95 100644
--- a/src/core/hle/service/ns/ns.cpp
+++ b/src/core/hle/service/ns/ns.cpp
@@ -7,13 +7,14 @@
#include "core/file_sys/control_metadata.h"
#include "core/file_sys/patch_manager.h"
#include "core/file_sys/vfs.h"
-#include "core/hle/ipc_helpers.h"
#include "core/hle/service/glue/glue_manager.h"
+#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/ns/errors.h"
#include "core/hle/service/ns/iplatform_service_manager.h"
#include "core/hle/service/ns/language.h"
#include "core/hle/service/ns/ns.h"
#include "core/hle/service/ns/pdm_qry.h"
+#include "core/hle/service/server_manager.h"
#include "core/hle/service/set/set.h"
namespace Service::NS {
@@ -159,6 +160,8 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_
{606, nullptr, "GetContentMetaStorage"},
{607, nullptr, "ListAvailableAddOnContent"},
{609, nullptr, "ListAvailabilityAssuredAddOnContent"},
+ {610, nullptr, "GetInstalledContentMetaStorage"},
+ {611, nullptr, "PrepareAddOnContent"},
{700, nullptr, "PushDownloadTaskList"},
{701, nullptr, "ClearTaskStatusList"},
{702, nullptr, "RequestDownloadTaskList"},
@@ -228,6 +231,7 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_
{1900, nullptr, "IsActiveAccount"},
{1901, nullptr, "RequestDownloadApplicationPrepurchasedRights"},
{1902, nullptr, "GetApplicationTicketInfo"},
+ {1903, nullptr, "RequestDownloadApplicationPrepurchasedRightsForAccount"},
{2000, nullptr, "GetSystemDeliveryInfo"},
{2001, nullptr, "SelectLatestSystemDeliveryInfo"},
{2002, nullptr, "VerifyDeliveryProtocolVersion"},
@@ -276,8 +280,11 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_
{2352, nullptr, "RequestResolveNoDownloadRightsError"},
{2353, nullptr, "GetApplicationDownloadTaskInfo"},
{2354, nullptr, "PrioritizeApplicationBackgroundTask"},
- {2355, nullptr, "Unknown2355"},
- {2356, nullptr, "Unknown2356"},
+ {2355, nullptr, "PreferStorageEfficientUpdate"},
+ {2356, nullptr, "RequestStorageEfficientUpdatePreferable"},
+ {2357, nullptr, "EnableMultiCoreDownload"},
+ {2358, nullptr, "DisableMultiCoreDownload"},
+ {2359, nullptr, "IsMultiCoreDownloadEnabled"},
{2400, nullptr, "GetPromotionInfo"},
{2401, nullptr, "CountPromotionInfo"},
{2402, nullptr, "ListPromotionInfo"},
@@ -295,6 +302,7 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_
{2519, nullptr, "IsQualificationTransitionSupported"},
{2520, nullptr, "IsQualificationTransitionSupportedByProcessId"},
{2521, nullptr, "GetRightsUserChangedEvent"},
+ {2522, nullptr, "IsRomRedirectionAvailable"},
{2800, nullptr, "GetApplicationIdOfPreomia"},
{3000, nullptr, "RegisterDeviceLockKey"},
{3001, nullptr, "UnregisterDeviceLockKey"},
@@ -311,6 +319,7 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_
{3012, nullptr, "IsApplicationTitleHidden"},
{3013, nullptr, "IsGameCardEnabled"},
{3014, nullptr, "IsLocalContentShareEnabled"},
+ {3050, nullptr, "ListAssignELicenseTaskResult"},
{9999, nullptr, "GetApplicationCertificate"},
};
// clang-format on
@@ -320,7 +329,7 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_
IApplicationManagerInterface::~IApplicationManagerInterface() = default;
-void IApplicationManagerInterface::GetApplicationControlData(Kernel::HLERequestContext& ctx) {
+void IApplicationManagerInterface::GetApplicationControlData(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto flag = rp.PopRaw<u64>();
LOG_DEBUG(Service_NS, "called with flag={:016X}", flag);
@@ -379,7 +388,7 @@ void IApplicationManagerInterface::GetApplicationControlData(Kernel::HLERequestC
rb.Push<u32>(static_cast<u32>(out.size()));
}
-void IApplicationManagerInterface::GetApplicationDesiredLanguage(Kernel::HLERequestContext& ctx) {
+void IApplicationManagerInterface::GetApplicationDesiredLanguage(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto supported_languages = rp.Pop<u32>();
@@ -407,14 +416,14 @@ ResultVal<u8> IApplicationManagerInterface::GetApplicationDesiredLanguage(
if (application_language == std::nullopt) {
LOG_ERROR(Service_NS, "Could not convert application language! language_code={}",
language_code);
- return ERR_APPLICATION_LANGUAGE_NOT_FOUND;
+ return Service::NS::ResultApplicationLanguageNotFound;
}
const auto priority_list = GetApplicationLanguagePriorityList(*application_language);
if (!priority_list) {
LOG_ERROR(Service_NS,
"Could not find application language priorities! application_language={}",
*application_language);
- return ERR_APPLICATION_LANGUAGE_NOT_FOUND;
+ return Service::NS::ResultApplicationLanguageNotFound;
}
// Try to find a valid language.
@@ -427,11 +436,11 @@ ResultVal<u8> IApplicationManagerInterface::GetApplicationDesiredLanguage(
LOG_ERROR(Service_NS, "Could not find a valid language! supported_languages={:08X}",
supported_languages);
- return ERR_APPLICATION_LANGUAGE_NOT_FOUND;
+ return Service::NS::ResultApplicationLanguageNotFound;
}
void IApplicationManagerInterface::ConvertApplicationLanguageToLanguageCode(
- Kernel::HLERequestContext& ctx) {
+ HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto application_language = rp.Pop<u8>();
@@ -452,7 +461,7 @@ ResultVal<u64> IApplicationManagerInterface::ConvertApplicationLanguageToLanguag
ConvertToLanguageCode(static_cast<ApplicationLanguage>(application_language));
if (language_code == std::nullopt) {
LOG_ERROR(Service_NS, "Language not found! application_language={}", application_language);
- return ERR_APPLICATION_LANGUAGE_NOT_FOUND;
+ return Service::NS::ResultApplicationLanguageNotFound;
}
return static_cast<u64>(*language_code);
@@ -595,8 +604,7 @@ IReadOnlyApplicationControlDataInterface::IReadOnlyApplicationControlDataInterfa
IReadOnlyApplicationControlDataInterface::~IReadOnlyApplicationControlDataInterface() = default;
-void IReadOnlyApplicationControlDataInterface::GetApplicationControlData(
- Kernel::HLERequestContext& ctx) {
+void IReadOnlyApplicationControlDataInterface::GetApplicationControlData(HLERequestContext& ctx) {
enum class ApplicationControlSource : u8 {
CacheOnly,
Storage,
@@ -744,7 +752,7 @@ public:
}
private:
- void OpenSystemUpdateControl(Kernel::HLERequestContext& ctx) {
+ void OpenSystemUpdateControl(HLERequestContext& ctx) {
LOG_DEBUG(Service_NS, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -768,7 +776,7 @@ public:
}
private:
- void NeedsUpdateVulnerability(Kernel::HLERequestContext& ctx) {
+ void NeedsUpdateVulnerability(HLERequestContext& ctx) {
LOG_WARNING(Service_NS, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
@@ -777,23 +785,26 @@ private:
}
};
-void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
-
- std::make_shared<NS>("ns:am2", system)->InstallAsService(service_manager);
- std::make_shared<NS>("ns:ec", system)->InstallAsService(service_manager);
- std::make_shared<NS>("ns:rid", system)->InstallAsService(service_manager);
- std::make_shared<NS>("ns:rt", system)->InstallAsService(service_manager);
- std::make_shared<NS>("ns:web", system)->InstallAsService(service_manager);
- std::make_shared<NS>("ns:ro", system)->InstallAsService(service_manager);
-
- std::make_shared<NS_DEV>(system)->InstallAsService(service_manager);
- std::make_shared<NS_SU>(system)->InstallAsService(service_manager);
- std::make_shared<NS_VM>(system)->InstallAsService(service_manager);
-
- std::make_shared<PDM_QRY>(system)->InstallAsService(service_manager);
-
- std::make_shared<IPlatformServiceManager>(system, "pl:s")->InstallAsService(service_manager);
- std::make_shared<IPlatformServiceManager>(system, "pl:u")->InstallAsService(service_manager);
+void LoopProcess(Core::System& system) {
+ auto server_manager = std::make_unique<ServerManager>(system);
+
+ server_manager->RegisterNamedService("ns:am2", std::make_shared<NS>("ns:am2", system));
+ server_manager->RegisterNamedService("ns:ec", std::make_shared<NS>("ns:ec", system));
+ server_manager->RegisterNamedService("ns:rid", std::make_shared<NS>("ns:rid", system));
+ server_manager->RegisterNamedService("ns:rt", std::make_shared<NS>("ns:rt", system));
+ server_manager->RegisterNamedService("ns:web", std::make_shared<NS>("ns:web", system));
+ server_manager->RegisterNamedService("ns:ro", std::make_shared<NS>("ns:ro", system));
+
+ server_manager->RegisterNamedService("ns:dev", std::make_shared<NS_DEV>(system));
+ server_manager->RegisterNamedService("ns:su", std::make_shared<NS_SU>(system));
+ server_manager->RegisterNamedService("ns:vm", std::make_shared<NS_VM>(system));
+ server_manager->RegisterNamedService("pdm:qry", std::make_shared<PDM_QRY>(system));
+
+ server_manager->RegisterNamedService("pl:s",
+ std::make_shared<IPlatformServiceManager>(system, "pl:s"));
+ server_manager->RegisterNamedService("pl:u",
+ std::make_shared<IPlatformServiceManager>(system, "pl:u"));
+ ServerManager::RunServer(std::move(server_manager));
}
} // namespace Service::NS
diff --git a/src/core/hle/service/ns/ns.h b/src/core/hle/service/ns/ns.h
index 9c18e935c..203388e1f 100644
--- a/src/core/hle/service/ns/ns.h
+++ b/src/core/hle/service/ns/ns.h
@@ -32,9 +32,9 @@ public:
ResultVal<u64> ConvertApplicationLanguageToLanguageCode(u8 application_language);
private:
- void GetApplicationControlData(Kernel::HLERequestContext& ctx);
- void GetApplicationDesiredLanguage(Kernel::HLERequestContext& ctx);
- void ConvertApplicationLanguageToLanguageCode(Kernel::HLERequestContext& ctx);
+ void GetApplicationControlData(HLERequestContext& ctx);
+ void GetApplicationDesiredLanguage(HLERequestContext& ctx);
+ void ConvertApplicationLanguageToLanguageCode(HLERequestContext& ctx);
};
class IApplicationVersionInterface final : public ServiceFramework<IApplicationVersionInterface> {
@@ -80,7 +80,7 @@ public:
~IReadOnlyApplicationControlDataInterface() override;
private:
- void GetApplicationControlData(Kernel::HLERequestContext& ctx);
+ void GetApplicationControlData(HLERequestContext& ctx);
};
class NS final : public ServiceFramework<NS> {
@@ -92,7 +92,7 @@ public:
private:
template <typename T, typename... Args>
- void PushInterface(Kernel::HLERequestContext& ctx) {
+ void PushInterface(HLERequestContext& ctx) {
LOG_DEBUG(Service_NS, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -100,7 +100,7 @@ private:
rb.PushIpcInterface<T>(system);
}
- void PushIApplicationManagerInterface(Kernel::HLERequestContext& ctx) {
+ void PushIApplicationManagerInterface(HLERequestContext& ctx) {
LOG_DEBUG(Service_NS, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -110,15 +110,14 @@ private:
template <typename T, typename... Args>
std::shared_ptr<T> GetInterface(Args&&... args) const {
- static_assert(std::is_base_of_v<Kernel::SessionRequestHandler, T>,
+ static_assert(std::is_base_of_v<SessionRequestHandler, T>,
"Not a base of ServiceFrameworkBase");
return std::make_shared<T>(std::forward<Args>(args)...);
}
};
-/// Registers all NS services with the specified service manager.
-void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system);
+void LoopProcess(Core::System& system);
} // namespace NS
} // namespace Service
diff --git a/src/core/hle/service/ns/pdm_qry.cpp b/src/core/hle/service/ns/pdm_qry.cpp
index aac8f573f..ce0ee30e0 100644
--- a/src/core/hle/service/ns/pdm_qry.cpp
+++ b/src/core/hle/service/ns/pdm_qry.cpp
@@ -5,7 +5,7 @@
#include "common/logging/log.h"
#include "common/uuid.h"
-#include "core/hle/ipc_helpers.h"
+#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/ns/pdm_qry.h"
#include "core/hle/service/service.h"
@@ -42,7 +42,7 @@ PDM_QRY::PDM_QRY(Core::System& system_) : ServiceFramework{system_, "pdm:qry"} {
PDM_QRY::~PDM_QRY() = default;
-void PDM_QRY::QueryPlayStatisticsByApplicationIdAndUserAccountId(Kernel::HLERequestContext& ctx) {
+void PDM_QRY::QueryPlayStatisticsByApplicationIdAndUserAccountId(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto unknown = rp.Pop<bool>();
rp.Pop<u8>(); // Padding
diff --git a/src/core/hle/service/ns/pdm_qry.h b/src/core/hle/service/ns/pdm_qry.h
index abcc3bef3..c98e01660 100644
--- a/src/core/hle/service/ns/pdm_qry.h
+++ b/src/core/hle/service/ns/pdm_qry.h
@@ -26,7 +26,7 @@ public:
~PDM_QRY() override;
private:
- void QueryPlayStatisticsByApplicationIdAndUserAccountId(Kernel::HLERequestContext& ctx);
+ void QueryPlayStatisticsByApplicationIdAndUserAccountId(HLERequestContext& ctx);
};
} // namespace Service::NS
diff --git a/src/core/hle/service/nvdrv/core/syncpoint_manager.cpp b/src/core/hle/service/nvdrv/core/syncpoint_manager.cpp
index aba51d280..c4c4c2593 100644
--- a/src/core/hle/service/nvdrv/core/syncpoint_manager.cpp
+++ b/src/core/hle/service/nvdrv/core/syncpoint_manager.cpp
@@ -64,7 +64,7 @@ void SyncpointManager::FreeSyncpoint(u32 id) {
}
bool SyncpointManager::IsSyncpointAllocated(u32 id) const {
- return (id <= SyncpointCount) && syncpoints[id].reserved;
+ return (id < SyncpointCount) && syncpoints[id].reserved;
}
bool SyncpointManager::HasSyncpointExpired(u32 id, u32 threshold) const {
diff --git a/src/core/hle/service/nvdrv/core/syncpoint_manager.h b/src/core/hle/service/nvdrv/core/syncpoint_manager.h
index 4f2cefae5..7728ff596 100644
--- a/src/core/hle/service/nvdrv/core/syncpoint_manager.h
+++ b/src/core/hle/service/nvdrv/core/syncpoint_manager.h
@@ -124,7 +124,7 @@ private:
//!< value
};
- constexpr static std::size_t SyncpointCount{192};
+ static constexpr std::size_t SyncpointCount{192};
std::array<SyncpointInfo, SyncpointCount> syncpoints{};
std::mutex reservation_lock;
diff --git a/src/core/hle/service/nvdrv/devices/nvdevice.h b/src/core/hle/service/nvdrv/devices/nvdevice.h
index 204b0e757..a04538d5d 100644
--- a/src/core/hle/service/nvdrv/devices/nvdevice.h
+++ b/src/core/hle/service/nvdrv/devices/nvdevice.h
@@ -3,7 +3,9 @@
#pragma once
+#include <span>
#include <vector>
+
#include "common/common_types.h"
#include "core/hle/service/nvdrv/nvdata.h"
@@ -31,8 +33,8 @@ public:
* @param output A buffer where the output data will be written to.
* @returns The result code of the ioctl.
*/
- virtual NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- std::vector<u8>& output) = 0;
+ virtual NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<u8> output) = 0;
/**
* Handles an ioctl2 request.
@@ -42,8 +44,8 @@ public:
* @param output A buffer where the output data will be written to.
* @returns The result code of the ioctl.
*/
- virtual NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- const std::vector<u8>& inline_input, std::vector<u8>& output) = 0;
+ virtual NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<const u8> inline_input, std::span<u8> output) = 0;
/**
* Handles an ioctl3 request.
@@ -53,11 +55,11 @@ public:
* @param inline_output A buffer where the inlined output data will be written to.
* @returns The result code of the ioctl.
*/
- virtual NvResult Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- std::vector<u8>& output, std::vector<u8>& inline_output) = 0;
+ virtual NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<u8> output, std::span<u8> inline_output) = 0;
/**
- * Called once a device is openned
+ * Called once a device is opened
* @param fd The device fd
*/
virtual void OnOpen(DeviceFD fd) = 0;
diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
index 4122fc98d..05a43d8dc 100644
--- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
@@ -17,20 +17,20 @@ nvdisp_disp0::nvdisp_disp0(Core::System& system_, NvCore::Container& core)
: nvdevice{system_}, container{core}, nvmap{core.GetNvMapFile()} {}
nvdisp_disp0::~nvdisp_disp0() = default;
-NvResult nvdisp_disp0::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- std::vector<u8>& output) {
+NvResult nvdisp_disp0::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<u8> output) {
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
return NvResult::NotImplemented;
}
-NvResult nvdisp_disp0::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- const std::vector<u8>& inline_input, std::vector<u8>& output) {
+NvResult nvdisp_disp0::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<const u8> inline_input, std::span<u8> output) {
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
return NvResult::NotImplemented;
}
-NvResult nvdisp_disp0::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- std::vector<u8>& output, std::vector<u8>& inline_output) {
+NvResult nvdisp_disp0::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<u8> output, std::span<u8> inline_output) {
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
return NvResult::NotImplemented;
}
@@ -51,8 +51,8 @@ void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, android::PixelFormat form
stride, format, transform, crop_rect};
system.GPU().RequestSwapBuffers(&framebuffer, fences, num_fences);
- system.GetPerfStats().EndSystemFrame();
system.SpeedLimiter().DoSpeedLimiting(system.CoreTiming().GetGlobalTimeUs());
+ system.GetPerfStats().EndSystemFrame();
system.GetPerfStats().BeginSystemFrame();
}
diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h
index 04217ab12..daee05fe8 100644
--- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h
+++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h
@@ -8,8 +8,8 @@
#include "common/common_types.h"
#include "common/math_util.h"
#include "core/hle/service/nvdrv/devices/nvdevice.h"
-#include "core/hle/service/nvflinger/buffer_transform_flags.h"
-#include "core/hle/service/nvflinger/pixel_format.h"
+#include "core/hle/service/nvnflinger/buffer_transform_flags.h"
+#include "core/hle/service/nvnflinger/pixel_format.h"
namespace Service::Nvidia::NvCore {
class Container;
@@ -25,12 +25,12 @@ public:
explicit nvdisp_disp0(Core::System& system_, NvCore::Container& core);
~nvdisp_disp0() override;
- NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- std::vector<u8>& output) override;
- NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- const std::vector<u8>& inline_input, std::vector<u8>& output) override;
- NvResult Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- std::vector<u8>& output, std::vector<u8>& inline_output) override;
+ NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<u8> output) override;
+ NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<const u8> inline_input, std::span<u8> output) override;
+ NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,
+ std::span<u8> inline_output) override;
void OnOpen(DeviceFD fd) override;
void OnClose(DeviceFD fd) override;
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 b635e6ed1..07e570a9f 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
@@ -27,8 +27,8 @@ nvhost_as_gpu::nvhost_as_gpu(Core::System& system_, Module& module_, NvCore::Con
nvhost_as_gpu::~nvhost_as_gpu() = default;
-NvResult nvhost_as_gpu::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- std::vector<u8>& output) {
+NvResult nvhost_as_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<u8> output) {
switch (command.group) {
case 'A':
switch (command.cmd) {
@@ -60,14 +60,14 @@ NvResult nvhost_as_gpu::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>
return NvResult::NotImplemented;
}
-NvResult nvhost_as_gpu::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- const std::vector<u8>& inline_input, std::vector<u8>& output) {
+NvResult nvhost_as_gpu::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<const u8> inline_input, std::span<u8> output) {
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
return NvResult::NotImplemented;
}
-NvResult nvhost_as_gpu::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- std::vector<u8>& output, std::vector<u8>& inline_output) {
+NvResult nvhost_as_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<u8> output, std::span<u8> inline_output) {
switch (command.group) {
case 'A':
switch (command.cmd) {
@@ -87,7 +87,7 @@ NvResult nvhost_as_gpu::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>
void nvhost_as_gpu::OnOpen(DeviceFD fd) {}
void nvhost_as_gpu::OnClose(DeviceFD fd) {}
-NvResult nvhost_as_gpu::AllocAsEx(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvhost_as_gpu::AllocAsEx(std::span<const u8> input, std::span<u8> output) {
IoctlAllocAsEx params{};
std::memcpy(&params, input.data(), input.size());
@@ -141,7 +141,7 @@ NvResult nvhost_as_gpu::AllocAsEx(const std::vector<u8>& input, std::vector<u8>&
return NvResult::Success;
}
-NvResult nvhost_as_gpu::AllocateSpace(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvhost_as_gpu::AllocateSpace(std::span<const u8> input, std::span<u8> output) {
IoctlAllocSpace params{};
std::memcpy(&params, input.data(), input.size());
@@ -220,7 +220,7 @@ void nvhost_as_gpu::FreeMappingLocked(u64 offset) {
mapping_map.erase(offset);
}
-NvResult nvhost_as_gpu::FreeSpace(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvhost_as_gpu::FreeSpace(std::span<const u8> input, std::span<u8> output) {
IoctlFreeSpace params{};
std::memcpy(&params, input.data(), input.size());
@@ -266,15 +266,14 @@ NvResult nvhost_as_gpu::FreeSpace(const std::vector<u8>& input, std::vector<u8>&
return NvResult::Success;
}
-NvResult nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvhost_as_gpu::Remap(std::span<const u8> input, std::span<u8> output) {
const auto num_entries = input.size() / sizeof(IoctlRemapEntry);
LOG_DEBUG(Service_NVDRV, "called, num_entries=0x{:X}", num_entries);
- std::vector<IoctlRemapEntry> entries(num_entries);
- std::memcpy(entries.data(), input.data(), input.size());
-
std::scoped_lock lock(mutex);
+ entries.resize_destructive(num_entries);
+ std::memcpy(entries.data(), input.data(), input.size());
if (!vm.initialised) {
return NvResult::BadValue;
@@ -320,7 +319,7 @@ NvResult nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& out
return NvResult::Success;
}
-NvResult nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvhost_as_gpu::MapBufferEx(std::span<const u8> input, std::span<u8> output) {
IoctlMapBufferEx params{};
std::memcpy(&params, input.data(), input.size());
@@ -424,7 +423,7 @@ NvResult nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8
return NvResult::Success;
}
-NvResult nvhost_as_gpu::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvhost_as_gpu::UnmapBuffer(std::span<const u8> input, std::span<u8> output) {
IoctlUnmapBuffer params{};
std::memcpy(&params, input.data(), input.size());
@@ -463,7 +462,7 @@ NvResult nvhost_as_gpu::UnmapBuffer(const std::vector<u8>& input, std::vector<u8
return NvResult::Success;
}
-NvResult nvhost_as_gpu::BindChannel(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvhost_as_gpu::BindChannel(std::span<const u8> input, std::span<u8> output) {
IoctlBindChannel params{};
std::memcpy(&params, input.data(), input.size());
LOG_DEBUG(Service_NVDRV, "called, fd={:X}", params.fd);
@@ -492,7 +491,7 @@ void nvhost_as_gpu::GetVARegionsImpl(IoctlGetVaRegions& params) {
};
}
-NvResult nvhost_as_gpu::GetVARegions(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvhost_as_gpu::GetVARegions(std::span<const u8> input, std::span<u8> output) {
IoctlGetVaRegions params{};
std::memcpy(&params, input.data(), input.size());
@@ -511,8 +510,8 @@ NvResult nvhost_as_gpu::GetVARegions(const std::vector<u8>& input, std::vector<u
return NvResult::Success;
}
-NvResult nvhost_as_gpu::GetVARegions(const std::vector<u8>& input, std::vector<u8>& output,
- std::vector<u8>& inline_output) {
+NvResult nvhost_as_gpu::GetVARegions(std::span<const u8> input, std::span<u8> output,
+ std::span<u8> inline_output) {
IoctlGetVaRegions params{};
std::memcpy(&params, input.data(), input.size());
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 86fe71c75..2af3e1260 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
@@ -15,6 +15,7 @@
#include "common/address_space.h"
#include "common/common_funcs.h"
#include "common/common_types.h"
+#include "common/scratch_buffer.h"
#include "common/swap.h"
#include "core/hle/service/nvdrv/core/nvmap.h"
#include "core/hle/service/nvdrv/devices/nvdevice.h"
@@ -47,12 +48,12 @@ public:
explicit nvhost_as_gpu(Core::System& system_, Module& module, NvCore::Container& core);
~nvhost_as_gpu() override;
- NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- std::vector<u8>& output) override;
- NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- const std::vector<u8>& inline_input, std::vector<u8>& output) override;
- NvResult Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- std::vector<u8>& output, std::vector<u8>& inline_output) override;
+ NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<u8> output) override;
+ NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<const u8> inline_input, std::span<u8> output) override;
+ NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,
+ std::span<u8> inline_output) override;
void OnOpen(DeviceFD fd) override;
void OnClose(DeviceFD fd) override;
@@ -138,18 +139,18 @@ private:
static_assert(sizeof(IoctlGetVaRegions) == 16 + sizeof(VaRegion) * 2,
"IoctlGetVaRegions is incorrect size");
- NvResult AllocAsEx(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult AllocateSpace(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult Remap(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult FreeSpace(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult BindChannel(const std::vector<u8>& input, std::vector<u8>& output);
+ NvResult AllocAsEx(std::span<const u8> input, std::span<u8> output);
+ NvResult AllocateSpace(std::span<const u8> input, std::span<u8> output);
+ NvResult Remap(std::span<const u8> input, std::span<u8> output);
+ NvResult MapBufferEx(std::span<const u8> input, std::span<u8> output);
+ NvResult UnmapBuffer(std::span<const u8> input, std::span<u8> output);
+ NvResult FreeSpace(std::span<const u8> input, std::span<u8> output);
+ NvResult BindChannel(std::span<const u8> input, std::span<u8> output);
void GetVARegionsImpl(IoctlGetVaRegions& params);
- NvResult GetVARegions(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult GetVARegions(const std::vector<u8>& input, std::vector<u8>& output,
- std::vector<u8>& inline_output);
+ NvResult GetVARegions(std::span<const u8> input, std::span<u8> output);
+ NvResult GetVARegions(std::span<const u8> input, std::span<u8> output,
+ std::span<u8> inline_output);
void FreeMappingLocked(u64 offset);
@@ -212,6 +213,7 @@ private:
bool initialised{};
} vm;
std::shared_ptr<Tegra::MemoryManager> gmmu;
+ Common::ScratchBuffer<IoctlRemapEntry> entries;
// s32 channel{};
// u32 big_page_size{VM::DEFAULT_BIG_PAGE_SIZE};
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
index eee11fab8..4d55554b4 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
@@ -34,8 +34,8 @@ nvhost_ctrl::~nvhost_ctrl() {
}
}
-NvResult nvhost_ctrl::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- std::vector<u8>& output) {
+NvResult nvhost_ctrl::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<u8> output) {
switch (command.group) {
case 0x0:
switch (command.cmd) {
@@ -63,14 +63,14 @@ NvResult nvhost_ctrl::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>&
return NvResult::NotImplemented;
}
-NvResult nvhost_ctrl::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- const std::vector<u8>& inline_input, std::vector<u8>& output) {
+NvResult nvhost_ctrl::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<const u8> inline_input, std::span<u8> output) {
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
return NvResult::NotImplemented;
}
-NvResult nvhost_ctrl::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- std::vector<u8>& output, std::vector<u8>& inline_outpu) {
+NvResult nvhost_ctrl::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<u8> output, std::span<u8> inline_outpu) {
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
return NvResult::NotImplemented;
}
@@ -79,7 +79,7 @@ void nvhost_ctrl::OnOpen(DeviceFD fd) {}
void nvhost_ctrl::OnClose(DeviceFD fd) {}
-NvResult nvhost_ctrl::NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvhost_ctrl::NvOsGetConfigU32(std::span<const u8> input, std::span<u8> output) {
IocGetConfigParams params{};
std::memcpy(&params, input.data(), sizeof(params));
LOG_TRACE(Service_NVDRV, "called, setting={}!{}", params.domain_str.data(),
@@ -87,7 +87,7 @@ NvResult nvhost_ctrl::NvOsGetConfigU32(const std::vector<u8>& input, std::vector
return NvResult::ConfigVarNotFound; // Returns error on production mode
}
-NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output,
+NvResult nvhost_ctrl::IocCtrlEventWait(std::span<const u8> input, std::span<u8> output,
bool is_allocation) {
IocCtrlEventWaitParams params{};
std::memcpy(&params, input.data(), sizeof(params));
@@ -150,9 +150,9 @@ NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector
const auto check_failing = [&]() {
if (events[slot].fails > 2) {
{
- auto lk = system.StallProcesses();
+ auto lk = system.StallApplication();
host1x_syncpoint_manager.WaitHost(fence_id, target_value);
- system.UnstallProcesses();
+ system.UnstallApplication();
}
params.value.raw = target_value;
return true;
@@ -231,7 +231,7 @@ NvResult nvhost_ctrl::FreeEvent(u32 slot) {
return NvResult::Success;
}
-NvResult nvhost_ctrl::IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvhost_ctrl::IocCtrlEventRegister(std::span<const u8> input, std::span<u8> output) {
IocCtrlEventRegisterParams params{};
std::memcpy(&params, input.data(), sizeof(params));
const u32 event_id = params.user_event_id;
@@ -252,8 +252,7 @@ NvResult nvhost_ctrl::IocCtrlEventRegister(const std::vector<u8>& input, std::ve
return NvResult::Success;
}
-NvResult nvhost_ctrl::IocCtrlEventUnregister(const std::vector<u8>& input,
- std::vector<u8>& output) {
+NvResult nvhost_ctrl::IocCtrlEventUnregister(std::span<const u8> input, std::span<u8> output) {
IocCtrlEventUnregisterParams params{};
std::memcpy(&params, input.data(), sizeof(params));
const u32 event_id = params.user_event_id & 0x00FF;
@@ -263,8 +262,7 @@ NvResult nvhost_ctrl::IocCtrlEventUnregister(const std::vector<u8>& input,
return FreeEvent(event_id);
}
-NvResult nvhost_ctrl::IocCtrlEventUnregisterBatch(const std::vector<u8>& input,
- std::vector<u8>& output) {
+NvResult nvhost_ctrl::IocCtrlEventUnregisterBatch(std::span<const u8> input, std::span<u8> output) {
IocCtrlEventUnregisterBatchParams params{};
std::memcpy(&params, input.data(), sizeof(params));
u64 event_mask = params.user_events;
@@ -282,7 +280,7 @@ NvResult nvhost_ctrl::IocCtrlEventUnregisterBatch(const std::vector<u8>& input,
return NvResult::Success;
}
-NvResult nvhost_ctrl::IocCtrlClearEventWait(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvhost_ctrl::IocCtrlClearEventWait(std::span<const u8> input, std::span<u8> output) {
IocCtrlEventClearParams params{};
std::memcpy(&params, input.data(), sizeof(params));
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h
index 0b56d7070..2efed4862 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h
@@ -25,12 +25,12 @@ public:
NvCore::Container& core);
~nvhost_ctrl() override;
- NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- std::vector<u8>& output) override;
- NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- const std::vector<u8>& inline_input, std::vector<u8>& output) override;
- NvResult Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- std::vector<u8>& output, std::vector<u8>& inline_output) override;
+ NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<u8> output) override;
+ NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<const u8> inline_input, std::span<u8> output) override;
+ NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,
+ std::span<u8> inline_output) override;
void OnOpen(DeviceFD fd) override;
void OnClose(DeviceFD fd) override;
@@ -186,13 +186,12 @@ private:
static_assert(sizeof(IocCtrlEventUnregisterBatchParams) == 8,
"IocCtrlEventKill is incorrect size");
- NvResult NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output,
- bool is_allocation);
- NvResult IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult IocCtrlEventUnregister(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult IocCtrlEventUnregisterBatch(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult IocCtrlClearEventWait(const std::vector<u8>& input, std::vector<u8>& output);
+ NvResult NvOsGetConfigU32(std::span<const u8> input, std::span<u8> output);
+ NvResult IocCtrlEventWait(std::span<const u8> input, std::span<u8> output, bool is_allocation);
+ NvResult IocCtrlEventRegister(std::span<const u8> input, std::span<u8> output);
+ NvResult IocCtrlEventUnregister(std::span<const u8> input, std::span<u8> output);
+ NvResult IocCtrlEventUnregisterBatch(std::span<const u8> input, std::span<u8> output);
+ NvResult IocCtrlClearEventWait(std::span<const u8> input, std::span<u8> output);
NvResult FreeEvent(u32 slot);
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 b97813fbc..6081d92e9 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
@@ -21,8 +21,8 @@ nvhost_ctrl_gpu::~nvhost_ctrl_gpu() {
events_interface.FreeEvent(unknown_event);
}
-NvResult nvhost_ctrl_gpu::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- std::vector<u8>& output) {
+NvResult nvhost_ctrl_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<u8> output) {
switch (command.group) {
case 'G':
switch (command.cmd) {
@@ -53,14 +53,14 @@ NvResult nvhost_ctrl_gpu::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u
return NvResult::NotImplemented;
}
-NvResult nvhost_ctrl_gpu::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- const std::vector<u8>& inline_input, std::vector<u8>& output) {
+NvResult nvhost_ctrl_gpu::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<const u8> inline_input, std::span<u8> output) {
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
return NvResult::NotImplemented;
}
-NvResult nvhost_ctrl_gpu::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- std::vector<u8>& output, std::vector<u8>& inline_output) {
+NvResult nvhost_ctrl_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<u8> output, std::span<u8> inline_output) {
switch (command.group) {
case 'G':
switch (command.cmd) {
@@ -82,8 +82,7 @@ NvResult nvhost_ctrl_gpu::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u
void nvhost_ctrl_gpu::OnOpen(DeviceFD fd) {}
void nvhost_ctrl_gpu::OnClose(DeviceFD fd) {}
-NvResult nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input,
- std::vector<u8>& output) {
+NvResult nvhost_ctrl_gpu::GetCharacteristics(std::span<const u8> input, std::span<u8> output) {
LOG_DEBUG(Service_NVDRV, "called");
IoctlCharacteristics params{};
std::memcpy(&params, input.data(), input.size());
@@ -128,8 +127,8 @@ NvResult nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input,
return NvResult::Success;
}
-NvResult nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output,
- std::vector<u8>& inline_output) {
+NvResult nvhost_ctrl_gpu::GetCharacteristics(std::span<const u8> input, std::span<u8> output,
+ std::span<u8> inline_output) {
LOG_DEBUG(Service_NVDRV, "called");
IoctlCharacteristics params{};
std::memcpy(&params, input.data(), input.size());
@@ -176,7 +175,7 @@ NvResult nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input, std::
return NvResult::Success;
}
-NvResult nvhost_ctrl_gpu::GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvhost_ctrl_gpu::GetTPCMasks(std::span<const u8> input, std::span<u8> output) {
IoctlGpuGetTpcMasksArgs params{};
std::memcpy(&params, input.data(), input.size());
LOG_DEBUG(Service_NVDRV, "called, mask_buffer_size=0x{:X}", params.mask_buffer_size);
@@ -187,8 +186,8 @@ NvResult nvhost_ctrl_gpu::GetTPCMasks(const std::vector<u8>& input, std::vector<
return NvResult::Success;
}
-NvResult nvhost_ctrl_gpu::GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output,
- std::vector<u8>& inline_output) {
+NvResult nvhost_ctrl_gpu::GetTPCMasks(std::span<const u8> input, std::span<u8> output,
+ std::span<u8> inline_output) {
IoctlGpuGetTpcMasksArgs params{};
std::memcpy(&params, input.data(), input.size());
LOG_DEBUG(Service_NVDRV, "called, mask_buffer_size=0x{:X}", params.mask_buffer_size);
@@ -200,7 +199,7 @@ NvResult nvhost_ctrl_gpu::GetTPCMasks(const std::vector<u8>& input, std::vector<
return NvResult::Success;
}
-NvResult nvhost_ctrl_gpu::GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvhost_ctrl_gpu::GetActiveSlotMask(std::span<const u8> input, std::span<u8> output) {
LOG_DEBUG(Service_NVDRV, "called");
IoctlActiveSlotMask params{};
@@ -213,7 +212,7 @@ NvResult nvhost_ctrl_gpu::GetActiveSlotMask(const std::vector<u8>& input, std::v
return NvResult::Success;
}
-NvResult nvhost_ctrl_gpu::ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvhost_ctrl_gpu::ZCullGetCtxSize(std::span<const u8> input, std::span<u8> output) {
LOG_DEBUG(Service_NVDRV, "called");
IoctlZcullGetCtxSize params{};
@@ -225,7 +224,7 @@ NvResult nvhost_ctrl_gpu::ZCullGetCtxSize(const std::vector<u8>& input, std::vec
return NvResult::Success;
}
-NvResult nvhost_ctrl_gpu::ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvhost_ctrl_gpu::ZCullGetInfo(std::span<const u8> input, std::span<u8> output) {
LOG_DEBUG(Service_NVDRV, "called");
IoctlNvgpuGpuZcullGetInfoArgs params{};
@@ -248,7 +247,7 @@ NvResult nvhost_ctrl_gpu::ZCullGetInfo(const std::vector<u8>& input, std::vector
return NvResult::Success;
}
-NvResult nvhost_ctrl_gpu::ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvhost_ctrl_gpu::ZBCSetTable(std::span<const u8> input, std::span<u8> output) {
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
IoctlZbcSetTable params{};
@@ -264,7 +263,7 @@ NvResult nvhost_ctrl_gpu::ZBCSetTable(const std::vector<u8>& input, std::vector<
return NvResult::Success;
}
-NvResult nvhost_ctrl_gpu::ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvhost_ctrl_gpu::ZBCQueryTable(std::span<const u8> input, std::span<u8> output) {
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
IoctlZbcQueryTable params{};
@@ -274,7 +273,7 @@ NvResult nvhost_ctrl_gpu::ZBCQueryTable(const std::vector<u8>& input, std::vecto
return NvResult::Success;
}
-NvResult nvhost_ctrl_gpu::FlushL2(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvhost_ctrl_gpu::FlushL2(std::span<const u8> input, std::span<u8> output) {
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
IoctlFlushL2 params{};
@@ -284,7 +283,7 @@ NvResult nvhost_ctrl_gpu::FlushL2(const std::vector<u8>& input, std::vector<u8>&
return NvResult::Success;
}
-NvResult nvhost_ctrl_gpu::GetGpuTime(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvhost_ctrl_gpu::GetGpuTime(std::span<const u8> input, std::span<u8> output) {
LOG_DEBUG(Service_NVDRV, "called");
IoctlGetGpuTime params{};
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 1e8f254e2..97995551c 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h
@@ -21,12 +21,12 @@ public:
explicit nvhost_ctrl_gpu(Core::System& system_, EventInterface& events_interface_);
~nvhost_ctrl_gpu() override;
- NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- std::vector<u8>& output) override;
- NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- const std::vector<u8>& inline_input, std::vector<u8>& output) override;
- NvResult Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- std::vector<u8>& output, std::vector<u8>& inline_output) override;
+ NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<u8> output) override;
+ NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<const u8> inline_input, std::span<u8> output) override;
+ NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,
+ std::span<u8> inline_output) override;
void OnOpen(DeviceFD fd) override;
void OnClose(DeviceFD fd) override;
@@ -151,21 +151,21 @@ private:
};
static_assert(sizeof(IoctlGetGpuTime) == 0x10, "IoctlGetGpuTime is incorrect size");
- NvResult GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output,
- std::vector<u8>& inline_output);
-
- NvResult GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output,
- std::vector<u8>& inline_output);
-
- NvResult GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult FlushL2(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult GetGpuTime(const std::vector<u8>& input, std::vector<u8>& output);
+ NvResult GetCharacteristics(std::span<const u8> input, std::span<u8> output);
+ NvResult GetCharacteristics(std::span<const u8> input, std::span<u8> output,
+ std::span<u8> inline_output);
+
+ NvResult GetTPCMasks(std::span<const u8> input, std::span<u8> output);
+ NvResult GetTPCMasks(std::span<const u8> input, std::span<u8> output,
+ std::span<u8> inline_output);
+
+ NvResult GetActiveSlotMask(std::span<const u8> input, std::span<u8> output);
+ NvResult ZCullGetCtxSize(std::span<const u8> input, std::span<u8> output);
+ NvResult ZCullGetInfo(std::span<const u8> input, std::span<u8> output);
+ NvResult ZBCSetTable(std::span<const u8> input, std::span<u8> output);
+ NvResult ZBCQueryTable(std::span<const u8> input, std::span<u8> output);
+ NvResult FlushL2(std::span<const u8> input, std::span<u8> output);
+ NvResult GetGpuTime(std::span<const u8> input, std::span<u8> output);
EventInterface& events_interface;
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
index e123564c6..46a25fcab 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
@@ -46,8 +46,8 @@ nvhost_gpu::~nvhost_gpu() {
syncpoint_manager.FreeSyncpoint(channel_syncpoint);
}
-NvResult nvhost_gpu::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- std::vector<u8>& output) {
+NvResult nvhost_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<u8> output) {
switch (command.group) {
case 0x0:
switch (command.cmd) {
@@ -98,8 +98,8 @@ NvResult nvhost_gpu::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& i
return NvResult::NotImplemented;
};
-NvResult nvhost_gpu::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- const std::vector<u8>& inline_input, std::vector<u8>& output) {
+NvResult nvhost_gpu::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<const u8> inline_input, std::span<u8> output) {
switch (command.group) {
case 'H':
switch (command.cmd) {
@@ -112,8 +112,8 @@ NvResult nvhost_gpu::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& i
return NvResult::NotImplemented;
}
-NvResult nvhost_gpu::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- std::vector<u8>& output, std::vector<u8>& inline_output) {
+NvResult nvhost_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<u8> output, std::span<u8> inline_output) {
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
return NvResult::NotImplemented;
}
@@ -121,7 +121,7 @@ NvResult nvhost_gpu::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& i
void nvhost_gpu::OnOpen(DeviceFD fd) {}
void nvhost_gpu::OnClose(DeviceFD fd) {}
-NvResult nvhost_gpu::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvhost_gpu::SetNVMAPfd(std::span<const u8> input, std::span<u8> output) {
IoctlSetNvmapFD params{};
std::memcpy(&params, input.data(), input.size());
LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
@@ -130,7 +130,7 @@ NvResult nvhost_gpu::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& o
return NvResult::Success;
}
-NvResult nvhost_gpu::SetClientData(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvhost_gpu::SetClientData(std::span<const u8> input, std::span<u8> output) {
LOG_DEBUG(Service_NVDRV, "called");
IoctlClientData params{};
@@ -139,7 +139,7 @@ NvResult nvhost_gpu::SetClientData(const std::vector<u8>& input, std::vector<u8>
return NvResult::Success;
}
-NvResult nvhost_gpu::GetClientData(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvhost_gpu::GetClientData(std::span<const u8> input, std::span<u8> output) {
LOG_DEBUG(Service_NVDRV, "called");
IoctlClientData params{};
@@ -149,7 +149,7 @@ NvResult nvhost_gpu::GetClientData(const std::vector<u8>& input, std::vector<u8>
return NvResult::Success;
}
-NvResult nvhost_gpu::ZCullBind(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvhost_gpu::ZCullBind(std::span<const u8> input, std::span<u8> output) {
std::memcpy(&zcull_params, input.data(), input.size());
LOG_DEBUG(Service_NVDRV, "called, gpu_va={:X}, mode={:X}", zcull_params.gpu_va,
zcull_params.mode);
@@ -158,7 +158,7 @@ NvResult nvhost_gpu::ZCullBind(const std::vector<u8>& input, std::vector<u8>& ou
return NvResult::Success;
}
-NvResult nvhost_gpu::SetErrorNotifier(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvhost_gpu::SetErrorNotifier(std::span<const u8> input, std::span<u8> output) {
IoctlSetErrorNotifier params{};
std::memcpy(&params, input.data(), input.size());
LOG_WARNING(Service_NVDRV, "(STUBBED) called, offset={:X}, size={:X}, mem={:X}", params.offset,
@@ -168,14 +168,14 @@ NvResult nvhost_gpu::SetErrorNotifier(const std::vector<u8>& input, std::vector<
return NvResult::Success;
}
-NvResult nvhost_gpu::SetChannelPriority(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvhost_gpu::SetChannelPriority(std::span<const u8> input, std::span<u8> output) {
std::memcpy(&channel_priority, input.data(), input.size());
LOG_DEBUG(Service_NVDRV, "(STUBBED) called, priority={:X}", channel_priority);
return NvResult::Success;
}
-NvResult nvhost_gpu::AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvhost_gpu::AllocGPFIFOEx2(std::span<const u8> input, std::span<u8> output) {
IoctlAllocGpfifoEx2 params{};
std::memcpy(&params, input.data(), input.size());
LOG_WARNING(Service_NVDRV,
@@ -197,7 +197,7 @@ NvResult nvhost_gpu::AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8
return NvResult::Success;
}
-NvResult nvhost_gpu::AllocateObjectContext(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvhost_gpu::AllocateObjectContext(std::span<const u8> input, std::span<u8> output) {
IoctlAllocObjCtx params{};
std::memcpy(&params, input.data(), input.size());
LOG_WARNING(Service_NVDRV, "(STUBBED) called, class_num={:X}, flags={:X}", params.class_num,
@@ -208,7 +208,8 @@ NvResult nvhost_gpu::AllocateObjectContext(const std::vector<u8>& input, std::ve
return NvResult::Success;
}
-static std::vector<Tegra::CommandHeader> BuildWaitCommandList(NvFence fence) {
+static boost::container::small_vector<Tegra::CommandHeader, 512> BuildWaitCommandList(
+ NvFence fence) {
return {
Tegra::BuildCommandHeader(Tegra::BufferMethods::SyncpointPayload, 1,
Tegra::SubmissionMode::Increasing),
@@ -219,35 +220,35 @@ static std::vector<Tegra::CommandHeader> BuildWaitCommandList(NvFence fence) {
};
}
-static std::vector<Tegra::CommandHeader> BuildIncrementCommandList(NvFence fence) {
- std::vector<Tegra::CommandHeader> result{
+static boost::container::small_vector<Tegra::CommandHeader, 512> BuildIncrementCommandList(
+ NvFence fence) {
+ boost::container::small_vector<Tegra::CommandHeader, 512> result{
Tegra::BuildCommandHeader(Tegra::BufferMethods::SyncpointPayload, 1,
Tegra::SubmissionMode::Increasing),
{}};
for (u32 count = 0; count < 2; ++count) {
- result.emplace_back(Tegra::BuildCommandHeader(Tegra::BufferMethods::SyncpointOperation, 1,
- Tegra::SubmissionMode::Increasing));
- result.emplace_back(
+ result.push_back(Tegra::BuildCommandHeader(Tegra::BufferMethods::SyncpointOperation, 1,
+ Tegra::SubmissionMode::Increasing));
+ result.push_back(
BuildFenceAction(Tegra::Engines::Puller::FenceOperation::Increment, fence.id));
}
return result;
}
-static std::vector<Tegra::CommandHeader> BuildIncrementWithWfiCommandList(NvFence fence) {
- std::vector<Tegra::CommandHeader> result{
+static boost::container::small_vector<Tegra::CommandHeader, 512> BuildIncrementWithWfiCommandList(
+ NvFence fence) {
+ boost::container::small_vector<Tegra::CommandHeader, 512> result{
Tegra::BuildCommandHeader(Tegra::BufferMethods::WaitForIdle, 1,
Tegra::SubmissionMode::Increasing),
{}};
- const std::vector<Tegra::CommandHeader> increment{BuildIncrementCommandList(fence)};
-
- result.insert(result.end(), increment.begin(), increment.end());
-
+ auto increment_list{BuildIncrementCommandList(fence)};
+ result.insert(result.end(), increment_list.begin(), increment_list.end());
return result;
}
-NvResult nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector<u8>& output,
+NvResult nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::span<u8> output,
Tegra::CommandList&& entries) {
LOG_TRACE(Service_NVDRV, "called, gpfifo={:X}, num_entries={:X}, flags={:X}", params.address,
params.num_entries, params.flags.raw);
@@ -293,7 +294,7 @@ NvResult nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector<u8>
return NvResult::Success;
}
-NvResult nvhost_gpu::SubmitGPFIFOBase(const std::vector<u8>& input, std::vector<u8>& output,
+NvResult nvhost_gpu::SubmitGPFIFOBase(std::span<const u8> input, std::span<u8> output,
bool kickoff) {
if (input.size() < sizeof(IoctlSubmitGpfifo)) {
UNIMPLEMENTED();
@@ -304,8 +305,8 @@ NvResult nvhost_gpu::SubmitGPFIFOBase(const std::vector<u8>& input, std::vector<
Tegra::CommandList entries(params.num_entries);
if (kickoff) {
- system.Memory().ReadBlock(params.address, entries.command_lists.data(),
- params.num_entries * sizeof(Tegra::CommandListHeader));
+ system.ApplicationMemory().ReadBlock(params.address, entries.command_lists.data(),
+ params.num_entries * sizeof(Tegra::CommandListHeader));
} else {
std::memcpy(entries.command_lists.data(), &input[sizeof(IoctlSubmitGpfifo)],
params.num_entries * sizeof(Tegra::CommandListHeader));
@@ -314,9 +315,8 @@ NvResult nvhost_gpu::SubmitGPFIFOBase(const std::vector<u8>& input, std::vector<
return SubmitGPFIFOImpl(params, output, std::move(entries));
}
-NvResult nvhost_gpu::SubmitGPFIFOBase(const std::vector<u8>& input,
- const std::vector<u8>& input_inline,
- std::vector<u8>& output) {
+NvResult nvhost_gpu::SubmitGPFIFOBase(std::span<const u8> input, std::span<const u8> input_inline,
+ std::span<u8> output) {
if (input.size() < sizeof(IoctlSubmitGpfifo)) {
UNIMPLEMENTED();
return NvResult::InvalidSize;
@@ -328,7 +328,7 @@ NvResult nvhost_gpu::SubmitGPFIFOBase(const std::vector<u8>& input,
return SubmitGPFIFOImpl(params, output, std::move(entries));
}
-NvResult nvhost_gpu::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvhost_gpu::GetWaitbase(std::span<const u8> input, std::span<u8> output) {
IoctlGetWaitbase params{};
std::memcpy(&params, input.data(), sizeof(IoctlGetWaitbase));
LOG_INFO(Service_NVDRV, "called, unknown=0x{:X}", params.unknown);
@@ -338,7 +338,7 @@ NvResult nvhost_gpu::GetWaitbase(const std::vector<u8>& input, std::vector<u8>&
return NvResult::Success;
}
-NvResult nvhost_gpu::ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvhost_gpu::ChannelSetTimeout(std::span<const u8> input, std::span<u8> output) {
IoctlChannelSetTimeout params{};
std::memcpy(&params, input.data(), sizeof(IoctlChannelSetTimeout));
LOG_INFO(Service_NVDRV, "called, timeout=0x{:X}", params.timeout);
@@ -346,7 +346,7 @@ NvResult nvhost_gpu::ChannelSetTimeout(const std::vector<u8>& input, std::vector
return NvResult::Success;
}
-NvResult nvhost_gpu::ChannelSetTimeslice(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvhost_gpu::ChannelSetTimeslice(std::span<const u8> input, std::span<u8> output) {
IoctlSetTimeslice params{};
std::memcpy(&params, input.data(), sizeof(IoctlSetTimeslice));
LOG_INFO(Service_NVDRV, "called, timeslice=0x{:X}", params.timeslice);
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
index 1e4ecd55b..529c20526 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
@@ -40,12 +40,12 @@ public:
NvCore::Container& core);
~nvhost_gpu() override;
- NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- std::vector<u8>& output) override;
- NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- const std::vector<u8>& inline_input, std::vector<u8>& output) override;
- NvResult Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- std::vector<u8>& output, std::vector<u8>& inline_output) override;
+ NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<u8> output) override;
+ NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<const u8> inline_input, std::span<u8> output) override;
+ NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,
+ std::span<u8> inline_output) override;
void OnOpen(DeviceFD fd) override;
void OnClose(DeviceFD fd) override;
@@ -186,23 +186,23 @@ private:
u32_le channel_priority{};
u32_le channel_timeslice{};
- NvResult SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult SetClientData(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult GetClientData(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult ZCullBind(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult SetErrorNotifier(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult SetChannelPriority(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult AllocateObjectContext(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector<u8>& output,
+ NvResult SetNVMAPfd(std::span<const u8> input, std::span<u8> output);
+ NvResult SetClientData(std::span<const u8> input, std::span<u8> output);
+ NvResult GetClientData(std::span<const u8> input, std::span<u8> output);
+ NvResult ZCullBind(std::span<const u8> input, std::span<u8> output);
+ NvResult SetErrorNotifier(std::span<const u8> input, std::span<u8> output);
+ NvResult SetChannelPriority(std::span<const u8> input, std::span<u8> output);
+ NvResult AllocGPFIFOEx2(std::span<const u8> input, std::span<u8> output);
+ NvResult AllocateObjectContext(std::span<const u8> input, std::span<u8> output);
+ NvResult SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::span<u8> output,
Tegra::CommandList&& entries);
- NvResult SubmitGPFIFOBase(const std::vector<u8>& input, std::vector<u8>& output,
+ NvResult SubmitGPFIFOBase(std::span<const u8> input, std::span<u8> output,
bool kickoff = false);
- NvResult SubmitGPFIFOBase(const std::vector<u8>& input, const std::vector<u8>& input_inline,
- std::vector<u8>& output);
- NvResult GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult ChannelSetTimeslice(const std::vector<u8>& input, std::vector<u8>& output);
+ NvResult SubmitGPFIFOBase(std::span<const u8> input, std::span<const u8> input_inline,
+ std::span<u8> output);
+ NvResult GetWaitbase(std::span<const u8> input, std::span<u8> output);
+ NvResult ChannelSetTimeout(std::span<const u8> input, std::span<u8> output);
+ NvResult ChannelSetTimeslice(std::span<const u8> input, std::span<u8> output);
EventInterface& events_interface;
NvCore::Container& core;
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
index 1703f9cc3..a174442a6 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
@@ -15,8 +15,8 @@ nvhost_nvdec::nvhost_nvdec(Core::System& system_, NvCore::Container& core_)
: nvhost_nvdec_common{system_, core_, NvCore::ChannelType::NvDec} {}
nvhost_nvdec::~nvhost_nvdec() = default;
-NvResult nvhost_nvdec::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- std::vector<u8>& output) {
+NvResult nvhost_nvdec::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<u8> output) {
switch (command.group) {
case 0x0:
switch (command.cmd) {
@@ -55,21 +55,21 @@ NvResult nvhost_nvdec::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>&
return NvResult::NotImplemented;
}
-NvResult nvhost_nvdec::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- const std::vector<u8>& inline_input, std::vector<u8>& output) {
+NvResult nvhost_nvdec::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<const u8> inline_input, std::span<u8> output) {
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
return NvResult::NotImplemented;
}
-NvResult nvhost_nvdec::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- std::vector<u8>& output, std::vector<u8>& inline_output) {
+NvResult nvhost_nvdec::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<u8> output, std::span<u8> inline_output) {
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
return NvResult::NotImplemented;
}
void nvhost_nvdec::OnOpen(DeviceFD fd) {
LOG_INFO(Service_NVDRV, "NVDEC video stream started");
- system.AudioCore().SetNVDECActive(true);
+ system.SetNVDECActive(true);
}
void nvhost_nvdec::OnClose(DeviceFD fd) {
@@ -79,7 +79,7 @@ void nvhost_nvdec::OnClose(DeviceFD fd) {
if (iter != host1x_file.fd_to_id.end()) {
system.GPU().ClearCdmaInstance(iter->second);
}
- system.AudioCore().SetNVDECActive(false);
+ system.SetNVDECActive(false);
}
} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h
index c1b4e53e8..ad2233c49 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h
@@ -13,12 +13,12 @@ public:
explicit nvhost_nvdec(Core::System& system_, NvCore::Container& core);
~nvhost_nvdec() override;
- NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- std::vector<u8>& output) override;
- NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- const std::vector<u8>& inline_input, std::vector<u8>& output) override;
- NvResult Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- std::vector<u8>& output, std::vector<u8>& inline_output) override;
+ NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<u8> output) override;
+ NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<const u8> inline_input, std::span<u8> output) override;
+ NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,
+ std::span<u8> inline_output) override;
void OnOpen(DeviceFD fd) override;
void OnClose(DeviceFD fd) override;
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 99eede702..61649aa4a 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp
@@ -23,7 +23,7 @@ namespace {
// Copies count amount of type T from the input vector into the dst vector.
// Returns the number of bytes written into dst.
template <typename T>
-std::size_t SliceVectors(const std::vector<u8>& input, std::vector<T>& dst, std::size_t count,
+std::size_t SliceVectors(std::span<const u8> input, std::vector<T>& dst, std::size_t count,
std::size_t offset) {
if (dst.empty()) {
return 0;
@@ -36,7 +36,7 @@ std::size_t SliceVectors(const std::vector<u8>& input, std::vector<T>& dst, std:
// Writes the data in src to an offset into the dst vector. The offset is specified in bytes
// Returns the number of bytes written into dst.
template <typename T>
-std::size_t WriteVectors(std::vector<u8>& dst, const std::vector<T>& src, std::size_t offset) {
+std::size_t WriteVectors(std::span<u8> dst, const std::vector<T>& src, std::size_t offset) {
if (src.empty()) {
return 0;
}
@@ -63,7 +63,7 @@ nvhost_nvdec_common::~nvhost_nvdec_common() {
core.Host1xDeviceFile().syncpts_accumulated.push_back(channel_syncpoint);
}
-NvResult nvhost_nvdec_common::SetNVMAPfd(const std::vector<u8>& input) {
+NvResult nvhost_nvdec_common::SetNVMAPfd(std::span<const u8> input) {
IoctlSetNvmapFD params{};
std::memcpy(&params, input.data(), sizeof(IoctlSetNvmapFD));
LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
@@ -72,8 +72,7 @@ NvResult nvhost_nvdec_common::SetNVMAPfd(const std::vector<u8>& input) {
return NvResult::Success;
}
-NvResult nvhost_nvdec_common::Submit(DeviceFD fd, const std::vector<u8>& input,
- std::vector<u8>& output) {
+NvResult nvhost_nvdec_common::Submit(DeviceFD fd, std::span<const u8> input, std::span<u8> output) {
IoctlSubmit params{};
std::memcpy(&params, input.data(), sizeof(IoctlSubmit));
LOG_DEBUG(Service_NVDRV, "called NVDEC Submit, cmd_buffer_count={}", params.cmd_buffer_count);
@@ -105,8 +104,8 @@ NvResult nvhost_nvdec_common::Submit(DeviceFD fd, const std::vector<u8>& input,
const auto object = nvmap.GetHandle(cmd_buffer.memory_id);
ASSERT_OR_EXECUTE(object, return NvResult::InvalidState;);
Tegra::ChCommandHeaderList cmdlist(cmd_buffer.word_count);
- system.Memory().ReadBlock(object->address + cmd_buffer.offset, cmdlist.data(),
- cmdlist.size() * sizeof(u32));
+ system.ApplicationMemory().ReadBlock(object->address + cmd_buffer.offset, cmdlist.data(),
+ cmdlist.size() * sizeof(u32));
gpu.PushCommandBuffer(core.Host1xDeviceFile().fd_to_id[fd], cmdlist);
}
std::memcpy(output.data(), &params, sizeof(IoctlSubmit));
@@ -121,7 +120,7 @@ NvResult nvhost_nvdec_common::Submit(DeviceFD fd, const std::vector<u8>& input,
return NvResult::Success;
}
-NvResult nvhost_nvdec_common::GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvhost_nvdec_common::GetSyncpoint(std::span<const u8> input, std::span<u8> output) {
IoctlGetSyncpoint params{};
std::memcpy(&params, input.data(), sizeof(IoctlGetSyncpoint));
LOG_DEBUG(Service_NVDRV, "called GetSyncpoint, id={}", params.param);
@@ -133,7 +132,7 @@ NvResult nvhost_nvdec_common::GetSyncpoint(const std::vector<u8>& input, std::ve
return NvResult::Success;
}
-NvResult nvhost_nvdec_common::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvhost_nvdec_common::GetWaitbase(std::span<const u8> input, std::span<u8> output) {
IoctlGetWaitbase params{};
LOG_CRITICAL(Service_NVDRV, "called WAITBASE");
std::memcpy(&params, input.data(), sizeof(IoctlGetWaitbase));
@@ -142,7 +141,7 @@ NvResult nvhost_nvdec_common::GetWaitbase(const std::vector<u8>& input, std::vec
return NvResult::Success;
}
-NvResult nvhost_nvdec_common::MapBuffer(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvhost_nvdec_common::MapBuffer(std::span<const u8> input, std::span<u8> output) {
IoctlMapBuffer params{};
std::memcpy(&params, input.data(), sizeof(IoctlMapBuffer));
std::vector<MapBufferEntry> cmd_buffer_handles(params.num_entries);
@@ -159,7 +158,7 @@ NvResult nvhost_nvdec_common::MapBuffer(const std::vector<u8>& input, std::vecto
return NvResult::Success;
}
-NvResult nvhost_nvdec_common::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvhost_nvdec_common::UnmapBuffer(std::span<const u8> input, std::span<u8> output) {
IoctlMapBuffer params{};
std::memcpy(&params, input.data(), sizeof(IoctlMapBuffer));
std::vector<MapBufferEntry> cmd_buffer_handles(params.num_entries);
@@ -173,8 +172,7 @@ NvResult nvhost_nvdec_common::UnmapBuffer(const std::vector<u8>& input, std::vec
return NvResult::Success;
}
-NvResult nvhost_nvdec_common::SetSubmitTimeout(const std::vector<u8>& input,
- std::vector<u8>& output) {
+NvResult nvhost_nvdec_common::SetSubmitTimeout(std::span<const u8> input, std::span<u8> output) {
std::memcpy(&submit_timeout, input.data(), input.size());
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
return NvResult::Success;
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 fe76100c8..9bb573bfe 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h
@@ -107,13 +107,13 @@ protected:
static_assert(sizeof(IoctlMapBuffer) == 0x0C, "IoctlMapBuffer is incorrect size");
/// Ioctl command implementations
- NvResult SetNVMAPfd(const std::vector<u8>& input);
- NvResult Submit(DeviceFD fd, const std::vector<u8>& input, std::vector<u8>& output);
- NvResult GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult MapBuffer(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult SetSubmitTimeout(const std::vector<u8>& input, std::vector<u8>& output);
+ NvResult SetNVMAPfd(std::span<const u8> input);
+ NvResult Submit(DeviceFD fd, std::span<const u8> input, std::span<u8> output);
+ NvResult GetSyncpoint(std::span<const u8> input, std::span<u8> output);
+ NvResult GetWaitbase(std::span<const u8> input, std::span<u8> output);
+ NvResult MapBuffer(std::span<const u8> input, std::span<u8> output);
+ NvResult UnmapBuffer(std::span<const u8> input, std::span<u8> output);
+ NvResult SetSubmitTimeout(std::span<const u8> input, std::span<u8> output);
Kernel::KEvent* QueryEvent(u32 event_id) override;
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp
index bdbc2f9e1..a05c8cdae 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp
@@ -12,8 +12,8 @@ namespace Service::Nvidia::Devices {
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,
- std::vector<u8>& output) {
+NvResult nvhost_nvjpg::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<u8> output) {
switch (command.group) {
case 'H':
switch (command.cmd) {
@@ -31,14 +31,14 @@ NvResult nvhost_nvjpg::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>&
return NvResult::NotImplemented;
}
-NvResult nvhost_nvjpg::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- const std::vector<u8>& inline_input, std::vector<u8>& output) {
+NvResult nvhost_nvjpg::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<const u8> inline_input, std::span<u8> output) {
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
return NvResult::NotImplemented;
}
-NvResult nvhost_nvjpg::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- std::vector<u8>& output, std::vector<u8>& inline_output) {
+NvResult nvhost_nvjpg::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<u8> output, std::span<u8> inline_output) {
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
return NvResult::NotImplemented;
}
@@ -46,7 +46,7 @@ NvResult nvhost_nvjpg::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>&
void nvhost_nvjpg::OnOpen(DeviceFD fd) {}
void nvhost_nvjpg::OnClose(DeviceFD fd) {}
-NvResult nvhost_nvjpg::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvhost_nvjpg::SetNVMAPfd(std::span<const u8> input, std::span<u8> output) {
IoctlSetNvmapFD params{};
std::memcpy(&params, input.data(), input.size());
LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h
index 440e7d371..5623e0d47 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h
@@ -15,12 +15,12 @@ public:
explicit nvhost_nvjpg(Core::System& system_);
~nvhost_nvjpg() override;
- NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- std::vector<u8>& output) override;
- NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- const std::vector<u8>& inline_input, std::vector<u8>& output) override;
- NvResult Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- std::vector<u8>& output, std::vector<u8>& inline_output) override;
+ NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<u8> output) override;
+ NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<const u8> inline_input, std::span<u8> output) override;
+ NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,
+ std::span<u8> inline_output) override;
void OnOpen(DeviceFD fd) override;
void OnClose(DeviceFD fd) override;
@@ -33,7 +33,7 @@ private:
s32_le nvmap_fd{};
- NvResult SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output);
+ NvResult SetNVMAPfd(std::span<const u8> input, std::span<u8> output);
};
} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
index 73f97136e..c0b8684c3 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
@@ -15,8 +15,8 @@ nvhost_vic::nvhost_vic(Core::System& system_, NvCore::Container& core_)
nvhost_vic::~nvhost_vic() = default;
-NvResult nvhost_vic::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- std::vector<u8>& output) {
+NvResult nvhost_vic::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<u8> output) {
switch (command.group) {
case 0x0:
switch (command.cmd) {
@@ -55,14 +55,14 @@ NvResult nvhost_vic::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& i
return NvResult::NotImplemented;
}
-NvResult nvhost_vic::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- const std::vector<u8>& inline_input, std::vector<u8>& output) {
+NvResult nvhost_vic::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<const u8> inline_input, std::span<u8> output) {
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
return NvResult::NotImplemented;
}
-NvResult nvhost_vic::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- std::vector<u8>& output, std::vector<u8>& inline_output) {
+NvResult nvhost_vic::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<u8> output, std::span<u8> inline_output) {
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
return NvResult::NotImplemented;
}
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.h b/src/core/hle/service/nvdrv/devices/nvhost_vic.h
index f164caafb..cadbcb0a5 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_vic.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.h
@@ -12,12 +12,12 @@ public:
explicit nvhost_vic(Core::System& system_, NvCore::Container& core);
~nvhost_vic();
- NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- std::vector<u8>& output) override;
- NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- const std::vector<u8>& inline_input, std::vector<u8>& output) override;
- NvResult Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- std::vector<u8>& output, std::vector<u8>& inline_output) override;
+ NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<u8> output) override;
+ NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<const u8> inline_input, std::span<u8> output) override;
+ NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,
+ std::span<u8> inline_output) override;
void OnOpen(DeviceFD fd) override;
void OnClose(DeviceFD fd) override;
diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp
index fa29db758..e7f7e273b 100644
--- a/src/core/hle/service/nvdrv/devices/nvmap.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp
@@ -25,8 +25,8 @@ nvmap::nvmap(Core::System& system_, NvCore::Container& container_)
nvmap::~nvmap() = default;
-NvResult nvmap::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- std::vector<u8>& output) {
+NvResult nvmap::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<u8> output) {
switch (command.group) {
case 0x1:
switch (command.cmd) {
@@ -54,14 +54,14 @@ NvResult nvmap::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
return NvResult::NotImplemented;
}
-NvResult nvmap::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- const std::vector<u8>& inline_input, std::vector<u8>& output) {
+NvResult nvmap::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<const u8> inline_input, std::span<u8> output) {
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
return NvResult::NotImplemented;
}
-NvResult nvmap::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- std::vector<u8>& output, std::vector<u8>& inline_output) {
+NvResult nvmap::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,
+ std::span<u8> inline_output) {
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
return NvResult::NotImplemented;
}
@@ -69,7 +69,7 @@ NvResult nvmap::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
void nvmap::OnOpen(DeviceFD fd) {}
void nvmap::OnClose(DeviceFD fd) {}
-NvResult nvmap::IocCreate(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvmap::IocCreate(std::span<const u8> input, std::span<u8> output) {
IocCreateParams params;
std::memcpy(&params, input.data(), sizeof(params));
LOG_DEBUG(Service_NVDRV, "called, size=0x{:08X}", params.size);
@@ -89,7 +89,7 @@ NvResult nvmap::IocCreate(const std::vector<u8>& input, std::vector<u8>& output)
return NvResult::Success;
}
-NvResult nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvmap::IocAlloc(std::span<const u8> input, std::span<u8> output) {
IocAllocParams params;
std::memcpy(&params, input.data(), sizeof(params));
LOG_DEBUG(Service_NVDRV, "called, addr={:X}", params.address);
@@ -127,7 +127,7 @@ NvResult nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output)
return result;
}
bool is_out_io{};
- ASSERT(system.CurrentProcess()
+ ASSERT(system.ApplicationProcess()
->PageTable()
.LockForMapDeviceAddressSpace(&is_out_io, handle_description->address,
handle_description->size,
@@ -137,7 +137,7 @@ NvResult nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output)
return result;
}
-NvResult nvmap::IocGetId(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvmap::IocGetId(std::span<const u8> input, std::span<u8> output) {
IocGetIdParams params;
std::memcpy(&params, input.data(), sizeof(params));
@@ -161,7 +161,7 @@ NvResult nvmap::IocGetId(const std::vector<u8>& input, std::vector<u8>& output)
return NvResult::Success;
}
-NvResult nvmap::IocFromId(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvmap::IocFromId(std::span<const u8> input, std::span<u8> output) {
IocFromIdParams params;
std::memcpy(&params, input.data(), sizeof(params));
@@ -192,7 +192,7 @@ NvResult nvmap::IocFromId(const std::vector<u8>& input, std::vector<u8>& output)
return NvResult::Success;
}
-NvResult nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvmap::IocParam(std::span<const u8> input, std::span<u8> output) {
enum class ParamTypes { Size = 1, Alignment = 2, Base = 3, Heap = 4, Kind = 5, Compr = 6 };
IocParamParams params;
@@ -241,7 +241,7 @@ NvResult nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output)
return NvResult::Success;
}
-NvResult nvmap::IocFree(const std::vector<u8>& input, std::vector<u8>& output) {
+NvResult nvmap::IocFree(std::span<const u8> input, std::span<u8> output) {
IocFreeParams params;
std::memcpy(&params, input.data(), sizeof(params));
@@ -254,7 +254,7 @@ NvResult nvmap::IocFree(const std::vector<u8>& input, std::vector<u8>& output) {
if (auto freeInfo{file.FreeHandle(params.handle, false)}) {
if (freeInfo->can_unlock) {
- ASSERT(system.CurrentProcess()
+ ASSERT(system.ApplicationProcess()
->PageTable()
.UnlockForDeviceAddressSpace(freeInfo->address, freeInfo->size)
.IsSuccess());
@@ -264,7 +264,7 @@ NvResult nvmap::IocFree(const std::vector<u8>& input, std::vector<u8>& output) {
params.flags.raw = 0;
params.flags.map_uncached.Assign(freeInfo->was_uncached);
} else {
- // This is possible when there's internel dups or other duplicates.
+ // This is possible when there's internal dups or other duplicates.
}
std::memcpy(output.data(), &params, sizeof(params));
diff --git a/src/core/hle/service/nvdrv/devices/nvmap.h b/src/core/hle/service/nvdrv/devices/nvmap.h
index e9bfd0358..40c65b430 100644
--- a/src/core/hle/service/nvdrv/devices/nvmap.h
+++ b/src/core/hle/service/nvdrv/devices/nvmap.h
@@ -26,12 +26,12 @@ public:
nvmap(const nvmap&) = delete;
nvmap& operator=(const nvmap&) = delete;
- NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- std::vector<u8>& output) override;
- NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- const std::vector<u8>& inline_input, std::vector<u8>& output) override;
- NvResult Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- std::vector<u8>& output, std::vector<u8>& inline_output) override;
+ NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<u8> output) override;
+ NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<const u8> inline_input, std::span<u8> output) override;
+ NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,
+ std::span<u8> inline_output) override;
void OnOpen(DeviceFD fd) override;
void OnClose(DeviceFD fd) override;
@@ -106,12 +106,12 @@ private:
};
static_assert(sizeof(IocGetIdParams) == 8, "IocGetIdParams has wrong size");
- NvResult IocCreate(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult IocAlloc(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult IocGetId(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult IocFromId(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult IocParam(const std::vector<u8>& input, std::vector<u8>& output);
- NvResult IocFree(const std::vector<u8>& input, std::vector<u8>& output);
+ NvResult IocCreate(std::span<const u8> input, std::span<u8> output);
+ NvResult IocAlloc(std::span<const u8> input, std::span<u8> output);
+ NvResult IocGetId(std::span<const u8> input, std::span<u8> output);
+ NvResult IocFromId(std::span<const u8> input, std::span<u8> output);
+ NvResult IocParam(std::span<const u8> input, std::span<u8> output);
+ NvResult IocFree(std::span<const u8> input, std::span<u8> output);
NvCore::Container& container;
NvCore::NvMap& file;
diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp
index 6fc8565c0..9e46ee8dd 100644
--- a/src/core/hle/service/nvdrv/nvdrv.cpp
+++ b/src/core/hle/service/nvdrv/nvdrv.cpp
@@ -6,8 +6,8 @@
#include <fmt/format.h>
#include "core/core.h"
-#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/k_event.h"
+#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/nvdrv/core/container.h"
#include "core/hle/service/nvdrv/devices/nvdevice.h"
#include "core/hle/service/nvdrv/devices/nvdisp_disp0.h"
@@ -23,7 +23,8 @@
#include "core/hle/service/nvdrv/nvdrv.h"
#include "core/hle/service/nvdrv/nvdrv_interface.h"
#include "core/hle/service/nvdrv/nvmemp.h"
-#include "core/hle/service/nvflinger/nvflinger.h"
+#include "core/hle/service/nvnflinger/nvnflinger.h"
+#include "core/hle/service/server_manager.h"
#include "video_core/gpu.h"
namespace Service::Nvidia {
@@ -41,15 +42,19 @@ void EventInterface::FreeEvent(Kernel::KEvent* event) {
module.service_context.CloseEvent(event);
}
-void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nvflinger,
- Core::System& system) {
- auto module_ = std::make_shared<Module>(system);
- std::make_shared<NVDRV>(system, module_, "nvdrv")->InstallAsService(service_manager);
- std::make_shared<NVDRV>(system, module_, "nvdrv:a")->InstallAsService(service_manager);
- std::make_shared<NVDRV>(system, module_, "nvdrv:s")->InstallAsService(service_manager);
- std::make_shared<NVDRV>(system, module_, "nvdrv:t")->InstallAsService(service_manager);
- std::make_shared<NVMEMP>(system)->InstallAsService(service_manager);
- nvflinger.SetNVDrvInstance(module_);
+void LoopProcess(Nvnflinger::Nvnflinger& nvnflinger, Core::System& system) {
+ auto server_manager = std::make_unique<ServerManager>(system);
+ auto module = std::make_shared<Module>(system);
+ server_manager->RegisterNamedService("nvdrv", std::make_shared<NVDRV>(system, module, "nvdrv"));
+ server_manager->RegisterNamedService("nvdrv:a",
+ std::make_shared<NVDRV>(system, module, "nvdrv:a"));
+ server_manager->RegisterNamedService("nvdrv:s",
+ std::make_shared<NVDRV>(system, module, "nvdrv:s"));
+ server_manager->RegisterNamedService("nvdrv:t",
+ std::make_shared<NVDRV>(system, module, "nvdrv:t"));
+ server_manager->RegisterNamedService("nvmemp", std::make_shared<NVMEMP>(system));
+ nvnflinger.SetNVDrvInstance(module);
+ ServerManager::RunServer(std::move(server_manager));
}
Module::Module(Core::System& system)
@@ -124,8 +129,8 @@ DeviceFD Module::Open(const std::string& device_name) {
return fd;
}
-NvResult Module::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- std::vector<u8>& output) {
+NvResult Module::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<u8> output) {
if (fd < 0) {
LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd);
return NvResult::InvalidState;
@@ -141,8 +146,8 @@ NvResult Module::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input
return itr->second->Ioctl1(fd, command, input, output);
}
-NvResult Module::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- const std::vector<u8>& inline_input, std::vector<u8>& output) {
+NvResult Module::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<const u8> inline_input, std::span<u8> output) {
if (fd < 0) {
LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd);
return NvResult::InvalidState;
@@ -158,8 +163,8 @@ NvResult Module::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input
return itr->second->Ioctl2(fd, command, input, inline_input, output);
}
-NvResult Module::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- std::vector<u8>& output, std::vector<u8>& inline_output) {
+NvResult Module::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,
+ std::span<u8> inline_output) {
if (fd < 0) {
LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd);
return NvResult::InvalidState;
diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h
index f3c81bd88..d8622b3ca 100644
--- a/src/core/hle/service/nvdrv/nvdrv.h
+++ b/src/core/hle/service/nvdrv/nvdrv.h
@@ -7,6 +7,7 @@
#include <functional>
#include <list>
#include <memory>
+#include <span>
#include <string>
#include <unordered_map>
#include <vector>
@@ -15,7 +16,7 @@
#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/nvdrv/core/container.h"
#include "core/hle/service/nvdrv/nvdata.h"
-#include "core/hle/service/nvflinger/ui/fence.h"
+#include "core/hle/service/nvnflinger/ui/fence.h"
#include "core/hle/service/service.h"
namespace Core {
@@ -26,8 +27,8 @@ namespace Kernel {
class KEvent;
}
-namespace Service::NVFlinger {
-class NVFlinger;
+namespace Service::Nvnflinger {
+class Nvnflinger;
}
namespace Service::Nvidia {
@@ -79,14 +80,13 @@ public:
DeviceFD Open(const std::string& device_name);
/// Sends an ioctl command to the specified file descriptor.
- NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- std::vector<u8>& output);
+ NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output);
- NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- const std::vector<u8>& inline_input, std::vector<u8>& output);
+ NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
+ std::span<const u8> inline_input, std::span<u8> output);
- NvResult Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
- std::vector<u8>& output, std::vector<u8>& inline_output);
+ NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,
+ std::span<u8> inline_output);
/// Closes a device file descriptor and returns operation success.
NvResult Close(DeviceFD fd);
@@ -95,7 +95,7 @@ public:
private:
friend class EventInterface;
- friend class Service::NVFlinger::NVFlinger;
+ friend class Service::Nvnflinger::Nvnflinger;
/// Manages syncpoints on the host
NvCore::Container container;
@@ -114,8 +114,6 @@ private:
std::unordered_map<std::string, std::function<FilesContainerType::iterator(DeviceFD)>> builders;
};
-/// Registers all NVDRV services with the specified service manager.
-void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nvflinger,
- Core::System& system);
+void LoopProcess(Nvnflinger::Nvnflinger& nvnflinger, Core::System& system);
} // namespace Service::Nvidia
diff --git a/src/core/hle/service/nvdrv/nvdrv_interface.cpp b/src/core/hle/service/nvdrv/nvdrv_interface.cpp
index edbdfee43..348207e25 100644
--- a/src/core/hle/service/nvdrv/nvdrv_interface.cpp
+++ b/src/core/hle/service/nvdrv/nvdrv_interface.cpp
@@ -5,16 +5,16 @@
#include <cinttypes>
#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/service/ipc_helpers.h"
#include "core/hle/service/nvdrv/nvdata.h"
#include "core/hle/service/nvdrv/nvdrv.h"
#include "core/hle/service/nvdrv/nvdrv_interface.h"
namespace Service::Nvidia {
-void NVDRV::Open(Kernel::HLERequestContext& ctx) {
+void NVDRV::Open(HLERequestContext& ctx) {
LOG_DEBUG(Service_NVDRV, "called");
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
@@ -44,13 +44,13 @@ void NVDRV::Open(Kernel::HLERequestContext& ctx) {
rb.PushEnum(fd != INVALID_NVDRV_FD ? NvResult::Success : NvResult::FileOperationFailed);
}
-void NVDRV::ServiceError(Kernel::HLERequestContext& ctx, NvResult result) {
+void NVDRV::ServiceError(HLERequestContext& ctx, NvResult result) {
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.PushEnum(result);
}
-void NVDRV::Ioctl1(Kernel::HLERequestContext& ctx) {
+void NVDRV::Ioctl1(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto fd = rp.Pop<DeviceFD>();
const auto command = rp.PopRaw<Ioctl>();
@@ -63,12 +63,12 @@ void NVDRV::Ioctl1(Kernel::HLERequestContext& ctx) {
}
// Check device
- std::vector<u8> output_buffer(ctx.GetWriteBufferSize(0));
+ tmp_output.resize_destructive(ctx.GetWriteBufferSize(0));
const auto input_buffer = ctx.ReadBuffer(0);
- const auto nv_result = nvdrv->Ioctl1(fd, command, input_buffer, output_buffer);
+ const auto nv_result = nvdrv->Ioctl1(fd, command, input_buffer, tmp_output);
if (command.is_out != 0) {
- ctx.WriteBuffer(output_buffer);
+ ctx.WriteBuffer(tmp_output);
}
IPC::ResponseBuilder rb{ctx, 3};
@@ -76,7 +76,7 @@ void NVDRV::Ioctl1(Kernel::HLERequestContext& ctx) {
rb.PushEnum(nv_result);
}
-void NVDRV::Ioctl2(Kernel::HLERequestContext& ctx) {
+void NVDRV::Ioctl2(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto fd = rp.Pop<DeviceFD>();
const auto command = rp.PopRaw<Ioctl>();
@@ -90,12 +90,12 @@ void NVDRV::Ioctl2(Kernel::HLERequestContext& ctx) {
const auto input_buffer = ctx.ReadBuffer(0);
const auto input_inlined_buffer = ctx.ReadBuffer(1);
- std::vector<u8> output_buffer(ctx.GetWriteBufferSize(0));
+ tmp_output.resize_destructive(ctx.GetWriteBufferSize(0));
const auto nv_result =
- nvdrv->Ioctl2(fd, command, input_buffer, input_inlined_buffer, output_buffer);
+ nvdrv->Ioctl2(fd, command, input_buffer, input_inlined_buffer, tmp_output);
if (command.is_out != 0) {
- ctx.WriteBuffer(output_buffer);
+ ctx.WriteBuffer(tmp_output);
}
IPC::ResponseBuilder rb{ctx, 3};
@@ -103,7 +103,7 @@ void NVDRV::Ioctl2(Kernel::HLERequestContext& ctx) {
rb.PushEnum(nv_result);
}
-void NVDRV::Ioctl3(Kernel::HLERequestContext& ctx) {
+void NVDRV::Ioctl3(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto fd = rp.Pop<DeviceFD>();
const auto command = rp.PopRaw<Ioctl>();
@@ -116,14 +116,12 @@ void NVDRV::Ioctl3(Kernel::HLERequestContext& ctx) {
}
const auto input_buffer = ctx.ReadBuffer(0);
- std::vector<u8> output_buffer(ctx.GetWriteBufferSize(0));
- std::vector<u8> output_buffer_inline(ctx.GetWriteBufferSize(1));
-
- const auto nv_result =
- nvdrv->Ioctl3(fd, command, input_buffer, output_buffer, output_buffer_inline);
+ tmp_output.resize_destructive(ctx.GetWriteBufferSize(0));
+ tmp_output_inline.resize_destructive(ctx.GetWriteBufferSize(1));
+ const auto nv_result = nvdrv->Ioctl3(fd, command, input_buffer, tmp_output, tmp_output_inline);
if (command.is_out != 0) {
- ctx.WriteBuffer(output_buffer, 0);
- ctx.WriteBuffer(output_buffer_inline, 1);
+ ctx.WriteBuffer(tmp_output, 0);
+ ctx.WriteBuffer(tmp_output_inline, 1);
}
IPC::ResponseBuilder rb{ctx, 3};
@@ -131,7 +129,7 @@ void NVDRV::Ioctl3(Kernel::HLERequestContext& ctx) {
rb.PushEnum(nv_result);
}
-void NVDRV::Close(Kernel::HLERequestContext& ctx) {
+void NVDRV::Close(HLERequestContext& ctx) {
LOG_DEBUG(Service_NVDRV, "called");
if (!is_initialized) {
@@ -149,7 +147,7 @@ void NVDRV::Close(Kernel::HLERequestContext& ctx) {
rb.PushEnum(result);
}
-void NVDRV::Initialize(Kernel::HLERequestContext& ctx) {
+void NVDRV::Initialize(HLERequestContext& ctx) {
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
is_initialized = true;
@@ -159,7 +157,7 @@ void NVDRV::Initialize(Kernel::HLERequestContext& ctx) {
rb.PushEnum(NvResult::Success);
}
-void NVDRV::QueryEvent(Kernel::HLERequestContext& ctx) {
+void NVDRV::QueryEvent(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto fd = rp.Pop<DeviceFD>();
const auto event_id = rp.Pop<u32>();
@@ -187,7 +185,7 @@ void NVDRV::QueryEvent(Kernel::HLERequestContext& ctx) {
}
}
-void NVDRV::SetAruid(Kernel::HLERequestContext& ctx) {
+void NVDRV::SetAruid(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
pid = rp.Pop<u64>();
LOG_WARNING(Service_NVDRV, "(STUBBED) called, pid=0x{:X}", pid);
@@ -197,14 +195,14 @@ void NVDRV::SetAruid(Kernel::HLERequestContext& ctx) {
rb.PushEnum(NvResult::Success);
}
-void NVDRV::SetGraphicsFirmwareMemoryMarginEnabled(Kernel::HLERequestContext& ctx) {
+void NVDRV::SetGraphicsFirmwareMemoryMarginEnabled(HLERequestContext& ctx) {
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
-void NVDRV::GetStatus(Kernel::HLERequestContext& ctx) {
+void NVDRV::GetStatus(HLERequestContext& ctx) {
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
@@ -212,7 +210,7 @@ void NVDRV::GetStatus(Kernel::HLERequestContext& ctx) {
rb.PushEnum(NvResult::Success);
}
-void NVDRV::DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx) {
+void NVDRV::DumpGraphicsMemoryInfo(HLERequestContext& ctx) {
// According to SwitchBrew, this has no inputs and no outputs, so effectively does nothing on
// retail hardware.
LOG_DEBUG(Service_NVDRV, "called");
@@ -222,7 +220,7 @@ void NVDRV::DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx) {
}
NVDRV::NVDRV(Core::System& system_, std::shared_ptr<Module> nvdrv_, const char* name)
- : ServiceFramework{system_, name, ServiceThreadType::CreateNew}, nvdrv{std::move(nvdrv_)} {
+ : ServiceFramework{system_, name}, nvdrv{std::move(nvdrv_)} {
static const FunctionInfo functions[] = {
{0, &NVDRV::Open, "Open"},
{1, &NVDRV::Ioctl1, "Ioctl"},
diff --git a/src/core/hle/service/nvdrv/nvdrv_interface.h b/src/core/hle/service/nvdrv/nvdrv_interface.h
index 5ac06ee30..4b593ff90 100644
--- a/src/core/hle/service/nvdrv/nvdrv_interface.h
+++ b/src/core/hle/service/nvdrv/nvdrv_interface.h
@@ -4,6 +4,7 @@
#pragma once
#include <memory>
+#include "common/scratch_buffer.h"
#include "core/hle/service/nvdrv/nvdrv.h"
#include "core/hle/service/service.h"
@@ -15,24 +16,26 @@ public:
~NVDRV() override;
private:
- void Open(Kernel::HLERequestContext& ctx);
- void Ioctl1(Kernel::HLERequestContext& ctx);
- void Ioctl2(Kernel::HLERequestContext& ctx);
- void Ioctl3(Kernel::HLERequestContext& ctx);
- void Close(Kernel::HLERequestContext& ctx);
- void Initialize(Kernel::HLERequestContext& ctx);
- void QueryEvent(Kernel::HLERequestContext& ctx);
- void SetAruid(Kernel::HLERequestContext& ctx);
- void SetGraphicsFirmwareMemoryMarginEnabled(Kernel::HLERequestContext& ctx);
- void GetStatus(Kernel::HLERequestContext& ctx);
- void DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx);
-
- void ServiceError(Kernel::HLERequestContext& ctx, NvResult result);
+ void Open(HLERequestContext& ctx);
+ void Ioctl1(HLERequestContext& ctx);
+ void Ioctl2(HLERequestContext& ctx);
+ void Ioctl3(HLERequestContext& ctx);
+ void Close(HLERequestContext& ctx);
+ void Initialize(HLERequestContext& ctx);
+ void QueryEvent(HLERequestContext& ctx);
+ void SetAruid(HLERequestContext& ctx);
+ void SetGraphicsFirmwareMemoryMarginEnabled(HLERequestContext& ctx);
+ void GetStatus(HLERequestContext& ctx);
+ void DumpGraphicsMemoryInfo(HLERequestContext& ctx);
+
+ void ServiceError(HLERequestContext& ctx, NvResult result);
std::shared_ptr<Module> nvdrv;
u64 pid{};
bool is_initialized{};
+ Common::ScratchBuffer<u8> tmp_output;
+ Common::ScratchBuffer<u8> tmp_output_inline;
};
} // namespace Service::Nvidia
diff --git a/src/core/hle/service/nvdrv/nvmemp.cpp b/src/core/hle/service/nvdrv/nvmemp.cpp
index e433580b1..fc10f6406 100644
--- a/src/core/hle/service/nvdrv/nvmemp.cpp
+++ b/src/core/hle/service/nvdrv/nvmemp.cpp
@@ -17,11 +17,11 @@ NVMEMP::NVMEMP(Core::System& system_) : ServiceFramework{system_, "nvmemp"} {
NVMEMP::~NVMEMP() = default;
-void NVMEMP::Open(Kernel::HLERequestContext& ctx) {
+void NVMEMP::Open(HLERequestContext& ctx) {
UNIMPLEMENTED();
}
-void NVMEMP::GetAruid(Kernel::HLERequestContext& ctx) {
+void NVMEMP::GetAruid(HLERequestContext& ctx) {
UNIMPLEMENTED();
}
diff --git a/src/core/hle/service/nvdrv/nvmemp.h b/src/core/hle/service/nvdrv/nvmemp.h
index 3d4276327..85e3053a8 100644
--- a/src/core/hle/service/nvdrv/nvmemp.h
+++ b/src/core/hle/service/nvdrv/nvmemp.h
@@ -17,8 +17,8 @@ public:
~NVMEMP() override;
private:
- void Open(Kernel::HLERequestContext& ctx);
- void GetAruid(Kernel::HLERequestContext& ctx);
+ void Open(HLERequestContext& ctx);
+ void GetAruid(HLERequestContext& ctx);
};
} // namespace Service::Nvidia
diff --git a/src/core/hle/service/nvflinger/parcel.h b/src/core/hle/service/nvflinger/parcel.h
deleted file mode 100644
index f3fa2587d..000000000
--- a/src/core/hle/service/nvflinger/parcel.h
+++ /dev/null
@@ -1,172 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-#pragma once
-
-#include <memory>
-#include <vector>
-
-#include "common/alignment.h"
-#include "common/assert.h"
-#include "common/common_types.h"
-
-namespace Service::android {
-
-class Parcel final {
-public:
- static constexpr std::size_t DefaultBufferSize = 0x40;
-
- Parcel() : buffer(DefaultBufferSize) {}
-
- template <typename T>
- explicit Parcel(const T& out_data) : buffer(DefaultBufferSize) {
- Write(out_data);
- }
-
- explicit Parcel(std::vector<u8> in_data) : buffer(std::move(in_data)) {
- DeserializeHeader();
- [[maybe_unused]] const std::u16string token = ReadInterfaceToken();
- }
-
- template <typename T>
- void Read(T& val) {
- static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable.");
- ASSERT(read_index + sizeof(T) <= buffer.size());
-
- std::memcpy(&val, buffer.data() + read_index, sizeof(T));
- read_index += sizeof(T);
- read_index = Common::AlignUp(read_index, 4);
- }
-
- template <typename T>
- T Read() {
- T val;
- Read(val);
- return val;
- }
-
- template <typename T>
- void ReadFlattened(T& val) {
- const auto flattened_size = Read<s64>();
- ASSERT(sizeof(T) == flattened_size);
- Read(val);
- }
-
- template <typename T>
- T ReadFlattened() {
- T val;
- ReadFlattened(val);
- return val;
- }
-
- template <typename T>
- T ReadUnaligned() {
- static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable.");
- ASSERT(read_index + sizeof(T) <= buffer.size());
-
- T val;
- std::memcpy(&val, buffer.data() + read_index, sizeof(T));
- read_index += sizeof(T);
- return val;
- }
-
- template <typename T>
- const std::shared_ptr<T> ReadObject() {
- static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable.");
-
- const auto is_valid{Read<bool>()};
-
- if (is_valid) {
- auto result = std::make_shared<T>();
- ReadFlattened(*result);
- return result;
- }
-
- return {};
- }
-
- std::u16string ReadInterfaceToken() {
- [[maybe_unused]] const u32 unknown = Read<u32>();
- const u32 length = Read<u32>();
-
- std::u16string token;
- token.reserve(length + 1);
-
- for (u32 ch = 0; ch < length + 1; ++ch) {
- token.push_back(ReadUnaligned<u16>());
- }
-
- read_index = Common::AlignUp(read_index, 4);
-
- return token;
- }
-
- template <typename T>
- void Write(const T& val) {
- static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable.");
-
- if (buffer.size() < write_index + sizeof(T)) {
- buffer.resize(buffer.size() + sizeof(T) + DefaultBufferSize);
- }
-
- std::memcpy(buffer.data() + write_index, &val, sizeof(T));
- write_index += sizeof(T);
- write_index = Common::AlignUp(write_index, 4);
- }
-
- template <typename T>
- void WriteObject(const T* ptr) {
- static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable.");
-
- if (!ptr) {
- Write<u32>(0);
- return;
- }
-
- Write<u32>(1);
- Write<s64>(sizeof(T));
- Write(*ptr);
- }
-
- template <typename T>
- void WriteObject(const std::shared_ptr<T> ptr) {
- WriteObject(ptr.get());
- }
-
- void DeserializeHeader() {
- ASSERT(buffer.size() > sizeof(Header));
-
- Header header{};
- std::memcpy(&header, buffer.data(), sizeof(Header));
-
- read_index = header.data_offset;
- }
-
- std::vector<u8> Serialize() const {
- ASSERT(read_index == 0);
-
- Header header{};
- header.data_size = static_cast<u32>(write_index - sizeof(Header));
- header.data_offset = sizeof(Header);
- header.objects_size = 4;
- header.objects_offset = static_cast<u32>(sizeof(Header) + header.data_size);
- std::memcpy(buffer.data(), &header, sizeof(Header));
-
- return buffer;
- }
-
-private:
- struct Header {
- u32 data_size;
- u32 data_offset;
- u32 objects_size;
- u32 objects_offset;
- };
- static_assert(sizeof(Header) == 16, "ParcelHeader has wrong size");
-
- mutable std::vector<u8> buffer;
- std::size_t read_index = 0;
- std::size_t write_index = sizeof(Header);
-};
-
-} // namespace Service::android
diff --git a/src/core/hle/service/nvflinger/binder.h b/src/core/hle/service/nvnflinger/binder.h
index 157333ff8..aef1477e3 100644
--- a/src/core/hle/service/nvflinger/binder.h
+++ b/src/core/hle/service/nvnflinger/binder.h
@@ -9,10 +9,13 @@
#include "common/common_types.h"
namespace Kernel {
-class HLERequestContext;
class KReadableEvent;
} // namespace Kernel
+namespace Service {
+class HLERequestContext;
+}
+
namespace Service::android {
enum class TransactionId {
@@ -35,8 +38,7 @@ enum class TransactionId {
class IBinder {
public:
virtual ~IBinder() = default;
- virtual void Transact(Kernel::HLERequestContext& ctx, android::TransactionId code,
- u32 flags) = 0;
+ virtual void Transact(HLERequestContext& ctx, android::TransactionId code, u32 flags) = 0;
virtual Kernel::KReadableEvent& GetNativeHandle() = 0;
};
diff --git a/src/core/hle/service/nvflinger/buffer_item.h b/src/core/hle/service/nvnflinger/buffer_item.h
index f73dec4f1..7fd808f54 100644
--- a/src/core/hle/service/nvflinger/buffer_item.h
+++ b/src/core/hle/service/nvnflinger/buffer_item.h
@@ -10,8 +10,8 @@
#include "common/common_types.h"
#include "common/math_util.h"
-#include "core/hle/service/nvflinger/ui/fence.h"
-#include "core/hle/service/nvflinger/window.h"
+#include "core/hle/service/nvnflinger/ui/fence.h"
+#include "core/hle/service/nvnflinger/window.h"
namespace Service::android {
diff --git a/src/core/hle/service/nvflinger/buffer_item_consumer.cpp b/src/core/hle/service/nvnflinger/buffer_item_consumer.cpp
index 152bb5bdf..cf151ea3a 100644
--- a/src/core/hle/service/nvflinger/buffer_item_consumer.cpp
+++ b/src/core/hle/service/nvnflinger/buffer_item_consumer.cpp
@@ -6,9 +6,9 @@
#include "common/assert.h"
#include "common/logging/log.h"
-#include "core/hle/service/nvflinger/buffer_item.h"
-#include "core/hle/service/nvflinger/buffer_item_consumer.h"
-#include "core/hle/service/nvflinger/buffer_queue_consumer.h"
+#include "core/hle/service/nvnflinger/buffer_item.h"
+#include "core/hle/service/nvnflinger/buffer_item_consumer.h"
+#include "core/hle/service/nvnflinger/buffer_queue_consumer.h"
namespace Service::android {
@@ -25,7 +25,7 @@ Status BufferItemConsumer::AcquireBuffer(BufferItem* item, std::chrono::nanoseco
if (const auto status = AcquireBufferLocked(item, present_when); status != Status::NoError) {
if (status != Status::NoBufferAvailable) {
- LOG_ERROR(Service_NVFlinger, "Failed to acquire buffer: {}", status);
+ LOG_ERROR(Service_Nvnflinger, "Failed to acquire buffer: {}", status);
}
return status;
}
@@ -44,12 +44,12 @@ Status BufferItemConsumer::ReleaseBuffer(const BufferItem& item, const Fence& re
if (const auto status = AddReleaseFenceLocked(item.buf, item.graphic_buffer, release_fence);
status != Status::NoError) {
- LOG_ERROR(Service_NVFlinger, "Failed to add fence: {}", status);
+ LOG_ERROR(Service_Nvnflinger, "Failed to add fence: {}", status);
}
if (const auto status = ReleaseBufferLocked(item.buf, item.graphic_buffer);
status != Status::NoError) {
- LOG_WARNING(Service_NVFlinger, "Failed to release buffer: {}", status);
+ LOG_WARNING(Service_Nvnflinger, "Failed to release buffer: {}", status);
return status;
}
diff --git a/src/core/hle/service/nvflinger/buffer_item_consumer.h b/src/core/hle/service/nvnflinger/buffer_item_consumer.h
index a5c655d9e..e0c6b3604 100644
--- a/src/core/hle/service/nvflinger/buffer_item_consumer.h
+++ b/src/core/hle/service/nvnflinger/buffer_item_consumer.h
@@ -10,8 +10,8 @@
#include <memory>
#include "common/common_types.h"
-#include "core/hle/service/nvflinger/consumer_base.h"
-#include "core/hle/service/nvflinger/status.h"
+#include "core/hle/service/nvnflinger/consumer_base.h"
+#include "core/hle/service/nvnflinger/status.h"
namespace Service::android {
diff --git a/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp b/src/core/hle/service/nvnflinger/buffer_queue_consumer.cpp
index 0767e548d..51291539d 100644
--- a/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp
+++ b/src/core/hle/service/nvnflinger/buffer_queue_consumer.cpp
@@ -6,11 +6,11 @@
#include "common/logging/log.h"
#include "core/hle/service/nvdrv/core/nvmap.h"
-#include "core/hle/service/nvflinger/buffer_item.h"
-#include "core/hle/service/nvflinger/buffer_queue_consumer.h"
-#include "core/hle/service/nvflinger/buffer_queue_core.h"
-#include "core/hle/service/nvflinger/producer_listener.h"
-#include "core/hle/service/nvflinger/ui/graphic_buffer.h"
+#include "core/hle/service/nvnflinger/buffer_item.h"
+#include "core/hle/service/nvnflinger/buffer_queue_consumer.h"
+#include "core/hle/service/nvnflinger/buffer_queue_core.h"
+#include "core/hle/service/nvnflinger/producer_listener.h"
+#include "core/hle/service/nvnflinger/ui/graphic_buffer.h"
namespace Service::android {
@@ -31,7 +31,7 @@ Status BufferQueueConsumer::AcquireBuffer(BufferItem* out_buffer,
}))};
if (num_acquired_buffers >= core->max_acquired_buffer_count + 1) {
- LOG_ERROR(Service_NVFlinger, "max acquired buffer count reached: {} (max {})",
+ LOG_ERROR(Service_Nvnflinger, "max acquired buffer count reached: {} (max {})",
num_acquired_buffers, core->max_acquired_buffer_count);
return Status::InvalidOperation;
}
@@ -57,12 +57,12 @@ Status BufferQueueConsumer::AcquireBuffer(BufferItem* out_buffer,
if (desired_present < expected_present.count() - MAX_REASONABLE_NSEC ||
desired_present > expected_present.count()) {
// This buffer is set to display in the near future, or desired_present is garbage.
- LOG_DEBUG(Service_NVFlinger, "nodrop desire={} expect={}", desired_present,
+ LOG_DEBUG(Service_Nvnflinger, "nodrop desire={} expect={}", desired_present,
expected_present.count());
break;
}
- LOG_DEBUG(Service_NVFlinger, "drop desire={} expect={} size={}", desired_present,
+ LOG_DEBUG(Service_Nvnflinger, "drop desire={} expect={} size={}", desired_present,
expected_present.count(), core->queue.size());
if (core->StillTracking(*front)) {
@@ -78,19 +78,19 @@ Status BufferQueueConsumer::AcquireBuffer(BufferItem* out_buffer,
const auto desired_present = front->timestamp;
if (desired_present > expected_present.count() &&
desired_present < expected_present.count() + MAX_REASONABLE_NSEC) {
- LOG_DEBUG(Service_NVFlinger, "defer desire={} expect={}", desired_present,
+ LOG_DEBUG(Service_Nvnflinger, "defer desire={} expect={}", desired_present,
expected_present.count());
return Status::PresentLater;
}
- LOG_DEBUG(Service_NVFlinger, "accept desire={} expect={}", desired_present,
+ LOG_DEBUG(Service_Nvnflinger, "accept desire={} expect={}", desired_present,
expected_present.count());
}
const auto slot = front->slot;
*out_buffer = *front;
- LOG_DEBUG(Service_NVFlinger, "acquiring slot={}", slot);
+ LOG_DEBUG(Service_Nvnflinger, "acquiring slot={}", slot);
// If the buffer has previously been acquired by the consumer, set graphic_buffer to nullptr to
// avoid unnecessarily remapping this buffer on the consumer side.
@@ -109,7 +109,7 @@ Status BufferQueueConsumer::AcquireBuffer(BufferItem* out_buffer,
Status BufferQueueConsumer::ReleaseBuffer(s32 slot, u64 frame_number, const Fence& release_fence) {
if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) {
- LOG_ERROR(Service_NVFlinger, "slot {} out of range", slot);
+ LOG_ERROR(Service_Nvnflinger, "slot {} out of range", slot);
return Status::BadValue;
}
@@ -127,7 +127,7 @@ Status BufferQueueConsumer::ReleaseBuffer(s32 slot, u64 frame_number, const Fenc
auto current(core->queue.begin());
while (current != core->queue.end()) {
if (current->slot == slot) {
- LOG_ERROR(Service_NVFlinger, "buffer slot {} pending release is currently queued",
+ LOG_ERROR(Service_Nvnflinger, "buffer slot {} pending release is currently queued",
slot);
return Status::BadValue;
}
@@ -140,7 +140,7 @@ Status BufferQueueConsumer::ReleaseBuffer(s32 slot, u64 frame_number, const Fenc
listener = core->connected_producer_listener;
- LOG_DEBUG(Service_NVFlinger, "releasing slot {}", slot);
+ LOG_DEBUG(Service_Nvnflinger, "releasing slot {}", slot);
core->SignalDequeueCondition();
}
@@ -156,16 +156,16 @@ Status BufferQueueConsumer::ReleaseBuffer(s32 slot, u64 frame_number, const Fenc
Status BufferQueueConsumer::Connect(std::shared_ptr<IConsumerListener> consumer_listener,
bool controlled_by_app) {
if (consumer_listener == nullptr) {
- LOG_ERROR(Service_NVFlinger, "consumer_listener may not be nullptr");
+ LOG_ERROR(Service_Nvnflinger, "consumer_listener may not be nullptr");
return Status::BadValue;
}
- LOG_DEBUG(Service_NVFlinger, "controlled_by_app={}", controlled_by_app);
+ LOG_DEBUG(Service_Nvnflinger, "controlled_by_app={}", controlled_by_app);
std::scoped_lock lock{core->mutex};
if (core->is_abandoned) {
- LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned");
+ LOG_ERROR(Service_Nvnflinger, "BufferQueue has been abandoned");
return Status::NoInit;
}
@@ -177,14 +177,14 @@ Status BufferQueueConsumer::Connect(std::shared_ptr<IConsumerListener> consumer_
Status BufferQueueConsumer::GetReleasedBuffers(u64* out_slot_mask) {
if (out_slot_mask == nullptr) {
- LOG_ERROR(Service_NVFlinger, "out_slot_mask may not be nullptr");
+ LOG_ERROR(Service_Nvnflinger, "out_slot_mask may not be nullptr");
return Status::BadValue;
}
std::scoped_lock lock{core->mutex};
if (core->is_abandoned) {
- LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned");
+ LOG_ERROR(Service_Nvnflinger, "BufferQueue has been abandoned");
return Status::NoInit;
}
@@ -205,7 +205,7 @@ Status BufferQueueConsumer::GetReleasedBuffers(u64* out_slot_mask) {
++current;
}
- LOG_DEBUG(Service_NVFlinger, "returning mask {}", mask);
+ LOG_DEBUG(Service_Nvnflinger, "returning mask {}", mask);
*out_slot_mask = mask;
return Status::NoError;
}
diff --git a/src/core/hle/service/nvflinger/buffer_queue_consumer.h b/src/core/hle/service/nvnflinger/buffer_queue_consumer.h
index 4ec06ca13..50ed0bb5f 100644
--- a/src/core/hle/service/nvflinger/buffer_queue_consumer.h
+++ b/src/core/hle/service/nvnflinger/buffer_queue_consumer.h
@@ -10,8 +10,8 @@
#include <memory>
#include "common/common_types.h"
-#include "core/hle/service/nvflinger/buffer_queue_defs.h"
-#include "core/hle/service/nvflinger/status.h"
+#include "core/hle/service/nvnflinger/buffer_queue_defs.h"
+#include "core/hle/service/nvnflinger/status.h"
namespace Service::Nvidia::NvCore {
class NvMap;
diff --git a/src/core/hle/service/nvflinger/buffer_queue_core.cpp b/src/core/hle/service/nvnflinger/buffer_queue_core.cpp
index 3d1338e66..2dbe29616 100644
--- a/src/core/hle/service/nvflinger/buffer_queue_core.cpp
+++ b/src/core/hle/service/nvnflinger/buffer_queue_core.cpp
@@ -6,7 +6,7 @@
#include "common/assert.h"
-#include "core/hle/service/nvflinger/buffer_queue_core.h"
+#include "core/hle/service/nvnflinger/buffer_queue_core.h"
namespace Service::android {
@@ -82,7 +82,7 @@ s32 BufferQueueCore::GetPreallocatedBufferCountLocked() const {
}
void BufferQueueCore::FreeBufferLocked(s32 slot) {
- LOG_DEBUG(Service_NVFlinger, "slot {}", slot);
+ LOG_DEBUG(Service_Nvnflinger, "slot {}", slot);
slots[slot].graphic_buffer.reset();
diff --git a/src/core/hle/service/nvflinger/buffer_queue_core.h b/src/core/hle/service/nvnflinger/buffer_queue_core.h
index 85b3bc4c1..9164f08a0 100644
--- a/src/core/hle/service/nvflinger/buffer_queue_core.h
+++ b/src/core/hle/service/nvnflinger/buffer_queue_core.h
@@ -13,11 +13,11 @@
#include <set>
#include <vector>
-#include "core/hle/service/nvflinger/buffer_item.h"
-#include "core/hle/service/nvflinger/buffer_queue_defs.h"
-#include "core/hle/service/nvflinger/pixel_format.h"
-#include "core/hle/service/nvflinger/status.h"
-#include "core/hle/service/nvflinger/window.h"
+#include "core/hle/service/nvnflinger/buffer_item.h"
+#include "core/hle/service/nvnflinger/buffer_queue_defs.h"
+#include "core/hle/service/nvnflinger/pixel_format.h"
+#include "core/hle/service/nvnflinger/status.h"
+#include "core/hle/service/nvnflinger/window.h"
namespace Service::android {
diff --git a/src/core/hle/service/nvflinger/buffer_queue_defs.h b/src/core/hle/service/nvnflinger/buffer_queue_defs.h
index 334445213..6fd3156f4 100644
--- a/src/core/hle/service/nvflinger/buffer_queue_defs.h
+++ b/src/core/hle/service/nvnflinger/buffer_queue_defs.h
@@ -9,7 +9,7 @@
#include <array>
#include "common/common_types.h"
-#include "core/hle/service/nvflinger/buffer_slot.h"
+#include "core/hle/service/nvnflinger/buffer_slot.h"
namespace Service::android::BufferQueueDefs {
diff --git a/src/core/hle/service/nvflinger/buffer_queue_producer.cpp b/src/core/hle/service/nvnflinger/buffer_queue_producer.cpp
index e601b5da1..b16f9933f 100644
--- a/src/core/hle/service/nvflinger/buffer_queue_producer.cpp
+++ b/src/core/hle/service/nvnflinger/buffer_queue_producer.cpp
@@ -8,18 +8,18 @@
#include "common/logging/log.h"
#include "common/settings.h"
#include "core/core.h"
-#include "core/hle/kernel/hle_ipc.h"
#include "core/hle/kernel/k_event.h"
#include "core/hle/kernel/k_readable_event.h"
#include "core/hle/kernel/kernel.h"
+#include "core/hle/service/hle_ipc.h"
#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/nvdrv/core/nvmap.h"
-#include "core/hle/service/nvflinger/buffer_queue_core.h"
-#include "core/hle/service/nvflinger/buffer_queue_producer.h"
-#include "core/hle/service/nvflinger/consumer_listener.h"
-#include "core/hle/service/nvflinger/parcel.h"
-#include "core/hle/service/nvflinger/ui/graphic_buffer.h"
-#include "core/hle/service/nvflinger/window.h"
+#include "core/hle/service/nvnflinger/buffer_queue_core.h"
+#include "core/hle/service/nvnflinger/buffer_queue_producer.h"
+#include "core/hle/service/nvnflinger/consumer_listener.h"
+#include "core/hle/service/nvnflinger/parcel.h"
+#include "core/hle/service/nvnflinger/ui/graphic_buffer.h"
+#include "core/hle/service/nvnflinger/window.h"
#include "core/hle/service/vi/vi.h"
namespace Service::android {
@@ -37,20 +37,20 @@ BufferQueueProducer::~BufferQueueProducer() {
}
Status BufferQueueProducer::RequestBuffer(s32 slot, std::shared_ptr<GraphicBuffer>* buf) {
- LOG_DEBUG(Service_NVFlinger, "slot {}", slot);
+ LOG_DEBUG(Service_Nvnflinger, "slot {}", slot);
std::scoped_lock lock{core->mutex};
if (core->is_abandoned) {
- LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned");
+ LOG_ERROR(Service_Nvnflinger, "BufferQueue has been abandoned");
return Status::NoInit;
}
if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) {
- LOG_ERROR(Service_NVFlinger, "slot index {} out of range [0, {})", slot,
+ LOG_ERROR(Service_Nvnflinger, "slot index {} out of range [0, {})", slot,
BufferQueueDefs::NUM_BUFFER_SLOTS);
return Status::BadValue;
} else if (slots[slot].buffer_state != BufferState::Dequeued) {
- LOG_ERROR(Service_NVFlinger, "slot {} is not owned by the producer (state = {})", slot,
+ LOG_ERROR(Service_Nvnflinger, "slot {} is not owned by the producer (state = {})", slot,
slots[slot].buffer_state);
return Status::BadValue;
}
@@ -62,7 +62,7 @@ Status BufferQueueProducer::RequestBuffer(s32 slot, std::shared_ptr<GraphicBuffe
}
Status BufferQueueProducer::SetBufferCount(s32 buffer_count) {
- LOG_DEBUG(Service_NVFlinger, "count = {}", buffer_count);
+ LOG_DEBUG(Service_Nvnflinger, "count = {}", buffer_count);
std::shared_ptr<IConsumerListener> listener;
{
@@ -70,12 +70,12 @@ Status BufferQueueProducer::SetBufferCount(s32 buffer_count) {
core->WaitWhileAllocatingLocked();
if (core->is_abandoned) {
- LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned");
+ LOG_ERROR(Service_Nvnflinger, "BufferQueue has been abandoned");
return Status::NoInit;
}
if (buffer_count > BufferQueueDefs::NUM_BUFFER_SLOTS) {
- LOG_ERROR(Service_NVFlinger, "buffer_count {} too large (max {})", buffer_count,
+ LOG_ERROR(Service_Nvnflinger, "buffer_count {} too large (max {})", buffer_count,
BufferQueueDefs::NUM_BUFFER_SLOTS);
return Status::BadValue;
}
@@ -83,7 +83,7 @@ Status BufferQueueProducer::SetBufferCount(s32 buffer_count) {
// There must be no dequeued buffers when changing the buffer count.
for (s32 s{}; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) {
if (slots[s].buffer_state == BufferState::Dequeued) {
- LOG_ERROR(Service_NVFlinger, "buffer owned by producer");
+ LOG_ERROR(Service_Nvnflinger, "buffer owned by producer");
return Status::BadValue;
}
}
@@ -96,7 +96,7 @@ Status BufferQueueProducer::SetBufferCount(s32 buffer_count) {
const s32 min_buffer_slots = core->GetMinMaxBufferCountLocked(false);
if (buffer_count < min_buffer_slots) {
- LOG_ERROR(Service_NVFlinger, "requested buffer count {} is less than minimum {}",
+ LOG_ERROR(Service_Nvnflinger, "requested buffer count {} is less than minimum {}",
buffer_count, min_buffer_slots);
return Status::BadValue;
}
@@ -127,14 +127,14 @@ Status BufferQueueProducer::WaitForFreeSlotThenRelock(bool async, s32* found, St
while (try_again) {
if (core->is_abandoned) {
- LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned");
+ LOG_ERROR(Service_Nvnflinger, "BufferQueue has been abandoned");
return Status::NoInit;
}
const s32 max_buffer_count = core->GetMaxBufferCountLocked(async);
if (async && core->override_max_buffer_count) {
if (core->override_max_buffer_count < max_buffer_count) {
- LOG_ERROR(Service_NVFlinger, "async mode is invalid with buffer count override");
+ LOG_ERROR(Service_Nvnflinger, "async mode is invalid with buffer count override");
return Status::BadValue;
}
}
@@ -176,7 +176,7 @@ Status BufferQueueProducer::WaitForFreeSlotThenRelock(bool async, s32* found, St
// Producers are not allowed to dequeue more than one buffer if they did not set a buffer
// count
if (!core->override_max_buffer_count && dequeued_count) {
- LOG_ERROR(Service_NVFlinger,
+ LOG_ERROR(Service_Nvnflinger,
"can't dequeue multiple buffers without setting the buffer count");
return Status::InvalidOperation;
}
@@ -188,7 +188,7 @@ Status BufferQueueProducer::WaitForFreeSlotThenRelock(bool async, s32* found, St
const s32 new_undequeued_count = max_buffer_count - (dequeued_count + 1);
const s32 min_undequeued_count = core->GetMinUndequeuedBufferCountLocked(async);
if (new_undequeued_count < min_undequeued_count) {
- LOG_ERROR(Service_NVFlinger,
+ LOG_ERROR(Service_Nvnflinger,
"min undequeued buffer count({}) exceeded (dequeued={} undequeued={})",
min_undequeued_count, dequeued_count, new_undequeued_count);
return Status::InvalidOperation;
@@ -200,7 +200,7 @@ Status BufferQueueProducer::WaitForFreeSlotThenRelock(bool async, s32* found, St
// outrun the consumer. Wait here if it looks like we have too many buffers queued up.
const bool too_many_buffers = core->queue.size() > static_cast<size_t>(max_buffer_count);
if (too_many_buffers) {
- LOG_ERROR(Service_NVFlinger, "queue size is {}, waiting", core->queue.size());
+ LOG_ERROR(Service_Nvnflinger, "queue size is {}, waiting", core->queue.size());
}
// If no buffer is found, or if the queue has too many buffers outstanding, wait for a
@@ -226,11 +226,11 @@ Status BufferQueueProducer::WaitForFreeSlotThenRelock(bool async, s32* found, St
Status BufferQueueProducer::DequeueBuffer(s32* out_slot, Fence* out_fence, bool async, u32 width,
u32 height, PixelFormat format, u32 usage) {
- LOG_DEBUG(Service_NVFlinger, "async={} w={} h={} format={}, usage={}", async ? "true" : "false",
- width, height, format, usage);
+ LOG_DEBUG(Service_Nvnflinger, "async={} w={} h={} format={}, usage={}",
+ async ? "true" : "false", width, height, format, usage);
if ((width != 0 && height == 0) || (width == 0 && height != 0)) {
- LOG_ERROR(Service_NVFlinger, "invalid size: w={} h={}", width, height);
+ LOG_ERROR(Service_Nvnflinger, "invalid size: w={} h={}", width, height);
return Status::BadValue;
}
@@ -255,7 +255,7 @@ Status BufferQueueProducer::DequeueBuffer(s32* out_slot, Fence* out_fence, bool
// This should not happen
if (found == BufferQueueCore::INVALID_BUFFER_SLOT) {
- LOG_ERROR(Service_NVFlinger, "no available buffer slots");
+ LOG_ERROR(Service_Nvnflinger, "no available buffer slots");
return Status::Busy;
}
@@ -287,11 +287,11 @@ Status BufferQueueProducer::DequeueBuffer(s32* out_slot, Fence* out_fence, bool
}
if ((return_flags & Status::BufferNeedsReallocation) != Status::None) {
- LOG_DEBUG(Service_NVFlinger, "allocating a new buffer for slot {}", *out_slot);
+ LOG_DEBUG(Service_Nvnflinger, "allocating a new buffer for slot {}", *out_slot);
auto graphic_buffer = std::make_shared<GraphicBuffer>(width, height, format, usage);
if (graphic_buffer == nullptr) {
- LOG_ERROR(Service_NVFlinger, "creating GraphicBuffer failed");
+ LOG_ERROR(Service_Nvnflinger, "creating GraphicBuffer failed");
return Status::NoMemory;
}
@@ -299,7 +299,7 @@ Status BufferQueueProducer::DequeueBuffer(s32* out_slot, Fence* out_fence, bool
std::scoped_lock lock{core->mutex};
if (core->is_abandoned) {
- LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned");
+ LOG_ERROR(Service_Nvnflinger, "BufferQueue has been abandoned");
return Status::NoInit;
}
@@ -312,32 +312,32 @@ Status BufferQueueProducer::DequeueBuffer(s32* out_slot, Fence* out_fence, bool
return_flags |= Status::BufferNeedsReallocation;
}
- LOG_DEBUG(Service_NVFlinger, "returning slot={} frame={}, flags={}", *out_slot,
+ LOG_DEBUG(Service_Nvnflinger, "returning slot={} frame={}, flags={}", *out_slot,
slots[*out_slot].frame_number, return_flags);
return return_flags;
}
Status BufferQueueProducer::DetachBuffer(s32 slot) {
- LOG_DEBUG(Service_NVFlinger, "slot {}", slot);
+ LOG_DEBUG(Service_Nvnflinger, "slot {}", slot);
std::scoped_lock lock{core->mutex};
if (core->is_abandoned) {
- LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned");
+ LOG_ERROR(Service_Nvnflinger, "BufferQueue has been abandoned");
return Status::NoInit;
}
if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) {
- LOG_ERROR(Service_NVFlinger, "slot {} out of range [0, {})", slot,
+ LOG_ERROR(Service_Nvnflinger, "slot {} out of range [0, {})", slot,
BufferQueueDefs::NUM_BUFFER_SLOTS);
return Status::BadValue;
} else if (slots[slot].buffer_state != BufferState::Dequeued) {
- LOG_ERROR(Service_NVFlinger, "slot {} is not owned by the producer (state = {})", slot,
+ LOG_ERROR(Service_Nvnflinger, "slot {} is not owned by the producer (state = {})", slot,
slots[slot].buffer_state);
return Status::BadValue;
} else if (!slots[slot].request_buffer_called) {
- LOG_ERROR(Service_NVFlinger, "buffer in slot {} has not been requested", slot);
+ LOG_ERROR(Service_Nvnflinger, "buffer in slot {} has not been requested", slot);
return Status::BadValue;
}
@@ -350,10 +350,10 @@ Status BufferQueueProducer::DetachBuffer(s32 slot) {
Status BufferQueueProducer::DetachNextBuffer(std::shared_ptr<GraphicBuffer>* out_buffer,
Fence* out_fence) {
if (out_buffer == nullptr) {
- LOG_ERROR(Service_NVFlinger, "out_buffer must not be nullptr");
+ LOG_ERROR(Service_Nvnflinger, "out_buffer must not be nullptr");
return Status::BadValue;
} else if (out_fence == nullptr) {
- LOG_ERROR(Service_NVFlinger, "out_fence must not be nullptr");
+ LOG_ERROR(Service_Nvnflinger, "out_fence must not be nullptr");
return Status::BadValue;
}
@@ -361,7 +361,7 @@ Status BufferQueueProducer::DetachNextBuffer(std::shared_ptr<GraphicBuffer>* out
core->WaitWhileAllocatingLocked();
if (core->is_abandoned) {
- LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned");
+ LOG_ERROR(Service_Nvnflinger, "BufferQueue has been abandoned");
return Status::NoInit;
}
@@ -380,7 +380,7 @@ Status BufferQueueProducer::DetachNextBuffer(std::shared_ptr<GraphicBuffer>* out
return Status::NoMemory;
}
- LOG_DEBUG(Service_NVFlinger, "Detached slot {}", found);
+ LOG_DEBUG(Service_Nvnflinger, "Detached slot {}", found);
*out_buffer = slots[found].graphic_buffer;
*out_fence = slots[found].fence;
@@ -393,10 +393,10 @@ Status BufferQueueProducer::DetachNextBuffer(std::shared_ptr<GraphicBuffer>* out
Status BufferQueueProducer::AttachBuffer(s32* out_slot,
const std::shared_ptr<GraphicBuffer>& buffer) {
if (out_slot == nullptr) {
- LOG_ERROR(Service_NVFlinger, "out_slot must not be nullptr");
+ LOG_ERROR(Service_Nvnflinger, "out_slot must not be nullptr");
return Status::BadValue;
} else if (buffer == nullptr) {
- LOG_ERROR(Service_NVFlinger, "Cannot attach nullptr buffer");
+ LOG_ERROR(Service_Nvnflinger, "Cannot attach nullptr buffer");
return Status::BadValue;
}
@@ -413,13 +413,13 @@ Status BufferQueueProducer::AttachBuffer(s32* out_slot,
// This should not happen
if (found == BufferQueueCore::INVALID_BUFFER_SLOT) {
- LOG_ERROR(Service_NVFlinger, "No available buffer slots");
+ LOG_ERROR(Service_Nvnflinger, "No available buffer slots");
return Status::Busy;
}
*out_slot = found;
- LOG_DEBUG(Service_NVFlinger, "Returning slot {} flags={}", *out_slot, return_flags);
+ LOG_DEBUG(Service_Nvnflinger, "Returning slot {} flags={}", *out_slot, return_flags);
slots[*out_slot].graphic_buffer = buffer;
slots[*out_slot].buffer_state = BufferState::Dequeued;
@@ -451,7 +451,7 @@ Status BufferQueueProducer::QueueBuffer(s32 slot, const QueueBufferInput& input,
case NativeWindowScalingMode::NoScaleCrop:
break;
default:
- LOG_ERROR(Service_NVFlinger, "unknown scaling mode {}", scaling_mode);
+ LOG_ERROR(Service_Nvnflinger, "unknown scaling mode {}", scaling_mode);
return Status::BadValue;
}
@@ -464,38 +464,38 @@ Status BufferQueueProducer::QueueBuffer(s32 slot, const QueueBufferInput& input,
std::scoped_lock lock{core->mutex};
if (core->is_abandoned) {
- LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned");
+ LOG_ERROR(Service_Nvnflinger, "BufferQueue has been abandoned");
return Status::NoInit;
}
const s32 max_buffer_count = core->GetMaxBufferCountLocked(async);
if (async && core->override_max_buffer_count) {
if (core->override_max_buffer_count < max_buffer_count) {
- LOG_ERROR(Service_NVFlinger, "async mode is invalid with "
- "buffer count override");
+ LOG_ERROR(Service_Nvnflinger, "async mode is invalid with "
+ "buffer count override");
return Status::BadValue;
}
}
if (slot < 0 || slot >= max_buffer_count) {
- LOG_ERROR(Service_NVFlinger, "slot index {} out of range [0, {})", slot,
+ LOG_ERROR(Service_Nvnflinger, "slot index {} out of range [0, {})", slot,
max_buffer_count);
return Status::BadValue;
} else if (slots[slot].buffer_state != BufferState::Dequeued) {
- LOG_ERROR(Service_NVFlinger,
+ LOG_ERROR(Service_Nvnflinger,
"slot {} is not owned by the producer "
"(state = {})",
slot, slots[slot].buffer_state);
return Status::BadValue;
} else if (!slots[slot].request_buffer_called) {
- LOG_ERROR(Service_NVFlinger,
+ LOG_ERROR(Service_Nvnflinger,
"slot {} was queued without requesting "
"a buffer",
slot);
return Status::BadValue;
}
- LOG_DEBUG(Service_NVFlinger,
+ LOG_DEBUG(Service_Nvnflinger,
"slot={} frame={} time={} crop=[{},{},{},{}] transform={} scale={}", slot,
core->frame_counter + 1, timestamp, crop.Left(), crop.Top(), crop.Right(),
crop.Bottom(), transform, scaling_mode);
@@ -506,7 +506,7 @@ Status BufferQueueProducer::QueueBuffer(s32 slot, const QueueBufferInput& input,
[[maybe_unused]] const bool unused = crop.Intersect(buffer_rect, &cropped_rect);
if (cropped_rect != crop) {
- LOG_ERROR(Service_NVFlinger, "crop rect is not contained within the buffer in slot {}",
+ LOG_ERROR(Service_Nvnflinger, "crop rect is not contained within the buffer in slot {}",
slot);
return Status::BadValue;
}
@@ -598,21 +598,21 @@ Status BufferQueueProducer::QueueBuffer(s32 slot, const QueueBufferInput& input,
}
void BufferQueueProducer::CancelBuffer(s32 slot, const Fence& fence) {
- LOG_DEBUG(Service_NVFlinger, "slot {}", slot);
+ LOG_DEBUG(Service_Nvnflinger, "slot {}", slot);
std::scoped_lock lock{core->mutex};
if (core->is_abandoned) {
- LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned");
+ LOG_ERROR(Service_Nvnflinger, "BufferQueue has been abandoned");
return;
}
if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) {
- LOG_ERROR(Service_NVFlinger, "slot index {} out of range [0, {})", slot,
+ LOG_ERROR(Service_Nvnflinger, "slot index {} out of range [0, {})", slot,
BufferQueueDefs::NUM_BUFFER_SLOTS);
return;
} else if (slots[slot].buffer_state != BufferState::Dequeued) {
- LOG_ERROR(Service_NVFlinger, "slot {} is not owned by the producer (state = {})", slot,
+ LOG_ERROR(Service_Nvnflinger, "slot {} is not owned by the producer (state = {})", slot,
slots[slot].buffer_state);
return;
}
@@ -629,12 +629,12 @@ Status BufferQueueProducer::Query(NativeWindow what, s32* out_value) {
std::scoped_lock lock{core->mutex};
if (out_value == nullptr) {
- LOG_ERROR(Service_NVFlinger, "outValue was nullptr");
+ LOG_ERROR(Service_Nvnflinger, "outValue was nullptr");
return Status::BadValue;
}
if (core->is_abandoned) {
- LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned");
+ LOG_ERROR(Service_Nvnflinger, "BufferQueue has been abandoned");
return Status::NoInit;
}
@@ -666,7 +666,7 @@ Status BufferQueueProducer::Query(NativeWindow what, s32* out_value) {
return Status::BadValue;
}
- LOG_DEBUG(Service_NVFlinger, "what = {}, value = {}", what, value);
+ LOG_DEBUG(Service_Nvnflinger, "what = {}, value = {}", what, value);
*out_value = static_cast<s32>(value);
@@ -678,26 +678,26 @@ Status BufferQueueProducer::Connect(const std::shared_ptr<IProducerListener>& li
QueueBufferOutput* output) {
std::scoped_lock lock{core->mutex};
- LOG_DEBUG(Service_NVFlinger, "api = {} producer_controlled_by_app = {}", api,
+ LOG_DEBUG(Service_Nvnflinger, "api = {} producer_controlled_by_app = {}", api,
producer_controlled_by_app);
if (core->is_abandoned) {
- LOG_ERROR(Service_NVFlinger, "BufferQueue has been abandoned");
+ LOG_ERROR(Service_Nvnflinger, "BufferQueue has been abandoned");
return Status::NoInit;
}
if (core->consumer_listener == nullptr) {
- LOG_ERROR(Service_NVFlinger, "BufferQueue has no consumer");
+ LOG_ERROR(Service_Nvnflinger, "BufferQueue has no consumer");
return Status::NoInit;
}
if (output == nullptr) {
- LOG_ERROR(Service_NVFlinger, "output was nullptr");
+ LOG_ERROR(Service_Nvnflinger, "output was nullptr");
return Status::BadValue;
}
if (core->connected_api != NativeWindowApi::NoConnectedApi) {
- LOG_ERROR(Service_NVFlinger, "already connected (cur = {} req = {})", core->connected_api,
+ LOG_ERROR(Service_Nvnflinger, "already connected (cur = {} req = {})", core->connected_api,
api);
return Status::BadValue;
}
@@ -714,7 +714,7 @@ Status BufferQueueProducer::Connect(const std::shared_ptr<IProducerListener>& li
core->connected_producer_listener = listener;
break;
default:
- LOG_ERROR(Service_NVFlinger, "unknown api = {}", api);
+ LOG_ERROR(Service_Nvnflinger, "unknown api = {}", api);
status = Status::BadValue;
break;
}
@@ -727,7 +727,7 @@ Status BufferQueueProducer::Connect(const std::shared_ptr<IProducerListener>& li
}
Status BufferQueueProducer::Disconnect(NativeWindowApi api) {
- LOG_DEBUG(Service_NVFlinger, "api = {}", api);
+ LOG_DEBUG(Service_Nvnflinger, "api = {}", api);
Status status = Status::NoError;
std::shared_ptr<IConsumerListener> listener;
@@ -762,13 +762,13 @@ Status BufferQueueProducer::Disconnect(NativeWindowApi api) {
buffer_wait_event->Signal();
listener = core->consumer_listener;
} else {
- LOG_ERROR(Service_NVFlinger, "still connected to another api (cur = {} req = {})",
+ LOG_ERROR(Service_Nvnflinger, "still connected to another api (cur = {} req = {})",
core->connected_api, api);
status = Status::BadValue;
}
break;
default:
- LOG_ERROR(Service_NVFlinger, "unknown api = {}", api);
+ LOG_ERROR(Service_Nvnflinger, "unknown api = {}", api);
status = Status::BadValue;
break;
}
@@ -784,7 +784,7 @@ Status BufferQueueProducer::Disconnect(NativeWindowApi api) {
Status BufferQueueProducer::SetPreallocatedBuffer(s32 slot,
const std::shared_ptr<GraphicBuffer>& buffer) {
- LOG_DEBUG(Service_NVFlinger, "slot {}", slot);
+ LOG_DEBUG(Service_Nvnflinger, "slot {}", slot);
if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) {
return Status::BadValue;
@@ -793,6 +793,7 @@ Status BufferQueueProducer::SetPreallocatedBuffer(s32 slot,
std::scoped_lock lock{core->mutex};
slots[slot] = {};
+ slots[slot].fence = Fence::NoFence();
slots[slot].graphic_buffer = buffer;
slots[slot].frame_number = 0;
@@ -813,10 +814,10 @@ Status BufferQueueProducer::SetPreallocatedBuffer(s32 slot,
return Status::NoError;
}
-void BufferQueueProducer::Transact(Kernel::HLERequestContext& ctx, TransactionId code, u32 flags) {
+void BufferQueueProducer::Transact(HLERequestContext& ctx, TransactionId code, u32 flags) {
Status status{Status::NoError};
- Parcel parcel_in{ctx.ReadBuffer()};
- Parcel parcel_out{};
+ InputParcel parcel_in{ctx.ReadBuffer()};
+ OutputParcel parcel_out{};
switch (code) {
case TransactionId::Connect: {
@@ -854,7 +855,7 @@ void BufferQueueProducer::Transact(Kernel::HLERequestContext& ctx, TransactionId
status = DequeueBuffer(&slot, &fence, is_async, width, height, pixel_format, usage);
parcel_out.Write(slot);
- parcel_out.WriteObject(&fence);
+ parcel_out.WriteFlattenedObject(&fence);
break;
}
case TransactionId::RequestBuffer: {
@@ -864,7 +865,7 @@ void BufferQueueProducer::Transact(Kernel::HLERequestContext& ctx, TransactionId
status = RequestBuffer(slot, &buf);
- parcel_out.WriteObject(buf);
+ parcel_out.WriteFlattenedObject(buf);
break;
}
case TransactionId::QueueBuffer: {
@@ -914,7 +915,7 @@ void BufferQueueProducer::Transact(Kernel::HLERequestContext& ctx, TransactionId
break;
}
case TransactionId::GetBufferHistory:
- LOG_WARNING(Service_NVFlinger, "(STUBBED) called, transaction=GetBufferHistory");
+ LOG_WARNING(Service_Nvnflinger, "(STUBBED) called, transaction=GetBufferHistory");
break;
default:
ASSERT_MSG(false, "Unimplemented TransactionId {}", code);
diff --git a/src/core/hle/service/nvflinger/buffer_queue_producer.h b/src/core/hle/service/nvnflinger/buffer_queue_producer.h
index 1d380480f..d4201c104 100644
--- a/src/core/hle/service/nvflinger/buffer_queue_producer.h
+++ b/src/core/hle/service/nvnflinger/buffer_queue_producer.h
@@ -12,13 +12,13 @@
#include "common/common_funcs.h"
#include "core/hle/service/nvdrv/nvdata.h"
-#include "core/hle/service/nvflinger/binder.h"
-#include "core/hle/service/nvflinger/buffer_queue_defs.h"
-#include "core/hle/service/nvflinger/buffer_slot.h"
-#include "core/hle/service/nvflinger/graphic_buffer_producer.h"
-#include "core/hle/service/nvflinger/pixel_format.h"
-#include "core/hle/service/nvflinger/status.h"
-#include "core/hle/service/nvflinger/window.h"
+#include "core/hle/service/nvnflinger/binder.h"
+#include "core/hle/service/nvnflinger/buffer_queue_defs.h"
+#include "core/hle/service/nvnflinger/buffer_slot.h"
+#include "core/hle/service/nvnflinger/graphic_buffer_producer.h"
+#include "core/hle/service/nvnflinger/pixel_format.h"
+#include "core/hle/service/nvnflinger/status.h"
+#include "core/hle/service/nvnflinger/window.h"
namespace Kernel {
class KernelCore;
@@ -46,7 +46,7 @@ public:
Service::Nvidia::NvCore::NvMap& nvmap_);
~BufferQueueProducer();
- void Transact(Kernel::HLERequestContext& ctx, android::TransactionId code, u32 flags) override;
+ void Transact(HLERequestContext& ctx, android::TransactionId code, u32 flags) override;
Kernel::KReadableEvent& GetNativeHandle() override;
diff --git a/src/core/hle/service/nvflinger/buffer_slot.h b/src/core/hle/service/nvnflinger/buffer_slot.h
index 0cd0e9964..d25bca049 100644
--- a/src/core/hle/service/nvflinger/buffer_slot.h
+++ b/src/core/hle/service/nvnflinger/buffer_slot.h
@@ -9,7 +9,7 @@
#include <memory>
#include "common/common_types.h"
-#include "core/hle/service/nvflinger/ui/fence.h"
+#include "core/hle/service/nvnflinger/ui/fence.h"
namespace Service::android {
diff --git a/src/core/hle/service/nvflinger/buffer_transform_flags.h b/src/core/hle/service/nvnflinger/buffer_transform_flags.h
index 67aa5dad6..67aa5dad6 100644
--- a/src/core/hle/service/nvflinger/buffer_transform_flags.h
+++ b/src/core/hle/service/nvnflinger/buffer_transform_flags.h
diff --git a/src/core/hle/service/nvflinger/consumer_base.cpp b/src/core/hle/service/nvnflinger/consumer_base.cpp
index 982531e2d..4dcda8dac 100644
--- a/src/core/hle/service/nvflinger/consumer_base.cpp
+++ b/src/core/hle/service/nvnflinger/consumer_base.cpp
@@ -6,11 +6,11 @@
#include "common/assert.h"
#include "common/logging/log.h"
-#include "core/hle/service/nvflinger/buffer_item.h"
-#include "core/hle/service/nvflinger/buffer_queue_consumer.h"
-#include "core/hle/service/nvflinger/buffer_queue_core.h"
-#include "core/hle/service/nvflinger/consumer_base.h"
-#include "core/hle/service/nvflinger/ui/graphic_buffer.h"
+#include "core/hle/service/nvnflinger/buffer_item.h"
+#include "core/hle/service/nvnflinger/buffer_queue_consumer.h"
+#include "core/hle/service/nvnflinger/buffer_queue_core.h"
+#include "core/hle/service/nvnflinger/consumer_base.h"
+#include "core/hle/service/nvnflinger/ui/graphic_buffer.h"
namespace Service::android {
@@ -28,7 +28,7 @@ void ConsumerBase::Connect(bool controlled_by_app) {
}
void ConsumerBase::FreeBufferLocked(s32 slot_index) {
- LOG_DEBUG(Service_NVFlinger, "slot_index={}", slot_index);
+ LOG_DEBUG(Service_Nvnflinger, "slot_index={}", slot_index);
slots[slot_index].graphic_buffer = nullptr;
slots[slot_index].fence = Fence::NoFence();
@@ -36,17 +36,17 @@ void ConsumerBase::FreeBufferLocked(s32 slot_index) {
}
void ConsumerBase::OnFrameAvailable(const BufferItem& item) {
- LOG_DEBUG(Service_NVFlinger, "called");
+ LOG_DEBUG(Service_Nvnflinger, "called");
}
void ConsumerBase::OnFrameReplaced(const BufferItem& item) {
- LOG_DEBUG(Service_NVFlinger, "called");
+ LOG_DEBUG(Service_Nvnflinger, "called");
}
void ConsumerBase::OnBuffersReleased() {
std::scoped_lock lock{mutex};
- LOG_DEBUG(Service_NVFlinger, "called");
+ LOG_DEBUG(Service_Nvnflinger, "called");
if (is_abandoned) {
// Nothing to do if we're already abandoned.
@@ -77,7 +77,7 @@ Status ConsumerBase::AcquireBufferLocked(BufferItem* item, std::chrono::nanoseco
slots[item->slot].frame_number = item->frame_number;
slots[item->slot].fence = item->fence;
- LOG_DEBUG(Service_NVFlinger, "slot={}", item->slot);
+ LOG_DEBUG(Service_Nvnflinger, "slot={}", item->slot);
return Status::NoError;
}
@@ -85,7 +85,7 @@ Status ConsumerBase::AcquireBufferLocked(BufferItem* item, std::chrono::nanoseco
Status ConsumerBase::AddReleaseFenceLocked(s32 slot,
const std::shared_ptr<GraphicBuffer>& graphic_buffer,
const Fence& fence) {
- LOG_DEBUG(Service_NVFlinger, "slot={}", slot);
+ LOG_DEBUG(Service_Nvnflinger, "slot={}", slot);
// If consumer no longer tracks this graphic_buffer, we can safely
// drop this fence, as it will never be received by the producer.
@@ -109,7 +109,7 @@ Status ConsumerBase::ReleaseBufferLocked(s32 slot,
return Status::NoError;
}
- LOG_DEBUG(Service_NVFlinger, "slot={}", slot);
+ LOG_DEBUG(Service_Nvnflinger, "slot={}", slot);
Status err = consumer->ReleaseBuffer(slot, slots[slot].frame_number, slots[slot].fence);
if (err == Status::StaleBufferSlot) {
FreeBufferLocked(slot);
diff --git a/src/core/hle/service/nvflinger/consumer_base.h b/src/core/hle/service/nvnflinger/consumer_base.h
index 9a8a5f6bb..264829414 100644
--- a/src/core/hle/service/nvflinger/consumer_base.h
+++ b/src/core/hle/service/nvnflinger/consumer_base.h
@@ -12,9 +12,9 @@
#include <mutex>
#include "common/common_types.h"
-#include "core/hle/service/nvflinger/buffer_queue_defs.h"
-#include "core/hle/service/nvflinger/consumer_listener.h"
-#include "core/hle/service/nvflinger/status.h"
+#include "core/hle/service/nvnflinger/buffer_queue_defs.h"
+#include "core/hle/service/nvnflinger/consumer_listener.h"
+#include "core/hle/service/nvnflinger/status.h"
namespace Service::android {
diff --git a/src/core/hle/service/nvflinger/consumer_listener.h b/src/core/hle/service/nvnflinger/consumer_listener.h
index 74a193988..74a193988 100644
--- a/src/core/hle/service/nvflinger/consumer_listener.h
+++ b/src/core/hle/service/nvnflinger/consumer_listener.h
diff --git a/src/core/hle/service/nvflinger/graphic_buffer_producer.cpp b/src/core/hle/service/nvnflinger/graphic_buffer_producer.cpp
index 4043c91f1..d72b49a8e 100644
--- a/src/core/hle/service/nvflinger/graphic_buffer_producer.cpp
+++ b/src/core/hle/service/nvnflinger/graphic_buffer_producer.cpp
@@ -4,12 +4,12 @@
// Parts of this implementation were based on:
// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/libs/gui/IGraphicBufferProducer.cpp
-#include "core/hle/service/nvflinger/graphic_buffer_producer.h"
-#include "core/hle/service/nvflinger/parcel.h"
+#include "core/hle/service/nvnflinger/graphic_buffer_producer.h"
+#include "core/hle/service/nvnflinger/parcel.h"
namespace Service::android {
-QueueBufferInput::QueueBufferInput(Parcel& parcel) {
+QueueBufferInput::QueueBufferInput(InputParcel& parcel) {
parcel.ReadFlattened(*this);
}
diff --git a/src/core/hle/service/nvflinger/graphic_buffer_producer.h b/src/core/hle/service/nvnflinger/graphic_buffer_producer.h
index 6ea327bbe..21d7b31f3 100644
--- a/src/core/hle/service/nvflinger/graphic_buffer_producer.h
+++ b/src/core/hle/service/nvnflinger/graphic_buffer_producer.h
@@ -9,16 +9,16 @@
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/math_util.h"
-#include "core/hle/service/nvflinger/ui/fence.h"
-#include "core/hle/service/nvflinger/window.h"
+#include "core/hle/service/nvnflinger/ui/fence.h"
+#include "core/hle/service/nvnflinger/window.h"
namespace Service::android {
-class Parcel;
+class InputParcel;
#pragma pack(push, 1)
struct QueueBufferInput final {
- explicit QueueBufferInput(Parcel& parcel);
+ explicit QueueBufferInput(InputParcel& parcel);
void Deflate(s64* timestamp_, bool* is_auto_timestamp_, Common::Rectangle<s32>* crop_,
NativeWindowScalingMode* scaling_mode_, NativeWindowTransform* transform_,
diff --git a/src/core/hle/service/nvflinger/hos_binder_driver_server.cpp b/src/core/hle/service/nvnflinger/hos_binder_driver_server.cpp
index dc9b2a9ec..b86a79ec9 100644
--- a/src/core/hle/service/nvflinger/hos_binder_driver_server.cpp
+++ b/src/core/hle/service/nvnflinger/hos_binder_driver_server.cpp
@@ -4,9 +4,9 @@
#include <mutex>
#include "common/common_types.h"
-#include "core/hle/service/nvflinger/hos_binder_driver_server.h"
+#include "core/hle/service/nvnflinger/hos_binder_driver_server.h"
-namespace Service::NVFlinger {
+namespace Service::Nvnflinger {
HosBinderDriverServer::HosBinderDriverServer(Core::System& system_)
: service_context(system_, "HosBinderDriverServer") {}
@@ -33,4 +33,4 @@ android::IBinder* HosBinderDriverServer::TryGetProducer(u64 id) {
return {};
}
-} // namespace Service::NVFlinger
+} // namespace Service::Nvnflinger
diff --git a/src/core/hle/service/nvflinger/hos_binder_driver_server.h b/src/core/hle/service/nvnflinger/hos_binder_driver_server.h
index 8fddc1206..58bb9469a 100644
--- a/src/core/hle/service/nvflinger/hos_binder_driver_server.h
+++ b/src/core/hle/service/nvnflinger/hos_binder_driver_server.h
@@ -9,13 +9,13 @@
#include "common/common_types.h"
#include "core/hle/service/kernel_helpers.h"
-#include "core/hle/service/nvflinger/binder.h"
+#include "core/hle/service/nvnflinger/binder.h"
namespace Core {
class System;
}
-namespace Service::NVFlinger {
+namespace Service::Nvnflinger {
class HosBinderDriverServer final {
public:
@@ -34,4 +34,4 @@ private:
u64 last_id{};
};
-} // namespace Service::NVFlinger
+} // namespace Service::Nvnflinger
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvnflinger/nvnflinger.cpp
index f4416f5b2..5f55cd31e 100644
--- a/src/core/hle/service/nvflinger/nvflinger.cpp
+++ b/src/core/hle/service/nvnflinger/nvnflinger.cpp
@@ -15,11 +15,11 @@
#include "core/hle/kernel/k_readable_event.h"
#include "core/hle/service/nvdrv/devices/nvdisp_disp0.h"
#include "core/hle/service/nvdrv/nvdrv.h"
-#include "core/hle/service/nvflinger/buffer_item_consumer.h"
-#include "core/hle/service/nvflinger/buffer_queue_core.h"
-#include "core/hle/service/nvflinger/hos_binder_driver_server.h"
-#include "core/hle/service/nvflinger/nvflinger.h"
-#include "core/hle/service/nvflinger/ui/graphic_buffer.h"
+#include "core/hle/service/nvnflinger/buffer_item_consumer.h"
+#include "core/hle/service/nvnflinger/buffer_queue_core.h"
+#include "core/hle/service/nvnflinger/hos_binder_driver_server.h"
+#include "core/hle/service/nvnflinger/nvnflinger.h"
+#include "core/hle/service/nvnflinger/ui/graphic_buffer.h"
#include "core/hle/service/vi/display/vi_display.h"
#include "core/hle/service/vi/layer/vi_layer.h"
#include "core/hle/service/vi/vi_results.h"
@@ -27,11 +27,11 @@
#include "video_core/host1x/host1x.h"
#include "video_core/host1x/syncpoint_manager.h"
-namespace Service::NVFlinger {
+namespace Service::Nvnflinger {
constexpr auto frame_ns = std::chrono::nanoseconds{1000000000 / 60};
-void NVFlinger::SplitVSync(std::stop_token stop_token) {
+void Nvnflinger::SplitVSync(std::stop_token stop_token) {
system.RegisterHostThread();
std::string name = "VSyncThread";
MicroProfileOnThreadCreate(name.c_str());
@@ -43,19 +43,15 @@ void NVFlinger::SplitVSync(std::stop_token stop_token) {
Common::SetCurrentThreadPriority(Common::ThreadPriority::High);
while (!stop_token.stop_requested()) {
- vsync_signal.wait(false);
- vsync_signal.store(false);
-
- guard->lock();
+ vsync_signal.Wait();
+ const auto lock_guard = Lock();
Compose();
-
- guard->unlock();
}
}
-NVFlinger::NVFlinger(Core::System& system_, HosBinderDriverServer& hos_binder_driver_server_)
- : system(system_), service_context(system_, "nvflinger"),
+Nvnflinger::Nvnflinger(Core::System& system_, HosBinderDriverServer& hos_binder_driver_server_)
+ : system(system_), service_context(system_, "nvnflinger"),
hos_binder_driver_server(hos_binder_driver_server_) {
displays.emplace_back(0, "Default", hos_binder_driver_server, service_context, system);
displays.emplace_back(1, "External", hos_binder_driver_server, service_context, system);
@@ -69,8 +65,8 @@ NVFlinger::NVFlinger(Core::System& system_, HosBinderDriverServer& hos_binder_dr
"ScreenComposition",
[this](std::uintptr_t, s64 time,
std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
- vsync_signal.store(true);
- vsync_signal.notify_all();
+ { const auto lock_guard = Lock(); }
+ vsync_signal.Set();
return std::chrono::nanoseconds(GetNextTicks());
});
@@ -92,12 +88,11 @@ NVFlinger::NVFlinger(Core::System& system_, HosBinderDriverServer& hos_binder_dr
}
}
-NVFlinger::~NVFlinger() {
+Nvnflinger::~Nvnflinger() {
if (system.IsMulticore()) {
system.CoreTiming().UnscheduleEvent(multi_composition_event, {});
vsync_thread.request_stop();
- vsync_signal.store(true);
- vsync_signal.notify_all();
+ vsync_signal.Set();
} else {
system.CoreTiming().UnscheduleEvent(single_composition_event, {});
}
@@ -109,7 +104,7 @@ NVFlinger::~NVFlinger() {
}
}
-void NVFlinger::ShutdownLayers() {
+void Nvnflinger::ShutdownLayers() {
for (auto& display : displays) {
for (size_t layer = 0; layer < display.GetNumLayers(); ++layer) {
display.GetLayer(layer).Core().NotifyShutdown();
@@ -117,15 +112,15 @@ void NVFlinger::ShutdownLayers() {
}
}
-void NVFlinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) {
+void Nvnflinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) {
nvdrv = std::move(instance);
disp_fd = nvdrv->Open("/dev/nvdisp_disp0");
}
-std::optional<u64> NVFlinger::OpenDisplay(std::string_view name) {
+std::optional<u64> Nvnflinger::OpenDisplay(std::string_view name) {
const auto lock_guard = Lock();
- LOG_DEBUG(Service_NVFlinger, "Opening \"{}\" display", name);
+ LOG_DEBUG(Service_Nvnflinger, "Opening \"{}\" display", name);
const auto itr =
std::find_if(displays.begin(), displays.end(),
@@ -138,7 +133,7 @@ std::optional<u64> NVFlinger::OpenDisplay(std::string_view name) {
return itr->GetID();
}
-bool NVFlinger::CloseDisplay(u64 display_id) {
+bool Nvnflinger::CloseDisplay(u64 display_id) {
const auto lock_guard = Lock();
auto* const display = FindDisplay(display_id);
@@ -151,7 +146,7 @@ bool NVFlinger::CloseDisplay(u64 display_id) {
return true;
}
-std::optional<u64> NVFlinger::CreateLayer(u64 display_id) {
+std::optional<u64> Nvnflinger::CreateLayer(u64 display_id) {
const auto lock_guard = Lock();
auto* const display = FindDisplay(display_id);
@@ -164,12 +159,12 @@ std::optional<u64> NVFlinger::CreateLayer(u64 display_id) {
return layer_id;
}
-void NVFlinger::CreateLayerAtId(VI::Display& display, u64 layer_id) {
+void Nvnflinger::CreateLayerAtId(VI::Display& display, u64 layer_id) {
const auto buffer_id = next_buffer_queue_id++;
display.CreateLayer(layer_id, buffer_id, nvdrv->container);
}
-void NVFlinger::CloseLayer(u64 layer_id) {
+void Nvnflinger::CloseLayer(u64 layer_id) {
const auto lock_guard = Lock();
for (auto& display : displays) {
@@ -177,7 +172,7 @@ void NVFlinger::CloseLayer(u64 layer_id) {
}
}
-std::optional<u32> NVFlinger::FindBufferQueueId(u64 display_id, u64 layer_id) {
+std::optional<u32> Nvnflinger::FindBufferQueueId(u64 display_id, u64 layer_id) {
const auto lock_guard = Lock();
const auto* const layer = FindOrCreateLayer(display_id, layer_id);
@@ -188,7 +183,7 @@ std::optional<u32> NVFlinger::FindBufferQueueId(u64 display_id, u64 layer_id) {
return layer->GetBinderId();
}
-ResultVal<Kernel::KReadableEvent*> NVFlinger::FindVsyncEvent(u64 display_id) {
+ResultVal<Kernel::KReadableEvent*> Nvnflinger::FindVsyncEvent(u64 display_id) {
const auto lock_guard = Lock();
auto* const display = FindDisplay(display_id);
@@ -199,7 +194,7 @@ ResultVal<Kernel::KReadableEvent*> NVFlinger::FindVsyncEvent(u64 display_id) {
return display->GetVSyncEvent();
}
-VI::Display* NVFlinger::FindDisplay(u64 display_id) {
+VI::Display* Nvnflinger::FindDisplay(u64 display_id) {
const auto itr =
std::find_if(displays.begin(), displays.end(),
[&](const VI::Display& display) { return display.GetID() == display_id; });
@@ -211,7 +206,7 @@ VI::Display* NVFlinger::FindDisplay(u64 display_id) {
return &*itr;
}
-const VI::Display* NVFlinger::FindDisplay(u64 display_id) const {
+const VI::Display* Nvnflinger::FindDisplay(u64 display_id) const {
const auto itr =
std::find_if(displays.begin(), displays.end(),
[&](const VI::Display& display) { return display.GetID() == display_id; });
@@ -223,7 +218,7 @@ const VI::Display* NVFlinger::FindDisplay(u64 display_id) const {
return &*itr;
}
-VI::Layer* NVFlinger::FindLayer(u64 display_id, u64 layer_id) {
+VI::Layer* Nvnflinger::FindLayer(u64 display_id, u64 layer_id) {
auto* const display = FindDisplay(display_id);
if (display == nullptr) {
@@ -233,7 +228,7 @@ VI::Layer* NVFlinger::FindLayer(u64 display_id, u64 layer_id) {
return display->FindLayer(layer_id);
}
-const VI::Layer* NVFlinger::FindLayer(u64 display_id, u64 layer_id) const {
+const VI::Layer* Nvnflinger::FindLayer(u64 display_id, u64 layer_id) const {
const auto* const display = FindDisplay(display_id);
if (display == nullptr) {
@@ -243,7 +238,7 @@ 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) {
+VI::Layer* Nvnflinger::FindOrCreateLayer(u64 display_id, u64 layer_id) {
auto* const display = FindDisplay(display_id);
if (display == nullptr) {
@@ -253,7 +248,7 @@ VI::Layer* NVFlinger::FindOrCreateLayer(u64 display_id, u64 layer_id) {
auto* layer = display->FindLayer(layer_id);
if (layer == nullptr) {
- LOG_DEBUG(Service_NVFlinger, "Layer at id {} not found. Trying to create it.", layer_id);
+ LOG_DEBUG(Service_Nvnflinger, "Layer at id {} not found. Trying to create it.", layer_id);
CreateLayerAtId(*display, layer_id);
return display->FindLayer(layer_id);
}
@@ -261,7 +256,7 @@ VI::Layer* NVFlinger::FindOrCreateLayer(u64 display_id, u64 layer_id) {
return layer;
}
-void NVFlinger::Compose() {
+void Nvnflinger::Compose() {
for (auto& display : displays) {
// Trigger vsync for this display at the end of drawing
SCOPE_EXIT({ display.SignalVSyncEvent(); });
@@ -311,7 +306,7 @@ void NVFlinger::Compose() {
}
}
-s64 NVFlinger::GetNextTicks() const {
+s64 Nvnflinger::GetNextTicks() const {
const auto& settings = Settings::values;
auto speed_scale = 1.f;
if (settings.use_multi_core.GetValue()) {
@@ -324,6 +319,10 @@ s64 NVFlinger::GetNextTicks() const {
speed_scale = 0.01f;
}
}
+ if (system.GetNVDECActive() && settings.use_video_framerate.GetValue()) {
+ // Run at intended presentation rate during video playback.
+ speed_scale = 1.f;
+ }
// As an extension, treat nonpositive swap interval as framerate multiplier.
const f32 effective_fps = swap_interval <= 0 ? 120.f * static_cast<f32>(1 - swap_interval)
@@ -332,4 +331,4 @@ s64 NVFlinger::GetNextTicks() const {
return static_cast<s64>(speed_scale * (1000000000.f / effective_fps));
}
-} // namespace Service::NVFlinger
+} // namespace Service::Nvnflinger
diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvnflinger/nvnflinger.h
index 3828cf272..ef236303a 100644
--- a/src/core/hle/service/nvflinger/nvflinger.h
+++ b/src/core/hle/service/nvnflinger/nvnflinger.h
@@ -12,6 +12,7 @@
#include "common/common_types.h"
#include "common/polyfill_thread.h"
+#include "common/thread.h"
#include "core/hle/result.h"
#include "core/hle/service/kernel_helpers.h"
@@ -42,12 +43,12 @@ class BufferQueueCore;
class BufferQueueProducer;
} // namespace Service::android
-namespace Service::NVFlinger {
+namespace Service::Nvnflinger {
-class NVFlinger final {
+class Nvnflinger final {
public:
- explicit NVFlinger(Core::System& system_, HosBinderDriverServer& hos_binder_driver_server_);
- ~NVFlinger();
+ explicit Nvnflinger(Core::System& system_, HosBinderDriverServer& hos_binder_driver_server_);
+ ~Nvnflinger();
void ShutdownLayers();
@@ -143,7 +144,7 @@ private:
Core::System& system;
- std::atomic<bool> vsync_signal;
+ Common::Event vsync_signal;
std::jthread vsync_thread;
@@ -152,4 +153,4 @@ private:
HosBinderDriverServer& hos_binder_driver_server;
};
-} // namespace Service::NVFlinger
+} // namespace Service::Nvnflinger
diff --git a/src/core/hle/service/nvnflinger/parcel.h b/src/core/hle/service/nvnflinger/parcel.h
new file mode 100644
index 000000000..23ba315a0
--- /dev/null
+++ b/src/core/hle/service/nvnflinger/parcel.h
@@ -0,0 +1,184 @@
+// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#pragma once
+
+#include <memory>
+#include <span>
+#include <vector>
+#include <boost/container/small_vector.hpp>
+
+#include "common/alignment.h"
+#include "common/assert.h"
+#include "common/common_types.h"
+
+namespace Service::android {
+
+struct ParcelHeader {
+ u32 data_size;
+ u32 data_offset;
+ u32 objects_size;
+ u32 objects_offset;
+};
+static_assert(sizeof(ParcelHeader) == 16, "ParcelHeader has wrong size");
+
+class InputParcel final {
+public:
+ explicit InputParcel(std::span<const u8> in_data) : read_buffer(std::move(in_data)) {
+ DeserializeHeader();
+ [[maybe_unused]] const std::u16string token = ReadInterfaceToken();
+ }
+
+ template <typename T>
+ void Read(T& val) {
+ static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable.");
+ ASSERT(read_index + sizeof(T) <= read_buffer.size());
+
+ std::memcpy(&val, read_buffer.data() + read_index, sizeof(T));
+ read_index += sizeof(T);
+ read_index = Common::AlignUp(read_index, 4);
+ }
+
+ template <typename T>
+ T Read() {
+ T val;
+ Read(val);
+ return val;
+ }
+
+ template <typename T>
+ void ReadFlattened(T& val) {
+ const auto flattened_size = Read<s64>();
+ ASSERT(sizeof(T) == flattened_size);
+ Read(val);
+ }
+
+ template <typename T>
+ T ReadFlattened() {
+ T val;
+ ReadFlattened(val);
+ return val;
+ }
+
+ template <typename T>
+ T ReadUnaligned() {
+ static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable.");
+ ASSERT(read_index + sizeof(T) <= read_buffer.size());
+
+ T val;
+ std::memcpy(&val, read_buffer.data() + read_index, sizeof(T));
+ read_index += sizeof(T);
+ return val;
+ }
+
+ template <typename T>
+ const std::shared_ptr<T> ReadObject() {
+ static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable.");
+
+ const auto is_valid{Read<bool>()};
+
+ if (is_valid) {
+ auto result = std::make_shared<T>();
+ ReadFlattened(*result);
+ return result;
+ }
+
+ return {};
+ }
+
+ std::u16string ReadInterfaceToken() {
+ [[maybe_unused]] const u32 unknown = Read<u32>();
+ const u32 length = Read<u32>();
+
+ std::u16string token;
+ token.reserve(length + 1);
+
+ for (u32 ch = 0; ch < length + 1; ++ch) {
+ token.push_back(ReadUnaligned<u16>());
+ }
+
+ read_index = Common::AlignUp(read_index, 4);
+
+ return token;
+ }
+
+ void DeserializeHeader() {
+ ASSERT(read_buffer.size() > sizeof(ParcelHeader));
+
+ ParcelHeader header{};
+ std::memcpy(&header, read_buffer.data(), sizeof(ParcelHeader));
+
+ read_index = header.data_offset;
+ }
+
+private:
+ std::span<const u8> read_buffer;
+ std::size_t read_index = 0;
+};
+
+class OutputParcel final {
+public:
+ OutputParcel() = default;
+
+ template <typename T>
+ void Write(const T& val) {
+ this->WriteImpl(val, m_data_buffer);
+ }
+
+ template <typename T>
+ void WriteFlattenedObject(const T* ptr) {
+ if (!ptr) {
+ this->Write<u32>(0);
+ return;
+ }
+
+ this->Write<u32>(1);
+ this->Write<s64>(sizeof(T));
+ this->Write(*ptr);
+ }
+
+ template <typename T>
+ void WriteFlattenedObject(const std::shared_ptr<T> ptr) {
+ this->WriteFlattenedObject(ptr.get());
+ }
+
+ template <typename T>
+ void WriteInterface(const T& val) {
+ this->WriteImpl(val, m_data_buffer);
+ this->WriteImpl(0U, m_object_buffer);
+ }
+
+ std::vector<u8> Serialize() const {
+ std::vector<u8> output_buffer(sizeof(ParcelHeader) + m_data_buffer.size() +
+ m_object_buffer.size());
+
+ ParcelHeader header{};
+ header.data_size = static_cast<u32>(m_data_buffer.size());
+ header.data_offset = sizeof(ParcelHeader);
+ header.objects_size = static_cast<u32>(m_object_buffer.size());
+ header.objects_offset = header.data_offset + header.data_size;
+
+ std::memcpy(output_buffer.data(), &header, sizeof(header));
+ std::ranges::copy(m_data_buffer, output_buffer.data() + header.data_offset);
+ std::ranges::copy(m_object_buffer, output_buffer.data() + header.objects_offset);
+
+ return output_buffer;
+ }
+
+private:
+ template <typename T>
+ requires(std::is_trivially_copyable_v<T>)
+ void WriteImpl(const T& val, boost::container::small_vector<u8, 0x200>& buffer) {
+ const size_t aligned_size = Common::AlignUp(sizeof(T), 4);
+ const size_t old_size = buffer.size();
+ buffer.resize(old_size + aligned_size);
+
+ std::memcpy(buffer.data() + old_size, &val, sizeof(T));
+ }
+
+private:
+ boost::container::small_vector<u8, 0x200> m_data_buffer;
+ boost::container::small_vector<u8, 0x200> m_object_buffer;
+};
+
+} // namespace Service::android
diff --git a/src/core/hle/service/nvflinger/pixel_format.h b/src/core/hle/service/nvnflinger/pixel_format.h
index f77d0acfb..f77d0acfb 100644
--- a/src/core/hle/service/nvflinger/pixel_format.h
+++ b/src/core/hle/service/nvnflinger/pixel_format.h
diff --git a/src/core/hle/service/nvflinger/producer_listener.h b/src/core/hle/service/nvnflinger/producer_listener.h
index 6bf8aaf1e..6bf8aaf1e 100644
--- a/src/core/hle/service/nvflinger/producer_listener.h
+++ b/src/core/hle/service/nvnflinger/producer_listener.h
diff --git a/src/core/hle/service/nvflinger/status.h b/src/core/hle/service/nvnflinger/status.h
index 7af166c40..7af166c40 100644
--- a/src/core/hle/service/nvflinger/status.h
+++ b/src/core/hle/service/nvnflinger/status.h
diff --git a/src/core/hle/service/nvflinger/ui/fence.h b/src/core/hle/service/nvnflinger/ui/fence.h
index 536e8156d..536e8156d 100644
--- a/src/core/hle/service/nvflinger/ui/fence.h
+++ b/src/core/hle/service/nvnflinger/ui/fence.h
diff --git a/src/core/hle/service/nvflinger/ui/graphic_buffer.h b/src/core/hle/service/nvnflinger/ui/graphic_buffer.h
index 9a27f8f02..75d1705a8 100644
--- a/src/core/hle/service/nvflinger/ui/graphic_buffer.h
+++ b/src/core/hle/service/nvnflinger/ui/graphic_buffer.h
@@ -8,7 +8,7 @@
#include "common/common_funcs.h"
#include "common/common_types.h"
-#include "core/hle/service/nvflinger/pixel_format.h"
+#include "core/hle/service/nvnflinger/pixel_format.h"
namespace Service::android {
diff --git a/src/core/hle/service/nvflinger/window.h b/src/core/hle/service/nvnflinger/window.h
index 61cca5b01..61cca5b01 100644
--- a/src/core/hle/service/nvflinger/window.h
+++ b/src/core/hle/service/nvnflinger/window.h
diff --git a/src/core/hle/service/olsc/olsc.cpp b/src/core/hle/service/olsc/olsc.cpp
index 530e1be3b..14ba67b4c 100644
--- a/src/core/hle/service/olsc/olsc.cpp
+++ b/src/core/hle/service/olsc/olsc.cpp
@@ -1,10 +1,10 @@
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
-#include "core/hle/ipc_helpers.h"
+#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/olsc/olsc.h"
+#include "core/hle/service/server_manager.h"
#include "core/hle/service/service.h"
-#include "core/hle/service/sm/sm.h"
namespace Service::OLSC {
@@ -42,7 +42,7 @@ public:
}
private:
- void Initialize(Kernel::HLERequestContext& ctx) {
+ void Initialize(HLERequestContext& ctx) {
LOG_WARNING(Service_OLSC, "(STUBBED) called");
initialized = true;
@@ -51,7 +51,7 @@ private:
rb.Push(ResultSuccess);
}
- void GetSaveDataBackupSetting(Kernel::HLERequestContext& ctx) {
+ void GetSaveDataBackupSetting(HLERequestContext& ctx) {
LOG_WARNING(Service_OLSC, "(STUBBED) called");
// backup_setting is set to 0 since real value is unknown
@@ -62,7 +62,7 @@ private:
rb.Push(backup_setting);
}
- void SetSaveDataBackupSettingEnabled(Kernel::HLERequestContext& ctx) {
+ void SetSaveDataBackupSettingEnabled(HLERequestContext& ctx) {
LOG_WARNING(Service_OLSC, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
@@ -72,8 +72,11 @@ private:
bool initialized{};
};
-void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
- std::make_shared<OLSC>(system)->InstallAsService(service_manager);
+void LoopProcess(Core::System& system) {
+ auto server_manager = std::make_unique<ServerManager>(system);
+
+ server_manager->RegisterNamedService("olsc:u", std::make_shared<OLSC>(system));
+ ServerManager::RunServer(std::move(server_manager));
}
} // namespace Service::OLSC
diff --git a/src/core/hle/service/olsc/olsc.h b/src/core/hle/service/olsc/olsc.h
index 1522d8d32..620b634fa 100644
--- a/src/core/hle/service/olsc/olsc.h
+++ b/src/core/hle/service/olsc/olsc.h
@@ -7,13 +7,8 @@ namespace Core {
class System;
}
-namespace Service::SM {
-class ServiceManager;
-}
-
namespace Service::OLSC {
-/// Registers all SSL services with the specified service manager.
-void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system);
+void LoopProcess(Core::System& system);
} // namespace Service::OLSC
diff --git a/src/core/hle/service/pcie/pcie.cpp b/src/core/hle/service/pcie/pcie.cpp
index 79501b9f9..c6da6eb51 100644
--- a/src/core/hle/service/pcie/pcie.cpp
+++ b/src/core/hle/service/pcie/pcie.cpp
@@ -4,8 +4,8 @@
#include <memory>
#include "core/hle/service/pcie/pcie.h"
+#include "core/hle/service/server_manager.h"
#include "core/hle/service/service.h"
-#include "core/hle/service/sm/sm.h"
namespace Service::PCIe {
@@ -59,8 +59,11 @@ public:
}
};
-void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
- std::make_shared<PCIe>(system)->InstallAsService(sm);
+void LoopProcess(Core::System& system) {
+ auto server_manager = std::make_unique<ServerManager>(system);
+
+ server_manager->RegisterNamedService("pcie", std::make_shared<PCIe>(system));
+ ServerManager::RunServer(std::move(server_manager));
}
} // namespace Service::PCIe
diff --git a/src/core/hle/service/pcie/pcie.h b/src/core/hle/service/pcie/pcie.h
index cebfd9042..5c2d4b805 100644
--- a/src/core/hle/service/pcie/pcie.h
+++ b/src/core/hle/service/pcie/pcie.h
@@ -7,12 +7,8 @@ namespace Core {
class System;
}
-namespace Service::SM {
-class ServiceManager;
-}
-
namespace Service::PCIe {
-void InstallInterfaces(SM::ServiceManager& sm, Core::System& system);
+void LoopProcess(Core::System& system);
} // namespace Service::PCIe
diff --git a/src/core/hle/service/pctl/pctl_module.cpp b/src/core/hle/service/pctl/pctl_module.cpp
index 2a123b42d..f966c5c8b 100644
--- a/src/core/hle/service/pctl/pctl_module.cpp
+++ b/src/core/hle/service/pctl/pctl_module.cpp
@@ -5,9 +5,10 @@
#include "core/core.h"
#include "core/file_sys/control_metadata.h"
#include "core/file_sys/patch_manager.h"
-#include "core/hle/ipc_helpers.h"
+#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/pctl/pctl.h"
#include "core/hle/service/pctl/pctl_module.h"
+#include "core/hle/service/server_manager.h"
namespace Service::PCTL {
@@ -176,7 +177,7 @@ private:
settings.is_stero_vision_restricted = is_restricted;
}
- void Initialize(Kernel::HLERequestContext& ctx) {
+ void Initialize(HLERequestContext& ctx) {
LOG_DEBUG(Service_PCTL, "called");
IPC::ResponseBuilder rb{ctx, 2};
@@ -187,7 +188,7 @@ private:
// TODO(ogniK): Recovery flag initialization for pctl:r
- const auto tid = system.GetCurrentProcessProgramID();
+ const auto tid = system.GetApplicationProcessProgramID();
if (tid != 0) {
const FileSys::PatchManager pm{tid, system.GetFileSystemController(),
system.GetContentProvider()};
@@ -214,7 +215,7 @@ private:
rb.Push(ResultSuccess);
}
- void CheckFreeCommunicationPermission(Kernel::HLERequestContext& ctx) {
+ void CheckFreeCommunicationPermission(HLERequestContext& ctx) {
LOG_DEBUG(Service_PCTL, "called");
IPC::ResponseBuilder rb{ctx, 2};
@@ -227,7 +228,7 @@ private:
states.free_communication = true;
}
- void ConfirmStereoVisionPermission(Kernel::HLERequestContext& ctx) {
+ void ConfirmStereoVisionPermission(HLERequestContext& ctx) {
LOG_DEBUG(Service_PCTL, "called");
states.stereo_vision = true;
@@ -235,14 +236,14 @@ private:
rb.Push(ResultSuccess);
}
- void EndFreeCommunication(Kernel::HLERequestContext& ctx) {
+ void EndFreeCommunication(HLERequestContext& ctx) {
LOG_WARNING(Service_PCTL, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
- void IsFreeCommunicationAvailable(Kernel::HLERequestContext& ctx) {
+ void IsFreeCommunicationAvailable(HLERequestContext& ctx) {
LOG_WARNING(Service_PCTL, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
@@ -253,7 +254,7 @@ private:
}
}
- void IsRestrictionEnabled(Kernel::HLERequestContext& ctx) {
+ void IsRestrictionEnabled(HLERequestContext& ctx) {
LOG_DEBUG(Service_PCTL, "called");
IPC::ResponseBuilder rb{ctx, 3};
@@ -267,7 +268,7 @@ private:
rb.Push(pin_code[0] != '\0');
}
- void ConfirmStereoVisionRestrictionConfigurable(Kernel::HLERequestContext& ctx) {
+ void ConfirmStereoVisionRestrictionConfigurable(HLERequestContext& ctx) {
LOG_DEBUG(Service_PCTL, "called");
IPC::ResponseBuilder rb{ctx, 2};
@@ -286,7 +287,7 @@ private:
rb.Push(ResultSuccess);
}
- void IsStereoVisionPermitted(Kernel::HLERequestContext& ctx) {
+ void IsStereoVisionPermitted(HLERequestContext& ctx) {
LOG_DEBUG(Service_PCTL, "called");
IPC::ResponseBuilder rb{ctx, 3};
@@ -299,7 +300,7 @@ private:
}
}
- void SetStereoVisionRestriction(Kernel::HLERequestContext& ctx) {
+ void SetStereoVisionRestriction(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto can_use = rp.Pop<bool>();
LOG_DEBUG(Service_PCTL, "called, can_use={}", can_use);
@@ -315,7 +316,7 @@ private:
rb.Push(ResultSuccess);
}
- void GetStereoVisionRestriction(Kernel::HLERequestContext& ctx) {
+ void GetStereoVisionRestriction(HLERequestContext& ctx) {
LOG_DEBUG(Service_PCTL, "called");
IPC::ResponseBuilder rb{ctx, 3};
@@ -330,7 +331,7 @@ private:
rb.Push(settings.is_stero_vision_restricted);
}
- void ResetConfirmedStereoVisionPermission(Kernel::HLERequestContext& ctx) {
+ void ResetConfirmedStereoVisionPermission(HLERequestContext& ctx) {
LOG_DEBUG(Service_PCTL, "called");
states.stereo_vision = false;
@@ -369,7 +370,7 @@ private:
Capability capability{};
};
-void Module::Interface::CreateService(Kernel::HLERequestContext& ctx) {
+void Module::Interface::CreateService(HLERequestContext& ctx) {
LOG_DEBUG(Service_PCTL, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -379,7 +380,7 @@ void Module::Interface::CreateService(Kernel::HLERequestContext& ctx) {
rb.PushIpcInterface<IParentalControlService>(system, capability);
}
-void Module::Interface::CreateServiceWithoutInitialize(Kernel::HLERequestContext& ctx) {
+void Module::Interface::CreateServiceWithoutInitialize(HLERequestContext& ctx) {
LOG_DEBUG(Service_PCTL, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -393,19 +394,22 @@ Module::Interface::Interface(Core::System& system_, std::shared_ptr<Module> modu
Module::Interface::~Interface() = default;
-void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
+void LoopProcess(Core::System& system) {
+ auto server_manager = std::make_unique<ServerManager>(system);
+
auto module = std::make_shared<Module>();
- std::make_shared<PCTL>(system, module, "pctl",
- Capability::Application | Capability::SnsPost | Capability::Status |
- Capability::StereoVision)
- ->InstallAsService(service_manager);
+ server_manager->RegisterNamedService(
+ "pctl", std::make_shared<PCTL>(system, module, "pctl",
+ Capability::Application | Capability::SnsPost |
+ Capability::Status | Capability::StereoVision));
// TODO(ogniK): Implement remaining capabilities
- std::make_shared<PCTL>(system, module, "pctl:a", Capability::None)
- ->InstallAsService(service_manager);
- std::make_shared<PCTL>(system, module, "pctl:r", Capability::None)
- ->InstallAsService(service_manager);
- std::make_shared<PCTL>(system, module, "pctl:s", Capability::None)
- ->InstallAsService(service_manager);
+ server_manager->RegisterNamedService(
+ "pctl:a", std::make_shared<PCTL>(system, module, "pctl:a", Capability::None));
+ server_manager->RegisterNamedService(
+ "pctl:r", std::make_shared<PCTL>(system, module, "pctl:r", Capability::None));
+ server_manager->RegisterNamedService(
+ "pctl:s", std::make_shared<PCTL>(system, module, "pctl:s", Capability::None));
+ ServerManager::RunServer(std::move(server_manager));
}
} // namespace Service::PCTL
diff --git a/src/core/hle/service/pctl/pctl_module.h b/src/core/hle/service/pctl/pctl_module.h
index 6f584530d..dff0d3f08 100644
--- a/src/core/hle/service/pctl/pctl_module.h
+++ b/src/core/hle/service/pctl/pctl_module.h
@@ -31,8 +31,8 @@ public:
const char* name_, Capability capability_);
~Interface() override;
- void CreateService(Kernel::HLERequestContext& ctx);
- void CreateServiceWithoutInitialize(Kernel::HLERequestContext& ctx);
+ void CreateService(HLERequestContext& ctx);
+ void CreateServiceWithoutInitialize(HLERequestContext& ctx);
protected:
std::shared_ptr<Module> module;
@@ -42,7 +42,6 @@ public:
};
};
-/// Registers all PCTL services with the specified service manager.
-void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system);
+void LoopProcess(Core::System& system);
} // namespace Service::PCTL
diff --git a/src/core/hle/service/pcv/pcv.cpp b/src/core/hle/service/pcv/pcv.cpp
index f7a497a14..c13ffa6f6 100644
--- a/src/core/hle/service/pcv/pcv.cpp
+++ b/src/core/hle/service/pcv/pcv.cpp
@@ -3,10 +3,10 @@
#include <memory>
-#include "core/hle/ipc_helpers.h"
+#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/pcv/pcv.h"
+#include "core/hle/service/server_manager.h"
#include "core/hle/service/service.h"
-#include "core/hle/service/sm/sm.h"
namespace Service::PCV {
@@ -52,32 +52,6 @@ public:
}
};
-class PCV_ARB final : public ServiceFramework<PCV_ARB> {
-public:
- explicit PCV_ARB(Core::System& system_) : ServiceFramework{system_, "pcv:arb"} {
- // clang-format off
- static const FunctionInfo functions[] = {
- {0, nullptr, "ReleaseControl"},
- };
- // clang-format on
-
- RegisterHandlers(functions);
- }
-};
-
-class PCV_IMM final : public ServiceFramework<PCV_IMM> {
-public:
- explicit PCV_IMM(Core::System& system_) : ServiceFramework{system_, "pcv:imm"} {
- // clang-format off
- static const FunctionInfo functions[] = {
- {0, nullptr, "SetClockRate"},
- };
- // clang-format on
-
- RegisterHandlers(functions);
- }
-};
-
class IClkrstSession final : public ServiceFramework<IClkrstSession> {
public:
explicit IClkrstSession(Core::System& system_, DeviceCode deivce_code_)
@@ -102,7 +76,7 @@ public:
}
private:
- void SetClockRate(Kernel::HLERequestContext& ctx) {
+ void SetClockRate(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
clock_rate = rp.Pop<u32>();
LOG_DEBUG(Service_PCV, "(STUBBED) called, clock_rate={}", clock_rate);
@@ -111,7 +85,7 @@ private:
rb.Push(ResultSuccess);
}
- void GetClockRate(Kernel::HLERequestContext& ctx) {
+ void GetClockRate(HLERequestContext& ctx) {
LOG_DEBUG(Service_PCV, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
@@ -141,7 +115,7 @@ public:
}
private:
- void OpenSession(Kernel::HLERequestContext& ctx) {
+ void OpenSession(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto device_code = static_cast<DeviceCode>(rp.Pop<u32>());
const auto unkonwn_input = rp.Pop<u32>();
@@ -167,13 +141,14 @@ public:
}
};
-void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
- std::make_shared<PCV>(system)->InstallAsService(sm);
- std::make_shared<PCV_ARB>(system)->InstallAsService(sm);
- std::make_shared<PCV_IMM>(system)->InstallAsService(sm);
- std::make_shared<CLKRST>(system, "clkrst")->InstallAsService(sm);
- std::make_shared<CLKRST>(system, "clkrst:i")->InstallAsService(sm);
- std::make_shared<CLKRST_A>(system)->InstallAsService(sm);
+void LoopProcess(Core::System& system) {
+ auto server_manager = std::make_unique<ServerManager>(system);
+
+ server_manager->RegisterNamedService("pcv", std::make_shared<PCV>(system));
+ server_manager->RegisterNamedService("clkrst", std::make_shared<CLKRST>(system, "clkrst"));
+ server_manager->RegisterNamedService("clkrst:i", std::make_shared<CLKRST>(system, "clkrst:i"));
+ server_manager->RegisterNamedService("clkrst:a", std::make_shared<CLKRST_A>(system));
+ ServerManager::RunServer(std::move(server_manager));
}
} // namespace Service::PCV
diff --git a/src/core/hle/service/pcv/pcv.h b/src/core/hle/service/pcv/pcv.h
index 6b26b6fa7..bf541e6fe 100644
--- a/src/core/hle/service/pcv/pcv.h
+++ b/src/core/hle/service/pcv/pcv.h
@@ -7,10 +7,6 @@ namespace Core {
class System;
}
-namespace Service::SM {
-class ServiceManager;
-}
-
namespace Service::PCV {
enum class DeviceCode : u32 {
@@ -104,6 +100,6 @@ enum class DeviceCode : u32 {
OscClk = 0x40000080
};
-void InstallInterfaces(SM::ServiceManager& sm, Core::System& system);
+void LoopProcess(Core::System& system);
} // namespace Service::PCV
diff --git a/src/core/hle/service/pm/pm.cpp b/src/core/hle/service/pm/pm.cpp
index b10e86c8f..f9cf2dda3 100644
--- a/src/core/hle/service/pm/pm.cpp
+++ b/src/core/hle/service/pm/pm.cpp
@@ -2,10 +2,11 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#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/service/ipc_helpers.h"
#include "core/hle/service/pm/pm.h"
+#include "core/hle/service/server_manager.h"
#include "core/hle/service/service.h"
namespace Service::PM {
@@ -33,15 +34,15 @@ std::optional<Kernel::KProcess*> SearchProcessList(
return *iter;
}
-void GetApplicationPidGeneric(Kernel::HLERequestContext& ctx,
+void GetApplicationPidGeneric(HLERequestContext& ctx,
const std::vector<Kernel::KProcess*>& process_list) {
const auto process = SearchProcessList(process_list, [](const auto& proc) {
- return proc->GetProcessID() == Kernel::KProcess::ProcessIDMin;
+ return proc->GetProcessId() == Kernel::KProcess::ProcessIDMin;
});
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
- rb.Push(process.has_value() ? (*process)->GetProcessID() : NO_PROCESS_FOUND_PID);
+ rb.Push(process.has_value() ? (*process)->GetProcessId() : NO_PROCESS_FOUND_PID);
}
} // Anonymous namespace
@@ -57,7 +58,7 @@ public:
}
private:
- void GetBootMode(Kernel::HLERequestContext& ctx) {
+ void GetBootMode(HLERequestContext& ctx) {
LOG_DEBUG(Service_PM, "called");
IPC::ResponseBuilder rb{ctx, 3};
@@ -65,7 +66,7 @@ private:
rb.PushEnum(boot_mode);
}
- void SetMaintenanceBoot(Kernel::HLERequestContext& ctx) {
+ void SetMaintenanceBoot(HLERequestContext& ctx) {
LOG_DEBUG(Service_PM, "called");
boot_mode = SystemBootMode::Maintenance;
@@ -99,7 +100,7 @@ public:
}
private:
- void GetProcessId(Kernel::HLERequestContext& ctx) {
+ void GetProcessId(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto program_id = rp.PopRaw<u64>();
@@ -107,7 +108,7 @@ private:
const auto process =
SearchProcessList(kernel.GetProcessList(), [program_id](const auto& proc) {
- return proc->GetProgramID() == program_id;
+ return proc->GetProgramId() == program_id;
});
if (!process.has_value()) {
@@ -118,15 +119,15 @@ private:
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
- rb.Push((*process)->GetProcessID());
+ rb.Push((*process)->GetProcessId());
}
- void GetApplicationProcessId(Kernel::HLERequestContext& ctx) {
+ void GetApplicationProcessId(HLERequestContext& ctx) {
LOG_DEBUG(Service_PM, "called");
GetApplicationPidGeneric(ctx, kernel.GetProcessList());
}
- void AtmosphereGetProcessInfo(Kernel::HLERequestContext& ctx) {
+ void AtmosphereGetProcessInfo(HLERequestContext& ctx) {
// https://github.com/Atmosphere-NX/Atmosphere/blob/master/stratosphere/pm/source/impl/pm_process_manager.cpp#L614
// This implementation is incomplete; only a handle to the process is returned.
IPC::RequestParser rp{ctx};
@@ -135,7 +136,7 @@ private:
LOG_WARNING(Service_PM, "(Partial Implementation) called, pid={:016X}", pid);
const auto process = SearchProcessList(kernel.GetProcessList(), [pid](const auto& proc) {
- return proc->GetProcessID() == pid;
+ return proc->GetProcessId() == pid;
});
if (!process.has_value()) {
@@ -158,7 +159,7 @@ private:
OverrideStatus override_status{};
ProgramLocation program_location{
- .program_id = (*process)->GetProgramID(),
+ .program_id = (*process)->GetProgramId(),
.storage_id = 0,
};
@@ -186,14 +187,14 @@ public:
}
private:
- void GetProgramId(Kernel::HLERequestContext& ctx) {
+ void GetProgramId(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto process_id = rp.PopRaw<u64>();
LOG_DEBUG(Service_PM, "called, process_id={:016X}", process_id);
const auto process = SearchProcessList(process_list, [process_id](const auto& proc) {
- return proc->GetProcessID() == process_id;
+ return proc->GetProcessId() == process_id;
});
if (!process.has_value()) {
@@ -204,17 +205,17 @@ private:
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
- rb.Push((*process)->GetProgramID());
+ rb.Push((*process)->GetProgramId());
}
- void AtmosphereGetProcessId(Kernel::HLERequestContext& ctx) {
+ void AtmosphereGetProcessId(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto program_id = rp.PopRaw<u64>();
LOG_DEBUG(Service_PM, "called, program_id={:016X}", program_id);
const auto process = SearchProcessList(process_list, [program_id](const auto& proc) {
- return proc->GetProgramID() == program_id;
+ return proc->GetProgramId() == program_id;
});
if (!process.has_value()) {
@@ -225,7 +226,7 @@ private:
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
- rb.Push((*process)->GetProcessID());
+ rb.Push((*process)->GetProcessId());
}
const std::vector<Kernel::KProcess*>& process_list;
@@ -254,7 +255,7 @@ public:
}
private:
- void GetApplicationProcessIdForShell(Kernel::HLERequestContext& ctx) {
+ void GetApplicationProcessIdForShell(HLERequestContext& ctx) {
LOG_DEBUG(Service_PM, "called");
GetApplicationPidGeneric(ctx, kernel.GetProcessList());
}
@@ -262,12 +263,15 @@ private:
const Kernel::KernelCore& kernel;
};
-void InstallInterfaces(Core::System& system) {
- std::make_shared<BootMode>(system)->InstallAsService(system.ServiceManager());
- std::make_shared<DebugMonitor>(system)->InstallAsService(system.ServiceManager());
- std::make_shared<Info>(system, system.Kernel().GetProcessList())
- ->InstallAsService(system.ServiceManager());
- std::make_shared<Shell>(system)->InstallAsService(system.ServiceManager());
+void LoopProcess(Core::System& system) {
+ auto server_manager = std::make_unique<ServerManager>(system);
+
+ server_manager->RegisterNamedService("pm:bm", std::make_shared<BootMode>(system));
+ server_manager->RegisterNamedService("pm:dmnt", std::make_shared<DebugMonitor>(system));
+ server_manager->RegisterNamedService(
+ "pm:info", std::make_shared<Info>(system, system.Kernel().GetProcessList()));
+ server_manager->RegisterNamedService("pm:shell", std::make_shared<Shell>(system));
+ ServerManager::RunServer(std::move(server_manager));
}
} // namespace Service::PM
diff --git a/src/core/hle/service/pm/pm.h b/src/core/hle/service/pm/pm.h
index 060103928..5d4a1a171 100644
--- a/src/core/hle/service/pm/pm.h
+++ b/src/core/hle/service/pm/pm.h
@@ -14,7 +14,6 @@ enum class SystemBootMode {
Maintenance,
};
-/// Registers all PM services with the specified service manager.
-void InstallInterfaces(Core::System& system);
+void LoopProcess(Core::System& system);
} // namespace Service::PM
diff --git a/src/core/hle/service/prepo/prepo.cpp b/src/core/hle/service/prepo/prepo.cpp
index 78f897d3e..ec4a84989 100644
--- a/src/core/hle/service/prepo/prepo.cpp
+++ b/src/core/hle/service/prepo/prepo.cpp
@@ -4,9 +4,10 @@
#include "common/hex_util.h"
#include "common/logging/log.h"
#include "core/core.h"
-#include "core/hle/ipc_helpers.h"
#include "core/hle/service/acc/profile_manager.h"
+#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/prepo/prepo.h"
+#include "core/hle/service/server_manager.h"
#include "core/hle/service/service.h"
#include "core/reporter.h"
@@ -53,7 +54,7 @@ public:
private:
template <Core::Reporter::PlayReportType Type>
- void SaveReport(Kernel::HLERequestContext& ctx) {
+ void SaveReport(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto process_id = rp.PopRaw<u64>();
@@ -63,7 +64,7 @@ private:
return ctx.ReadBuffer(1);
}
- return std::vector<u8>{};
+ return std::span<const u8>{};
}();
LOG_DEBUG(Service_PREPO,
@@ -71,7 +72,7 @@ private:
Type, process_id, data1.size(), data2.size());
const auto& reporter{system.GetReporter()};
- reporter.SavePlayReport(Type, system.GetCurrentProcessProgramID(), {data1, data2},
+ reporter.SavePlayReport(Type, system.GetApplicationProcessProgramID(), {data1, data2},
process_id);
IPC::ResponseBuilder rb{ctx, 2};
@@ -79,7 +80,7 @@ private:
}
template <Core::Reporter::PlayReportType Type>
- void SaveReportWithUser(Kernel::HLERequestContext& ctx) {
+ void SaveReportWithUser(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto user_id = rp.PopRaw<u128>();
const auto process_id = rp.PopRaw<u64>();
@@ -90,7 +91,7 @@ private:
return ctx.ReadBuffer(1);
}
- return std::vector<u8>{};
+ return std::span<const u8>{};
}();
LOG_DEBUG(Service_PREPO,
@@ -99,21 +100,21 @@ private:
Type, user_id[1], user_id[0], process_id, data1.size(), data2.size());
const auto& reporter{system.GetReporter()};
- reporter.SavePlayReport(Type, system.GetCurrentProcessProgramID(), {data1, data2},
+ reporter.SavePlayReport(Type, system.GetApplicationProcessProgramID(), {data1, data2},
process_id, user_id);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
- void RequestImmediateTransmission(Kernel::HLERequestContext& ctx) {
+ void RequestImmediateTransmission(HLERequestContext& ctx) {
LOG_WARNING(Service_PREPO, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
- void GetTransmissionStatus(Kernel::HLERequestContext& ctx) {
+ void GetTransmissionStatus(HLERequestContext& ctx) {
LOG_WARNING(Service_PREPO, "(STUBBED) called");
constexpr s32 status = 0;
@@ -123,7 +124,7 @@ private:
rb.Push(status);
}
- void GetSystemSessionId(Kernel::HLERequestContext& ctx) {
+ void GetSystemSessionId(HLERequestContext& ctx) {
LOG_WARNING(Service_PREPO, "(STUBBED) called");
constexpr u64 system_session_id = 0;
@@ -132,7 +133,7 @@ private:
rb.Push(system_session_id);
}
- void SaveSystemReport(Kernel::HLERequestContext& ctx) {
+ void SaveSystemReport(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto title_id = rp.PopRaw<u64>();
@@ -142,7 +143,7 @@ private:
return ctx.ReadBuffer(1);
}
- return std::vector<u8>{};
+ return std::span<const u8>{};
}();
LOG_DEBUG(Service_PREPO, "called, title_id={:016X}, data1_size={:016X}, data2_size={:016X}",
@@ -155,7 +156,7 @@ private:
rb.Push(ResultSuccess);
}
- void SaveSystemReportWithUser(Kernel::HLERequestContext& ctx) {
+ void SaveSystemReportWithUser(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto user_id = rp.PopRaw<u128>();
const auto title_id = rp.PopRaw<u64>();
@@ -166,7 +167,7 @@ private:
return ctx.ReadBuffer(1);
}
- return std::vector<u8>{};
+ return std::span<const u8>{};
}();
LOG_DEBUG(Service_PREPO,
@@ -183,12 +184,20 @@ private:
}
};
-void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
- std::make_shared<PlayReport>("prepo:a", system)->InstallAsService(service_manager);
- std::make_shared<PlayReport>("prepo:a2", system)->InstallAsService(service_manager);
- std::make_shared<PlayReport>("prepo:m", system)->InstallAsService(service_manager);
- std::make_shared<PlayReport>("prepo:s", system)->InstallAsService(service_manager);
- std::make_shared<PlayReport>("prepo:u", system)->InstallAsService(service_manager);
+void LoopProcess(Core::System& system) {
+ auto server_manager = std::make_unique<ServerManager>(system);
+
+ server_manager->RegisterNamedService("prepo:a",
+ std::make_shared<PlayReport>("prepo:a", system));
+ server_manager->RegisterNamedService("prepo:a2",
+ std::make_shared<PlayReport>("prepo:a2", system));
+ server_manager->RegisterNamedService("prepo:m",
+ std::make_shared<PlayReport>("prepo:m", system));
+ server_manager->RegisterNamedService("prepo:s",
+ std::make_shared<PlayReport>("prepo:s", system));
+ server_manager->RegisterNamedService("prepo:u",
+ std::make_shared<PlayReport>("prepo:u", system));
+ ServerManager::RunServer(std::move(server_manager));
}
} // namespace Service::PlayReport
diff --git a/src/core/hle/service/prepo/prepo.h b/src/core/hle/service/prepo/prepo.h
index 37ea5afad..2c2462f93 100644
--- a/src/core/hle/service/prepo/prepo.h
+++ b/src/core/hle/service/prepo/prepo.h
@@ -7,12 +7,8 @@ namespace Core {
class System;
}
-namespace Service::SM {
-class ServiceManager;
-}
-
namespace Service::PlayReport {
-void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system);
+void LoopProcess(Core::System& system);
} // namespace Service::PlayReport
diff --git a/src/core/hle/service/psc/psc.cpp b/src/core/hle/service/psc/psc.cpp
index 3a9412cf5..cd0cc9287 100644
--- a/src/core/hle/service/psc/psc.cpp
+++ b/src/core/hle/service/psc/psc.cpp
@@ -4,16 +4,16 @@
#include <memory>
#include "common/logging/log.h"
-#include "core/hle/ipc_helpers.h"
+#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/psc/psc.h"
+#include "core/hle/service/server_manager.h"
#include "core/hle/service/service.h"
-#include "core/hle/service/sm/sm.h"
namespace Service::PSC {
-class PSC_C final : public ServiceFramework<PSC_C> {
+class IPmControl final : public ServiceFramework<IPmControl> {
public:
- explicit PSC_C(Core::System& system_) : ServiceFramework{system_, "psc:c"} {
+ explicit IPmControl(Core::System& system_) : ServiceFramework{system_, "psc:c"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "Initialize"},
@@ -23,8 +23,8 @@ public:
{4, nullptr, "Cancel"},
{5, nullptr, "PrintModuleInformation"},
{6, nullptr, "GetModuleInformation"},
- {10, nullptr, "Unknown10"},
- {11, nullptr, "Unknown11"},
+ {10, nullptr, "AcquireStateLock"},
+ {11, nullptr, "HasStateLock"},
};
// clang-format on
@@ -49,12 +49,12 @@ public:
}
};
-class PSC_M final : public ServiceFramework<PSC_M> {
+class IPmService final : public ServiceFramework<IPmService> {
public:
- explicit PSC_M(Core::System& system_) : ServiceFramework{system_, "psc:m"} {
+ explicit IPmService(Core::System& system_) : ServiceFramework{system_, "psc:m"} {
// clang-format off
static const FunctionInfo functions[] = {
- {0, &PSC_M::GetPmModule, "GetPmModule"},
+ {0, &IPmService::GetPmModule, "GetPmModule"},
};
// clang-format on
@@ -62,7 +62,7 @@ public:
}
private:
- void GetPmModule(Kernel::HLERequestContext& ctx) {
+ void GetPmModule(HLERequestContext& ctx) {
LOG_DEBUG(Service_PSC, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -71,9 +71,12 @@ private:
}
};
-void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
- std::make_shared<PSC_C>(system)->InstallAsService(sm);
- std::make_shared<PSC_M>(system)->InstallAsService(sm);
+void LoopProcess(Core::System& system) {
+ auto server_manager = std::make_unique<ServerManager>(system);
+
+ server_manager->RegisterNamedService("psc:c", std::make_shared<IPmControl>(system));
+ server_manager->RegisterNamedService("psc:m", std::make_shared<IPmService>(system));
+ ServerManager::RunServer(std::move(server_manager));
}
} // namespace Service::PSC
diff --git a/src/core/hle/service/psc/psc.h b/src/core/hle/service/psc/psc.h
index d248372c2..459137f42 100644
--- a/src/core/hle/service/psc/psc.h
+++ b/src/core/hle/service/psc/psc.h
@@ -13,6 +13,6 @@ class ServiceManager;
namespace Service::PSC {
-void InstallInterfaces(SM::ServiceManager& sm, Core::System& system);
+void LoopProcess(Core::System& system);
} // namespace Service::PSC
diff --git a/src/core/hle/service/ptm/psm.cpp b/src/core/hle/service/ptm/psm.cpp
index 1ac97fe31..136313d7b 100644
--- a/src/core/hle/service/ptm/psm.cpp
+++ b/src/core/hle/service/ptm/psm.cpp
@@ -5,8 +5,8 @@
#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/service/ipc_helpers.h"
#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/ptm/psm.h"
@@ -54,7 +54,7 @@ public:
}
private:
- void BindStateChangeEvent(Kernel::HLERequestContext& ctx) {
+ void BindStateChangeEvent(HLERequestContext& ctx) {
LOG_DEBUG(Service_PTM, "called");
should_signal = true;
@@ -64,7 +64,7 @@ private:
rb.PushCopyObjects(state_change_event->GetReadableEvent());
}
- void UnbindStateChangeEvent(Kernel::HLERequestContext& ctx) {
+ void UnbindStateChangeEvent(HLERequestContext& ctx) {
LOG_DEBUG(Service_PTM, "called");
should_signal = false;
@@ -73,7 +73,7 @@ private:
rb.Push(ResultSuccess);
}
- void SetChargerTypeChangeEventEnabled(Kernel::HLERequestContext& ctx) {
+ void SetChargerTypeChangeEventEnabled(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto state = rp.Pop<bool>();
LOG_DEBUG(Service_PTM, "called, state={}", state);
@@ -84,7 +84,7 @@ private:
rb.Push(ResultSuccess);
}
- void SetPowerSupplyChangeEventEnabled(Kernel::HLERequestContext& ctx) {
+ void SetPowerSupplyChangeEventEnabled(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto state = rp.Pop<bool>();
LOG_DEBUG(Service_PTM, "called, state={}", state);
@@ -95,7 +95,7 @@ private:
rb.Push(ResultSuccess);
}
- void SetBatteryVoltageStateChangeEventEnabled(Kernel::HLERequestContext& ctx) {
+ void SetBatteryVoltageStateChangeEventEnabled(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto state = rp.Pop<bool>();
LOG_DEBUG(Service_PTM, "called, state={}", state);
@@ -145,7 +145,7 @@ PSM::PSM(Core::System& system_) : ServiceFramework{system_, "psm"} {
PSM::~PSM() = default;
-void PSM::GetBatteryChargePercentage(Kernel::HLERequestContext& ctx) {
+void PSM::GetBatteryChargePercentage(HLERequestContext& ctx) {
LOG_DEBUG(Service_PTM, "called");
IPC::ResponseBuilder rb{ctx, 3};
@@ -153,7 +153,7 @@ void PSM::GetBatteryChargePercentage(Kernel::HLERequestContext& ctx) {
rb.Push<u32>(battery_charge_percentage);
}
-void PSM::GetChargerType(Kernel::HLERequestContext& ctx) {
+void PSM::GetChargerType(HLERequestContext& ctx) {
LOG_DEBUG(Service_PTM, "called");
IPC::ResponseBuilder rb{ctx, 3};
@@ -161,7 +161,7 @@ void PSM::GetChargerType(Kernel::HLERequestContext& ctx) {
rb.PushEnum(charger_type);
}
-void PSM::OpenSession(Kernel::HLERequestContext& ctx) {
+void PSM::OpenSession(HLERequestContext& ctx) {
LOG_DEBUG(Service_PTM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
diff --git a/src/core/hle/service/ptm/psm.h b/src/core/hle/service/ptm/psm.h
index f674ba8bc..fa47919e5 100644
--- a/src/core/hle/service/ptm/psm.h
+++ b/src/core/hle/service/ptm/psm.h
@@ -20,9 +20,9 @@ private:
Unknown = 3,
};
- void GetBatteryChargePercentage(Kernel::HLERequestContext& ctx);
- void GetChargerType(Kernel::HLERequestContext& ctx);
- void OpenSession(Kernel::HLERequestContext& ctx);
+ void GetBatteryChargePercentage(HLERequestContext& ctx);
+ void GetChargerType(HLERequestContext& ctx);
+ void OpenSession(HLERequestContext& ctx);
u32 battery_charge_percentage{100};
ChargerType charger_type{ChargerType::RegularCharger};
diff --git a/src/core/hle/service/ptm/ptm.cpp b/src/core/hle/service/ptm/ptm.cpp
index 4bea995c6..6f0cfe04b 100644
--- a/src/core/hle/service/ptm/ptm.cpp
+++ b/src/core/hle/service/ptm/ptm.cpp
@@ -7,12 +7,16 @@
#include "core/hle/service/ptm/psm.h"
#include "core/hle/service/ptm/ptm.h"
#include "core/hle/service/ptm/ts.h"
+#include "core/hle/service/server_manager.h"
namespace Service::PTM {
-void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
- std::make_shared<PSM>(system)->InstallAsService(sm);
- std::make_shared<TS>(system)->InstallAsService(sm);
+void LoopProcess(Core::System& system) {
+ auto server_manager = std::make_unique<ServerManager>(system);
+
+ server_manager->RegisterNamedService("psm", std::make_shared<PSM>(system));
+ server_manager->RegisterNamedService("ts", std::make_shared<TS>(system));
+ ServerManager::RunServer(std::move(server_manager));
}
} // namespace Service::PTM
diff --git a/src/core/hle/service/ptm/ptm.h b/src/core/hle/service/ptm/ptm.h
index 06224a24e..a0ae03d28 100644
--- a/src/core/hle/service/ptm/ptm.h
+++ b/src/core/hle/service/ptm/ptm.h
@@ -7,12 +7,8 @@ namespace Core {
class System;
}
-namespace Service::SM {
-class ServiceManager;
-}
-
namespace Service::PTM {
-void InstallInterfaces(SM::ServiceManager& sm, Core::System& system);
+void LoopProcess(Core::System& system);
} // namespace Service::PTM
diff --git a/src/core/hle/service/ptm/ts.cpp b/src/core/hle/service/ptm/ts.cpp
index b1a0a5544..ca064dd90 100644
--- a/src/core/hle/service/ptm/ts.cpp
+++ b/src/core/hle/service/ptm/ts.cpp
@@ -4,7 +4,7 @@
#include <memory>
#include "core/core.h"
-#include "core/hle/ipc_helpers.h"
+#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/ptm/ts.h"
namespace Service::PTM {
@@ -25,7 +25,7 @@ TS::TS(Core::System& system_) : ServiceFramework{system_, "ts"} {
TS::~TS() = default;
-void TS::GetTemperature(Kernel::HLERequestContext& ctx) {
+void TS::GetTemperature(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto location{rp.PopEnum<Location>()};
@@ -36,7 +36,7 @@ void TS::GetTemperature(Kernel::HLERequestContext& ctx) {
rb.Push(temperature);
}
-void TS::GetTemperatureMilliC(Kernel::HLERequestContext& ctx) {
+void TS::GetTemperatureMilliC(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto location{rp.PopEnum<Location>()};
diff --git a/src/core/hle/service/ptm/ts.h b/src/core/hle/service/ptm/ts.h
index 39d51847e..c3f43d5a3 100644
--- a/src/core/hle/service/ptm/ts.h
+++ b/src/core/hle/service/ptm/ts.h
@@ -19,8 +19,8 @@ private:
External,
};
- void GetTemperature(Kernel::HLERequestContext& ctx);
- void GetTemperatureMilliC(Kernel::HLERequestContext& ctx);
+ void GetTemperature(HLERequestContext& ctx);
+ void GetTemperatureMilliC(HLERequestContext& ctx);
};
} // namespace Service::PTM
diff --git a/src/core/hle/service/server_manager.cpp b/src/core/hle/service/server_manager.cpp
new file mode 100644
index 000000000..d1e99b184
--- /dev/null
+++ b/src/core/hle/service/server_manager.cpp
@@ -0,0 +1,451 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "common/scope_exit.h"
+
+#include "core/core.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_object_name.h"
+#include "core/hle/kernel/k_port.h"
+#include "core/hle/kernel/k_server_port.h"
+#include "core/hle/kernel/k_server_session.h"
+#include "core/hle/kernel/k_synchronization_object.h"
+#include "core/hle/kernel/svc_results.h"
+#include "core/hle/service/hle_ipc.h"
+#include "core/hle/service/ipc_helpers.h"
+#include "core/hle/service/server_manager.h"
+#include "core/hle/service/sm/sm.h"
+
+namespace Service {
+
+constexpr size_t MaximumWaitObjects = 0x40;
+
+enum HandleType {
+ Port,
+ Session,
+ DeferEvent,
+ Event,
+};
+
+ServerManager::ServerManager(Core::System& system) : m_system{system}, m_serve_mutex{system} {
+ // Initialize event.
+ m_event = Kernel::KEvent::Create(system.Kernel());
+ m_event->Initialize(nullptr);
+
+ // Register event.
+ Kernel::KEvent::Register(system.Kernel(), m_event);
+}
+
+ServerManager::~ServerManager() {
+ // Signal stop.
+ m_stop_source.request_stop();
+ m_event->Signal();
+
+ // Wait for processing to stop.
+ m_stopped.Wait();
+ m_threads.clear();
+
+ // Clean up ports.
+ for (const auto& [port, handler] : m_ports) {
+ port->Close();
+ }
+
+ // Clean up sessions.
+ for (const auto& [session, manager] : m_sessions) {
+ session->Close();
+ }
+
+ for (const auto& request : m_deferrals) {
+ request.session->Close();
+ }
+
+ // Close event.
+ m_event->GetReadableEvent().Close();
+ m_event->Close();
+
+ if (m_deferral_event) {
+ m_deferral_event->GetReadableEvent().Close();
+ // Write event is owned by ServiceManager
+ }
+}
+
+void ServerManager::RunServer(std::unique_ptr<ServerManager>&& server_manager) {
+ server_manager->m_system.RunServer(std::move(server_manager));
+}
+
+Result ServerManager::RegisterSession(Kernel::KServerSession* session,
+ std::shared_ptr<SessionRequestManager> manager) {
+ ASSERT(m_sessions.size() + m_ports.size() < MaximumWaitObjects);
+
+ // We are taking ownership of the server session, so don't open it.
+ // Begin tracking the server session.
+ {
+ std::scoped_lock ll{m_list_mutex};
+ m_sessions.emplace(session, std::move(manager));
+ }
+
+ // Signal the wakeup event.
+ m_event->Signal();
+
+ R_SUCCEED();
+}
+
+Result ServerManager::RegisterNamedService(const std::string& service_name,
+ std::shared_ptr<SessionRequestHandler>&& handler,
+ u32 max_sessions) {
+ ASSERT(m_sessions.size() + m_ports.size() < MaximumWaitObjects);
+
+ // Add the new server to sm:.
+ ASSERT(R_SUCCEEDED(
+ m_system.ServiceManager().RegisterService(service_name, max_sessions, handler)));
+
+ // Get the registered port.
+ auto port = m_system.ServiceManager().GetServicePort(service_name);
+ ASSERT(port.Succeeded());
+
+ // Open a new reference to the server port.
+ (*port)->GetServerPort().Open();
+
+ // Begin tracking the server port.
+ {
+ std::scoped_lock ll{m_list_mutex};
+ m_ports.emplace(std::addressof((*port)->GetServerPort()), std::move(handler));
+ }
+
+ // Signal the wakeup event.
+ m_event->Signal();
+
+ R_SUCCEED();
+}
+
+Result ServerManager::ManageNamedPort(const std::string& service_name,
+ std::shared_ptr<SessionRequestHandler>&& handler,
+ u32 max_sessions) {
+ ASSERT(m_sessions.size() + m_ports.size() < MaximumWaitObjects);
+
+ // Create a new port.
+ auto* port = Kernel::KPort::Create(m_system.Kernel());
+ port->Initialize(max_sessions, false, 0);
+
+ // Register the port.
+ Kernel::KPort::Register(m_system.Kernel(), port);
+
+ // Ensure that our reference to the port is closed if we fail to register it.
+ SCOPE_EXIT({
+ port->GetClientPort().Close();
+ port->GetServerPort().Close();
+ });
+
+ // Register the object name with the kernel.
+ R_TRY(Kernel::KObjectName::NewFromName(m_system.Kernel(), std::addressof(port->GetClientPort()),
+ service_name.c_str()));
+
+ // Open a new reference to the server port.
+ port->GetServerPort().Open();
+
+ // Begin tracking the server port.
+ {
+ std::scoped_lock ll{m_list_mutex};
+ m_ports.emplace(std::addressof(port->GetServerPort()), std::move(handler));
+ }
+
+ // We succeeded.
+ R_SUCCEED();
+}
+
+Result ServerManager::ManageDeferral(Kernel::KEvent** out_event) {
+ // Create a new event.
+ m_deferral_event = Kernel::KEvent::Create(m_system.Kernel());
+ ASSERT(m_deferral_event != nullptr);
+
+ // Initialize the event.
+ m_deferral_event->Initialize(nullptr);
+
+ // Register the event.
+ Kernel::KEvent::Register(m_system.Kernel(), m_deferral_event);
+
+ // Set the output.
+ *out_event = m_deferral_event;
+
+ // We succeeded.
+ R_SUCCEED();
+}
+
+void ServerManager::StartAdditionalHostThreads(const char* name, size_t num_threads) {
+ for (size_t i = 0; i < num_threads; i++) {
+ auto thread_name = fmt::format("{}:{}", name, i + 1);
+ m_threads.emplace_back(m_system.Kernel().RunOnHostCoreThread(
+ std::move(thread_name), [&] { this->LoopProcessImpl(); }));
+ }
+}
+
+Result ServerManager::LoopProcess() {
+ SCOPE_EXIT({ m_stopped.Set(); });
+
+ R_RETURN(this->LoopProcessImpl());
+}
+
+Result ServerManager::LoopProcessImpl() {
+ while (!m_stop_source.stop_requested()) {
+ R_TRY(this->WaitAndProcessImpl());
+ }
+
+ R_SUCCEED();
+}
+
+Result ServerManager::WaitAndProcessImpl() {
+ Kernel::KScopedAutoObject<Kernel::KSynchronizationObject> wait_obj;
+ HandleType wait_type{};
+
+ // Ensure we are the only thread waiting for this server.
+ std::unique_lock sl{m_serve_mutex};
+
+ // If we're done, return before we start waiting.
+ R_SUCCEED_IF(m_stop_source.stop_requested());
+
+ // Wait for a tracked object to become signaled.
+ {
+ s32 num_objs{};
+ std::array<HandleType, MaximumWaitObjects> wait_types{};
+ std::array<Kernel::KSynchronizationObject*, MaximumWaitObjects> wait_objs{};
+
+ const auto AddWaiter{
+ [&](Kernel::KSynchronizationObject* synchronization_object, HandleType type) {
+ // Open a new reference to the object.
+ synchronization_object->Open();
+
+ // Insert into the list.
+ wait_types[num_objs] = type;
+ wait_objs[num_objs++] = synchronization_object;
+ }};
+
+ {
+ std::scoped_lock ll{m_list_mutex};
+
+ // Add all of our ports.
+ for (const auto& [port, handler] : m_ports) {
+ AddWaiter(port, HandleType::Port);
+ }
+
+ // Add all of our sessions.
+ for (const auto& [session, manager] : m_sessions) {
+ AddWaiter(session, HandleType::Session);
+ }
+ }
+
+ // Add the deferral wakeup event.
+ if (m_deferral_event != nullptr) {
+ AddWaiter(std::addressof(m_deferral_event->GetReadableEvent()), HandleType::DeferEvent);
+ }
+
+ // Add the wakeup event.
+ AddWaiter(std::addressof(m_event->GetReadableEvent()), HandleType::Event);
+
+ // Clean up extra references on exit.
+ SCOPE_EXIT({
+ for (s32 i = 0; i < num_objs; i++) {
+ wait_objs[i]->Close();
+ }
+ });
+
+ // Wait for a signal.
+ s32 out_index{-1};
+ R_TRY(Kernel::KSynchronizationObject::Wait(m_system.Kernel(), &out_index, wait_objs.data(),
+ num_objs, -1));
+ ASSERT(out_index >= 0 && out_index < num_objs);
+
+ // Set the output index.
+ wait_obj = wait_objs[out_index];
+ wait_type = wait_types[out_index];
+ }
+
+ // Process what we just received, temporarily removing the object so it is
+ // not processed concurrently by another thread.
+ {
+ switch (wait_type) {
+ case HandleType::Port: {
+ // Port signaled.
+ auto* port = wait_obj->DynamicCast<Kernel::KServerPort*>();
+ std::shared_ptr<SessionRequestHandler> handler;
+
+ // Remove from tracking.
+ {
+ std::scoped_lock ll{m_list_mutex};
+ ASSERT(m_ports.contains(port));
+ m_ports.at(port).swap(handler);
+ m_ports.erase(port);
+ }
+
+ // Allow other threads to serve.
+ sl.unlock();
+
+ // Finish.
+ R_RETURN(this->OnPortEvent(port, std::move(handler)));
+ }
+ case HandleType::Session: {
+ // Session signaled.
+ auto* session = wait_obj->DynamicCast<Kernel::KServerSession*>();
+ std::shared_ptr<SessionRequestManager> manager;
+
+ // Remove from tracking.
+ {
+ std::scoped_lock ll{m_list_mutex};
+ ASSERT(m_sessions.contains(session));
+ m_sessions.at(session).swap(manager);
+ m_sessions.erase(session);
+ }
+
+ // Allow other threads to serve.
+ sl.unlock();
+
+ // Finish.
+ R_RETURN(this->OnSessionEvent(session, std::move(manager)));
+ }
+ case HandleType::DeferEvent: {
+ // Clear event.
+ ASSERT(R_SUCCEEDED(m_deferral_event->Clear()));
+
+ // Drain the list of deferrals while we process.
+ std::list<RequestState> deferrals;
+ {
+ std::scoped_lock ll{m_list_mutex};
+ m_deferrals.swap(deferrals);
+ }
+
+ // Allow other threads to serve.
+ sl.unlock();
+
+ // Finish.
+ R_RETURN(this->OnDeferralEvent(std::move(deferrals)));
+ }
+ case HandleType::Event: {
+ // Clear event and finish.
+ R_RETURN(m_event->Clear());
+ }
+ default: {
+ UNREACHABLE();
+ }
+ }
+ }
+}
+
+Result ServerManager::OnPortEvent(Kernel::KServerPort* port,
+ std::shared_ptr<SessionRequestHandler>&& handler) {
+ // Accept a new server session.
+ Kernel::KServerSession* session = port->AcceptSession();
+ ASSERT(session != nullptr);
+
+ // Create the session manager and install the handler.
+ auto manager = std::make_shared<SessionRequestManager>(m_system.Kernel(), *this);
+ manager->SetSessionHandler(std::shared_ptr(handler));
+
+ // Track the server session.
+ {
+ std::scoped_lock ll{m_list_mutex};
+ m_ports.emplace(port, std::move(handler));
+ m_sessions.emplace(session, std::move(manager));
+ }
+
+ // Signal the wakeup event.
+ m_event->Signal();
+
+ // We succeeded.
+ R_SUCCEED();
+}
+
+Result ServerManager::OnSessionEvent(Kernel::KServerSession* session,
+ std::shared_ptr<SessionRequestManager>&& manager) {
+ Result rc{ResultSuccess};
+
+ // Try to receive a message.
+ std::shared_ptr<HLERequestContext> context;
+ rc = session->ReceiveRequest(&context, manager);
+
+ // If the session has been closed, we're done.
+ if (rc == Kernel::ResultSessionClosed) {
+ // Close the session.
+ session->Close();
+
+ // Finish.
+ R_SUCCEED();
+ }
+ ASSERT(R_SUCCEEDED(rc));
+
+ RequestState request{
+ .session = session,
+ .context = std::move(context),
+ .manager = std::move(manager),
+ };
+
+ // Complete the sync request with deferral handling.
+ R_RETURN(this->CompleteSyncRequest(std::move(request)));
+}
+
+Result ServerManager::CompleteSyncRequest(RequestState&& request) {
+ Result rc{ResultSuccess};
+ Result service_rc{ResultSuccess};
+
+ // Mark the request as not deferred.
+ request.context->SetIsDeferred(false);
+
+ // Complete the request. We have exclusive access to this session.
+ service_rc = request.manager->CompleteSyncRequest(request.session, *request.context);
+
+ // If we've been deferred, we're done.
+ if (request.context->GetIsDeferred()) {
+ // Insert into deferral list.
+ std::scoped_lock ll{m_list_mutex};
+ m_deferrals.emplace_back(std::move(request));
+
+ // Finish.
+ R_SUCCEED();
+ }
+
+ // Send the reply.
+ rc = request.session->SendReplyHLE();
+
+ // If the session has been closed, we're done.
+ if (rc == Kernel::ResultSessionClosed || service_rc == IPC::ResultSessionClosed) {
+ // Close the session.
+ request.session->Close();
+
+ // Finish.
+ R_SUCCEED();
+ }
+
+ ASSERT(R_SUCCEEDED(rc));
+ ASSERT(R_SUCCEEDED(service_rc));
+
+ // Reinsert the session.
+ {
+ std::scoped_lock ll{m_list_mutex};
+ m_sessions.emplace(request.session, std::move(request.manager));
+ }
+
+ // Signal the wakeup event.
+ m_event->Signal();
+
+ // We succeeded.
+ R_SUCCEED();
+}
+
+Result ServerManager::OnDeferralEvent(std::list<RequestState>&& deferrals) {
+ ON_RESULT_FAILURE {
+ std::scoped_lock ll{m_list_mutex};
+ m_deferrals.splice(m_deferrals.end(), deferrals);
+ };
+
+ while (!deferrals.empty()) {
+ RequestState request = deferrals.front();
+ deferrals.pop_front();
+
+ // Try again to complete the request.
+ R_TRY(this->CompleteSyncRequest(std::move(request)));
+ }
+
+ R_SUCCEED();
+}
+
+} // namespace Service
diff --git a/src/core/hle/service/server_manager.h b/src/core/hle/service/server_manager.h
new file mode 100644
index 000000000..58b0a0832
--- /dev/null
+++ b/src/core/hle/service/server_manager.h
@@ -0,0 +1,90 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include <functional>
+#include <list>
+#include <map>
+#include <mutex>
+#include <string_view>
+#include <vector>
+
+#include "common/polyfill_thread.h"
+#include "common/thread.h"
+#include "core/hle/result.h"
+#include "core/hle/service/mutex.h"
+
+namespace Core {
+class System;
+}
+
+namespace Kernel {
+class KEvent;
+class KServerPort;
+class KServerSession;
+class KSynchronizationObject;
+} // namespace Kernel
+
+namespace Service {
+
+class HLERequestContext;
+class SessionRequestHandler;
+class SessionRequestManager;
+
+class ServerManager {
+public:
+ explicit ServerManager(Core::System& system);
+ ~ServerManager();
+
+ Result RegisterSession(Kernel::KServerSession* session,
+ std::shared_ptr<SessionRequestManager> manager);
+ Result RegisterNamedService(const std::string& service_name,
+ std::shared_ptr<SessionRequestHandler>&& handler,
+ u32 max_sessions = 64);
+ Result ManageNamedPort(const std::string& service_name,
+ std::shared_ptr<SessionRequestHandler>&& handler, u32 max_sessions = 64);
+ Result ManageDeferral(Kernel::KEvent** out_event);
+
+ Result LoopProcess();
+ void StartAdditionalHostThreads(const char* name, size_t num_threads);
+
+ static void RunServer(std::unique_ptr<ServerManager>&& server);
+
+private:
+ struct RequestState;
+
+ Result LoopProcessImpl();
+ Result WaitAndProcessImpl();
+ Result OnPortEvent(Kernel::KServerPort* port, std::shared_ptr<SessionRequestHandler>&& handler);
+ Result OnSessionEvent(Kernel::KServerSession* session,
+ std::shared_ptr<SessionRequestManager>&& manager);
+ Result OnDeferralEvent(std::list<RequestState>&& deferrals);
+ Result CompleteSyncRequest(RequestState&& state);
+
+private:
+ Core::System& m_system;
+ Mutex m_serve_mutex;
+ std::mutex m_list_mutex;
+
+ // Guest state tracking
+ std::map<Kernel::KServerPort*, std::shared_ptr<SessionRequestHandler>> m_ports{};
+ std::map<Kernel::KServerSession*, std::shared_ptr<SessionRequestManager>> m_sessions{};
+ Kernel::KEvent* m_event{};
+ Kernel::KEvent* m_deferral_event{};
+
+ // Deferral tracking
+ struct RequestState {
+ Kernel::KServerSession* session;
+ std::shared_ptr<HLERequestContext> context;
+ std::shared_ptr<SessionRequestManager> manager;
+ };
+ std::list<RequestState> m_deferrals{};
+
+ // Host state tracking
+ Common::Event m_stopped{};
+ std::vector<std::jthread> m_threads{};
+ std::stop_source m_stop_source{};
+};
+
+} // namespace Service
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index 0de67f1e1..69cdb5918 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -7,7 +7,6 @@
#include "common/settings.h"
#include "core/core.h"
#include "core/hle/ipc.h"
-#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_server_port.h"
#include "core/hle/kernel/kernel.h"
@@ -31,6 +30,7 @@
#include "core/hle/service/glue/glue.h"
#include "core/hle/service/grc/grc.h"
#include "core/hle/service/hid/hid.h"
+#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/jit/jit.h"
#include "core/hle/service/lbl/lbl.h"
#include "core/hle/service/ldn/ldn.h"
@@ -49,8 +49,8 @@
#include "core/hle/service/npns/npns.h"
#include "core/hle/service/ns/ns.h"
#include "core/hle/service/nvdrv/nvdrv.h"
-#include "core/hle/service/nvflinger/hos_binder_driver_server.h"
-#include "core/hle/service/nvflinger/nvflinger.h"
+#include "core/hle/service/nvnflinger/hos_binder_driver_server.h"
+#include "core/hle/service/nvnflinger/nvnflinger.h"
#include "core/hle/service/olsc/olsc.h"
#include "core/hle/service/pcie/pcie.h"
#include "core/hle/service/pctl/pctl_module.h"
@@ -68,7 +68,6 @@
#include "core/hle/service/time/time.h"
#include "core/hle/service/usb/usb.h"
#include "core/hle/service/vi/vi.h"
-#include "core/hle/service/wlan/wlan.h"
#include "core/reporter.h"
namespace Service {
@@ -91,44 +90,13 @@ namespace Service {
}
ServiceFrameworkBase::ServiceFrameworkBase(Core::System& system_, const char* service_name_,
- ServiceThreadType thread_type, u32 max_sessions_,
- InvokerFn* handler_invoker_)
- : SessionRequestHandler(system_.Kernel(), service_name_, thread_type), system{system_},
+ u32 max_sessions_, InvokerFn* handler_invoker_)
+ : SessionRequestHandler(system_.Kernel(), service_name_), system{system_},
service_name{service_name_}, max_sessions{max_sessions_}, handler_invoker{handler_invoker_} {}
ServiceFrameworkBase::~ServiceFrameworkBase() {
// Wait for other threads to release access before destroying
const auto guard = LockService();
-
- if (named_port != nullptr) {
- named_port->GetClientPort().Close();
- named_port->GetServerPort().Close();
- named_port = nullptr;
- }
-}
-
-void ServiceFrameworkBase::InstallAsService(SM::ServiceManager& service_manager) {
- const auto guard = LockService();
-
- ASSERT(!service_registered);
-
- service_manager.RegisterService(service_name, max_sessions, shared_from_this());
- service_registered = true;
-}
-
-Kernel::KClientPort& ServiceFrameworkBase::CreatePort() {
- const auto guard = LockService();
-
- if (named_port == nullptr) {
- ASSERT(!service_registered);
-
- named_port = Kernel::KPort::Create(kernel);
- named_port->Initialize(max_sessions, false, service_name);
-
- service_registered = true;
- }
-
- return named_port->GetClientPort();
}
void ServiceFrameworkBase::RegisterHandlersBase(const FunctionInfoBase* functions, std::size_t n) {
@@ -149,7 +117,7 @@ void ServiceFrameworkBase::RegisterHandlersBaseTipc(const FunctionInfoBase* func
}
}
-void ServiceFrameworkBase::ReportUnimplementedFunction(Kernel::HLERequestContext& ctx,
+void ServiceFrameworkBase::ReportUnimplementedFunction(HLERequestContext& ctx,
const FunctionInfoBase* info) {
auto cmd_buf = ctx.CommandBuffer();
std::string function_name = info == nullptr ? fmt::format("{}", ctx.GetCommand()) : info->name;
@@ -172,7 +140,7 @@ void ServiceFrameworkBase::ReportUnimplementedFunction(Kernel::HLERequestContext
}
}
-void ServiceFrameworkBase::InvokeRequest(Kernel::HLERequestContext& ctx) {
+void ServiceFrameworkBase::InvokeRequest(HLERequestContext& ctx) {
auto itr = handlers.find(ctx.GetCommand());
const FunctionInfoBase* info = itr == handlers.end() ? nullptr : &itr->second;
if (info == nullptr || info->handler_callback == nullptr) {
@@ -183,7 +151,7 @@ void ServiceFrameworkBase::InvokeRequest(Kernel::HLERequestContext& ctx) {
handler_invoker(this, info->handler_callback, ctx);
}
-void ServiceFrameworkBase::InvokeRequestTipc(Kernel::HLERequestContext& ctx) {
+void ServiceFrameworkBase::InvokeRequestTipc(HLERequestContext& ctx) {
boost::container::flat_map<u32, FunctionInfoBase>::iterator itr;
itr = handlers_tipc.find(ctx.GetCommand());
@@ -198,7 +166,7 @@ void ServiceFrameworkBase::InvokeRequestTipc(Kernel::HLERequestContext& ctx) {
}
Result ServiceFrameworkBase::HandleSyncRequest(Kernel::KServerSession& session,
- Kernel::HLERequestContext& ctx) {
+ HLERequestContext& ctx) {
const auto guard = LockService();
Result result = ResultSuccess;
@@ -208,7 +176,7 @@ Result ServiceFrameworkBase::HandleSyncRequest(Kernel::KServerSession& session,
case IPC::CommandType::TIPC_Close: {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
- result = IPC::ERR_REMOTE_PROCESS_DEAD;
+ result = IPC::ResultSessionClosed;
break;
}
case IPC::CommandType::ControlWithContext:
@@ -242,71 +210,72 @@ Result ServiceFrameworkBase::HandleSyncRequest(Kernel::KServerSession& session,
/// Initialize Services
Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system)
- : hos_binder_driver_server{std::make_unique<NVFlinger::HosBinderDriverServer>(system)},
- nv_flinger{std::make_unique<NVFlinger::NVFlinger>(system, *hos_binder_driver_server)} {
+ : hos_binder_driver_server{std::make_unique<Nvnflinger::HosBinderDriverServer>(system)},
+ nv_flinger{std::make_unique<Nvnflinger::Nvnflinger>(system, *hos_binder_driver_server)} {
- // NVFlinger needs to be accessed by several services like Vi and AppletOE so we instantiate it
- // here and pass it into the respective InstallInterfaces functions.
+ auto& kernel = system.Kernel();
+ // Nvnflinger needs to be accessed by several services like Vi and AppletOE so we instantiate it
+ // here and pass it into the respective InstallInterfaces functions.
system.GetFileSystemController().CreateFactories(*system.GetFilesystem(), false);
- system.Kernel().RegisterNamedService("sm:", SM::ServiceManager::InterfaceFactory);
- system.Kernel().RegisterInterfaceForNamedService("sm:", SM::ServiceManager::SessionHandler);
-
- Account::InstallInterfaces(system);
- AM::InstallInterfaces(*sm, *nv_flinger, system);
- AOC::InstallInterfaces(*sm, system);
- APM::InstallInterfaces(system);
- Audio::InstallInterfaces(*sm, system);
- BCAT::InstallInterfaces(system);
- BPC::InstallInterfaces(*sm, system);
- BtDrv::InstallInterfaces(*sm, system);
- BTM::InstallInterfaces(*sm, system);
- Capture::InstallInterfaces(*sm, system);
- ERPT::InstallInterfaces(*sm, system);
- ES::InstallInterfaces(*sm, system);
- EUPLD::InstallInterfaces(*sm, system);
- Fatal::InstallInterfaces(*sm, system);
- FGM::InstallInterfaces(*sm, system);
- FileSystem::InstallInterfaces(system);
- Friend::InstallInterfaces(*sm, system);
- Glue::InstallInterfaces(system);
- GRC::InstallInterfaces(*sm, system);
- HID::InstallInterfaces(*sm, system);
- JIT::InstallInterfaces(*sm, system);
- LBL::InstallInterfaces(*sm, system);
- LDN::InstallInterfaces(*sm, system);
- LDR::InstallInterfaces(*sm, system);
- LM::InstallInterfaces(system);
- Migration::InstallInterfaces(*sm, system);
- Mii::InstallInterfaces(*sm, system);
- MM::InstallInterfaces(*sm, system);
- MNPP::InstallInterfaces(*sm, system);
- NCM::InstallInterfaces(*sm, system);
- NFC::InstallInterfaces(*sm, system);
- NFP::InstallInterfaces(*sm, system);
- NGCT::InstallInterfaces(*sm, system);
- NIFM::InstallInterfaces(*sm, system);
- NIM::InstallInterfaces(*sm, system);
- NPNS::InstallInterfaces(*sm, system);
- NS::InstallInterfaces(*sm, system);
- Nvidia::InstallInterfaces(*sm, *nv_flinger, system);
- OLSC::InstallInterfaces(*sm, system);
- PCIe::InstallInterfaces(*sm, system);
- PCTL::InstallInterfaces(*sm, system);
- PCV::InstallInterfaces(*sm, system);
- PlayReport::InstallInterfaces(*sm, system);
- PM::InstallInterfaces(system);
- PSC::InstallInterfaces(*sm, system);
- PTM::InstallInterfaces(*sm, system);
- Set::InstallInterfaces(*sm, system);
- Sockets::InstallInterfaces(*sm, system);
- SPL::InstallInterfaces(*sm, system);
- SSL::InstallInterfaces(*sm, system);
- Time::InstallInterfaces(system);
- USB::InstallInterfaces(*sm, system);
- VI::InstallInterfaces(*sm, system, *nv_flinger, *hos_binder_driver_server);
- WLAN::InstallInterfaces(*sm, system);
+ // clang-format off
+ kernel.RunOnHostCoreProcess("audio", [&] { Audio::LoopProcess(system); }).detach();
+ kernel.RunOnHostCoreProcess("FS", [&] { FileSystem::LoopProcess(system); }).detach();
+ kernel.RunOnHostCoreProcess("jit", [&] { JIT::LoopProcess(system); }).detach();
+ kernel.RunOnHostCoreProcess("ldn", [&] { LDN::LoopProcess(system); }).detach();
+ kernel.RunOnHostCoreProcess("Loader", [&] { LDR::LoopProcess(system); }).detach();
+ kernel.RunOnHostCoreProcess("nvservices", [&] { Nvidia::LoopProcess(*nv_flinger, system); }).detach();
+ kernel.RunOnHostCoreProcess("bsdsocket", [&] { Sockets::LoopProcess(system); }).detach();
+ kernel.RunOnHostCoreProcess("vi", [&] { VI::LoopProcess(system, *nv_flinger, *hos_binder_driver_server); }).detach();
+
+ kernel.RunOnGuestCoreProcess("sm", [&] { SM::LoopProcess(system); });
+ kernel.RunOnGuestCoreProcess("account", [&] { Account::LoopProcess(system); });
+ kernel.RunOnGuestCoreProcess("am", [&] { AM::LoopProcess(*nv_flinger, system); });
+ kernel.RunOnGuestCoreProcess("aoc", [&] { AOC::LoopProcess(system); });
+ kernel.RunOnGuestCoreProcess("apm", [&] { APM::LoopProcess(system); });
+ kernel.RunOnGuestCoreProcess("bcat", [&] { BCAT::LoopProcess(system); });
+ kernel.RunOnGuestCoreProcess("bpc", [&] { BPC::LoopProcess(system); });
+ kernel.RunOnGuestCoreProcess("btdrv", [&] { BtDrv::LoopProcess(system); });
+ kernel.RunOnGuestCoreProcess("btm", [&] { BTM::LoopProcess(system); });
+ kernel.RunOnGuestCoreProcess("capsrv", [&] { Capture::LoopProcess(system); });
+ kernel.RunOnGuestCoreProcess("erpt", [&] { ERPT::LoopProcess(system); });
+ kernel.RunOnGuestCoreProcess("es", [&] { ES::LoopProcess(system); });
+ kernel.RunOnGuestCoreProcess("eupld", [&] { EUPLD::LoopProcess(system); });
+ kernel.RunOnGuestCoreProcess("fatal", [&] { Fatal::LoopProcess(system); });
+ kernel.RunOnGuestCoreProcess("fgm", [&] { FGM::LoopProcess(system); });
+ kernel.RunOnGuestCoreProcess("friends", [&] { Friend::LoopProcess(system); });
+ kernel.RunOnGuestCoreProcess("glue", [&] { Glue::LoopProcess(system); });
+ kernel.RunOnGuestCoreProcess("grc", [&] { GRC::LoopProcess(system); });
+ kernel.RunOnGuestCoreProcess("hid", [&] { HID::LoopProcess(system); });
+ kernel.RunOnGuestCoreProcess("lbl", [&] { LBL::LoopProcess(system); });
+ kernel.RunOnGuestCoreProcess("LogManager.Prod", [&] { LM::LoopProcess(system); });
+ kernel.RunOnGuestCoreProcess("mig", [&] { Migration::LoopProcess(system); });
+ kernel.RunOnGuestCoreProcess("mii", [&] { Mii::LoopProcess(system); });
+ kernel.RunOnGuestCoreProcess("mm", [&] { MM::LoopProcess(system); });
+ kernel.RunOnGuestCoreProcess("mnpp", [&] { MNPP::LoopProcess(system); });
+ kernel.RunOnGuestCoreProcess("NCM", [&] { NCM::LoopProcess(system); });
+ kernel.RunOnGuestCoreProcess("nfc", [&] { NFC::LoopProcess(system); });
+ kernel.RunOnGuestCoreProcess("nfp", [&] { NFP::LoopProcess(system); });
+ kernel.RunOnGuestCoreProcess("ngct", [&] { NGCT::LoopProcess(system); });
+ kernel.RunOnGuestCoreProcess("nifm", [&] { NIFM::LoopProcess(system); });
+ kernel.RunOnGuestCoreProcess("nim", [&] { NIM::LoopProcess(system); });
+ kernel.RunOnGuestCoreProcess("npns", [&] { NPNS::LoopProcess(system); });
+ kernel.RunOnGuestCoreProcess("ns", [&] { NS::LoopProcess(system); });
+ kernel.RunOnGuestCoreProcess("olsc", [&] { OLSC::LoopProcess(system); });
+ kernel.RunOnGuestCoreProcess("pcie", [&] { PCIe::LoopProcess(system); });
+ kernel.RunOnGuestCoreProcess("pctl", [&] { PCTL::LoopProcess(system); });
+ kernel.RunOnGuestCoreProcess("pcv", [&] { PCV::LoopProcess(system); });
+ kernel.RunOnGuestCoreProcess("prepo", [&] { PlayReport::LoopProcess(system); });
+ kernel.RunOnGuestCoreProcess("ProcessManager", [&] { PM::LoopProcess(system); });
+ kernel.RunOnGuestCoreProcess("psc", [&] { PSC::LoopProcess(system); });
+ kernel.RunOnGuestCoreProcess("ptm", [&] { PTM::LoopProcess(system); });
+ kernel.RunOnGuestCoreProcess("settings", [&] { Set::LoopProcess(system); });
+ kernel.RunOnGuestCoreProcess("spl", [&] { SPL::LoopProcess(system); });
+ kernel.RunOnGuestCoreProcess("ssl", [&] { SSL::LoopProcess(system); });
+ kernel.RunOnGuestCoreProcess("time", [&] { Time::LoopProcess(system); });
+ kernel.RunOnGuestCoreProcess("usb", [&] { USB::LoopProcess(system); });
+ // clang-format on
}
Services::~Services() = default;
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index 22e2119d7..45b2c43b7 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -8,7 +8,7 @@
#include <string>
#include <boost/container/flat_map.hpp>
#include "common/common_types.h"
-#include "core/hle/kernel/hle_ipc.h"
+#include "core/hle/service/hle_ipc.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
// Namespace Service
@@ -18,9 +18,6 @@ class System;
}
namespace Kernel {
-class HLERequestContext;
-class KClientPort;
-class KPort;
class KServerSession;
class ServiceThread;
} // namespace Kernel
@@ -31,10 +28,10 @@ namespace FileSystem {
class FileSystemController;
}
-namespace NVFlinger {
+namespace Nvnflinger {
class HosBinderDriverServer;
-class NVFlinger;
-} // namespace NVFlinger
+class Nvnflinger;
+} // namespace Nvnflinger
namespace SM {
class ServiceManager;
@@ -52,7 +49,7 @@ static_assert(ServerSessionCountMax == 0x40,
*
* @see ServiceFramework
*/
-class ServiceFrameworkBase : public Kernel::SessionRequestHandler {
+class ServiceFrameworkBase : public SessionRequestHandler {
public:
/// Returns the string identifier used to connect to the service.
std::string GetServiceName() const {
@@ -67,26 +64,19 @@ public:
return max_sessions;
}
- /// Creates a port pair and registers this service with the given ServiceManager.
- void InstallAsService(SM::ServiceManager& service_manager);
-
/// Invokes a service request routine using the HIPC protocol.
- void InvokeRequest(Kernel::HLERequestContext& ctx);
+ void InvokeRequest(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();
+ void InvokeRequestTipc(HLERequestContext& ctx);
/// Handles a synchronization request for the service.
- Result HandleSyncRequest(Kernel::KServerSession& session,
- Kernel::HLERequestContext& context) override;
+ Result HandleSyncRequest(Kernel::KServerSession& session, HLERequestContext& context) override;
protected:
/// Member-function pointer type of SyncRequest handlers.
template <typename Self>
- using HandlerFnP = void (Self::*)(Kernel::HLERequestContext&);
+ using HandlerFnP = void (Self::*)(HLERequestContext&);
/// Used to gain exclusive access to the service members, e.g. from CoreTiming thread.
[[nodiscard]] std::scoped_lock<std::mutex> LockService() {
@@ -99,9 +89,6 @@ protected:
/// Identifier string used to connect to the service.
std::string service_name;
- /// Port used by ManageNamedPort.
- Kernel::KPort* named_port{};
-
private:
template <typename T>
friend class ServiceFramework;
@@ -113,16 +100,15 @@ private:
};
using InvokerFn = void(ServiceFrameworkBase* object, HandlerFnP<ServiceFrameworkBase> member,
- Kernel::HLERequestContext& ctx);
+ HLERequestContext& ctx);
explicit ServiceFrameworkBase(Core::System& system_, const char* service_name_,
- ServiceThreadType thread_type, u32 max_sessions_,
- InvokerFn* handler_invoker_);
+ u32 max_sessions_, InvokerFn* handler_invoker_);
~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);
+ void ReportUnimplementedFunction(HLERequestContext& ctx, const FunctionInfoBase* info);
/// Maximum number of concurrent sessions that this service can handle.
u32 max_sessions;
@@ -156,7 +142,8 @@ template <typename Self>
class ServiceFramework : public ServiceFrameworkBase {
protected:
/// Contains information about a request type which is handled by the service.
- struct FunctionInfo : FunctionInfoBase {
+ template <typename T>
+ struct FunctionInfoTyped : FunctionInfoBase {
// TODO(yuriks): This function could be constexpr, but clang is the only compiler that
// doesn't emit an ICE or a wrong diagnostic because of the static_cast.
@@ -169,31 +156,29 @@ protected:
* the request
* @param name_ human-friendly name for the request. Used mostly for logging purposes.
*/
- FunctionInfo(u32 expected_header_, HandlerFnP<Self> handler_callback_, const char* name_)
+ FunctionInfoTyped(u32 expected_header_, HandlerFnP<T> handler_callback_, const char* name_)
: FunctionInfoBase{
expected_header_,
// Type-erase member function pointer by casting it down to the base class.
static_cast<HandlerFnP<ServiceFrameworkBase>>(handler_callback_), name_} {}
};
+ using FunctionInfo = FunctionInfoTyped<Self>;
/**
* Initializes the handler with no functions installed.
*
* @param system_ The system context to construct this service under.
* @param service_name_ Name of the service.
- * @param thread_type Specifies the thread type for this service. If this is set to CreateNew,
- * it creates a new thread for it, otherwise this uses the default thread.
* @param max_sessions_ Maximum number of sessions that can be connected to this service at the
* same time.
*/
explicit ServiceFramework(Core::System& system_, const char* service_name_,
- ServiceThreadType thread_type = ServiceThreadType::Default,
u32 max_sessions_ = ServerSessionCountMax)
- : ServiceFrameworkBase(system_, service_name_, thread_type, max_sessions_, Invoker) {}
+ : ServiceFrameworkBase(system_, service_name_, max_sessions_, Invoker) {}
/// Registers handlers in the service.
- template <std::size_t N>
- void RegisterHandlers(const FunctionInfo (&functions)[N]) {
+ template <typename T = Self, std::size_t N>
+ void RegisterHandlers(const FunctionInfoTyped<T> (&functions)[N]) {
RegisterHandlers(functions, N);
}
@@ -201,13 +186,14 @@ protected:
* Registers handlers in the service. Usually prefer using the other RegisterHandlers
* overload in order to avoid needing to specify the array size.
*/
- void RegisterHandlers(const FunctionInfo* functions, std::size_t n) {
+ template <typename T = Self>
+ void RegisterHandlers(const FunctionInfoTyped<T>* functions, std::size_t n) {
RegisterHandlersBase(functions, n);
}
/// Registers handlers in the service.
- template <std::size_t N>
- void RegisterHandlersTipc(const FunctionInfo (&functions)[N]) {
+ template <typename T = Self, std::size_t N>
+ void RegisterHandlersTipc(const FunctionInfoTyped<T> (&functions)[N]) {
RegisterHandlersTipc(functions, N);
}
@@ -215,7 +201,8 @@ protected:
* 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) {
+ template <typename T = Self>
+ void RegisterHandlersTipc(const FunctionInfoTyped<T>* functions, std::size_t n) {
RegisterHandlersBaseTipc(functions, n);
}
@@ -227,7 +214,7 @@ private:
* of the derived class in order to invoke one of it's functions through a pointer.
*/
static void Invoker(ServiceFrameworkBase* object, HandlerFnP<ServiceFrameworkBase> member,
- Kernel::HLERequestContext& ctx) {
+ HLERequestContext& ctx) {
// Cast back up to our original types and call the member function
(static_cast<Self*>(object)->*static_cast<HandlerFnP<Self>>(member))(ctx);
}
@@ -245,8 +232,8 @@ public:
void KillNVNFlinger();
private:
- std::unique_ptr<NVFlinger::HosBinderDriverServer> hos_binder_driver_server;
- std::unique_ptr<NVFlinger::NVFlinger> nv_flinger;
+ std::unique_ptr<Nvnflinger::HosBinderDriverServer> hos_binder_driver_server;
+ std::unique_ptr<Nvnflinger::Nvnflinger> nv_flinger;
};
} // namespace Service
diff --git a/src/core/hle/service/set/set.cpp b/src/core/hle/service/set/set.cpp
index 16c5eaf75..f5788b481 100644
--- a/src/core/hle/service/set/set.cpp
+++ b/src/core/hle/service/set/set.cpp
@@ -6,7 +6,7 @@
#include <chrono>
#include "common/logging/log.h"
#include "common/settings.h"
-#include "core/hle/ipc_helpers.h"
+#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/set/set.h"
namespace Service::Set {
@@ -74,15 +74,15 @@ constexpr std::array<std::pair<LanguageCode, KeyboardLayout>, 18> language_to_la
constexpr std::size_t PRE_4_0_0_MAX_ENTRIES = 0xF;
constexpr std::size_t POST_4_0_0_MAX_ENTRIES = 0x40;
-constexpr Result ERR_INVALID_LANGUAGE{ErrorModule::Settings, 625};
+constexpr Result ResultInvalidLanguage{ErrorModule::Settings, 625};
-void PushResponseLanguageCode(Kernel::HLERequestContext& ctx, std::size_t num_language_codes) {
+void PushResponseLanguageCode(HLERequestContext& ctx, std::size_t num_language_codes) {
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(static_cast<u32>(num_language_codes));
}
-void GetAvailableLanguageCodesImpl(Kernel::HLERequestContext& ctx, std::size_t max_entries) {
+void GetAvailableLanguageCodesImpl(HLERequestContext& ctx, std::size_t max_entries) {
const std::size_t requested_amount = ctx.GetWriteBufferNumElements<LanguageCode>();
const std::size_t max_amount = std::min(requested_amount, max_entries);
const std::size_t copy_amount = std::min(available_language_codes.size(), max_amount);
@@ -92,7 +92,7 @@ void GetAvailableLanguageCodesImpl(Kernel::HLERequestContext& ctx, std::size_t m
PushResponseLanguageCode(ctx, copy_amount);
}
-void GetKeyCodeMapImpl(Kernel::HLERequestContext& ctx) {
+void GetKeyCodeMapImpl(HLERequestContext& ctx) {
const auto language_code = available_language_codes[Settings::values.language_index.GetValue()];
const auto key_code =
std::find_if(language_to_layout.cbegin(), language_to_layout.cend(),
@@ -117,20 +117,20 @@ LanguageCode GetLanguageCodeFromIndex(std::size_t index) {
return available_language_codes.at(index);
}
-void SET::GetAvailableLanguageCodes(Kernel::HLERequestContext& ctx) {
+void SET::GetAvailableLanguageCodes(HLERequestContext& ctx) {
LOG_DEBUG(Service_SET, "called");
GetAvailableLanguageCodesImpl(ctx, PRE_4_0_0_MAX_ENTRIES);
}
-void SET::MakeLanguageCode(Kernel::HLERequestContext& ctx) {
+void SET::MakeLanguageCode(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto index = rp.Pop<u32>();
if (index >= available_language_codes.size()) {
LOG_ERROR(Service_SET, "Invalid language code index! index={}", index);
IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ERR_INVALID_LANGUAGE);
+ rb.Push(Set::ResultInvalidLanguage);
return;
}
@@ -139,25 +139,25 @@ void SET::MakeLanguageCode(Kernel::HLERequestContext& ctx) {
rb.PushEnum(available_language_codes[index]);
}
-void SET::GetAvailableLanguageCodes2(Kernel::HLERequestContext& ctx) {
+void SET::GetAvailableLanguageCodes2(HLERequestContext& ctx) {
LOG_DEBUG(Service_SET, "called");
GetAvailableLanguageCodesImpl(ctx, POST_4_0_0_MAX_ENTRIES);
}
-void SET::GetAvailableLanguageCodeCount(Kernel::HLERequestContext& ctx) {
+void SET::GetAvailableLanguageCodeCount(HLERequestContext& ctx) {
LOG_DEBUG(Service_SET, "called");
PushResponseLanguageCode(ctx, PRE_4_0_0_MAX_ENTRIES);
}
-void SET::GetAvailableLanguageCodeCount2(Kernel::HLERequestContext& ctx) {
+void SET::GetAvailableLanguageCodeCount2(HLERequestContext& ctx) {
LOG_DEBUG(Service_SET, "called");
PushResponseLanguageCode(ctx, POST_4_0_0_MAX_ENTRIES);
}
-void SET::GetQuestFlag(Kernel::HLERequestContext& ctx) {
+void SET::GetQuestFlag(HLERequestContext& ctx) {
LOG_DEBUG(Service_SET, "called");
IPC::ResponseBuilder rb{ctx, 3};
@@ -165,7 +165,7 @@ void SET::GetQuestFlag(Kernel::HLERequestContext& ctx) {
rb.Push(static_cast<u32>(Settings::values.quest_flag.GetValue()));
}
-void SET::GetLanguageCode(Kernel::HLERequestContext& ctx) {
+void SET::GetLanguageCode(HLERequestContext& ctx) {
LOG_DEBUG(Service_SET, "called {}", Settings::values.language_index.GetValue());
IPC::ResponseBuilder rb{ctx, 4};
@@ -173,7 +173,7 @@ void SET::GetLanguageCode(Kernel::HLERequestContext& ctx) {
rb.PushEnum(available_language_codes[Settings::values.language_index.GetValue()]);
}
-void SET::GetRegionCode(Kernel::HLERequestContext& ctx) {
+void SET::GetRegionCode(HLERequestContext& ctx) {
LOG_DEBUG(Service_SET, "called");
IPC::ResponseBuilder rb{ctx, 3};
@@ -181,17 +181,17 @@ void SET::GetRegionCode(Kernel::HLERequestContext& ctx) {
rb.Push(Settings::values.region_index.GetValue());
}
-void SET::GetKeyCodeMap(Kernel::HLERequestContext& ctx) {
+void SET::GetKeyCodeMap(HLERequestContext& ctx) {
LOG_DEBUG(Service_SET, "Called {}", ctx.Description());
GetKeyCodeMapImpl(ctx);
}
-void SET::GetKeyCodeMap2(Kernel::HLERequestContext& ctx) {
+void SET::GetKeyCodeMap2(HLERequestContext& ctx) {
LOG_DEBUG(Service_SET, "Called {}", ctx.Description());
GetKeyCodeMapImpl(ctx);
}
-void SET::GetDeviceNickName(Kernel::HLERequestContext& ctx) {
+void SET::GetDeviceNickName(HLERequestContext& ctx) {
LOG_DEBUG(Service_SET, "called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
diff --git a/src/core/hle/service/set/set.h b/src/core/hle/service/set/set.h
index 375975711..7fd3a7654 100644
--- a/src/core/hle/service/set/set.h
+++ b/src/core/hle/service/set/set.h
@@ -40,17 +40,17 @@ public:
~SET() override;
private:
- void GetLanguageCode(Kernel::HLERequestContext& ctx);
- void GetAvailableLanguageCodes(Kernel::HLERequestContext& ctx);
- void MakeLanguageCode(Kernel::HLERequestContext& ctx);
- void GetAvailableLanguageCodes2(Kernel::HLERequestContext& ctx);
- void GetAvailableLanguageCodeCount(Kernel::HLERequestContext& ctx);
- void GetAvailableLanguageCodeCount2(Kernel::HLERequestContext& ctx);
- void GetQuestFlag(Kernel::HLERequestContext& ctx);
- void GetRegionCode(Kernel::HLERequestContext& ctx);
- void GetKeyCodeMap(Kernel::HLERequestContext& ctx);
- void GetKeyCodeMap2(Kernel::HLERequestContext& ctx);
- void GetDeviceNickName(Kernel::HLERequestContext& ctx);
+ void GetLanguageCode(HLERequestContext& ctx);
+ void GetAvailableLanguageCodes(HLERequestContext& ctx);
+ void MakeLanguageCode(HLERequestContext& ctx);
+ void GetAvailableLanguageCodes2(HLERequestContext& ctx);
+ void GetAvailableLanguageCodeCount(HLERequestContext& ctx);
+ void GetAvailableLanguageCodeCount2(HLERequestContext& ctx);
+ void GetQuestFlag(HLERequestContext& ctx);
+ void GetRegionCode(HLERequestContext& ctx);
+ void GetKeyCodeMap(HLERequestContext& ctx);
+ void GetKeyCodeMap2(HLERequestContext& ctx);
+ void GetDeviceNickName(HLERequestContext& ctx);
};
} // namespace Service::Set
diff --git a/src/core/hle/service/set/set_sys.cpp b/src/core/hle/service/set/set_sys.cpp
index 94c20edda..2e38d1cfc 100644
--- a/src/core/hle/service/set/set_sys.cpp
+++ b/src/core/hle/service/set/set_sys.cpp
@@ -6,8 +6,8 @@
#include "common/settings.h"
#include "core/file_sys/errors.h"
#include "core/file_sys/system_archive/system_version.h"
-#include "core/hle/ipc_helpers.h"
#include "core/hle/service/filesystem/filesystem.h"
+#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/set/set_sys.h"
namespace Service::Set {
@@ -20,7 +20,7 @@ enum class GetFirmwareVersionType {
Version2,
};
-void GetFirmwareVersionImpl(Kernel::HLERequestContext& ctx, GetFirmwareVersionType type) {
+void GetFirmwareVersionImpl(HLERequestContext& ctx, GetFirmwareVersionType type) {
LOG_WARNING(Service_SET, "called - Using hardcoded firmware version '{}'",
FileSys::SystemArchive::GetLongDisplayVersion());
@@ -73,17 +73,17 @@ void GetFirmwareVersionImpl(Kernel::HLERequestContext& ctx, GetFirmwareVersionTy
}
} // Anonymous namespace
-void SET_SYS::GetFirmwareVersion(Kernel::HLERequestContext& ctx) {
+void SET_SYS::GetFirmwareVersion(HLERequestContext& ctx) {
LOG_DEBUG(Service_SET, "called");
GetFirmwareVersionImpl(ctx, GetFirmwareVersionType::Version1);
}
-void SET_SYS::GetFirmwareVersion2(Kernel::HLERequestContext& ctx) {
+void SET_SYS::GetFirmwareVersion2(HLERequestContext& ctx) {
LOG_DEBUG(Service_SET, "called");
GetFirmwareVersionImpl(ctx, GetFirmwareVersionType::Version2);
}
-void SET_SYS::GetColorSetId(Kernel::HLERequestContext& ctx) {
+void SET_SYS::GetColorSetId(HLERequestContext& ctx) {
LOG_DEBUG(Service_SET, "called");
IPC::ResponseBuilder rb{ctx, 3};
@@ -92,7 +92,7 @@ void SET_SYS::GetColorSetId(Kernel::HLERequestContext& ctx) {
rb.PushEnum(color_set);
}
-void SET_SYS::SetColorSetId(Kernel::HLERequestContext& ctx) {
+void SET_SYS::SetColorSetId(HLERequestContext& ctx) {
LOG_DEBUG(Service_SET, "called");
IPC::RequestParser rp{ctx};
@@ -126,7 +126,7 @@ static Settings GetSettings() {
return ret;
}
-void SET_SYS::GetSettingsItemValueSize(Kernel::HLERequestContext& ctx) {
+void SET_SYS::GetSettingsItemValueSize(HLERequestContext& ctx) {
LOG_DEBUG(Service_SET, "called");
// The category of the setting. This corresponds to the top-level keys of
@@ -151,7 +151,7 @@ void SET_SYS::GetSettingsItemValueSize(Kernel::HLERequestContext& ctx) {
rb.Push(response_size);
}
-void SET_SYS::GetSettingsItemValue(Kernel::HLERequestContext& ctx) {
+void SET_SYS::GetSettingsItemValue(HLERequestContext& ctx) {
LOG_DEBUG(Service_SET, "called");
// The category of the setting. This corresponds to the top-level keys of
@@ -177,7 +177,7 @@ void SET_SYS::GetSettingsItemValue(Kernel::HLERequestContext& ctx) {
rb.Push(response);
}
-void SET_SYS::GetDeviceNickName(Kernel::HLERequestContext& ctx) {
+void SET_SYS::GetDeviceNickName(HLERequestContext& ctx) {
LOG_DEBUG(Service_SET, "called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
diff --git a/src/core/hle/service/set/set_sys.h b/src/core/hle/service/set/set_sys.h
index 464ac3da1..1efbcc97a 100644
--- a/src/core/hle/service/set/set_sys.h
+++ b/src/core/hle/service/set/set_sys.h
@@ -23,13 +23,13 @@ private:
BasicBlack = 1,
};
- void GetSettingsItemValueSize(Kernel::HLERequestContext& ctx);
- void GetSettingsItemValue(Kernel::HLERequestContext& ctx);
- void GetFirmwareVersion(Kernel::HLERequestContext& ctx);
- void GetFirmwareVersion2(Kernel::HLERequestContext& ctx);
- void GetColorSetId(Kernel::HLERequestContext& ctx);
- void SetColorSetId(Kernel::HLERequestContext& ctx);
- void GetDeviceNickName(Kernel::HLERequestContext& ctx);
+ void GetSettingsItemValueSize(HLERequestContext& ctx);
+ void GetSettingsItemValue(HLERequestContext& ctx);
+ void GetFirmwareVersion(HLERequestContext& ctx);
+ void GetFirmwareVersion2(HLERequestContext& ctx);
+ void GetColorSetId(HLERequestContext& ctx);
+ void SetColorSetId(HLERequestContext& ctx);
+ void GetDeviceNickName(HLERequestContext& ctx);
ColorSet color_set = ColorSet::BasicWhite;
};
diff --git a/src/core/hle/service/set/settings.cpp b/src/core/hle/service/set/settings.cpp
index 4ebc2a0ec..c48844f77 100644
--- a/src/core/hle/service/set/settings.cpp
+++ b/src/core/hle/service/set/settings.cpp
@@ -1,20 +1,23 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
+#include "core/hle/service/server_manager.h"
#include "core/hle/service/set/set.h"
#include "core/hle/service/set/set_cal.h"
#include "core/hle/service/set/set_fd.h"
#include "core/hle/service/set/set_sys.h"
#include "core/hle/service/set/settings.h"
-#include "core/hle/service/sm/sm.h"
namespace Service::Set {
-void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
- std::make_shared<SET>(system)->InstallAsService(service_manager);
- std::make_shared<SET_CAL>(system)->InstallAsService(service_manager);
- std::make_shared<SET_FD>(system)->InstallAsService(service_manager);
- std::make_shared<SET_SYS>(system)->InstallAsService(service_manager);
+void LoopProcess(Core::System& system) {
+ auto server_manager = std::make_unique<ServerManager>(system);
+
+ server_manager->RegisterNamedService("set", std::make_shared<SET>(system));
+ server_manager->RegisterNamedService("set:cal", std::make_shared<SET_CAL>(system));
+ server_manager->RegisterNamedService("set:fd", std::make_shared<SET_FD>(system));
+ server_manager->RegisterNamedService("set:sys", std::make_shared<SET_SYS>(system));
+ ServerManager::RunServer(std::move(server_manager));
}
} // namespace Service::Set
diff --git a/src/core/hle/service/set/settings.h b/src/core/hle/service/set/settings.h
index 6cd7d634c..03cd4bb66 100644
--- a/src/core/hle/service/set/settings.h
+++ b/src/core/hle/service/set/settings.h
@@ -7,13 +7,8 @@ namespace Core {
class System;
}
-namespace Service::SM {
-class ServiceManager;
-}
-
namespace Service::Set {
-/// Registers all Settings services with the specified service manager.
-void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system);
+void LoopProcess(Core::System& system);
} // namespace Service::Set
diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp
index 84720094f..1608fa24c 100644
--- a/src/core/hle/service/sm/sm.cpp
+++ b/src/core/hle/service/sm/sm.cpp
@@ -5,69 +5,73 @@
#include "common/assert.h"
#include "common/scope_exit.h"
#include "core/core.h"
-#include "core/hle/ipc_helpers.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/result.h"
+#include "core/hle/service/ipc_helpers.h"
+#include "core/hle/service/server_manager.h"
#include "core/hle/service/sm/sm.h"
#include "core/hle/service/sm/sm_controller.h"
namespace Service::SM {
-constexpr Result ERR_NOT_INITIALIZED(ErrorModule::SM, 2);
-constexpr Result ERR_ALREADY_REGISTERED(ErrorModule::SM, 4);
-constexpr Result ERR_INVALID_NAME(ErrorModule::SM, 6);
-constexpr Result ERR_SERVICE_NOT_REGISTERED(ErrorModule::SM, 7);
+constexpr Result ResultInvalidClient(ErrorModule::SM, 2);
+constexpr Result ResultAlreadyRegistered(ErrorModule::SM, 4);
+constexpr Result ResultInvalidServiceName(ErrorModule::SM, 6);
+constexpr Result ResultNotRegistered(ErrorModule::SM, 7);
-ServiceManager::ServiceManager(Kernel::KernelCore& kernel_) : kernel{kernel_} {}
+ServiceManager::ServiceManager(Kernel::KernelCore& kernel_) : kernel{kernel_} {
+ controller_interface = std::make_unique<Controller>(kernel.System());
+}
ServiceManager::~ServiceManager() {
for (auto& [name, port] : service_ports) {
port->GetClientPort().Close();
port->GetServerPort().Close();
}
+
+ if (deferral_event) {
+ deferral_event->Close();
+ }
}
-void ServiceManager::InvokeControlRequest(Kernel::HLERequestContext& context) {
+void ServiceManager::InvokeControlRequest(HLERequestContext& context) {
controller_interface->InvokeRequest(context);
}
static Result ValidateServiceName(const std::string& name) {
if (name.empty() || name.size() > 8) {
LOG_ERROR(Service_SM, "Invalid service name! service={}", name);
- return ERR_INVALID_NAME;
+ return Service::SM::ResultInvalidServiceName;
}
return ResultSuccess;
}
-Kernel::KClientPort& ServiceManager::InterfaceFactory(ServiceManager& self, Core::System& system) {
- self.sm_interface = std::make_shared<SM>(self, system);
- self.controller_interface = std::make_unique<Controller>(system);
- return self.sm_interface->CreatePort();
-}
-
-void ServiceManager::SessionHandler(ServiceManager& self, Kernel::KServerPort* server_port) {
- self.sm_interface->AcceptSession(server_port);
-}
-
Result ServiceManager::RegisterService(std::string name, u32 max_sessions,
- Kernel::SessionRequestHandlerPtr handler) {
+ SessionRequestHandlerPtr handler) {
CASCADE_CODE(ValidateServiceName(name));
+ std::scoped_lock lk{lock};
if (registered_services.find(name) != registered_services.end()) {
LOG_ERROR(Service_SM, "Service is already registered! service={}", name);
- return ERR_ALREADY_REGISTERED;
+ return Service::SM::ResultAlreadyRegistered;
}
auto* port = Kernel::KPort::Create(kernel);
- port->Initialize(ServerSessionCountMax, false, name);
+ port->Initialize(ServerSessionCountMax, false, 0);
+
+ // Register the port.
+ Kernel::KPort::Register(kernel, port);
service_ports.emplace(name, port);
registered_services.emplace(name, handler);
+ if (deferral_event) {
+ deferral_event->Signal();
+ }
return ResultSuccess;
}
@@ -75,10 +79,11 @@ Result ServiceManager::RegisterService(std::string name, u32 max_sessions,
Result ServiceManager::UnregisterService(const std::string& name) {
CASCADE_CODE(ValidateServiceName(name));
+ std::scoped_lock lk{lock};
const auto iter = registered_services.find(name);
if (iter == registered_services.end()) {
LOG_ERROR(Service_SM, "Server is not registered! service={}", name);
- return ERR_SERVICE_NOT_REGISTERED;
+ return Service::SM::ResultNotRegistered;
}
registered_services.erase(iter);
@@ -89,10 +94,12 @@ Result ServiceManager::UnregisterService(const std::string& name) {
ResultVal<Kernel::KPort*> ServiceManager::GetServicePort(const std::string& name) {
CASCADE_CODE(ValidateServiceName(name));
+
+ std::scoped_lock lk{lock};
auto it = service_ports.find(name);
if (it == service_ports.end()) {
- LOG_ERROR(Service_SM, "Server is not registered! service={}", name);
- return ERR_SERVICE_NOT_REGISTERED;
+ LOG_WARNING(Service_SM, "Server is not registered! service={}", name);
+ return Service::SM::ResultNotRegistered;
}
return it->second;
@@ -105,17 +112,22 @@ ResultVal<Kernel::KPort*> ServiceManager::GetServicePort(const std::string& name
* Outputs:
* 0: Result
*/
-void SM::Initialize(Kernel::HLERequestContext& ctx) {
+void SM::Initialize(HLERequestContext& ctx) {
LOG_DEBUG(Service_SM, "called");
- is_initialized = true;
+ ctx.GetManager()->SetIsInitializedForSm();
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
-void SM::GetService(Kernel::HLERequestContext& ctx) {
+void SM::GetService(HLERequestContext& ctx) {
auto result = GetServiceImpl(ctx);
+ if (ctx.GetIsDeferred()) {
+ // Don't overwrite the command buffer.
+ return;
+ }
+
if (result.Succeeded()) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
rb.Push(result.Code());
@@ -126,8 +138,13 @@ void SM::GetService(Kernel::HLERequestContext& ctx) {
}
}
-void SM::GetServiceTipc(Kernel::HLERequestContext& ctx) {
+void SM::GetServiceTipc(HLERequestContext& ctx) {
auto result = GetServiceImpl(ctx);
+ if (ctx.GetIsDeferred()) {
+ // Don't overwrite the command buffer.
+ return;
+ }
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
rb.Push(result.Code());
rb.PushMoveObjects(result.Succeeded() ? result.Unwrap() : nullptr);
@@ -144,9 +161,9 @@ static std::string PopServiceName(IPC::RequestParser& rp) {
return result;
}
-ResultVal<Kernel::KClientSession*> SM::GetServiceImpl(Kernel::HLERequestContext& ctx) {
- if (!is_initialized) {
- return ERR_NOT_INITIALIZED;
+ResultVal<Kernel::KClientSession*> SM::GetServiceImpl(HLERequestContext& ctx) {
+ if (!ctx.GetManager()->GetIsInitializedForSm()) {
+ return Service::SM::ResultInvalidClient;
}
IPC::RequestParser rp{ctx};
@@ -154,10 +171,15 @@ ResultVal<Kernel::KClientSession*> SM::GetServiceImpl(Kernel::HLERequestContext&
// Find the named port.
auto port_result = service_manager.GetServicePort(name);
- auto service = service_manager.GetService<Kernel::SessionRequestHandler>(name);
- if (port_result.Failed() || !service) {
- LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, port_result.Code().raw);
- return port_result.Code();
+ if (port_result.Code() == Service::SM::ResultInvalidServiceName) {
+ LOG_ERROR(Service_SM, "Invalid service name '{}'", name);
+ return Service::SM::ResultInvalidServiceName;
+ }
+
+ if (port_result.Failed()) {
+ LOG_INFO(Service_SM, "Waiting for service {} to become available", name);
+ ctx.SetIsDeferred();
+ return Service::SM::ResultNotRegistered;
}
auto& port = port_result.Unwrap();
@@ -167,14 +189,13 @@ ResultVal<Kernel::KClientSession*> SM::GetServiceImpl(Kernel::HLERequestContext&
LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, result.raw);
return result;
}
- service->AcceptSession(&port->GetServerPort());
LOG_DEBUG(Service_SM, "called service={} -> session={}", name, session->GetId());
return session;
}
-void SM::RegisterService(Kernel::HLERequestContext& ctx) {
+void SM::RegisterService(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
std::string name(PopServiceName(rp));
@@ -193,7 +214,7 @@ void SM::RegisterService(Kernel::HLERequestContext& ctx) {
}
auto* port = Kernel::KPort::Create(kernel);
- port->Initialize(ServerSessionCountMax, is_light, name);
+ port->Initialize(ServerSessionCountMax, is_light, 0);
SCOPE_EXIT({ port->GetClientPort().Close(); });
IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
@@ -201,7 +222,7 @@ void SM::RegisterService(Kernel::HLERequestContext& ctx) {
rb.PushMoveObjects(port->GetServerPort());
}
-void SM::UnregisterService(Kernel::HLERequestContext& ctx) {
+void SM::UnregisterService(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
std::string name(PopServiceName(rp));
@@ -212,7 +233,7 @@ void SM::UnregisterService(Kernel::HLERequestContext& ctx) {
}
SM::SM(ServiceManager& service_manager_, Core::System& system_)
- : ServiceFramework{system_, "sm:", ServiceThreadType::Default, 4},
+ : ServiceFramework{system_, "sm:", 4},
service_manager{service_manager_}, kernel{system_.Kernel()} {
RegisterHandlers({
{0, &SM::Initialize, "Initialize"},
@@ -232,4 +253,16 @@ SM::SM(ServiceManager& service_manager_, Core::System& system_)
SM::~SM() = default;
+void LoopProcess(Core::System& system) {
+ auto& service_manager = system.ServiceManager();
+ auto server_manager = std::make_unique<ServerManager>(system);
+
+ Kernel::KEvent* deferral_event{};
+ server_manager->ManageDeferral(&deferral_event);
+ service_manager.SetDeferralEvent(deferral_event);
+
+ server_manager->ManageNamedPort("sm:", std::make_shared<SM>(system.ServiceManager(), system));
+ ServerManager::RunServer(std::move(server_manager));
+}
+
} // namespace Service::SM
diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h
index 02a5dde9e..6697f4007 100644
--- a/src/core/hle/service/sm/sm.h
+++ b/src/core/hle/service/sm/sm.h
@@ -4,6 +4,7 @@
#pragma once
#include <memory>
+#include <mutex>
#include <string>
#include <unordered_map>
@@ -35,33 +36,28 @@ public:
~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);
+ void Initialize(HLERequestContext& ctx);
+ void GetService(HLERequestContext& ctx);
+ void GetServiceTipc(HLERequestContext& ctx);
+ void RegisterService(HLERequestContext& ctx);
+ void UnregisterService(HLERequestContext& ctx);
- ResultVal<Kernel::KClientSession*> GetServiceImpl(Kernel::HLERequestContext& ctx);
+ ResultVal<Kernel::KClientSession*> GetServiceImpl(HLERequestContext& ctx);
ServiceManager& service_manager;
- bool is_initialized{};
Kernel::KernelCore& kernel;
};
class ServiceManager {
public:
- static Kernel::KClientPort& InterfaceFactory(ServiceManager& self, Core::System& system);
- static void SessionHandler(ServiceManager& self, Kernel::KServerPort* server_port);
-
explicit ServiceManager(Kernel::KernelCore& kernel_);
~ServiceManager();
- Result RegisterService(std::string name, u32 max_sessions,
- Kernel::SessionRequestHandlerPtr handler);
+ Result RegisterService(std::string name, u32 max_sessions, SessionRequestHandlerPtr handler);
Result UnregisterService(const std::string& name);
ResultVal<Kernel::KPort*> GetServicePort(const std::string& name);
- template <Common::DerivedFrom<Kernel::SessionRequestHandler> T>
+ template <Common::DerivedFrom<SessionRequestHandler> T>
std::shared_ptr<T> GetService(const std::string& service_name) const {
auto service = registered_services.find(service_name);
if (service == registered_services.end()) {
@@ -71,18 +67,27 @@ public:
return std::static_pointer_cast<T>(service->second);
}
- void InvokeControlRequest(Kernel::HLERequestContext& context);
+ void InvokeControlRequest(HLERequestContext& context);
+
+ void SetDeferralEvent(Kernel::KEvent* deferral_event_) {
+ deferral_event = deferral_event_;
+ }
private:
std::shared_ptr<SM> sm_interface;
std::unique_ptr<Controller> controller_interface;
/// Map of registered services, retrieved using GetServicePort.
- std::unordered_map<std::string, Kernel::SessionRequestHandlerPtr> registered_services;
+ std::mutex lock;
+ std::unordered_map<std::string, SessionRequestHandlerPtr> registered_services;
std::unordered_map<std::string, Kernel::KPort*> service_ports;
/// Kernel context
Kernel::KernelCore& kernel;
+ Kernel::KEvent* deferral_event{};
};
+/// Runs SM services.
+void LoopProcess(Core::System& system);
+
} // namespace Service::SM
diff --git a/src/core/hle/service/sm/sm_controller.cpp b/src/core/hle/service/sm/sm_controller.cpp
index 1cf9dd1c4..7dce28fe0 100644
--- a/src/core/hle/service/sm/sm_controller.cpp
+++ b/src/core/hle/service/sm/sm_controller.cpp
@@ -4,17 +4,18 @@
#include "common/assert.h"
#include "common/logging/log.h"
#include "core/core.h"
-#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/k_client_port.h"
#include "core/hle/kernel/k_port.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"
+#include "core/hle/service/ipc_helpers.h"
+#include "core/hle/service/server_manager.h"
#include "core/hle/service/sm/sm_controller.h"
namespace Service::SM {
-void Controller::ConvertCurrentObjectToDomain(Kernel::HLERequestContext& ctx) {
+void Controller::ConvertCurrentObjectToDomain(HLERequestContext& ctx) {
ASSERT_MSG(!ctx.GetManager()->IsDomain(), "Session is already a domain");
LOG_DEBUG(Service, "called, server_session={}", ctx.Session()->GetId());
ctx.GetManager()->ConvertToDomainOnRequestEnd();
@@ -24,7 +25,7 @@ void Controller::ConvertCurrentObjectToDomain(Kernel::HLERequestContext& ctx) {
rb.Push<u32>(1); // Converted sessions start with 1 request handler
}
-void Controller::CloneCurrentObject(Kernel::HLERequestContext& ctx) {
+void Controller::CloneCurrentObject(HLERequestContext& ctx) {
LOG_DEBUG(Service, "called");
auto& process = *ctx.GetThread().GetOwnerProcess();
@@ -43,14 +44,17 @@ void Controller::CloneCurrentObject(Kernel::HLERequestContext& ctx) {
ASSERT(session != nullptr);
// Initialize the session.
- session->Initialize(nullptr, "");
+ session->Initialize(nullptr, 0);
// Commit the session reservation.
session_reservation.Commit();
- // Register with manager.
- session_manager->SessionHandler().RegisterSession(&session->GetServerSession(),
- session_manager);
+ // Register the session.
+ Kernel::KSession::Register(system.Kernel(), session);
+
+ // Register with server manager.
+ session_manager->GetServerManager().RegisterSession(&session->GetServerSession(),
+ session_manager);
// We succeeded.
IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
@@ -58,13 +62,13 @@ void Controller::CloneCurrentObject(Kernel::HLERequestContext& ctx) {
rb.PushMoveObjects(session->GetClientSession());
}
-void Controller::CloneCurrentObjectEx(Kernel::HLERequestContext& ctx) {
+void Controller::CloneCurrentObjectEx(HLERequestContext& ctx) {
LOG_DEBUG(Service, "called");
CloneCurrentObject(ctx);
}
-void Controller::QueryPointerBufferSize(Kernel::HLERequestContext& ctx) {
+void Controller::QueryPointerBufferSize(HLERequestContext& ctx) {
LOG_WARNING(Service, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
diff --git a/src/core/hle/service/sm/sm_controller.h b/src/core/hle/service/sm/sm_controller.h
index ed386f660..4e748b36d 100644
--- a/src/core/hle/service/sm/sm_controller.h
+++ b/src/core/hle/service/sm/sm_controller.h
@@ -17,10 +17,10 @@ public:
~Controller() override;
private:
- void ConvertCurrentObjectToDomain(Kernel::HLERequestContext& ctx);
- void CloneCurrentObject(Kernel::HLERequestContext& ctx);
- void CloneCurrentObjectEx(Kernel::HLERequestContext& ctx);
- void QueryPointerBufferSize(Kernel::HLERequestContext& ctx);
+ void ConvertCurrentObjectToDomain(HLERequestContext& ctx);
+ void CloneCurrentObject(HLERequestContext& ctx);
+ void CloneCurrentObjectEx(HLERequestContext& ctx);
+ void QueryPointerBufferSize(HLERequestContext& ctx);
};
} // namespace Service::SM
diff --git a/src/core/hle/service/sockets/bsd.cpp b/src/core/hle/service/sockets/bsd.cpp
index 9e94a462f..bce45d321 100644
--- a/src/core/hle/service/sockets/bsd.cpp
+++ b/src/core/hle/service/sockets/bsd.cpp
@@ -11,8 +11,8 @@
#include "common/microprofile.h"
#include "common/socket_types.h"
#include "core/core.h"
-#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/k_thread.h"
+#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/sockets/bsd.h"
#include "core/hle/service/sockets/sockets_translate.h"
#include "core/internal_network/network.h"
@@ -42,7 +42,7 @@ void BSD::PollWork::Execute(BSD* bsd) {
std::tie(ret, bsd_errno) = bsd->PollImpl(write_buffer, read_buffer, nfds, timeout);
}
-void BSD::PollWork::Response(Kernel::HLERequestContext& ctx) {
+void BSD::PollWork::Response(HLERequestContext& ctx) {
if (write_buffer.size() > 0) {
ctx.WriteBuffer(write_buffer);
}
@@ -57,7 +57,7 @@ void BSD::AcceptWork::Execute(BSD* bsd) {
std::tie(ret, bsd_errno) = bsd->AcceptImpl(fd, write_buffer);
}
-void BSD::AcceptWork::Response(Kernel::HLERequestContext& ctx) {
+void BSD::AcceptWork::Response(HLERequestContext& ctx) {
if (write_buffer.size() > 0) {
ctx.WriteBuffer(write_buffer);
}
@@ -73,7 +73,7 @@ void BSD::ConnectWork::Execute(BSD* bsd) {
bsd_errno = bsd->ConnectImpl(fd, addr);
}
-void BSD::ConnectWork::Response(Kernel::HLERequestContext& ctx) {
+void BSD::ConnectWork::Response(HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.Push<s32>(bsd_errno == Errno::SUCCESS ? 0 : -1);
@@ -84,7 +84,7 @@ void BSD::RecvWork::Execute(BSD* bsd) {
std::tie(ret, bsd_errno) = bsd->RecvImpl(fd, flags, message);
}
-void BSD::RecvWork::Response(Kernel::HLERequestContext& ctx) {
+void BSD::RecvWork::Response(HLERequestContext& ctx) {
ctx.WriteBuffer(message);
IPC::ResponseBuilder rb{ctx, 4};
@@ -97,7 +97,7 @@ void BSD::RecvFromWork::Execute(BSD* bsd) {
std::tie(ret, bsd_errno) = bsd->RecvFromImpl(fd, flags, message, addr);
}
-void BSD::RecvFromWork::Response(Kernel::HLERequestContext& ctx) {
+void BSD::RecvFromWork::Response(HLERequestContext& ctx) {
ctx.WriteBuffer(message, 0);
if (!addr.empty()) {
ctx.WriteBuffer(addr, 1);
@@ -114,7 +114,7 @@ void BSD::SendWork::Execute(BSD* bsd) {
std::tie(ret, bsd_errno) = bsd->SendImpl(fd, flags, message);
}
-void BSD::SendWork::Response(Kernel::HLERequestContext& ctx) {
+void BSD::SendWork::Response(HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.Push<s32>(ret);
@@ -125,14 +125,14 @@ void BSD::SendToWork::Execute(BSD* bsd) {
std::tie(ret, bsd_errno) = bsd->SendToImpl(fd, flags, message, addr);
}
-void BSD::SendToWork::Response(Kernel::HLERequestContext& ctx) {
+void BSD::SendToWork::Response(HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.Push<s32>(ret);
rb.PushEnum(bsd_errno);
}
-void BSD::RegisterClient(Kernel::HLERequestContext& ctx) {
+void BSD::RegisterClient(HLERequestContext& ctx) {
LOG_WARNING(Service, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
@@ -141,7 +141,7 @@ void BSD::RegisterClient(Kernel::HLERequestContext& ctx) {
rb.Push<s32>(0); // bsd errno
}
-void BSD::StartMonitoring(Kernel::HLERequestContext& ctx) {
+void BSD::StartMonitoring(HLERequestContext& ctx) {
LOG_WARNING(Service, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
@@ -149,7 +149,7 @@ void BSD::StartMonitoring(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void BSD::Socket(Kernel::HLERequestContext& ctx) {
+void BSD::Socket(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u32 domain = rp.Pop<u32>();
const u32 type = rp.Pop<u32>();
@@ -166,7 +166,7 @@ void BSD::Socket(Kernel::HLERequestContext& ctx) {
rb.PushEnum(bsd_errno);
}
-void BSD::Select(Kernel::HLERequestContext& ctx) {
+void BSD::Select(HLERequestContext& ctx) {
LOG_WARNING(Service, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 4};
@@ -176,7 +176,7 @@ void BSD::Select(Kernel::HLERequestContext& ctx) {
rb.Push<u32>(0); // bsd errno
}
-void BSD::Poll(Kernel::HLERequestContext& ctx) {
+void BSD::Poll(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const s32 nfds = rp.Pop<s32>();
const s32 timeout = rp.Pop<s32>();
@@ -191,7 +191,7 @@ void BSD::Poll(Kernel::HLERequestContext& ctx) {
});
}
-void BSD::Accept(Kernel::HLERequestContext& ctx) {
+void BSD::Accept(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const s32 fd = rp.Pop<s32>();
@@ -203,16 +203,15 @@ void BSD::Accept(Kernel::HLERequestContext& ctx) {
});
}
-void BSD::Bind(Kernel::HLERequestContext& ctx) {
+void BSD::Bind(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const s32 fd = rp.Pop<s32>();
LOG_DEBUG(Service, "called. fd={} addrlen={}", fd, ctx.GetReadBufferSize());
-
BuildErrnoResponse(ctx, BindImpl(fd, ctx.ReadBuffer()));
}
-void BSD::Connect(Kernel::HLERequestContext& ctx) {
+void BSD::Connect(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const s32 fd = rp.Pop<s32>();
@@ -224,7 +223,7 @@ void BSD::Connect(Kernel::HLERequestContext& ctx) {
});
}
-void BSD::GetPeerName(Kernel::HLERequestContext& ctx) {
+void BSD::GetPeerName(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const s32 fd = rp.Pop<s32>();
@@ -242,7 +241,7 @@ void BSD::GetPeerName(Kernel::HLERequestContext& ctx) {
rb.Push<u32>(static_cast<u32>(write_buffer.size()));
}
-void BSD::GetSockName(Kernel::HLERequestContext& ctx) {
+void BSD::GetSockName(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const s32 fd = rp.Pop<s32>();
@@ -260,7 +259,7 @@ void BSD::GetSockName(Kernel::HLERequestContext& ctx) {
rb.Push<u32>(static_cast<u32>(write_buffer.size()));
}
-void BSD::GetSockOpt(Kernel::HLERequestContext& ctx) {
+void BSD::GetSockOpt(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const s32 fd = rp.Pop<s32>();
const u32 level = rp.Pop<u32>();
@@ -279,7 +278,7 @@ void BSD::GetSockOpt(Kernel::HLERequestContext& ctx) {
rb.Push<u32>(static_cast<u32>(optval.size()));
}
-void BSD::Listen(Kernel::HLERequestContext& ctx) {
+void BSD::Listen(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const s32 fd = rp.Pop<s32>();
const s32 backlog = rp.Pop<s32>();
@@ -289,7 +288,7 @@ void BSD::Listen(Kernel::HLERequestContext& ctx) {
BuildErrnoResponse(ctx, ListenImpl(fd, backlog));
}
-void BSD::Fcntl(Kernel::HLERequestContext& ctx) {
+void BSD::Fcntl(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const s32 fd = rp.Pop<s32>();
const s32 cmd = rp.Pop<s32>();
@@ -305,14 +304,14 @@ void BSD::Fcntl(Kernel::HLERequestContext& ctx) {
rb.PushEnum(bsd_errno);
}
-void BSD::SetSockOpt(Kernel::HLERequestContext& ctx) {
+void BSD::SetSockOpt(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const s32 fd = rp.Pop<s32>();
const u32 level = rp.Pop<u32>();
const OptName optname = static_cast<OptName>(rp.Pop<u32>());
- const std::vector<u8> buffer = ctx.ReadBuffer();
+ const auto buffer = ctx.ReadBuffer();
const u8* optval = buffer.empty() ? nullptr : buffer.data();
size_t optlen = buffer.size();
@@ -329,7 +328,7 @@ void BSD::SetSockOpt(Kernel::HLERequestContext& ctx) {
BuildErrnoResponse(ctx, SetSockOptImpl(fd, level, optname, optlen, optval));
}
-void BSD::Shutdown(Kernel::HLERequestContext& ctx) {
+void BSD::Shutdown(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const s32 fd = rp.Pop<s32>();
@@ -340,7 +339,7 @@ void BSD::Shutdown(Kernel::HLERequestContext& ctx) {
BuildErrnoResponse(ctx, ShutdownImpl(fd, how));
}
-void BSD::Recv(Kernel::HLERequestContext& ctx) {
+void BSD::Recv(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const s32 fd = rp.Pop<s32>();
@@ -355,7 +354,7 @@ void BSD::Recv(Kernel::HLERequestContext& ctx) {
});
}
-void BSD::RecvFrom(Kernel::HLERequestContext& ctx) {
+void BSD::RecvFrom(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const s32 fd = rp.Pop<s32>();
@@ -372,7 +371,7 @@ void BSD::RecvFrom(Kernel::HLERequestContext& ctx) {
});
}
-void BSD::Send(Kernel::HLERequestContext& ctx) {
+void BSD::Send(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const s32 fd = rp.Pop<s32>();
@@ -387,7 +386,7 @@ void BSD::Send(Kernel::HLERequestContext& ctx) {
});
}
-void BSD::SendTo(Kernel::HLERequestContext& ctx) {
+void BSD::SendTo(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const s32 fd = rp.Pop<s32>();
const u32 flags = rp.Pop<u32>();
@@ -403,7 +402,7 @@ void BSD::SendTo(Kernel::HLERequestContext& ctx) {
});
}
-void BSD::Write(Kernel::HLERequestContext& ctx) {
+void BSD::Write(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const s32 fd = rp.Pop<s32>();
@@ -416,7 +415,7 @@ void BSD::Write(Kernel::HLERequestContext& ctx) {
});
}
-void BSD::Read(Kernel::HLERequestContext& ctx) {
+void BSD::Read(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const s32 fd = rp.Pop<s32>();
@@ -428,7 +427,7 @@ void BSD::Read(Kernel::HLERequestContext& ctx) {
rb.Push<u32>(0); // bsd errno
}
-void BSD::Close(Kernel::HLERequestContext& ctx) {
+void BSD::Close(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const s32 fd = rp.Pop<s32>();
@@ -437,7 +436,7 @@ void BSD::Close(Kernel::HLERequestContext& ctx) {
BuildErrnoResponse(ctx, CloseImpl(fd));
}
-void BSD::EventFd(Kernel::HLERequestContext& ctx) {
+void BSD::EventFd(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u64 initval = rp.Pop<u64>();
const u32 flags = rp.Pop<u32>();
@@ -448,7 +447,7 @@ void BSD::EventFd(Kernel::HLERequestContext& ctx) {
}
template <typename Work>
-void BSD::ExecuteWork(Kernel::HLERequestContext& ctx, Work work) {
+void BSD::ExecuteWork(HLERequestContext& ctx, Work work) {
work.Execute(this);
work.Response(ctx);
}
@@ -489,7 +488,7 @@ std::pair<s32, Errno> BSD::SocketImpl(Domain domain, Type type, Protocol protoco
return {fd, Errno::SUCCESS};
}
-std::pair<s32, Errno> BSD::PollImpl(std::vector<u8>& write_buffer, std::vector<u8> read_buffer,
+std::pair<s32, Errno> BSD::PollImpl(std::vector<u8>& write_buffer, std::span<const u8> read_buffer,
s32 nfds, s32 timeout) {
if (write_buffer.size() < nfds * sizeof(PollFD)) {
return {-1, Errno::INVAL};
@@ -584,7 +583,7 @@ std::pair<s32, Errno> BSD::AcceptImpl(s32 fd, std::vector<u8>& write_buffer) {
return {new_fd, Errno::SUCCESS};
}
-Errno BSD::BindImpl(s32 fd, const std::vector<u8>& addr) {
+Errno BSD::BindImpl(s32 fd, std::span<const u8> addr) {
if (!IsFileDescriptorValid(fd)) {
return Errno::BADF;
}
@@ -595,7 +594,7 @@ Errno BSD::BindImpl(s32 fd, const std::vector<u8>& addr) {
return Translate(file_descriptors[fd]->socket->Bind(Translate(addr_in)));
}
-Errno BSD::ConnectImpl(s32 fd, const std::vector<u8>& addr) {
+Errno BSD::ConnectImpl(s32 fd, std::span<const u8> addr) {
if (!IsFileDescriptorValid(fd)) {
return Errno::BADF;
}
@@ -800,15 +799,15 @@ std::pair<s32, Errno> BSD::RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& mess
return {ret, bsd_errno};
}
-std::pair<s32, Errno> BSD::SendImpl(s32 fd, u32 flags, const std::vector<u8>& message) {
+std::pair<s32, Errno> BSD::SendImpl(s32 fd, u32 flags, std::span<const u8> message) {
if (!IsFileDescriptorValid(fd)) {
return {-1, Errno::BADF};
}
return Translate(file_descriptors[fd]->socket->Send(message, flags));
}
-std::pair<s32, Errno> BSD::SendToImpl(s32 fd, u32 flags, const std::vector<u8>& message,
- const std::vector<u8>& addr) {
+std::pair<s32, Errno> BSD::SendToImpl(s32 fd, u32 flags, std::span<const u8> message,
+ std::span<const u8> addr) {
if (!IsFileDescriptorValid(fd)) {
return {-1, Errno::BADF};
}
@@ -863,7 +862,7 @@ bool BSD::IsFileDescriptorValid(s32 fd) const noexcept {
return true;
}
-void BSD::BuildErrnoResponse(Kernel::HLERequestContext& ctx, Errno bsd_errno) const noexcept {
+void BSD::BuildErrnoResponse(HLERequestContext& ctx, Errno bsd_errno) const noexcept {
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
@@ -882,8 +881,7 @@ void BSD::OnProxyPacketReceived(const Network::ProxyPacket& packet) {
}
BSD::BSD(Core::System& system_, const char* name)
- : ServiceFramework{system_, name, ServiceThreadType::CreateNew}, room_network{
- system_.GetRoomNetwork()} {
+ : ServiceFramework{system_, name}, room_network{system_.GetRoomNetwork()} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &BSD::RegisterClient, "RegisterClient"},
@@ -955,6 +953,9 @@ BSDCFG::BSDCFG(Core::System& system_) : ServiceFramework{system_, "bsdcfg"} {
{10, nullptr, "ClearArpEntries"},
{11, nullptr, "ClearArpEntries2"},
{12, nullptr, "PrintArpEntries"},
+ {13, nullptr, "Unknown13"},
+ {14, nullptr, "Unknown14"},
+ {15, nullptr, "Unknown15"},
};
// clang-format on
diff --git a/src/core/hle/service/sockets/bsd.h b/src/core/hle/service/sockets/bsd.h
index 81e855e0f..30ae9c140 100644
--- a/src/core/hle/service/sockets/bsd.h
+++ b/src/core/hle/service/sockets/bsd.h
@@ -4,6 +4,7 @@
#pragma once
#include <memory>
+#include <span>
#include <vector>
#include "common/common_types.h"
@@ -40,11 +41,11 @@ private:
struct PollWork {
void Execute(BSD* bsd);
- void Response(Kernel::HLERequestContext& ctx);
+ void Response(HLERequestContext& ctx);
s32 nfds;
s32 timeout;
- std::vector<u8> read_buffer;
+ std::span<const u8> read_buffer;
std::vector<u8> write_buffer;
s32 ret{};
Errno bsd_errno{};
@@ -52,7 +53,7 @@ private:
struct AcceptWork {
void Execute(BSD* bsd);
- void Response(Kernel::HLERequestContext& ctx);
+ void Response(HLERequestContext& ctx);
s32 fd;
std::vector<u8> write_buffer;
@@ -62,16 +63,16 @@ private:
struct ConnectWork {
void Execute(BSD* bsd);
- void Response(Kernel::HLERequestContext& ctx);
+ void Response(HLERequestContext& ctx);
s32 fd;
- std::vector<u8> addr;
+ std::span<const u8> addr;
Errno bsd_errno{};
};
struct RecvWork {
void Execute(BSD* bsd);
- void Response(Kernel::HLERequestContext& ctx);
+ void Response(HLERequestContext& ctx);
s32 fd;
u32 flags;
@@ -82,7 +83,7 @@ private:
struct RecvFromWork {
void Execute(BSD* bsd);
- void Response(Kernel::HLERequestContext& ctx);
+ void Response(HLERequestContext& ctx);
s32 fd;
u32 flags;
@@ -94,60 +95,60 @@ private:
struct SendWork {
void Execute(BSD* bsd);
- void Response(Kernel::HLERequestContext& ctx);
+ void Response(HLERequestContext& ctx);
s32 fd;
u32 flags;
- std::vector<u8> message;
+ std::span<const u8> message;
s32 ret{};
Errno bsd_errno{};
};
struct SendToWork {
void Execute(BSD* bsd);
- void Response(Kernel::HLERequestContext& ctx);
+ void Response(HLERequestContext& ctx);
s32 fd;
u32 flags;
- std::vector<u8> message;
- std::vector<u8> addr;
+ std::span<const u8> message;
+ std::span<const u8> addr;
s32 ret{};
Errno bsd_errno{};
};
- void RegisterClient(Kernel::HLERequestContext& ctx);
- void StartMonitoring(Kernel::HLERequestContext& ctx);
- void Socket(Kernel::HLERequestContext& ctx);
- void Select(Kernel::HLERequestContext& ctx);
- void Poll(Kernel::HLERequestContext& ctx);
- void Accept(Kernel::HLERequestContext& ctx);
- void Bind(Kernel::HLERequestContext& ctx);
- void Connect(Kernel::HLERequestContext& ctx);
- void GetPeerName(Kernel::HLERequestContext& ctx);
- void GetSockName(Kernel::HLERequestContext& ctx);
- void GetSockOpt(Kernel::HLERequestContext& ctx);
- void Listen(Kernel::HLERequestContext& ctx);
- void Fcntl(Kernel::HLERequestContext& ctx);
- void SetSockOpt(Kernel::HLERequestContext& ctx);
- void Shutdown(Kernel::HLERequestContext& ctx);
- void Recv(Kernel::HLERequestContext& ctx);
- void RecvFrom(Kernel::HLERequestContext& ctx);
- void Send(Kernel::HLERequestContext& ctx);
- void SendTo(Kernel::HLERequestContext& ctx);
- void Write(Kernel::HLERequestContext& ctx);
- void Read(Kernel::HLERequestContext& ctx);
- void Close(Kernel::HLERequestContext& ctx);
- void EventFd(Kernel::HLERequestContext& ctx);
+ void RegisterClient(HLERequestContext& ctx);
+ void StartMonitoring(HLERequestContext& ctx);
+ void Socket(HLERequestContext& ctx);
+ void Select(HLERequestContext& ctx);
+ void Poll(HLERequestContext& ctx);
+ void Accept(HLERequestContext& ctx);
+ void Bind(HLERequestContext& ctx);
+ void Connect(HLERequestContext& ctx);
+ void GetPeerName(HLERequestContext& ctx);
+ void GetSockName(HLERequestContext& ctx);
+ void GetSockOpt(HLERequestContext& ctx);
+ void Listen(HLERequestContext& ctx);
+ void Fcntl(HLERequestContext& ctx);
+ void SetSockOpt(HLERequestContext& ctx);
+ void Shutdown(HLERequestContext& ctx);
+ void Recv(HLERequestContext& ctx);
+ void RecvFrom(HLERequestContext& ctx);
+ void Send(HLERequestContext& ctx);
+ void SendTo(HLERequestContext& ctx);
+ void Write(HLERequestContext& ctx);
+ void Read(HLERequestContext& ctx);
+ void Close(HLERequestContext& ctx);
+ void EventFd(HLERequestContext& ctx);
template <typename Work>
- void ExecuteWork(Kernel::HLERequestContext& ctx, Work work);
+ void ExecuteWork(HLERequestContext& ctx, Work work);
std::pair<s32, Errno> SocketImpl(Domain domain, Type type, Protocol protocol);
- std::pair<s32, Errno> PollImpl(std::vector<u8>& write_buffer, std::vector<u8> read_buffer,
+ std::pair<s32, Errno> PollImpl(std::vector<u8>& write_buffer, std::span<const u8> read_buffer,
s32 nfds, s32 timeout);
std::pair<s32, Errno> AcceptImpl(s32 fd, std::vector<u8>& write_buffer);
- Errno BindImpl(s32 fd, const std::vector<u8>& addr);
- Errno ConnectImpl(s32 fd, const std::vector<u8>& addr);
+ Errno BindImpl(s32 fd, std::span<const u8> addr);
+ Errno ConnectImpl(s32 fd, std::span<const u8> addr);
Errno GetPeerNameImpl(s32 fd, std::vector<u8>& write_buffer);
Errno GetSockNameImpl(s32 fd, std::vector<u8>& write_buffer);
Errno ListenImpl(s32 fd, s32 backlog);
@@ -157,15 +158,15 @@ private:
std::pair<s32, Errno> RecvImpl(s32 fd, u32 flags, std::vector<u8>& message);
std::pair<s32, Errno> RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& message,
std::vector<u8>& addr);
- std::pair<s32, Errno> SendImpl(s32 fd, u32 flags, const std::vector<u8>& message);
- std::pair<s32, Errno> SendToImpl(s32 fd, u32 flags, const std::vector<u8>& message,
- const std::vector<u8>& addr);
+ std::pair<s32, Errno> SendImpl(s32 fd, u32 flags, std::span<const u8> message);
+ std::pair<s32, Errno> SendToImpl(s32 fd, u32 flags, std::span<const u8> message,
+ std::span<const u8> addr);
Errno CloseImpl(s32 fd);
s32 FindFreeFileDescriptorHandle() noexcept;
bool IsFileDescriptorValid(s32 fd) const noexcept;
- void BuildErrnoResponse(Kernel::HLERequestContext& ctx, Errno bsd_errno) const noexcept;
+ void BuildErrnoResponse(HLERequestContext& ctx, Errno bsd_errno) const noexcept;
std::array<std::optional<FileDescriptor>, MAX_FD> file_descriptors;
diff --git a/src/core/hle/service/sockets/ethc.cpp b/src/core/hle/service/sockets/ethc.cpp
deleted file mode 100644
index c12ea999b..000000000
--- a/src/core/hle/service/sockets/ethc.cpp
+++ /dev/null
@@ -1,42 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#include "core/hle/service/sockets/ethc.h"
-
-namespace Service::Sockets {
-
-ETHC_C::ETHC_C(Core::System& system_) : ServiceFramework{system_, "ethc:c"} {
- // clang-format off
- static const FunctionInfo functions[] = {
- {0, nullptr, "Initialize"},
- {1, nullptr, "Cancel"},
- {2, nullptr, "GetResult"},
- {3, nullptr, "GetMediaList"},
- {4, nullptr, "SetMediaType"},
- {5, nullptr, "GetMediaType"},
- {6, nullptr, "Unknown6"},
- };
- // clang-format on
-
- RegisterHandlers(functions);
-}
-
-ETHC_C::~ETHC_C() = default;
-
-ETHC_I::ETHC_I(Core::System& system_) : ServiceFramework{system_, "ethc:i"} {
- // clang-format off
- static const FunctionInfo functions[] = {
- {0, nullptr, "GetReadableHandle"},
- {1, nullptr, "Cancel"},
- {2, nullptr, "GetResult"},
- {3, nullptr, "GetInterfaceList"},
- {4, nullptr, "GetInterfaceCount"},
- };
- // clang-format on
-
- RegisterHandlers(functions);
-}
-
-ETHC_I::~ETHC_I() = default;
-
-} // namespace Service::Sockets
diff --git a/src/core/hle/service/sockets/ethc.h b/src/core/hle/service/sockets/ethc.h
deleted file mode 100644
index 7c5759a96..000000000
--- a/src/core/hle/service/sockets/ethc.h
+++ /dev/null
@@ -1,26 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#pragma once
-
-#include "core/hle/service/service.h"
-
-namespace Core {
-class System;
-}
-
-namespace Service::Sockets {
-
-class ETHC_C final : public ServiceFramework<ETHC_C> {
-public:
- explicit ETHC_C(Core::System& system_);
- ~ETHC_C() override;
-};
-
-class ETHC_I final : public ServiceFramework<ETHC_I> {
-public:
- explicit ETHC_I(Core::System& system_);
- ~ETHC_I() override;
-};
-
-} // namespace Service::Sockets
diff --git a/src/core/hle/service/sockets/sfdnsres.cpp b/src/core/hle/service/sockets/sfdnsres.cpp
index 097c37d7a..132dd5797 100644
--- a/src/core/hle/service/sockets/sfdnsres.cpp
+++ b/src/core/hle/service/sockets/sfdnsres.cpp
@@ -8,7 +8,7 @@
#include "common/string_util.h"
#include "common/swap.h"
#include "core/core.h"
-#include "core/hle/ipc_helpers.h"
+#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/sockets/sfdnsres.h"
#include "core/memory.h"
@@ -185,7 +185,7 @@ static std::vector<u8> SerializeAddrInfo(const addrinfo* addrinfo, s32 result_co
return data;
}
-static std::pair<u32, s32> GetAddrInfoRequestImpl(Kernel::HLERequestContext& ctx) {
+static std::pair<u32, s32> GetAddrInfoRequestImpl(HLERequestContext& ctx) {
struct Parameters {
u8 use_nsd_resolve;
u32 unknown;
@@ -221,7 +221,7 @@ static std::pair<u32, s32> GetAddrInfoRequestImpl(Kernel::HLERequestContext& ctx
return std::make_pair(data_size, result_code);
}
-void SFDNSRES::GetAddrInfoRequest(Kernel::HLERequestContext& ctx) {
+void SFDNSRES::GetAddrInfoRequest(HLERequestContext& ctx) {
auto [data_size, result_code] = GetAddrInfoRequestImpl(ctx);
IPC::ResponseBuilder rb{ctx, 4};
@@ -231,7 +231,7 @@ void SFDNSRES::GetAddrInfoRequest(Kernel::HLERequestContext& ctx) {
rb.Push(data_size); // serialized size
}
-void SFDNSRES::GetAddrInfoRequestWithOptions(Kernel::HLERequestContext& ctx) {
+void SFDNSRES::GetAddrInfoRequestWithOptions(HLERequestContext& ctx) {
// Additional options are ignored
auto [data_size, result_code] = GetAddrInfoRequestImpl(ctx);
@@ -243,4 +243,4 @@ void SFDNSRES::GetAddrInfoRequestWithOptions(Kernel::HLERequestContext& ctx) {
rb.Push(0);
}
-} // namespace Service::Sockets \ No newline at end of file
+} // namespace Service::Sockets
diff --git a/src/core/hle/service/sockets/sfdnsres.h b/src/core/hle/service/sockets/sfdnsres.h
index 96018ea77..18e3cd60c 100644
--- a/src/core/hle/service/sockets/sfdnsres.h
+++ b/src/core/hle/service/sockets/sfdnsres.h
@@ -17,8 +17,8 @@ public:
~SFDNSRES() override;
private:
- void GetAddrInfoRequest(Kernel::HLERequestContext& ctx);
- void GetAddrInfoRequestWithOptions(Kernel::HLERequestContext& ctx);
+ void GetAddrInfoRequest(HLERequestContext& ctx);
+ void GetAddrInfoRequestWithOptions(HLERequestContext& ctx);
};
} // namespace Service::Sockets
diff --git a/src/core/hle/service/sockets/sockets.cpp b/src/core/hle/service/sockets/sockets.cpp
index 8d3ba6f96..676d24e03 100644
--- a/src/core/hle/service/sockets/sockets.cpp
+++ b/src/core/hle/service/sockets/sockets.cpp
@@ -1,26 +1,25 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
+#include "core/hle/service/server_manager.h"
#include "core/hle/service/sockets/bsd.h"
-#include "core/hle/service/sockets/ethc.h"
#include "core/hle/service/sockets/nsd.h"
#include "core/hle/service/sockets/sfdnsres.h"
#include "core/hle/service/sockets/sockets.h"
namespace Service::Sockets {
-void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
- std::make_shared<BSD>(system, "bsd:s")->InstallAsService(service_manager);
- std::make_shared<BSD>(system, "bsd:u")->InstallAsService(service_manager);
- std::make_shared<BSDCFG>(system)->InstallAsService(service_manager);
+void LoopProcess(Core::System& system) {
+ auto server_manager = std::make_unique<ServerManager>(system);
- std::make_shared<ETHC_C>(system)->InstallAsService(service_manager);
- std::make_shared<ETHC_I>(system)->InstallAsService(service_manager);
-
- std::make_shared<NSD>(system, "nsd:a")->InstallAsService(service_manager);
- std::make_shared<NSD>(system, "nsd:u")->InstallAsService(service_manager);
-
- std::make_shared<SFDNSRES>(system)->InstallAsService(service_manager);
+ server_manager->RegisterNamedService("bsd:s", std::make_shared<BSD>(system, "bsd:s"));
+ server_manager->RegisterNamedService("bsd:u", std::make_shared<BSD>(system, "bsd:u"));
+ server_manager->RegisterNamedService("bsdcfg", std::make_shared<BSDCFG>(system));
+ server_manager->RegisterNamedService("nsd:a", std::make_shared<NSD>(system, "nsd:a"));
+ server_manager->RegisterNamedService("nsd:u", std::make_shared<NSD>(system, "nsd:u"));
+ server_manager->RegisterNamedService("sfdnsres", std::make_shared<SFDNSRES>(system));
+ server_manager->StartAdditionalHostThreads("bsdsocket", 2);
+ ServerManager::RunServer(std::move(server_manager));
}
} // namespace Service::Sockets
diff --git a/src/core/hle/service/sockets/sockets.h b/src/core/hle/service/sockets/sockets.h
index 31b7dad33..acd2dae7b 100644
--- a/src/core/hle/service/sockets/sockets.h
+++ b/src/core/hle/service/sockets/sockets.h
@@ -10,10 +10,6 @@ namespace Core {
class System;
}
-namespace Service::SM {
-class ServiceManager;
-}
-
namespace Service::Sockets {
enum class Errno : u32 {
@@ -23,6 +19,7 @@ enum class Errno : u32 {
INVAL = 22,
MFILE = 24,
MSGSIZE = 90,
+ CONNRESET = 104,
NOTCONN = 107,
TIMEDOUT = 110,
};
@@ -98,7 +95,6 @@ struct Linger {
u32 linger;
};
-/// Registers all Sockets services with the specified service manager.
-void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system);
+void LoopProcess(Core::System& system);
} // namespace Service::Sockets
diff --git a/src/core/hle/service/sockets/sockets_translate.cpp b/src/core/hle/service/sockets/sockets_translate.cpp
index 023aa0486..594e58f90 100644
--- a/src/core/hle/service/sockets/sockets_translate.cpp
+++ b/src/core/hle/service/sockets/sockets_translate.cpp
@@ -27,6 +27,8 @@ Errno Translate(Network::Errno value) {
return Errno::NOTCONN;
case Network::Errno::TIMEDOUT:
return Errno::TIMEDOUT;
+ case Network::Errno::CONNRESET:
+ return Errno::CONNRESET;
default:
UNIMPLEMENTED_MSG("Unimplemented errno={}", value);
return Errno::SUCCESS;
diff --git a/src/core/hle/service/spl/spl_module.cpp b/src/core/hle/service/spl/spl_module.cpp
index 64eae1ebf..0227d4393 100644
--- a/src/core/hle/service/spl/spl_module.cpp
+++ b/src/core/hle/service/spl/spl_module.cpp
@@ -8,7 +8,8 @@
#include "common/logging/log.h"
#include "common/settings.h"
#include "core/hle/api_version.h"
-#include "core/hle/ipc_helpers.h"
+#include "core/hle/service/ipc_helpers.h"
+#include "core/hle/service/server_manager.h"
#include "core/hle/service/spl/csrng.h"
#include "core/hle/service/spl/spl.h"
#include "core/hle/service/spl/spl_module.h"
@@ -22,7 +23,7 @@ Module::Interface::Interface(Core::System& system_, std::shared_ptr<Module> modu
Module::Interface::~Interface() = default;
-void Module::Interface::GetConfig(Kernel::HLERequestContext& ctx) {
+void Module::Interface::GetConfig(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto config_item = rp.PopEnum<ConfigItem>();
@@ -47,21 +48,21 @@ void Module::Interface::GetConfig(Kernel::HLERequestContext& ctx) {
rb.Push(*smc_result);
}
-void Module::Interface::ModularExponentiate(Kernel::HLERequestContext& ctx) {
+void Module::Interface::ModularExponentiate(HLERequestContext& ctx) {
UNIMPLEMENTED_MSG("ModularExponentiate is not implemented!");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSecureMonitorNotImplemented);
}
-void Module::Interface::SetConfig(Kernel::HLERequestContext& ctx) {
+void Module::Interface::SetConfig(HLERequestContext& ctx) {
UNIMPLEMENTED_MSG("SetConfig is not implemented!");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSecureMonitorNotImplemented);
}
-void Module::Interface::GenerateRandomBytes(Kernel::HLERequestContext& ctx) {
+void Module::Interface::GenerateRandomBytes(HLERequestContext& ctx) {
LOG_DEBUG(Service_SPL, "called");
const std::size_t size = ctx.GetWriteBufferSize();
@@ -76,21 +77,21 @@ void Module::Interface::GenerateRandomBytes(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void Module::Interface::IsDevelopment(Kernel::HLERequestContext& ctx) {
+void Module::Interface::IsDevelopment(HLERequestContext& ctx) {
UNIMPLEMENTED_MSG("IsDevelopment is not implemented!");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSecureMonitorNotImplemented);
}
-void Module::Interface::SetBootReason(Kernel::HLERequestContext& ctx) {
+void Module::Interface::SetBootReason(HLERequestContext& ctx) {
UNIMPLEMENTED_MSG("SetBootReason is not implemented!");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSecureMonitorNotImplemented);
}
-void Module::Interface::GetBootReason(Kernel::HLERequestContext& ctx) {
+void Module::Interface::GetBootReason(HLERequestContext& ctx) {
UNIMPLEMENTED_MSG("GetBootReason is not implemented!");
IPC::ResponseBuilder rb{ctx, 2};
@@ -158,15 +159,18 @@ ResultVal<u64> Module::Interface::GetConfigImpl(ConfigItem config_item) const {
}
}
-void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
+void LoopProcess(Core::System& system) {
+ auto server_manager = std::make_unique<ServerManager>(system);
auto module = std::make_shared<Module>();
- std::make_shared<CSRNG>(system, module)->InstallAsService(service_manager);
- std::make_shared<SPL>(system, module)->InstallAsService(service_manager);
- std::make_shared<SPL_MIG>(system, module)->InstallAsService(service_manager);
- std::make_shared<SPL_FS>(system, module)->InstallAsService(service_manager);
- std::make_shared<SPL_SSL>(system, module)->InstallAsService(service_manager);
- std::make_shared<SPL_ES>(system, module)->InstallAsService(service_manager);
- std::make_shared<SPL_MANU>(system, module)->InstallAsService(service_manager);
+
+ server_manager->RegisterNamedService("csrng", std::make_shared<CSRNG>(system, module));
+ server_manager->RegisterNamedService("spl", std::make_shared<SPL>(system, module));
+ server_manager->RegisterNamedService("spl:mig", std::make_shared<SPL_MIG>(system, module));
+ server_manager->RegisterNamedService("spl:fs", std::make_shared<SPL_FS>(system, module));
+ server_manager->RegisterNamedService("spl:ssl", std::make_shared<SPL_SSL>(system, module));
+ server_manager->RegisterNamedService("spl:es", std::make_shared<SPL_ES>(system, module));
+ server_manager->RegisterNamedService("spl:manu", std::make_shared<SPL_MANU>(system, module));
+ ServerManager::RunServer(std::move(server_manager));
}
} // namespace Service::SPL
diff --git a/src/core/hle/service/spl/spl_module.h b/src/core/hle/service/spl/spl_module.h
index 4c9a3c618..e074e115d 100644
--- a/src/core/hle/service/spl/spl_module.h
+++ b/src/core/hle/service/spl/spl_module.h
@@ -23,13 +23,13 @@ public:
~Interface() override;
// General
- void GetConfig(Kernel::HLERequestContext& ctx);
- void ModularExponentiate(Kernel::HLERequestContext& ctx);
- void SetConfig(Kernel::HLERequestContext& ctx);
- void GenerateRandomBytes(Kernel::HLERequestContext& ctx);
- void IsDevelopment(Kernel::HLERequestContext& ctx);
- void SetBootReason(Kernel::HLERequestContext& ctx);
- void GetBootReason(Kernel::HLERequestContext& ctx);
+ void GetConfig(HLERequestContext& ctx);
+ void ModularExponentiate(HLERequestContext& ctx);
+ void SetConfig(HLERequestContext& ctx);
+ void GenerateRandomBytes(HLERequestContext& ctx);
+ void IsDevelopment(HLERequestContext& ctx);
+ void SetBootReason(HLERequestContext& ctx);
+ void GetBootReason(HLERequestContext& ctx);
protected:
std::shared_ptr<Module> module;
@@ -41,7 +41,6 @@ public:
};
};
-/// Registers all SPL services with the specified service manager.
-void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system);
+void LoopProcess(Core::System& system);
} // namespace Service::SPL
diff --git a/src/core/hle/service/ssl/ssl.cpp b/src/core/hle/service/ssl/ssl.cpp
index 3735e0452..2b99dd7ac 100644
--- a/src/core/hle/service/ssl/ssl.cpp
+++ b/src/core/hle/service/ssl/ssl.cpp
@@ -1,21 +1,43 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
-#include "core/hle/ipc_helpers.h"
+#include "core/hle/service/ipc_helpers.h"
+#include "core/hle/service/server_manager.h"
#include "core/hle/service/service.h"
-#include "core/hle/service/sm/sm.h"
#include "core/hle/service/ssl/ssl.h"
namespace Service::SSL {
+// This is nn::ssl::sf::CertificateFormat
enum class CertificateFormat : u32 {
Pem = 1,
Der = 2,
};
+// This is nn::ssl::sf::ContextOption
+enum class ContextOption : u32 {
+ None = 0,
+ CrlImportDateCheckEnable = 1,
+};
+
+// This is nn::ssl::sf::SslVersion
+struct SslVersion {
+ union {
+ u32 raw{};
+
+ BitField<0, 1, u32> tls_auto;
+ BitField<3, 1, u32> tls_v10;
+ BitField<4, 1, u32> tls_v11;
+ BitField<5, 1, u32> tls_v12;
+ BitField<6, 1, u32> tls_v13;
+ BitField<24, 7, u32> api_version;
+ };
+};
+
class ISslConnection final : public ServiceFramework<ISslConnection> {
public:
- explicit ISslConnection(Core::System& system_) : ServiceFramework{system_, "ISslConnection"} {
+ explicit ISslConnection(Core::System& system_, SslVersion version)
+ : ServiceFramework{system_, "ISslConnection"}, ssl_version{version} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "SetSocketDescriptor"},
@@ -46,16 +68,28 @@ public:
{25, nullptr, "GetCipherInfo"},
{26, nullptr, "SetNextAlpnProto"},
{27, nullptr, "GetNextAlpnProto"},
+ {28, nullptr, "SetDtlsSocketDescriptor"},
+ {29, nullptr, "GetDtlsHandshakeTimeout"},
+ {30, nullptr, "SetPrivateOption"},
+ {31, nullptr, "SetSrtpCiphers"},
+ {32, nullptr, "GetSrtpCipher"},
+ {33, nullptr, "ExportKeyingMaterial"},
+ {34, nullptr, "SetIoTimeout"},
+ {35, nullptr, "GetIoTimeout"},
};
// clang-format on
RegisterHandlers(functions);
}
+
+private:
+ SslVersion ssl_version;
};
class ISslContext final : public ServiceFramework<ISslContext> {
public:
- explicit ISslContext(Core::System& system_) : ServiceFramework{system_, "ISslContext"} {
+ explicit ISslContext(Core::System& system_, SslVersion version)
+ : ServiceFramework{system_, "ISslContext"}, ssl_version{version} {
static const FunctionInfo functions[] = {
{0, &ISslContext::SetOption, "SetOption"},
{1, nullptr, "GetOption"},
@@ -69,39 +103,44 @@ public:
{9, nullptr, "AddPolicyOid"},
{10, nullptr, "ImportCrl"},
{11, nullptr, "RemoveCrl"},
+ {12, nullptr, "ImportClientCertKeyPki"},
+ {13, nullptr, "GeneratePrivateKeyAndCert"},
};
RegisterHandlers(functions);
}
private:
- void SetOption(Kernel::HLERequestContext& ctx) {
+ SslVersion ssl_version;
+
+ void SetOption(HLERequestContext& ctx) {
struct Parameters {
- u8 enable;
- u32 option;
+ ContextOption option;
+ s32 value;
};
+ static_assert(sizeof(Parameters) == 0x8, "Parameters is an invalid size");
IPC::RequestParser rp{ctx};
const auto parameters = rp.PopRaw<Parameters>();
- LOG_WARNING(Service_SSL, "(STUBBED) called. enable={}, option={}", parameters.enable,
- parameters.option);
+ LOG_WARNING(Service_SSL, "(STUBBED) called. option={}, value={}", parameters.option,
+ parameters.value);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
- void CreateConnection(Kernel::HLERequestContext& ctx) {
+ void CreateConnection(HLERequestContext& ctx) {
LOG_WARNING(Service_SSL, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
- rb.PushIpcInterface<ISslConnection>(system);
+ rb.PushIpcInterface<ISslConnection>(system, ssl_version);
}
- void ImportServerPki(Kernel::HLERequestContext& ctx) {
+ void ImportServerPki(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto certificate_format = rp.PopEnum<CertificateFormat>();
- const auto pkcs_12_certificates = ctx.ReadBuffer(0);
+ [[maybe_unused]] const auto pkcs_12_certificates = ctx.ReadBuffer(0);
constexpr u64 server_id = 0;
@@ -112,14 +151,14 @@ private:
rb.Push(server_id);
}
- void ImportClientPki(Kernel::HLERequestContext& ctx) {
- const auto pkcs_12_certificate = ctx.ReadBuffer(0);
- const auto ascii_password = [&ctx] {
+ void ImportClientPki(HLERequestContext& ctx) {
+ [[maybe_unused]] const auto pkcs_12_certificate = ctx.ReadBuffer(0);
+ [[maybe_unused]] const auto ascii_password = [&ctx] {
if (ctx.CanReadBuffer(1)) {
return ctx.ReadBuffer(1);
}
- return std::vector<u8>{};
+ return std::span<const u8>{};
}();
constexpr u64 client_id = 0;
@@ -132,20 +171,21 @@ private:
}
};
-class SSL final : public ServiceFramework<SSL> {
+class ISslService final : public ServiceFramework<ISslService> {
public:
- explicit SSL(Core::System& system_) : ServiceFramework{system_, "ssl"} {
+ explicit ISslService(Core::System& system_) : ServiceFramework{system_, "ssl"} {
// clang-format off
static const FunctionInfo functions[] = {
- {0, &SSL::CreateContext, "CreateContext"},
+ {0, &ISslService::CreateContext, "CreateContext"},
{1, nullptr, "GetContextCount"},
{2, nullptr, "GetCertificates"},
{3, nullptr, "GetCertificateBufSize"},
{4, nullptr, "DebugIoctl"},
- {5, &SSL::SetInterfaceVersion, "SetInterfaceVersion"},
+ {5, &ISslService::SetInterfaceVersion, "SetInterfaceVersion"},
{6, nullptr, "FlushSessionCache"},
{7, nullptr, "SetDebugOption"},
{8, nullptr, "GetDebugOption"},
+ {8, nullptr, "ClearTls12FallbackFlag"},
};
// clang-format on
@@ -153,28 +193,41 @@ public:
}
private:
- u32 ssl_version{};
- void CreateContext(Kernel::HLERequestContext& ctx) {
- LOG_WARNING(Service_SSL, "(STUBBED) called");
+ void CreateContext(HLERequestContext& ctx) {
+ struct Parameters {
+ SslVersion ssl_version;
+ INSERT_PADDING_BYTES(0x4);
+ u64 pid_placeholder;
+ };
+ static_assert(sizeof(Parameters) == 0x10, "Parameters is an invalid size");
+
+ IPC::RequestParser rp{ctx};
+ const auto parameters = rp.PopRaw<Parameters>();
+
+ LOG_WARNING(Service_SSL, "(STUBBED) called, api_version={}, pid_placeholder={}",
+ parameters.ssl_version.api_version, parameters.pid_placeholder);
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
- rb.PushIpcInterface<ISslContext>(system);
+ rb.PushIpcInterface<ISslContext>(system, parameters.ssl_version);
}
- void SetInterfaceVersion(Kernel::HLERequestContext& ctx) {
- LOG_DEBUG(Service_SSL, "called");
-
+ void SetInterfaceVersion(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
- ssl_version = rp.Pop<u32>();
+ u32 ssl_version = rp.Pop<u32>();
+
+ LOG_DEBUG(Service_SSL, "called, ssl_version={}", ssl_version);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
};
-void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
- std::make_shared<SSL>(system)->InstallAsService(service_manager);
+void LoopProcess(Core::System& system) {
+ auto server_manager = std::make_unique<ServerManager>(system);
+
+ server_manager->RegisterNamedService("ssl", std::make_shared<ISslService>(system));
+ ServerManager::RunServer(std::move(server_manager));
}
} // namespace Service::SSL
diff --git a/src/core/hle/service/ssl/ssl.h b/src/core/hle/service/ssl/ssl.h
index 27b38a003..f6e21bbb3 100644
--- a/src/core/hle/service/ssl/ssl.h
+++ b/src/core/hle/service/ssl/ssl.h
@@ -7,13 +7,8 @@ namespace Core {
class System;
}
-namespace Service::SM {
-class ServiceManager;
-}
-
namespace Service::SSL {
-/// Registers all SSL services with the specified service manager.
-void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system);
+void LoopProcess(Core::System& system);
} // namespace Service::SSL
diff --git a/src/core/hle/service/time/clock_types.h b/src/core/hle/service/time/clock_types.h
index ed1eb5b2d..9fc01ea90 100644
--- a/src/core/hle/service/time/clock_types.h
+++ b/src/core/hle/service/time/clock_types.h
@@ -3,6 +3,8 @@
#pragma once
+#include <ratio>
+
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/uuid.h"
@@ -59,21 +61,34 @@ static_assert(sizeof(SystemClockContext) == 0x20, "SystemClockContext is incorre
static_assert(std::is_trivially_copyable_v<SystemClockContext>,
"SystemClockContext must be trivially copyable");
+struct ContinuousAdjustmentTimePoint {
+ s64 measurement_offset;
+ s64 diff_scale;
+ u32 shift_amount;
+ s64 lower;
+ s64 upper;
+ Common::UUID clock_source_id;
+};
+static_assert(sizeof(ContinuousAdjustmentTimePoint) == 0x38);
+static_assert(std::is_trivially_copyable_v<ContinuousAdjustmentTimePoint>,
+ "ContinuousAdjustmentTimePoint must be trivially copyable");
+
/// https://switchbrew.org/wiki/Glue_services#TimeSpanType
struct TimeSpanType {
s64 nanoseconds{};
- static constexpr s64 ns_per_second{1000000000ULL};
s64 ToSeconds() const {
- return nanoseconds / ns_per_second;
+ return nanoseconds / std::nano::den;
}
static TimeSpanType FromSeconds(s64 seconds) {
- return {seconds * ns_per_second};
+ return {seconds * std::nano::den};
}
- static TimeSpanType FromTicks(u64 ticks, u64 frequency) {
- return FromSeconds(static_cast<s64>(ticks) / static_cast<s64>(frequency));
+ template <u64 Frequency>
+ static TimeSpanType FromTicks(u64 ticks) {
+ using TicksToNSRatio = std::ratio<std::nano::den, Frequency>;
+ return {static_cast<s64>(ticks * TicksToNSRatio::num / TicksToNSRatio::den)};
}
};
static_assert(sizeof(TimeSpanType) == 8, "TimeSpanType is incorrect size");
diff --git a/src/core/hle/service/time/standard_steady_clock_core.cpp b/src/core/hle/service/time/standard_steady_clock_core.cpp
index 3dbbb9850..5627b7003 100644
--- a/src/core/hle/service/time/standard_steady_clock_core.cpp
+++ b/src/core/hle/service/time/standard_steady_clock_core.cpp
@@ -10,7 +10,7 @@ namespace Service::Time::Clock {
TimeSpanType StandardSteadyClockCore::GetCurrentRawTimePoint(Core::System& system) {
const TimeSpanType ticks_time_span{
- TimeSpanType::FromTicks(system.CoreTiming().GetClockTicks(), Core::Hardware::CNTFREQ)};
+ TimeSpanType::FromTicks<Core::Hardware::CNTFREQ>(system.CoreTiming().GetClockTicks())};
TimeSpanType raw_time_point{setup_value.nanoseconds + ticks_time_span.nanoseconds};
if (raw_time_point.nanoseconds < cached_raw_time_point.nanoseconds) {
diff --git a/src/core/hle/service/time/tick_based_steady_clock_core.cpp b/src/core/hle/service/time/tick_based_steady_clock_core.cpp
index 27600413e..0d9fb3143 100644
--- a/src/core/hle/service/time/tick_based_steady_clock_core.cpp
+++ b/src/core/hle/service/time/tick_based_steady_clock_core.cpp
@@ -10,7 +10,7 @@ namespace Service::Time::Clock {
SteadyClockTimePoint TickBasedSteadyClockCore::GetTimePoint(Core::System& system) {
const TimeSpanType ticks_time_span{
- TimeSpanType::FromTicks(system.CoreTiming().GetClockTicks(), Core::Hardware::CNTFREQ)};
+ TimeSpanType::FromTicks<Core::Hardware::CNTFREQ>(system.CoreTiming().GetClockTicks())};
return {ticks_time_span.ToSeconds(), GetClockSourceId()};
}
diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp
index f77cdbb43..7197ca30f 100644
--- a/src/core/hle/service/time/time.cpp
+++ b/src/core/hle/service/time/time.cpp
@@ -5,8 +5,9 @@
#include "core/core.h"
#include "core/core_timing.h"
#include "core/hardware_properties.h"
-#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/kernel.h"
+#include "core/hle/service/ipc_helpers.h"
+#include "core/hle/service/server_manager.h"
#include "core/hle/service/time/time.h"
#include "core/hle/service/time/time_interface.h"
#include "core/hle/service/time/time_manager.h"
@@ -33,7 +34,7 @@ public:
}
private:
- void GetCurrentTime(Kernel::HLERequestContext& ctx) {
+ void GetCurrentTime(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called");
if (!clock_core.IsInitialized()) {
@@ -54,7 +55,7 @@ private:
rb.Push<s64>(posix_time);
}
- void GetSystemClockContext(Kernel::HLERequestContext& ctx) {
+ void GetSystemClockContext(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called");
if (!clock_core.IsInitialized()) {
@@ -97,7 +98,7 @@ public:
}
private:
- void GetCurrentTimePoint(Kernel::HLERequestContext& ctx) {
+ void GetCurrentTimePoint(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called");
if (!clock_core.IsInitialized()) {
@@ -177,7 +178,7 @@ Result Module::Interface::GetClockSnapshotFromSystemClockContextInternal(
return ResultSuccess;
}
-void Module::Interface::GetStandardUserSystemClock(Kernel::HLERequestContext& ctx) {
+void Module::Interface::GetStandardUserSystemClock(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
@@ -185,7 +186,7 @@ void Module::Interface::GetStandardUserSystemClock(Kernel::HLERequestContext& ct
system);
}
-void Module::Interface::GetStandardNetworkSystemClock(Kernel::HLERequestContext& ctx) {
+void Module::Interface::GetStandardNetworkSystemClock(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
@@ -193,14 +194,14 @@ void Module::Interface::GetStandardNetworkSystemClock(Kernel::HLERequestContext&
system);
}
-void Module::Interface::GetStandardSteadyClock(Kernel::HLERequestContext& ctx) {
+void Module::Interface::GetStandardSteadyClock(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<ISteadyClock>(system.GetTimeManager().GetStandardSteadyClockCore(), system);
}
-void Module::Interface::GetTimeZoneService(Kernel::HLERequestContext& ctx) {
+void Module::Interface::GetTimeZoneService(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
@@ -208,7 +209,7 @@ void Module::Interface::GetTimeZoneService(Kernel::HLERequestContext& ctx) {
system.GetTimeManager().GetTimeZoneContentManager());
}
-void Module::Interface::GetStandardLocalSystemClock(Kernel::HLERequestContext& ctx) {
+void Module::Interface::GetStandardLocalSystemClock(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
@@ -216,8 +217,7 @@ void Module::Interface::GetStandardLocalSystemClock(Kernel::HLERequestContext& c
system);
}
-void Module::Interface::IsStandardNetworkSystemClockAccuracySufficient(
- Kernel::HLERequestContext& ctx) {
+void Module::Interface::IsStandardNetworkSystemClockAccuracySufficient(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called");
auto& clock_core{system.GetTimeManager().GetStandardNetworkSystemClockCore()};
IPC::ResponseBuilder rb{ctx, 3};
@@ -225,7 +225,7 @@ void Module::Interface::IsStandardNetworkSystemClockAccuracySufficient(
rb.Push<u32>(clock_core.IsStandardNetworkSystemClockAccuracySufficient(system));
}
-void Module::Interface::CalculateMonotonicSystemClockBaseTimePoint(Kernel::HLERequestContext& ctx) {
+void Module::Interface::CalculateMonotonicSystemClockBaseTimePoint(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called");
auto& steady_clock_core{system.GetTimeManager().GetStandardSteadyClockCore()};
@@ -240,8 +240,8 @@ void Module::Interface::CalculateMonotonicSystemClockBaseTimePoint(Kernel::HLERe
const auto current_time_point{steady_clock_core.GetCurrentTimePoint(system)};
if (current_time_point.clock_source_id == context.steady_time_point.clock_source_id) {
- const auto ticks{Clock::TimeSpanType::FromTicks(system.CoreTiming().GetClockTicks(),
- Core::Hardware::CNTFREQ)};
+ const auto ticks{Clock::TimeSpanType::FromTicks<Core::Hardware::CNTFREQ>(
+ system.CoreTiming().GetClockTicks())};
const s64 base_time_point{context.offset + current_time_point.time_point -
ticks.ToSeconds()};
IPC::ResponseBuilder rb{ctx, (sizeof(s64) / 4) + 2};
@@ -254,7 +254,7 @@ void Module::Interface::CalculateMonotonicSystemClockBaseTimePoint(Kernel::HLERe
rb.Push(ERROR_TIME_MISMATCH);
}
-void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) {
+void Module::Interface::GetClockSnapshot(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto type{rp.PopEnum<Clock::TimeType>()};
@@ -295,7 +295,7 @@ void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void Module::Interface::GetClockSnapshotFromSystemClockContext(Kernel::HLERequestContext& ctx) {
+void Module::Interface::GetClockSnapshotFromSystemClockContext(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto type{rp.PopEnum<Clock::TimeType>()};
@@ -321,8 +321,7 @@ void Module::Interface::GetClockSnapshotFromSystemClockContext(Kernel::HLEReques
rb.Push(ResultSuccess);
}
-void Module::Interface::CalculateStandardUserSystemClockDifferenceByUser(
- Kernel::HLERequestContext& ctx) {
+void Module::Interface::CalculateStandardUserSystemClockDifferenceByUser(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called");
Clock::ClockSnapshot snapshot_a;
@@ -349,7 +348,7 @@ void Module::Interface::CalculateStandardUserSystemClockDifferenceByUser(
rb.PushRaw(time_span_type.nanoseconds);
}
-void Module::Interface::CalculateSpanBetween(Kernel::HLERequestContext& ctx) {
+void Module::Interface::CalculateSpanBetween(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called");
Clock::ClockSnapshot snapshot_a;
@@ -384,7 +383,7 @@ void Module::Interface::CalculateSpanBetween(Kernel::HLERequestContext& ctx) {
rb.PushRaw(time_span_type.nanoseconds);
}
-void Module::Interface::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) {
+void Module::Interface::GetSharedMemoryNativeHandle(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called");
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(ResultSuccess);
@@ -397,11 +396,17 @@ Module::Interface::Interface(std::shared_ptr<Module> module_, Core::System& syst
Module::Interface::~Interface() = default;
-void InstallInterfaces(Core::System& system) {
+void LoopProcess(Core::System& system) {
+ auto server_manager = std::make_unique<ServerManager>(system);
auto module{std::make_shared<Module>()};
- std::make_shared<Time>(module, system, "time:a")->InstallAsService(system.ServiceManager());
- std::make_shared<Time>(module, system, "time:s")->InstallAsService(system.ServiceManager());
- std::make_shared<Time>(module, system, "time:u")->InstallAsService(system.ServiceManager());
+
+ server_manager->RegisterNamedService("time:a",
+ std::make_shared<Time>(module, system, "time:a"));
+ server_manager->RegisterNamedService("time:s",
+ std::make_shared<Time>(module, system, "time:s"));
+ server_manager->RegisterNamedService("time:u",
+ std::make_shared<Time>(module, system, "time:u"));
+ ServerManager::RunServer(std::move(server_manager));
}
} // namespace Service::Time
diff --git a/src/core/hle/service/time/time.h b/src/core/hle/service/time/time.h
index 76a46cfc7..b2d754ef3 100644
--- a/src/core/hle/service/time/time.h
+++ b/src/core/hle/service/time/time.h
@@ -22,18 +22,18 @@ public:
const char* name);
~Interface() override;
- void GetStandardUserSystemClock(Kernel::HLERequestContext& ctx);
- void GetStandardNetworkSystemClock(Kernel::HLERequestContext& ctx);
- void GetStandardSteadyClock(Kernel::HLERequestContext& ctx);
- void GetTimeZoneService(Kernel::HLERequestContext& ctx);
- void GetStandardLocalSystemClock(Kernel::HLERequestContext& ctx);
- void IsStandardNetworkSystemClockAccuracySufficient(Kernel::HLERequestContext& ctx);
- void CalculateMonotonicSystemClockBaseTimePoint(Kernel::HLERequestContext& ctx);
- void GetClockSnapshot(Kernel::HLERequestContext& ctx);
- void GetClockSnapshotFromSystemClockContext(Kernel::HLERequestContext& ctx);
- void CalculateStandardUserSystemClockDifferenceByUser(Kernel::HLERequestContext& ctx);
- void CalculateSpanBetween(Kernel::HLERequestContext& ctx);
- void GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx);
+ void GetStandardUserSystemClock(HLERequestContext& ctx);
+ void GetStandardNetworkSystemClock(HLERequestContext& ctx);
+ void GetStandardSteadyClock(HLERequestContext& ctx);
+ void GetTimeZoneService(HLERequestContext& ctx);
+ void GetStandardLocalSystemClock(HLERequestContext& ctx);
+ void IsStandardNetworkSystemClockAccuracySufficient(HLERequestContext& ctx);
+ void CalculateMonotonicSystemClockBaseTimePoint(HLERequestContext& ctx);
+ void GetClockSnapshot(HLERequestContext& ctx);
+ void GetClockSnapshotFromSystemClockContext(HLERequestContext& ctx);
+ void CalculateStandardUserSystemClockDifferenceByUser(HLERequestContext& ctx);
+ void CalculateSpanBetween(HLERequestContext& ctx);
+ void GetSharedMemoryNativeHandle(HLERequestContext& ctx);
private:
Result GetClockSnapshotFromSystemClockContextInternal(
@@ -46,7 +46,6 @@ public:
};
};
-/// Registers all Time services with the specified service manager.
-void InstallInterfaces(Core::System& system);
+void LoopProcess(Core::System& system);
} // namespace Service::Time
diff --git a/src/core/hle/service/time/time_manager.cpp b/src/core/hle/service/time/time_manager.cpp
index 28667710e..fa0fd0531 100644
--- a/src/core/hle/service/time/time_manager.cpp
+++ b/src/core/hle/service/time/time_manager.cpp
@@ -22,10 +22,6 @@ s64 GetSecondsSinceEpoch() {
return std::chrono::duration_cast<std::chrono::seconds>(time_since_epoch).count() +
Settings::values.custom_rtc_differential;
}
-
-s64 GetExternalRtcValue() {
- return GetSecondsSinceEpoch() + TimeManager::GetExternalTimeZoneOffset();
-}
} // Anonymous namespace
struct TimeManager::Impl final {
@@ -43,7 +39,7 @@ struct TimeManager::Impl final {
std::make_shared<Clock::EphemeralNetworkSystemClockContextWriter>()},
time_zone_content_manager{system} {
- const auto system_time{Clock::TimeSpanType::FromSeconds(GetExternalRtcValue())};
+ const auto system_time{Clock::TimeSpanType::FromSeconds(GetSecondsSinceEpoch())};
SetupStandardSteadyClock(system, Common::UUID::MakeRandom(), system_time, {}, {});
SetupStandardLocalSystemClock(system, {}, system_time.ToSeconds());
@@ -107,7 +103,7 @@ struct TimeManager::Impl final {
void SetupTimeZoneManager(std::string location_name,
Clock::SteadyClockTimePoint time_zone_updated_time_point,
- std::size_t total_location_name_count, u128 time_zone_rule_version,
+ std::vector<std::string> location_names, u128 time_zone_rule_version,
FileSys::VirtualFile& vfs_file) {
if (time_zone_content_manager.GetTimeZoneManager().SetDeviceLocationNameWithTimeZoneRule(
location_name, vfs_file) != ResultSuccess) {
@@ -117,20 +113,13 @@ struct TimeManager::Impl final {
time_zone_content_manager.GetTimeZoneManager().SetUpdatedTime(time_zone_updated_time_point);
time_zone_content_manager.GetTimeZoneManager().SetTotalLocationNameCount(
- total_location_name_count);
+ location_names.size());
+ time_zone_content_manager.GetTimeZoneManager().SetLocationNames(location_names);
time_zone_content_manager.GetTimeZoneManager().SetTimeZoneRuleVersion(
time_zone_rule_version);
time_zone_content_manager.GetTimeZoneManager().MarkAsInitialized();
}
- static s64 GetExternalTimeZoneOffset() {
- // With "auto" timezone setting, we use the external system's timezone offset
- if (Settings::GetTimeZoneString() == "auto") {
- return Common::TimeZone::GetCurrentOffsetSeconds().count();
- }
- return 0;
- }
-
void SetupStandardSteadyClock(Core::System& system_, Common::UUID clock_source_id,
Clock::TimeSpanType setup_value,
Clock::TimeSpanType internal_offset, bool is_rtc_reset_detected) {
@@ -295,19 +284,10 @@ void TimeManager::UpdateLocalSystemClockTime(s64 posix_time) {
void TimeManager::SetupTimeZoneManager(std::string location_name,
Clock::SteadyClockTimePoint time_zone_updated_time_point,
- std::size_t total_location_name_count,
+ std::vector<std::string> location_names,
u128 time_zone_rule_version,
FileSys::VirtualFile& vfs_file) {
- impl->SetupTimeZoneManager(location_name, time_zone_updated_time_point,
- total_location_name_count, time_zone_rule_version, vfs_file);
+ impl->SetupTimeZoneManager(location_name, time_zone_updated_time_point, location_names,
+ time_zone_rule_version, vfs_file);
}
-
-/*static*/ s64 TimeManager::GetExternalTimeZoneOffset() {
- // With "auto" timezone setting, we use the external system's timezone offset
- if (Settings::GetTimeZoneString() == "auto") {
- return Common::TimeZone::GetCurrentOffsetSeconds().count();
- }
- return 0;
-}
-
} // namespace Service::Time
diff --git a/src/core/hle/service/time/time_manager.h b/src/core/hle/service/time/time_manager.h
index 4f046f266..84572dbfa 100644
--- a/src/core/hle/service/time/time_manager.h
+++ b/src/core/hle/service/time/time_manager.h
@@ -61,11 +61,9 @@ public:
void SetupTimeZoneManager(std::string location_name,
Clock::SteadyClockTimePoint time_zone_updated_time_point,
- std::size_t total_location_name_count, u128 time_zone_rule_version,
+ std::vector<std::string> location_names, u128 time_zone_rule_version,
FileSys::VirtualFile& vfs_file);
- static s64 GetExternalTimeZoneOffset();
-
private:
Core::System& system;
diff --git a/src/core/hle/service/time/time_sharedmemory.cpp b/src/core/hle/service/time/time_sharedmemory.cpp
index ff53a7d6f..a00676669 100644
--- a/src/core/hle/service/time/time_sharedmemory.cpp
+++ b/src/core/hle/service/time/time_sharedmemory.cpp
@@ -21,8 +21,9 @@ SharedMemory::~SharedMemory() = default;
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)};
+ const Clock::TimeSpanType ticks_time_span{
+ Clock::TimeSpanType::FromTicks<Core::Hardware::CNTFREQ>(
+ system.CoreTiming().GetClockTicks())};
const Clock::SteadyClockContext context{
static_cast<u64>(current_time_point.nanoseconds - ticks_time_span.nanoseconds),
clock_source_id};
@@ -30,6 +31,25 @@ void SharedMemory::SetupStandardSteadyClock(const Common::UUID& clock_source_id,
}
void SharedMemory::UpdateLocalSystemClockContext(const Clock::SystemClockContext& context) {
+ // lower and upper are related to the measurement point for the steady time point,
+ // and compare equal on boot
+ const s64 time_point_ns = context.steady_time_point.time_point * 1'000'000'000LL;
+
+ // This adjusts for some sort of time skew
+ // Both 0 on boot
+ const s64 diff_scale = 0;
+ const u32 shift_amount = 0;
+
+ const Clock::ContinuousAdjustmentTimePoint adjustment{
+ .measurement_offset = system.CoreTiming().GetGlobalTimeNs().count(),
+ .diff_scale = diff_scale,
+ .shift_amount = shift_amount,
+ .lower = time_point_ns,
+ .upper = time_point_ns,
+ .clock_source_id = context.steady_time_point.clock_source_id,
+ };
+
+ StoreToLockFreeAtomicType(&GetFormat()->continuous_adjustment_timepoint, adjustment);
StoreToLockFreeAtomicType(&GetFormat()->standard_local_system_clock_context, context);
}
diff --git a/src/core/hle/service/time/time_sharedmemory.h b/src/core/hle/service/time/time_sharedmemory.h
index 044a4d24e..c89be9765 100644
--- a/src/core/hle/service/time/time_sharedmemory.h
+++ b/src/core/hle/service/time/time_sharedmemory.h
@@ -65,14 +65,15 @@ public:
LockFreeAtomicType<Clock::SystemClockContext> standard_local_system_clock_context;
LockFreeAtomicType<Clock::SystemClockContext> standard_network_system_clock_context;
LockFreeAtomicType<bool> is_standard_user_system_clock_automatic_correction_enabled;
- u32 format_version;
+ LockFreeAtomicType<Clock::ContinuousAdjustmentTimePoint> continuous_adjustment_timepoint;
};
static_assert(offsetof(Format, standard_steady_clock_timepoint) == 0x0);
static_assert(offsetof(Format, standard_local_system_clock_context) == 0x38);
static_assert(offsetof(Format, standard_network_system_clock_context) == 0x80);
static_assert(offsetof(Format, is_standard_user_system_clock_automatic_correction_enabled) ==
0xc8);
- static_assert(sizeof(Format) == 0xd8, "Format is an invalid size");
+ static_assert(offsetof(Format, continuous_adjustment_timepoint) == 0xd0);
+ static_assert(sizeof(Format) == 0x148, "Format is an invalid size");
void SetupStandardSteadyClock(const Common::UUID& clock_source_id,
Clock::TimeSpanType current_time_point);
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 afbfe9715..5d60be67a 100644
--- a/src/core/hle/service/time/time_zone_content_manager.cpp
+++ b/src/core/hle/service/time/time_zone_content_manager.cpp
@@ -1,6 +1,7 @@
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
+#include <chrono>
#include <sstream>
#include "common/logging/log.h"
@@ -12,7 +13,11 @@
#include "core/file_sys/registered_cache.h"
#include "core/file_sys/romfs.h"
#include "core/file_sys/system_archive/system_archive.h"
+#include "core/file_sys/vfs.h"
+#include "core/file_sys/vfs_types.h"
+#include "core/hle/result.h"
#include "core/hle/service/filesystem/filesystem.h"
+#include "core/hle/service/time/errors.h"
#include "core/hle/service/time/time_manager.h"
#include "core/hle/service/time/time_zone_content_manager.h"
@@ -71,19 +76,13 @@ TimeZoneContentManager::TimeZoneContentManager(Core::System& system_)
: system{system_}, location_name_cache{BuildLocationNameCache(system)} {}
void TimeZoneContentManager::Initialize(TimeManager& time_manager) {
- std::string location_name;
const auto timezone_setting = Settings::GetTimeZoneString();
- if (timezone_setting == "auto" || timezone_setting == "default") {
- location_name = Common::TimeZone::GetDefaultTimeZone();
- } else {
- location_name = timezone_setting;
- }
if (FileSys::VirtualFile vfs_file;
- GetTimeZoneInfoFile(location_name, vfs_file) == ResultSuccess) {
+ GetTimeZoneInfoFile(timezone_setting, vfs_file) == ResultSuccess) {
const auto time_point{
time_manager.GetStandardSteadyClockCore().GetCurrentTimePoint(system)};
- time_manager.SetupTimeZoneManager(location_name, time_point, location_name_cache.size(), {},
+ time_manager.SetupTimeZoneManager(timezone_setting, time_point, location_name_cache, {},
vfs_file);
} else {
time_zone_manager.MarkAsInitialized();
@@ -126,8 +125,15 @@ Result TimeZoneContentManager::GetTimeZoneInfoFile(const std::string& location_n
vfs_file = zoneinfo_dir->GetFileRelative(location_name);
if (!vfs_file) {
- LOG_ERROR(Service_Time, "{:016X} has no file \"{}\"! Using default timezone.",
- time_zone_binary_titleid, location_name);
+ LOG_WARNING(Service_Time, "{:016X} has no file \"{}\"! Using system timezone.",
+ time_zone_binary_titleid, location_name);
+ const std::string system_time_zone{Common::TimeZone::FindSystemTimeZone()};
+ vfs_file = zoneinfo_dir->GetFile(system_time_zone);
+ }
+
+ if (!vfs_file) {
+ LOG_WARNING(Service_Time, "{:016X} has no file \"{}\"! Using default timezone.",
+ time_zone_binary_titleid, location_name);
vfs_file = zoneinfo_dir->GetFile(Common::TimeZone::GetDefaultTimeZone());
}
diff --git a/src/core/hle/service/time/time_zone_manager.cpp b/src/core/hle/service/time/time_zone_manager.cpp
index f9ada7c93..205371a26 100644
--- a/src/core/hle/service/time/time_zone_manager.cpp
+++ b/src/core/hle/service/time/time_zone_manager.cpp
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include <climits>
+#include <limits>
#include "common/assert.h"
#include "common/logging/log.h"
@@ -9,6 +10,7 @@
#include "core/file_sys/nca_metadata.h"
#include "core/file_sys/registered_cache.h"
#include "core/hle/service/time/time_zone_manager.h"
+#include "core/hle/service/time/time_zone_types.h"
namespace Service::Time::TimeZone {
@@ -128,10 +130,10 @@ static constexpr int GetQZName(const char* name, int offset, char delimiter) {
}
static constexpr int GetTZName(const char* name, int offset) {
- for (char value{name[offset]};
- value != '\0' && !IsDigit(value) && value != ',' && value != '-' && value != '+';
- offset++) {
- value = name[offset];
+ char c;
+
+ while ((c = name[offset]) != '\0' && !IsDigit(c) && c != ',' && c != '-' && c != '+') {
+ ++offset;
}
return offset;
}
@@ -147,6 +149,7 @@ static constexpr bool GetInteger(const char* name, int& offset, int& value, int
if (value > max) {
return {};
}
+ offset++;
temp = name[offset];
} while (IsDigit(temp));
@@ -286,7 +289,7 @@ static constexpr int TransitionTime(int year, Rule rule, int offset) {
}
static bool ParsePosixName(const char* name, TimeZoneRule& rule) {
- constexpr char default_rule[]{",M4.1.0,M10.5.0"};
+ static constexpr char default_rule[]{",M4.1.0,M10.5.0"};
const char* std_name{name};
int std_len{};
int offset{};
@@ -471,6 +474,13 @@ static bool ParsePosixName(const char* name, TimeZoneRule& rule) {
their_std_offset = their_offset;
}
}
+
+ if (rule.time_count > 0) {
+ UNIMPLEMENTED();
+ // TODO (lat9nq): Implement eggert/tz/localtime.c:tzparse:1329
+ // Seems to be unused in yuzu for now: I never hit the UNIMPLEMENTED in testing
+ }
+
rule.ttis[0].gmt_offset = -std_offset;
rule.ttis[0].is_dst = false;
rule.ttis[0].abbreviation_list_index = 0;
@@ -514,6 +524,7 @@ static bool ParseTimeZoneBinary(TimeZoneRule& time_zone_rule, FileSys::VirtualFi
constexpr s32 time_zone_max_leaps{50};
constexpr s32 time_zone_max_chars{50};
+ constexpr s32 time_zone_max_times{1000};
if (!(0 <= header.leap_count && header.leap_count < time_zone_max_leaps &&
0 < header.type_count && header.type_count < s32(time_zone_rule.ttis.size()) &&
0 <= header.time_count && header.time_count < s32(time_zone_rule.ats.size()) &&
@@ -546,7 +557,7 @@ static bool ParseTimeZoneBinary(TimeZoneRule& time_zone_rule, FileSys::VirtualFi
for (int index{}; index < time_zone_rule.time_count; ++index) {
const u8 type{*vfs_file->ReadByte(read_offset)};
read_offset += sizeof(u8);
- if (time_zone_rule.time_count <= type) {
+ if (time_zone_rule.type_count <= type) {
return {};
}
if (time_zone_rule.types[index] != 0) {
@@ -624,16 +635,109 @@ static bool ParseTimeZoneBinary(TimeZoneRule& time_zone_rule, FileSys::VirtualFi
std::array<char, time_zone_name_max> name{};
std::memcpy(name.data(), temp_name.data() + 1, std::size_t(bytes_read - 1));
+ // Fill in computed transition times with temp rule
TimeZoneRule temp_rule;
if (ParsePosixName(name.data(), temp_rule)) {
- UNIMPLEMENTED();
+ int have_abbreviation = 0;
+ int char_count = time_zone_rule.char_count;
+
+ for (int i = 0; i < temp_rule.type_count; i++) {
+ char* temp_abbreviation =
+ temp_rule.chars.data() + temp_rule.ttis[i].abbreviation_list_index;
+ int j;
+ for (j = 0; j < char_count; j++) {
+ if (std::strcmp(time_zone_rule.chars.data() + j, temp_abbreviation) == 0) {
+ temp_rule.ttis[i].abbreviation_list_index = j;
+ have_abbreviation++;
+ break;
+ }
+ }
+ if (j >= char_count) {
+ int temp_abbreviation_length = static_cast<int>(std::strlen(temp_abbreviation));
+ if (j + temp_abbreviation_length < time_zone_max_chars) {
+ std::strcpy(time_zone_rule.chars.data() + j, temp_abbreviation);
+ char_count = j + temp_abbreviation_length + 1;
+ temp_rule.ttis[i].abbreviation_list_index = j;
+ have_abbreviation++;
+ }
+ }
+ }
+
+ if (have_abbreviation == temp_rule.type_count) {
+ time_zone_rule.char_count = char_count;
+
+ // Original comment:
+ /* Ignore any trailing, no-op transitions generated
+ by zic as they don't help here and can run afoul
+ of bugs in zic 2016j or earlier. */
+ // This is possibly unnecessary for yuzu, since Nintendo doesn't run zic
+ while (1 < time_zone_rule.time_count &&
+ (time_zone_rule.types[time_zone_rule.time_count - 1] ==
+ time_zone_rule.types[time_zone_rule.time_count - 2])) {
+ time_zone_rule.time_count--;
+ }
+
+ for (int i = 0;
+ i < temp_rule.time_count && time_zone_rule.time_count < time_zone_max_times;
+ i++) {
+ const s64 transition_time = temp_rule.ats[i];
+ if (0 < time_zone_rule.time_count &&
+ transition_time <= time_zone_rule.ats[time_zone_rule.time_count - 1]) {
+ continue;
+ }
+
+ time_zone_rule.ats[time_zone_rule.time_count] = transition_time;
+ time_zone_rule.types[time_zone_rule.time_count] =
+ static_cast<s8>(time_zone_rule.type_count + temp_rule.types[i]);
+ time_zone_rule.time_count++;
+ }
+ for (int i = 0; i < temp_rule.type_count; i++) {
+ time_zone_rule.ttis[time_zone_rule.type_count++] = temp_rule.ttis[i];
+ }
+ }
}
}
+
+ const auto typesequiv = [](TimeZoneRule& rule, int a, int b) -> bool {
+ if (a < 0 || a >= rule.type_count || b < 0 || b >= rule.type_count) {
+ return {};
+ }
+
+ const struct TimeTypeInfo* ap = &rule.ttis[a];
+ const struct TimeTypeInfo* bp = &rule.ttis[b];
+
+ return (ap->gmt_offset == bp->gmt_offset && ap->is_dst == bp->is_dst &&
+ (std::strcmp(&rule.chars[ap->abbreviation_list_index],
+ &rule.chars[bp->abbreviation_list_index]) == 0));
+ };
+
if (time_zone_rule.type_count == 0) {
return {};
}
if (time_zone_rule.time_count > 1) {
- UNIMPLEMENTED();
+ if (time_zone_rule.ats[0] <= std::numeric_limits<s64>::max() - seconds_per_repeat) {
+ s64 repeatat = time_zone_rule.ats[0] + seconds_per_repeat;
+ int repeatattype = time_zone_rule.types[0];
+ for (int i = 1; i < time_zone_rule.time_count; ++i) {
+ if (time_zone_rule.ats[i] == repeatat &&
+ typesequiv(time_zone_rule, time_zone_rule.types[i], repeatattype)) {
+ time_zone_rule.go_back = true;
+ break;
+ }
+ }
+ }
+ if (std::numeric_limits<s64>::min() + seconds_per_repeat <=
+ time_zone_rule.ats[time_zone_rule.time_count - 1]) {
+ s64 repeatat = time_zone_rule.ats[time_zone_rule.time_count - 1] - seconds_per_repeat;
+ int repeatattype = time_zone_rule.types[time_zone_rule.time_count - 1];
+ for (int i = time_zone_rule.time_count; i >= 0; --i) {
+ if (time_zone_rule.ats[i] == repeatat &&
+ typesequiv(time_zone_rule, time_zone_rule.types[i], repeatattype)) {
+ time_zone_rule.go_ahead = true;
+ break;
+ }
+ }
+ }
}
s32 default_type{};
@@ -745,8 +849,9 @@ static Result CreateCalendarTime(s64 time, int gmt_offset, CalendarTimeInternal&
static Result ToCalendarTimeInternal(const TimeZoneRule& rules, s64 time,
CalendarTimeInternal& calendar_time,
CalendarAdditionalInfo& calendar_additional_info) {
- if ((rules.go_ahead && time < rules.ats[0]) ||
- (rules.go_back && time > rules.ats[rules.time_count - 1])) {
+ ASSERT(rules.go_ahead ? rules.time_count > 0 : true);
+ if ((rules.go_back && time < rules.ats[0]) ||
+ (rules.go_ahead && time > rules.ats[rules.time_count - 1])) {
s64 seconds{};
if (time < rules.ats[0]) {
seconds = rules.ats[0] - time;
@@ -806,9 +911,13 @@ static Result ToCalendarTimeInternal(const TimeZoneRule& rules, s64 time,
calendar_additional_info.is_dst = rules.ttis[tti_index].is_dst;
const char* time_zone{&rules.chars[rules.ttis[tti_index].abbreviation_list_index]};
- for (int index{}; time_zone[index] != '\0'; ++index) {
+ u32 index;
+ for (index = 0; time_zone[index] != '\0' && time_zone[index] != ',' &&
+ index < calendar_additional_info.timezone_name.size() - 1;
+ ++index) {
calendar_additional_info.timezone_name[index] = time_zone[index];
}
+ calendar_additional_info.timezone_name[index] = '\0';
return ResultSuccess;
}
@@ -1038,4 +1147,36 @@ Result TimeZoneManager::GetDeviceLocationName(LocationName& value) const {
return ResultSuccess;
}
+Result TimeZoneManager::GetTotalLocationNameCount(s32& count) const {
+ if (!is_initialized) {
+ return ERROR_UNINITIALIZED_CLOCK;
+ }
+ count = static_cast<u32>(total_location_name_count);
+
+ return ResultSuccess;
+}
+
+Result TimeZoneManager::GetTimeZoneRuleVersion(u128& version) const {
+ if (!is_initialized) {
+ return ERROR_UNINITIALIZED_CLOCK;
+ }
+ version = time_zone_rule_version;
+
+ return ResultSuccess;
+}
+
+Result TimeZoneManager::LoadLocationNameList(std::vector<LocationName>& values) const {
+ if (!is_initialized) {
+ return ERROR_UNINITIALIZED_CLOCK;
+ }
+
+ for (const auto& name : total_location_names) {
+ LocationName entry{};
+ std::memcpy(entry.data(), name.c_str(), name.size());
+ values.push_back(entry);
+ }
+
+ return ResultSuccess;
+}
+
} // namespace Service::Time::TimeZone
diff --git a/src/core/hle/service/time/time_zone_manager.h b/src/core/hle/service/time/time_zone_manager.h
index 5ebd4035e..8664f28d1 100644
--- a/src/core/hle/service/time/time_zone_manager.h
+++ b/src/core/hle/service/time/time_zone_manager.h
@@ -21,6 +21,10 @@ public:
total_location_name_count = value;
}
+ void SetLocationNames(std::vector<std::string> location_names) {
+ total_location_names = location_names;
+ }
+
void SetTimeZoneRuleVersion(const u128& value) {
time_zone_rule_version = value;
}
@@ -33,6 +37,9 @@ public:
FileSys::VirtualFile& vfs_file);
Result SetUpdatedTime(const Clock::SteadyClockTimePoint& value);
Result GetDeviceLocationName(TimeZone::LocationName& value) const;
+ Result GetTotalLocationNameCount(s32& count) const;
+ Result GetTimeZoneRuleVersion(u128& version) const;
+ Result LoadLocationNameList(std::vector<TimeZone::LocationName>& values) const;
Result ToCalendarTime(const TimeZoneRule& rules, s64 time, CalendarInfo& calendar) const;
Result ToCalendarTimeWithMyRules(s64 time, CalendarInfo& calendar) const;
Result ParseTimeZoneRuleBinary(TimeZoneRule& rules, FileSys::VirtualFile& vfs_file) const;
@@ -46,6 +53,7 @@ private:
std::string device_location_name{"GMT"};
u128 time_zone_rule_version{};
std::size_t total_location_name_count{};
+ std::vector<std::string> total_location_names{};
Clock::SteadyClockTimePoint time_zone_update_time_point{
Clock::SteadyClockTimePoint::GetRandom()};
};
diff --git a/src/core/hle/service/time/time_zone_service.cpp b/src/core/hle/service/time/time_zone_service.cpp
index 961040bfc..8171c82a5 100644
--- a/src/core/hle/service/time/time_zone_service.cpp
+++ b/src/core/hle/service/time/time_zone_service.cpp
@@ -2,7 +2,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/logging/log.h"
-#include "core/hle/ipc_helpers.h"
+#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/time/time_zone_content_manager.h"
#include "core/hle/service/time/time_zone_service.h"
#include "core/hle/service/time/time_zone_types.h"
@@ -15,10 +15,10 @@ ITimeZoneService::ITimeZoneService(Core::System& system_,
static const FunctionInfo functions[] = {
{0, &ITimeZoneService::GetDeviceLocationName, "GetDeviceLocationName"},
{1, nullptr, "SetDeviceLocationName"},
- {2, nullptr, "GetTotalLocationNameCount"},
- {3, nullptr, "LoadLocationNameList"},
+ {2, &ITimeZoneService::GetTotalLocationNameCount, "GetTotalLocationNameCount"},
+ {3, &ITimeZoneService::LoadLocationNameList, "LoadLocationNameList"},
{4, &ITimeZoneService::LoadTimeZoneRule, "LoadTimeZoneRule"},
- {5, nullptr, "GetTimeZoneRuleVersion"},
+ {5, &ITimeZoneService::GetTimeZoneRuleVersion, "GetTimeZoneRuleVersion"},
{6, nullptr, "GetDeviceLocationNameAndUpdatedTime"},
{100, &ITimeZoneService::ToCalendarTime, "ToCalendarTime"},
{101, &ITimeZoneService::ToCalendarTimeWithMyRule, "ToCalendarTimeWithMyRule"},
@@ -28,7 +28,7 @@ ITimeZoneService::ITimeZoneService(Core::System& system_,
RegisterHandlers(functions);
}
-void ITimeZoneService::GetDeviceLocationName(Kernel::HLERequestContext& ctx) {
+void ITimeZoneService::GetDeviceLocationName(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called");
TimeZone::LocationName location_name{};
@@ -45,7 +45,58 @@ void ITimeZoneService::GetDeviceLocationName(Kernel::HLERequestContext& ctx) {
rb.PushRaw(location_name);
}
-void ITimeZoneService::LoadTimeZoneRule(Kernel::HLERequestContext& ctx) {
+void ITimeZoneService::GetTotalLocationNameCount(HLERequestContext& ctx) {
+ LOG_DEBUG(Service_Time, "called");
+
+ s32 count{};
+ if (const Result result{
+ time_zone_content_manager.GetTimeZoneManager().GetTotalLocationNameCount(count)};
+ result != ResultSuccess) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+ return;
+ }
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.Push(count);
+}
+
+void ITimeZoneService::LoadLocationNameList(HLERequestContext& ctx) {
+ LOG_DEBUG(Service_Time, "called");
+
+ std::vector<TimeZone::LocationName> location_names{};
+ if (const Result result{
+ time_zone_content_manager.GetTimeZoneManager().LoadLocationNameList(location_names)};
+ result != ResultSuccess) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+ return;
+ }
+
+ ctx.WriteBuffer(location_names);
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.Push(static_cast<s32>(location_names.size()));
+}
+void ITimeZoneService::GetTimeZoneRuleVersion(HLERequestContext& ctx) {
+ LOG_DEBUG(Service_Time, "called");
+
+ u128 rule_version{};
+ if (const Result result{
+ time_zone_content_manager.GetTimeZoneManager().GetTimeZoneRuleVersion(rule_version)};
+ result != ResultSuccess) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+ return;
+ }
+
+ IPC::ResponseBuilder rb{ctx, 6};
+ rb.Push(ResultSuccess);
+ rb.PushRaw(rule_version);
+}
+
+void ITimeZoneService::LoadTimeZoneRule(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto raw_location_name{rp.PopRaw<std::array<u8, 0x24>>()};
@@ -61,23 +112,17 @@ void ITimeZoneService::LoadTimeZoneRule(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called, location_name={}", location_name);
TimeZone::TimeZoneRule time_zone_rule{};
- if (const Result result{
- time_zone_content_manager.LoadTimeZoneRule(time_zone_rule, location_name)};
- result != ResultSuccess) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
- return;
- }
+ const Result result{time_zone_content_manager.LoadTimeZoneRule(time_zone_rule, location_name)};
std::vector<u8> time_zone_rule_outbuffer(sizeof(TimeZone::TimeZoneRule));
std::memcpy(time_zone_rule_outbuffer.data(), &time_zone_rule, sizeof(TimeZone::TimeZoneRule));
ctx.WriteBuffer(time_zone_rule_outbuffer);
IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
+ rb.Push(result);
}
-void ITimeZoneService::ToCalendarTime(Kernel::HLERequestContext& ctx) {
+void ITimeZoneService::ToCalendarTime(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto posix_time{rp.Pop<s64>()};
@@ -101,7 +146,7 @@ void ITimeZoneService::ToCalendarTime(Kernel::HLERequestContext& ctx) {
rb.PushRaw(calendar_info);
}
-void ITimeZoneService::ToCalendarTimeWithMyRule(Kernel::HLERequestContext& ctx) {
+void ITimeZoneService::ToCalendarTimeWithMyRule(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto posix_time{rp.Pop<s64>()};
@@ -122,7 +167,7 @@ void ITimeZoneService::ToCalendarTimeWithMyRule(Kernel::HLERequestContext& ctx)
rb.PushRaw(calendar_info);
}
-void ITimeZoneService::ToPosixTime(Kernel::HLERequestContext& ctx) {
+void ITimeZoneService::ToPosixTime(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called");
IPC::RequestParser rp{ctx};
@@ -147,7 +192,7 @@ void ITimeZoneService::ToPosixTime(Kernel::HLERequestContext& ctx) {
rb.PushRaw<u32>(1); // Number of times we're returning
}
-void ITimeZoneService::ToPosixTimeWithMyRule(Kernel::HLERequestContext& ctx) {
+void ITimeZoneService::ToPosixTimeWithMyRule(HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called");
IPC::RequestParser rp{ctx};
diff --git a/src/core/hle/service/time/time_zone_service.h b/src/core/hle/service/time/time_zone_service.h
index f151f4b56..952fcb0e2 100644
--- a/src/core/hle/service/time/time_zone_service.h
+++ b/src/core/hle/service/time/time_zone_service.h
@@ -21,12 +21,15 @@ public:
TimeZone::TimeZoneContentManager& time_zone_manager_);
private:
- void GetDeviceLocationName(Kernel::HLERequestContext& ctx);
- void LoadTimeZoneRule(Kernel::HLERequestContext& ctx);
- void ToCalendarTime(Kernel::HLERequestContext& ctx);
- void ToCalendarTimeWithMyRule(Kernel::HLERequestContext& ctx);
- void ToPosixTime(Kernel::HLERequestContext& ctx);
- void ToPosixTimeWithMyRule(Kernel::HLERequestContext& ctx);
+ void GetDeviceLocationName(HLERequestContext& ctx);
+ void GetTotalLocationNameCount(HLERequestContext& ctx);
+ void LoadLocationNameList(HLERequestContext& ctx);
+ void GetTimeZoneRuleVersion(HLERequestContext& ctx);
+ void LoadTimeZoneRule(HLERequestContext& ctx);
+ void ToCalendarTime(HLERequestContext& ctx);
+ void ToCalendarTimeWithMyRule(HLERequestContext& ctx);
+ void ToPosixTime(HLERequestContext& ctx);
+ void ToPosixTimeWithMyRule(HLERequestContext& ctx);
private:
TimeZone::TimeZoneContentManager& time_zone_content_manager;
diff --git a/src/core/hle/service/usb/usb.cpp b/src/core/hle/service/usb/usb.cpp
index ac46a406c..f29fff1dd 100644
--- a/src/core/hle/service/usb/usb.cpp
+++ b/src/core/hle/service/usb/usb.cpp
@@ -4,9 +4,9 @@
#include <memory>
#include "common/logging/log.h"
-#include "core/hle/ipc_helpers.h"
+#include "core/hle/service/ipc_helpers.h"
+#include "core/hle/service/server_manager.h"
#include "core/hle/service/service.h"
-#include "core/hle/service/sm/sm.h"
#include "core/hle/service/usb/usb.h"
namespace Service::USB {
@@ -16,19 +16,19 @@ public:
explicit IDsInterface(Core::System& system_) : ServiceFramework{system_, "IDsInterface"} {
// clang-format off
static const FunctionInfo functions[] = {
- {0, nullptr, "BindDevice"},
- {1, nullptr, "BindClientProcess"},
- {2, nullptr, "AddInterface"},
- {3, nullptr, "GetStateChangeEvent"},
- {4, nullptr, "GetState"},
- {5, nullptr, "ClearDeviceData"},
- {6, nullptr, "AddUsbStringDescriptor"},
- {7, nullptr, "DeleteUsbStringDescriptor"},
- {8, nullptr, "SetUsbDeviceDescriptor"},
- {9, nullptr, "SetBinaryObjectStore"},
- {10, nullptr, "Enable"},
- {11, nullptr, "Disable"},
- {12, nullptr, "Unknown12"},
+ {0, nullptr, "AddEndpoint"},
+ {1, nullptr, "GetSetupEvent"},
+ {2, nullptr, "GetSetupPacket"},
+ {3, nullptr, "Enable"},
+ {4, nullptr, "Disable"},
+ {5, nullptr, "CtrlIn"},
+ {6, nullptr, "CtrlOut"},
+ {7, nullptr, "GetCtrlInCompletionEvent"},
+ {8, nullptr, "GetCtrlInUrbReport"},
+ {9, nullptr, "GetCtrlOutCompletionEvent"},
+ {10, nullptr, "GetCtrlOutUrbReport"},
+ {11, nullptr, "CtrlStall"},
+ {12, nullptr, "AppendConfigurationData"},
};
// clang-format on
@@ -36,9 +36,9 @@ public:
}
};
-class USB_DS final : public ServiceFramework<USB_DS> {
+class IDsRootSession final : public ServiceFramework<IDsRootSession> {
public:
- explicit USB_DS(Core::System& system_) : ServiceFramework{system_, "usb:ds"} {
+ explicit IDsRootSession(Core::System& system_) : ServiceFramework{system_, "usb:ds"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "OpenDsService"},
@@ -94,9 +94,9 @@ public:
}
};
-class USB_HS final : public ServiceFramework<USB_HS> {
+class IClientRootSession final : public ServiceFramework<IClientRootSession> {
public:
- explicit USB_HS(Core::System& system_) : ServiceFramework{system_, "usb:hs"} {
+ explicit IClientRootSession(Core::System& system_) : ServiceFramework{system_, "usb:hs"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "BindClientProcess"},
@@ -107,7 +107,7 @@ public:
{5, nullptr, "DestroyInterfaceAvailableEvent"},
{6, nullptr, "GetInterfaceStateChangeEvent"},
{7, nullptr, "AcquireUsbIf"},
- {8, nullptr, "ResetDevice"},
+ {8, nullptr, "SetTestMode"},
};
// clang-format on
@@ -134,12 +134,12 @@ public:
}
};
-class USB_PD final : public ServiceFramework<USB_PD> {
+class IPdManager final : public ServiceFramework<IPdManager> {
public:
- explicit USB_PD(Core::System& system_) : ServiceFramework{system_, "usb:pd"} {
+ explicit IPdManager(Core::System& system_) : ServiceFramework{system_, "usb:pd"} {
// clang-format off
static const FunctionInfo functions[] = {
- {0, &USB_PD::GetPdSession, "GetPdSession"},
+ {0, &IPdManager::OpenSession, "OpenSession"},
};
// clang-format on
@@ -147,7 +147,7 @@ public:
}
private:
- void GetPdSession(Kernel::HLERequestContext& ctx) {
+ void OpenSession(HLERequestContext& ctx) {
LOG_DEBUG(Service_USB, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -178,12 +178,12 @@ public:
}
};
-class USB_PD_C final : public ServiceFramework<USB_PD_C> {
+class IPdCradleManager final : public ServiceFramework<IPdCradleManager> {
public:
- explicit USB_PD_C(Core::System& system_) : ServiceFramework{system_, "usb:pd:c"} {
+ explicit IPdCradleManager(Core::System& system_) : ServiceFramework{system_, "usb:pd:c"} {
// clang-format off
static const FunctionInfo functions[] = {
- {0, &USB_PD_C::GetPdCradleSession, "GetPdCradleSession"},
+ {0, &IPdCradleManager::OpenCradleSession, "OpenCradleSession"},
};
// clang-format on
@@ -191,18 +191,18 @@ public:
}
private:
- void GetPdCradleSession(Kernel::HLERequestContext& ctx) {
+ void OpenCradleSession(HLERequestContext& ctx) {
+ LOG_DEBUG(Service_USB, "called");
+
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IPdCradleSession>(system);
-
- LOG_DEBUG(Service_USB, "called");
}
};
-class USB_PM final : public ServiceFramework<USB_PM> {
+class IPmMainService final : public ServiceFramework<IPmMainService> {
public:
- explicit USB_PM(Core::System& system_) : ServiceFramework{system_, "usb:pm"} {
+ explicit IPmMainService(Core::System& system_) : ServiceFramework{system_, "usb:pm"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "GetPowerEvent"},
@@ -218,12 +218,15 @@ public:
}
};
-void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
- std::make_shared<USB_DS>(system)->InstallAsService(sm);
- std::make_shared<USB_HS>(system)->InstallAsService(sm);
- std::make_shared<USB_PD>(system)->InstallAsService(sm);
- std::make_shared<USB_PD_C>(system)->InstallAsService(sm);
- std::make_shared<USB_PM>(system)->InstallAsService(sm);
+void LoopProcess(Core::System& system) {
+ auto server_manager = std::make_unique<ServerManager>(system);
+
+ server_manager->RegisterNamedService("usb:ds", std::make_shared<IDsRootSession>(system));
+ server_manager->RegisterNamedService("usb:hs", std::make_shared<IClientRootSession>(system));
+ server_manager->RegisterNamedService("usb:pd", std::make_shared<IPdManager>(system));
+ server_manager->RegisterNamedService("usb:pd:c", std::make_shared<IPdCradleManager>(system));
+ server_manager->RegisterNamedService("usb:pm", std::make_shared<IPmMainService>(system));
+ ServerManager::RunServer(std::move(server_manager));
}
} // namespace Service::USB
diff --git a/src/core/hle/service/usb/usb.h b/src/core/hle/service/usb/usb.h
index b41b9684c..98376ebc0 100644
--- a/src/core/hle/service/usb/usb.h
+++ b/src/core/hle/service/usb/usb.h
@@ -7,12 +7,8 @@ namespace Core {
class System;
}
-namespace Service::SM {
-class ServiceManager;
-}
-
namespace Service::USB {
-void InstallInterfaces(SM::ServiceManager& sm, Core::System& system);
+void LoopProcess(Core::System& system);
} // namespace Service::USB
diff --git a/src/core/hle/service/vi/display/vi_display.cpp b/src/core/hle/service/vi/display/vi_display.cpp
index 8ef74f1f0..69af2868a 100644
--- a/src/core/hle/service/vi/display/vi_display.cpp
+++ b/src/core/hle/service/vi/display/vi_display.cpp
@@ -12,11 +12,11 @@
#include "core/hle/kernel/k_readable_event.h"
#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/nvdrv/core/container.h"
-#include "core/hle/service/nvflinger/buffer_item_consumer.h"
-#include "core/hle/service/nvflinger/buffer_queue_consumer.h"
-#include "core/hle/service/nvflinger/buffer_queue_core.h"
-#include "core/hle/service/nvflinger/buffer_queue_producer.h"
-#include "core/hle/service/nvflinger/hos_binder_driver_server.h"
+#include "core/hle/service/nvnflinger/buffer_item_consumer.h"
+#include "core/hle/service/nvnflinger/buffer_queue_consumer.h"
+#include "core/hle/service/nvnflinger/buffer_queue_core.h"
+#include "core/hle/service/nvnflinger/buffer_queue_producer.h"
+#include "core/hle/service/nvnflinger/hos_binder_driver_server.h"
#include "core/hle/service/vi/display/vi_display.h"
#include "core/hle/service/vi/layer/vi_layer.h"
#include "core/hle/service/vi/vi_results.h"
@@ -39,7 +39,7 @@ static BufferQueue CreateBufferQueue(KernelHelpers::ServiceContext& service_cont
}
Display::Display(u64 id, std::string name_,
- NVFlinger::HosBinderDriverServer& hos_binder_driver_server_,
+ Nvnflinger::HosBinderDriverServer& hos_binder_driver_server_,
KernelHelpers::ServiceContext& service_context_, Core::System& system_)
: display_id{id}, name{std::move(name_)}, hos_binder_driver_server{hos_binder_driver_server_},
service_context{service_context_} {
diff --git a/src/core/hle/service/vi/display/vi_display.h b/src/core/hle/service/vi/display/vi_display.h
index 0b65a65da..3f31d1f32 100644
--- a/src/core/hle/service/vi/display/vi_display.h
+++ b/src/core/hle/service/vi/display/vi_display.h
@@ -23,7 +23,7 @@ namespace Service::KernelHelpers {
class ServiceContext;
}
-namespace Service::NVFlinger {
+namespace Service::Nvnflinger {
class HosBinderDriverServer;
}
@@ -45,12 +45,12 @@ public:
/// Constructs a display with a given unique ID and name.
///
/// @param id The unique ID for this display.
- /// @param hos_binder_driver_server_ NVFlinger HOSBinderDriver server instance.
+ /// @param hos_binder_driver_server_ Nvnflinger HOSBinderDriver server instance.
/// @param service_context_ The ServiceContext for the owning service.
/// @param name_ The name for this display.
/// @param system_ The global system instance.
///
- Display(u64 id, std::string name_, NVFlinger::HosBinderDriverServer& hos_binder_driver_server_,
+ Display(u64 id, std::string name_, Nvnflinger::HosBinderDriverServer& hos_binder_driver_server_,
KernelHelpers::ServiceContext& service_context_, Core::System& system_);
~Display();
@@ -133,7 +133,7 @@ public:
private:
u64 display_id;
std::string name;
- NVFlinger::HosBinderDriverServer& hos_binder_driver_server;
+ Nvnflinger::HosBinderDriverServer& hos_binder_driver_server;
KernelHelpers::ServiceContext& service_context;
std::vector<std::unique_ptr<Layer>> layers;
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index bb283e74e..1b193f00c 100644
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -17,15 +17,16 @@
#include "common/settings.h"
#include "common/swap.h"
#include "core/core_timing.h"
-#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/k_readable_event.h"
#include "core/hle/kernel/k_thread.h"
+#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/nvdrv/nvdata.h"
-#include "core/hle/service/nvflinger/binder.h"
-#include "core/hle/service/nvflinger/buffer_queue_producer.h"
-#include "core/hle/service/nvflinger/hos_binder_driver_server.h"
-#include "core/hle/service/nvflinger/nvflinger.h"
-#include "core/hle/service/nvflinger/parcel.h"
+#include "core/hle/service/nvnflinger/binder.h"
+#include "core/hle/service/nvnflinger/buffer_queue_producer.h"
+#include "core/hle/service/nvnflinger/hos_binder_driver_server.h"
+#include "core/hle/service/nvnflinger/nvnflinger.h"
+#include "core/hle/service/nvnflinger/parcel.h"
+#include "core/hle/service/server_manager.h"
#include "core/hle/service/service.h"
#include "core/hle/service/vi/vi.h"
#include "core/hle/service/vi/vi_m.h"
@@ -63,8 +64,8 @@ public:
private:
const u32 magic = 2;
const u32 process_id = 1;
- const u32 id;
- INSERT_PADDING_WORDS(3);
+ const u64 id;
+ INSERT_PADDING_WORDS(2);
std::array<u8, 8> dispdrv = {'d', 'i', 's', 'p', 'd', 'r', 'v', '\0'};
INSERT_PADDING_WORDS(2);
};
@@ -72,9 +73,8 @@ static_assert(sizeof(NativeWindow) == 0x28, "NativeWindow has wrong size");
class IHOSBinderDriver final : public ServiceFramework<IHOSBinderDriver> {
public:
- explicit IHOSBinderDriver(Core::System& system_, NVFlinger::HosBinderDriverServer& server_)
- : ServiceFramework{system_, "IHOSBinderDriver", ServiceThreadType::CreateNew},
- server(server_) {
+ explicit IHOSBinderDriver(Core::System& system_, Nvnflinger::HosBinderDriverServer& server_)
+ : ServiceFramework{system_, "IHOSBinderDriver"}, server(server_) {
static const FunctionInfo functions[] = {
{0, &IHOSBinderDriver::TransactParcel, "TransactParcel"},
{1, &IHOSBinderDriver::AdjustRefcount, "AdjustRefcount"},
@@ -85,7 +85,7 @@ public:
}
private:
- void TransactParcel(Kernel::HLERequestContext& ctx) {
+ void TransactParcel(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u32 id = rp.Pop<u32>();
const auto transaction = static_cast<android::TransactionId>(rp.Pop<u32>());
@@ -100,7 +100,7 @@ private:
rb.Push(ResultSuccess);
}
- void AdjustRefcount(Kernel::HLERequestContext& ctx) {
+ void AdjustRefcount(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u32 id = rp.Pop<u32>();
const s32 addval = rp.PopRaw<s32>();
@@ -113,7 +113,7 @@ private:
rb.Push(ResultSuccess);
}
- void GetNativeHandle(Kernel::HLERequestContext& ctx) {
+ void GetNativeHandle(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u32 id = rp.Pop<u32>();
const u32 unknown = rp.Pop<u32>();
@@ -126,7 +126,7 @@ private:
}
private:
- NVFlinger::HosBinderDriverServer& server;
+ Nvnflinger::HosBinderDriverServer& server;
};
class ISystemDisplayService final : public ServiceFramework<ISystemDisplayService> {
@@ -186,7 +186,7 @@ public:
}
private:
- void SetLayerZ(Kernel::HLERequestContext& ctx) {
+ void SetLayerZ(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u64 layer_id = rp.Pop<u64>();
const u64 z_value = rp.Pop<u64>();
@@ -200,7 +200,7 @@ private:
// This function currently does nothing but return a success error code in
// the vi library itself, so do the same thing, but log out the passed in values.
- void SetLayerVisibility(Kernel::HLERequestContext& ctx) {
+ void SetLayerVisibility(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u64 layer_id = rp.Pop<u64>();
const bool visibility = rp.Pop<bool>();
@@ -211,7 +211,7 @@ private:
rb.Push(ResultSuccess);
}
- void GetDisplayMode(Kernel::HLERequestContext& ctx) {
+ void GetDisplayMode(HLERequestContext& ctx) {
LOG_WARNING(Service_VI, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 6};
@@ -232,7 +232,7 @@ private:
class IManagerDisplayService final : public ServiceFramework<IManagerDisplayService> {
public:
- explicit IManagerDisplayService(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_)
+ explicit IManagerDisplayService(Core::System& system_, Nvnflinger::Nvnflinger& nv_flinger_)
: ServiceFramework{system_, "IManagerDisplayService"}, nv_flinger{nv_flinger_} {
// clang-format off
static const FunctionInfo functions[] = {
@@ -249,6 +249,9 @@ public:
{2053, nullptr, "DestroyIndirectProducerEndPoint"},
{2054, nullptr, "CreateIndirectConsumerEndPoint"},
{2055, nullptr, "DestroyIndirectConsumerEndPoint"},
+ {2060, nullptr, "CreateWatermarkCompositor"},
+ {2062, nullptr, "SetWatermarkText"},
+ {2063, nullptr, "SetWatermarkLayerStacks"},
{2300, nullptr, "AcquireLayerTexturePresentingEvent"},
{2301, nullptr, "ReleaseLayerTexturePresentingEvent"},
{2302, nullptr, "GetDisplayHotplugEvent"},
@@ -279,6 +282,8 @@ public:
{6011, nullptr, "EnableLayerAutoClearTransitionBuffer"},
{6012, nullptr, "DisableLayerAutoClearTransitionBuffer"},
{6013, nullptr, "SetLayerOpacity"},
+ {6014, nullptr, "AttachLayerWatermarkCompositor"},
+ {6015, nullptr, "DetachLayerWatermarkCompositor"},
{7000, nullptr, "SetContentVisibility"},
{8000, nullptr, "SetConductorLayer"},
{8001, nullptr, "SetTimestampTracking"},
@@ -320,7 +325,7 @@ public:
}
private:
- void CloseDisplay(Kernel::HLERequestContext& ctx) {
+ void CloseDisplay(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u64 display = rp.Pop<u64>();
@@ -330,7 +335,7 @@ private:
rb.Push(rc);
}
- void CreateManagedLayer(Kernel::HLERequestContext& ctx) {
+ void CreateManagedLayer(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u32 unknown = rp.Pop<u32>();
rp.Skip(1, false);
@@ -354,7 +359,7 @@ private:
rb.Push(*layer_id);
}
- void AddToLayerStack(Kernel::HLERequestContext& ctx) {
+ void AddToLayerStack(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u32 stack = rp.Pop<u32>();
const u64 layer_id = rp.Pop<u64>();
@@ -366,7 +371,7 @@ private:
rb.Push(ResultSuccess);
}
- void SetLayerVisibility(Kernel::HLERequestContext& ctx) {
+ void SetLayerVisibility(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u64 layer_id = rp.Pop<u64>();
const bool visibility = rp.Pop<bool>();
@@ -378,13 +383,13 @@ private:
rb.Push(ResultSuccess);
}
- NVFlinger::NVFlinger& nv_flinger;
+ Nvnflinger::Nvnflinger& nv_flinger;
};
class IApplicationDisplayService final : public ServiceFramework<IApplicationDisplayService> {
public:
- IApplicationDisplayService(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_,
- NVFlinger::HosBinderDriverServer& hos_binder_driver_server_)
+ IApplicationDisplayService(Core::System& system_, Nvnflinger::Nvnflinger& nv_flinger_,
+ Nvnflinger::HosBinderDriverServer& hos_binder_driver_server_)
: ServiceFramework{system_, "IApplicationDisplayService"}, nv_flinger{nv_flinger_},
hos_binder_driver_server{hos_binder_driver_server_} {
@@ -435,7 +440,7 @@ private:
PreserveAspectRatio = 4,
};
- void GetRelayService(Kernel::HLERequestContext& ctx) {
+ void GetRelayService(HLERequestContext& ctx) {
LOG_WARNING(Service_VI, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -443,7 +448,7 @@ private:
rb.PushIpcInterface<IHOSBinderDriver>(system, hos_binder_driver_server);
}
- void GetSystemDisplayService(Kernel::HLERequestContext& ctx) {
+ void GetSystemDisplayService(HLERequestContext& ctx) {
LOG_WARNING(Service_VI, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -451,7 +456,7 @@ private:
rb.PushIpcInterface<ISystemDisplayService>(system);
}
- void GetManagerDisplayService(Kernel::HLERequestContext& ctx) {
+ void GetManagerDisplayService(HLERequestContext& ctx) {
LOG_WARNING(Service_VI, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -459,7 +464,7 @@ private:
rb.PushIpcInterface<IManagerDisplayService>(system, nv_flinger);
}
- void GetIndirectDisplayTransactionService(Kernel::HLERequestContext& ctx) {
+ void GetIndirectDisplayTransactionService(HLERequestContext& ctx) {
LOG_WARNING(Service_VI, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@@ -467,7 +472,7 @@ private:
rb.PushIpcInterface<IHOSBinderDriver>(system, hos_binder_driver_server);
}
- void OpenDisplay(Kernel::HLERequestContext& ctx) {
+ void OpenDisplay(HLERequestContext& ctx) {
LOG_WARNING(Service_VI, "(STUBBED) called");
IPC::RequestParser rp{ctx};
@@ -476,13 +481,13 @@ private:
OpenDisplayImpl(ctx, std::string_view{name_buf.data(), name_buf.size()});
}
- void OpenDefaultDisplay(Kernel::HLERequestContext& ctx) {
+ void OpenDefaultDisplay(HLERequestContext& ctx) {
LOG_DEBUG(Service_VI, "called");
OpenDisplayImpl(ctx, "Default");
}
- void OpenDisplayImpl(Kernel::HLERequestContext& ctx, std::string_view name) {
+ void OpenDisplayImpl(HLERequestContext& ctx, std::string_view name) {
const auto trim_pos = name.find('\0');
if (trim_pos != std::string_view::npos) {
@@ -504,7 +509,7 @@ private:
rb.Push<u64>(*display_id);
}
- void CloseDisplay(Kernel::HLERequestContext& ctx) {
+ void CloseDisplay(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u64 display_id = rp.Pop<u64>();
@@ -516,14 +521,14 @@ private:
// This literally does nothing internally in the actual service itself,
// and just returns a successful result code regardless of the input.
- void SetDisplayEnabled(Kernel::HLERequestContext& ctx) {
+ void SetDisplayEnabled(HLERequestContext& ctx) {
LOG_DEBUG(Service_VI, "called.");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
- void GetDisplayResolution(Kernel::HLERequestContext& ctx) {
+ void GetDisplayResolution(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u64 display_id = rp.Pop<u64>();
@@ -539,7 +544,7 @@ private:
rb.Push(static_cast<u64>(DisplayResolution::UndockedHeight));
}
- void SetLayerScalingMode(Kernel::HLERequestContext& ctx) {
+ void SetLayerScalingMode(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto scaling_mode = rp.PopEnum<NintendoScaleMode>();
const u64 unknown = rp.Pop<u64>();
@@ -565,7 +570,7 @@ private:
rb.Push(ResultSuccess);
}
- void ListDisplays(Kernel::HLERequestContext& ctx) {
+ void ListDisplays(HLERequestContext& ctx) {
LOG_WARNING(Service_VI, "(STUBBED) called");
const DisplayInfo display_info;
@@ -575,7 +580,7 @@ private:
rb.Push<u64>(1);
}
- void OpenLayer(Kernel::HLERequestContext& ctx) {
+ void OpenLayer(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto name_buf = rp.PopRaw<std::array<u8, 0x40>>();
const auto end = std::find(name_buf.begin(), name_buf.end(), '\0');
@@ -603,7 +608,9 @@ private:
return;
}
- const auto parcel = android::Parcel{NativeWindow{*buffer_queue_id}};
+ android::OutputParcel parcel;
+ parcel.WriteInterface(NativeWindow{*buffer_queue_id});
+
const auto buffer_size = ctx.WriteBuffer(parcel.Serialize());
IPC::ResponseBuilder rb{ctx, 4};
@@ -611,7 +618,7 @@ private:
rb.Push<u64>(buffer_size);
}
- void CloseLayer(Kernel::HLERequestContext& ctx) {
+ void CloseLayer(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto layer_id{rp.Pop<u64>()};
@@ -623,7 +630,7 @@ private:
rb.Push(ResultSuccess);
}
- void CreateStrayLayer(Kernel::HLERequestContext& ctx) {
+ void CreateStrayLayer(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u32 flags = rp.Pop<u32>();
rp.Pop<u32>(); // padding
@@ -649,7 +656,9 @@ private:
return;
}
- const auto parcel = android::Parcel{NativeWindow{*buffer_queue_id}};
+ android::OutputParcel parcel;
+ parcel.WriteInterface(NativeWindow{*buffer_queue_id});
+
const auto buffer_size = ctx.WriteBuffer(parcel.Serialize());
IPC::ResponseBuilder rb{ctx, 6};
@@ -658,7 +667,7 @@ private:
rb.Push<u64>(buffer_size);
}
- void DestroyStrayLayer(Kernel::HLERequestContext& ctx) {
+ void DestroyStrayLayer(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u64 layer_id = rp.Pop<u64>();
@@ -668,7 +677,7 @@ private:
rb.Push(ResultSuccess);
}
- void GetDisplayVsyncEvent(Kernel::HLERequestContext& ctx) {
+ void GetDisplayVsyncEvent(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u64 display_id = rp.Pop<u64>();
@@ -691,7 +700,7 @@ private:
rb.PushCopyObjects(*vsync_event);
}
- void ConvertScalingMode(Kernel::HLERequestContext& ctx) {
+ void ConvertScalingMode(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto mode = rp.PopEnum<NintendoScaleMode>();
LOG_DEBUG(Service_VI, "called mode={}", mode);
@@ -708,7 +717,7 @@ private:
}
}
- void GetIndirectLayerImageMap(Kernel::HLERequestContext& ctx) {
+ void GetIndirectLayerImageMap(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto width = rp.Pop<s64>();
const auto height = rp.Pop<s64>();
@@ -734,7 +743,7 @@ private:
rb.Push(ResultSuccess);
}
- void GetIndirectLayerImageRequiredMemoryInfo(Kernel::HLERequestContext& ctx) {
+ void GetIndirectLayerImageRequiredMemoryInfo(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto width = rp.Pop<u64>();
const auto height = rp.Pop<u64>();
@@ -769,8 +778,8 @@ private:
}
}
- NVFlinger::NVFlinger& nv_flinger;
- NVFlinger::HosBinderDriverServer& hos_binder_driver_server;
+ Nvnflinger::Nvnflinger& nv_flinger;
+ Nvnflinger::HosBinderDriverServer& hos_binder_driver_server;
};
static bool IsValidServiceAccess(Permission permission, Policy policy) {
@@ -785,9 +794,9 @@ static bool IsValidServiceAccess(Permission permission, Policy policy) {
return false;
}
-void detail::GetDisplayServiceImpl(Kernel::HLERequestContext& ctx, Core::System& system,
- NVFlinger::NVFlinger& nv_flinger,
- NVFlinger::HosBinderDriverServer& hos_binder_driver_server,
+void detail::GetDisplayServiceImpl(HLERequestContext& ctx, Core::System& system,
+ Nvnflinger::Nvnflinger& nv_flinger,
+ Nvnflinger::HosBinderDriverServer& hos_binder_driver_server,
Permission permission) {
IPC::RequestParser rp{ctx};
const auto policy = rp.PopEnum<Policy>();
@@ -804,15 +813,17 @@ void detail::GetDisplayServiceImpl(Kernel::HLERequestContext& ctx, Core::System&
rb.PushIpcInterface<IApplicationDisplayService>(system, nv_flinger, hos_binder_driver_server);
}
-void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system,
- NVFlinger::NVFlinger& nv_flinger,
- NVFlinger::HosBinderDriverServer& hos_binder_driver_server) {
- std::make_shared<VI_M>(system, nv_flinger, hos_binder_driver_server)
- ->InstallAsService(service_manager);
- std::make_shared<VI_S>(system, nv_flinger, hos_binder_driver_server)
- ->InstallAsService(service_manager);
- std::make_shared<VI_U>(system, nv_flinger, hos_binder_driver_server)
- ->InstallAsService(service_manager);
+void LoopProcess(Core::System& system, Nvnflinger::Nvnflinger& nv_flinger,
+ Nvnflinger::HosBinderDriverServer& hos_binder_driver_server) {
+ auto server_manager = std::make_unique<ServerManager>(system);
+
+ server_manager->RegisterNamedService(
+ "vi:m", std::make_shared<VI_M>(system, nv_flinger, hos_binder_driver_server));
+ server_manager->RegisterNamedService(
+ "vi:s", std::make_shared<VI_S>(system, nv_flinger, hos_binder_driver_server));
+ server_manager->RegisterNamedService(
+ "vi:u", std::make_shared<VI_U>(system, nv_flinger, hos_binder_driver_server));
+ ServerManager::RunServer(std::move(server_manager));
}
} // namespace Service::VI
diff --git a/src/core/hle/service/vi/vi.h b/src/core/hle/service/vi/vi.h
index fc2d717e7..a35b62f97 100644
--- a/src/core/hle/service/vi/vi.h
+++ b/src/core/hle/service/vi/vi.h
@@ -9,18 +9,14 @@ namespace Core {
class System;
}
-namespace Kernel {
+namespace Service {
class HLERequestContext;
}
-namespace Service::NVFlinger {
+namespace Service::Nvnflinger {
class HosBinderDriverServer;
-class NVFlinger;
-} // namespace Service::NVFlinger
-
-namespace Service::SM {
-class ServiceManager;
-}
+class Nvnflinger;
+} // namespace Service::Nvnflinger
namespace Service::VI {
@@ -46,15 +42,13 @@ enum class Policy {
};
namespace detail {
-void GetDisplayServiceImpl(Kernel::HLERequestContext& ctx, Core::System& system,
- NVFlinger::NVFlinger& nv_flinger,
- NVFlinger::HosBinderDriverServer& hos_binder_driver_server,
+void GetDisplayServiceImpl(HLERequestContext& ctx, Core::System& system,
+ Nvnflinger::Nvnflinger& nv_flinger,
+ Nvnflinger::HosBinderDriverServer& hos_binder_driver_server,
Permission permission);
} // namespace detail
-/// Registers all VI services with the specified service manager.
-void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system,
- NVFlinger::NVFlinger& nv_flinger,
- NVFlinger::HosBinderDriverServer& hos_binder_driver_server);
+void LoopProcess(Core::System& system, Nvnflinger::Nvnflinger& nv_flinger,
+ Nvnflinger::HosBinderDriverServer& hos_binder_driver_server);
} // namespace Service::VI
diff --git a/src/core/hle/service/vi/vi_m.cpp b/src/core/hle/service/vi/vi_m.cpp
index 1ab7fe4ab..0f06dc2f3 100644
--- a/src/core/hle/service/vi/vi_m.cpp
+++ b/src/core/hle/service/vi/vi_m.cpp
@@ -7,20 +7,24 @@
namespace Service::VI {
-VI_M::VI_M(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_,
- NVFlinger::HosBinderDriverServer& hos_binder_driver_server_)
+VI_M::VI_M(Core::System& system_, Nvnflinger::Nvnflinger& nv_flinger_,
+ Nvnflinger::HosBinderDriverServer& hos_binder_driver_server_)
: ServiceFramework{system_, "vi:m"}, nv_flinger{nv_flinger_}, hos_binder_driver_server{
hos_binder_driver_server_} {
static const FunctionInfo functions[] = {
{2, &VI_M::GetDisplayService, "GetDisplayService"},
{3, nullptr, "GetDisplayServiceWithProxyNameExchange"},
+ {100, nullptr, "PrepareFatal"},
+ {101, nullptr, "ShowFatal"},
+ {102, nullptr, "DrawFatalRectangle"},
+ {103, nullptr, "DrawFatalText32"},
};
RegisterHandlers(functions);
}
VI_M::~VI_M() = default;
-void VI_M::GetDisplayService(Kernel::HLERequestContext& ctx) {
+void VI_M::GetDisplayService(HLERequestContext& ctx) {
LOG_DEBUG(Service_VI, "called");
detail::GetDisplayServiceImpl(ctx, system, nv_flinger, hos_binder_driver_server,
diff --git a/src/core/hle/service/vi/vi_m.h b/src/core/hle/service/vi/vi_m.h
index 3bf76d439..9ca6f3905 100644
--- a/src/core/hle/service/vi/vi_m.h
+++ b/src/core/hle/service/vi/vi_m.h
@@ -9,28 +9,24 @@ namespace Core {
class System;
}
-namespace Kernel {
-class HLERequestContext;
-}
-
-namespace Service::NVFlinger {
+namespace Service::Nvnflinger {
class HosBinderDriverServer;
-class NVFlinger;
-} // namespace Service::NVFlinger
+class Nvnflinger;
+} // namespace Service::Nvnflinger
namespace Service::VI {
class VI_M final : public ServiceFramework<VI_M> {
public:
- explicit VI_M(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_,
- NVFlinger::HosBinderDriverServer& hos_binder_driver_server_);
+ explicit VI_M(Core::System& system_, Nvnflinger::Nvnflinger& nv_flinger_,
+ Nvnflinger::HosBinderDriverServer& hos_binder_driver_server_);
~VI_M() override;
private:
- void GetDisplayService(Kernel::HLERequestContext& ctx);
+ void GetDisplayService(HLERequestContext& ctx);
- NVFlinger::NVFlinger& nv_flinger;
- NVFlinger::HosBinderDriverServer& hos_binder_driver_server;
+ Nvnflinger::Nvnflinger& nv_flinger;
+ Nvnflinger::HosBinderDriverServer& hos_binder_driver_server;
};
} // namespace Service::VI
diff --git a/src/core/hle/service/vi/vi_s.cpp b/src/core/hle/service/vi/vi_s.cpp
index fd799dac1..77f7a88ff 100644
--- a/src/core/hle/service/vi/vi_s.cpp
+++ b/src/core/hle/service/vi/vi_s.cpp
@@ -7,8 +7,8 @@
namespace Service::VI {
-VI_S::VI_S(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_,
- NVFlinger::HosBinderDriverServer& hos_binder_driver_server_)
+VI_S::VI_S(Core::System& system_, Nvnflinger::Nvnflinger& nv_flinger_,
+ Nvnflinger::HosBinderDriverServer& hos_binder_driver_server_)
: ServiceFramework{system_, "vi:s"}, nv_flinger{nv_flinger_}, hos_binder_driver_server{
hos_binder_driver_server_} {
static const FunctionInfo functions[] = {
@@ -20,7 +20,7 @@ VI_S::VI_S(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_,
VI_S::~VI_S() = default;
-void VI_S::GetDisplayService(Kernel::HLERequestContext& ctx) {
+void VI_S::GetDisplayService(HLERequestContext& ctx) {
LOG_DEBUG(Service_VI, "called");
detail::GetDisplayServiceImpl(ctx, system, nv_flinger, hos_binder_driver_server,
diff --git a/src/core/hle/service/vi/vi_s.h b/src/core/hle/service/vi/vi_s.h
index 97503ac7f..157839c91 100644
--- a/src/core/hle/service/vi/vi_s.h
+++ b/src/core/hle/service/vi/vi_s.h
@@ -9,28 +9,24 @@ namespace Core {
class System;
}
-namespace Kernel {
-class HLERequestContext;
-}
-
-namespace Service::NVFlinger {
+namespace Service::Nvnflinger {
class HosBinderDriverServer;
-class NVFlinger;
-} // namespace Service::NVFlinger
+class Nvnflinger;
+} // namespace Service::Nvnflinger
namespace Service::VI {
class VI_S final : public ServiceFramework<VI_S> {
public:
- explicit VI_S(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_,
- NVFlinger::HosBinderDriverServer& hos_binder_driver_server_);
+ explicit VI_S(Core::System& system_, Nvnflinger::Nvnflinger& nv_flinger_,
+ Nvnflinger::HosBinderDriverServer& hos_binder_driver_server_);
~VI_S() override;
private:
- void GetDisplayService(Kernel::HLERequestContext& ctx);
+ void GetDisplayService(HLERequestContext& ctx);
- NVFlinger::NVFlinger& nv_flinger;
- NVFlinger::HosBinderDriverServer& hos_binder_driver_server;
+ Nvnflinger::Nvnflinger& nv_flinger;
+ Nvnflinger::HosBinderDriverServer& hos_binder_driver_server;
};
} // namespace Service::VI
diff --git a/src/core/hle/service/vi/vi_u.cpp b/src/core/hle/service/vi/vi_u.cpp
index 6cc54bd13..59e13c86b 100644
--- a/src/core/hle/service/vi/vi_u.cpp
+++ b/src/core/hle/service/vi/vi_u.cpp
@@ -7,8 +7,8 @@
namespace Service::VI {
-VI_U::VI_U(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_,
- NVFlinger::HosBinderDriverServer& hos_binder_driver_server_)
+VI_U::VI_U(Core::System& system_, Nvnflinger::Nvnflinger& nv_flinger_,
+ Nvnflinger::HosBinderDriverServer& hos_binder_driver_server_)
: ServiceFramework{system_, "vi:u"}, nv_flinger{nv_flinger_}, hos_binder_driver_server{
hos_binder_driver_server_} {
static const FunctionInfo functions[] = {
@@ -20,7 +20,7 @@ VI_U::VI_U(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_,
VI_U::~VI_U() = default;
-void VI_U::GetDisplayService(Kernel::HLERequestContext& ctx) {
+void VI_U::GetDisplayService(HLERequestContext& ctx) {
LOG_DEBUG(Service_VI, "called");
detail::GetDisplayServiceImpl(ctx, system, nv_flinger, hos_binder_driver_server,
diff --git a/src/core/hle/service/vi/vi_u.h b/src/core/hle/service/vi/vi_u.h
index 797941bd7..5d9ca54c6 100644
--- a/src/core/hle/service/vi/vi_u.h
+++ b/src/core/hle/service/vi/vi_u.h
@@ -9,28 +9,24 @@ namespace Core {
class System;
}
-namespace Kernel {
-class HLERequestContext;
-}
-
-namespace Service::NVFlinger {
+namespace Service::Nvnflinger {
class HosBinderDriverServer;
-class NVFlinger;
-} // namespace Service::NVFlinger
+class Nvnflinger;
+} // namespace Service::Nvnflinger
namespace Service::VI {
class VI_U final : public ServiceFramework<VI_U> {
public:
- explicit VI_U(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_,
- NVFlinger::HosBinderDriverServer& hos_binder_driver_server_);
+ explicit VI_U(Core::System& system_, Nvnflinger::Nvnflinger& nv_flinger_,
+ Nvnflinger::HosBinderDriverServer& hos_binder_driver_server_);
~VI_U() override;
private:
- void GetDisplayService(Kernel::HLERequestContext& ctx);
+ void GetDisplayService(HLERequestContext& ctx);
- NVFlinger::NVFlinger& nv_flinger;
- NVFlinger::HosBinderDriverServer& hos_binder_driver_server;
+ Nvnflinger::Nvnflinger& nv_flinger;
+ Nvnflinger::HosBinderDriverServer& hos_binder_driver_server;
};
} // namespace Service::VI
diff --git a/src/core/hle/service/wlan/wlan.cpp b/src/core/hle/service/wlan/wlan.cpp
deleted file mode 100644
index 226e3034c..000000000
--- a/src/core/hle/service/wlan/wlan.cpp
+++ /dev/null
@@ -1,186 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#include <memory>
-
-#include "core/hle/service/service.h"
-#include "core/hle/service/sm/sm.h"
-#include "core/hle/service/wlan/wlan.h"
-
-namespace Service::WLAN {
-
-class WLANInfra final : public ServiceFramework<WLANInfra> {
-public:
- explicit WLANInfra(Core::System& system_) : ServiceFramework{system_, "wlan:inf"} {
- // clang-format off
- static const FunctionInfo functions[] = {
- {0, nullptr, "OpenMode"},
- {1, nullptr, "CloseMode"},
- {2, nullptr, "GetMacAddress"},
- {3, nullptr, "StartScan"},
- {4, nullptr, "StopScan"},
- {5, nullptr, "Connect"},
- {6, nullptr, "CancelConnect"},
- {7, nullptr, "Disconnect"},
- {8, nullptr, "GetConnectionEvent"},
- {9, nullptr, "GetConnectionStatus"},
- {10, nullptr, "GetState"},
- {11, nullptr, "GetScanResult"},
- {12, nullptr, "GetRssi"},
- {13, nullptr, "ChangeRxAntenna"},
- {14, nullptr, "GetFwVersion"},
- {15, nullptr, "RequestSleep"},
- {16, nullptr, "RequestWakeUp"},
- {17, nullptr, "RequestIfUpDown"},
- {18, nullptr, "Unknown18"},
- {19, nullptr, "Unknown19"},
- {20, nullptr, "Unknown20"},
- {21, nullptr, "Unknown21"},
- {22, nullptr, "Unknown22"},
- {23, nullptr, "Unknown23"},
- {24, nullptr, "Unknown24"},
- {25, nullptr, "Unknown25"},
- {26, nullptr, "Unknown26"},
- {27, nullptr, "Unknown27"},
- {28, nullptr, "Unknown28"},
- {29, nullptr, "Unknown29"},
- {30, nullptr, "Unknown30"},
- {31, nullptr, "Unknown31"},
- {32, nullptr, "Unknown32"},
- {33, nullptr, "Unknown33"},
- {34, nullptr, "Unknown34"},
- {35, nullptr, "Unknown35"},
- {36, nullptr, "Unknown36"},
- {37, nullptr, "Unknown37"},
- {38, nullptr, "Unknown38"},
- };
- // clang-format on
-
- RegisterHandlers(functions);
- }
-};
-
-class WLANLocal final : public ServiceFramework<WLANLocal> {
-public:
- explicit WLANLocal(Core::System& system_) : ServiceFramework{system_, "wlan:lcl"} {
- // clang-format off
- static const FunctionInfo functions[] = {
- {0, nullptr, "Unknown0"},
- {1, nullptr, "Unknown1"},
- {2, nullptr, "Unknown2"},
- {3, nullptr, "Unknown3"},
- {4, nullptr, "Unknown4"},
- {5, nullptr, "Unknown5"},
- {6, nullptr, "GetMacAddress"},
- {7, nullptr, "CreateBss"},
- {8, nullptr, "DestroyBss"},
- {9, nullptr, "StartScan"},
- {10, nullptr, "StopScan"},
- {11, nullptr, "Connect"},
- {12, nullptr, "CancelConnect"},
- {13, nullptr, "Join"},
- {14, nullptr, "CancelJoin"},
- {15, nullptr, "Disconnect"},
- {16, nullptr, "SetBeaconLostCount"},
- {17, nullptr, "Unknown17"},
- {18, nullptr, "Unknown18"},
- {19, nullptr, "Unknown19"},
- {20, nullptr, "GetBssIndicationEvent"},
- {21, nullptr, "GetBssIndicationInfo"},
- {22, nullptr, "GetState"},
- {23, nullptr, "GetAllowedChannels"},
- {24, nullptr, "AddIe"},
- {25, nullptr, "DeleteIe"},
- {26, nullptr, "Unknown26"},
- {27, nullptr, "Unknown27"},
- {28, nullptr, "CreateRxEntry"},
- {29, nullptr, "DeleteRxEntry"},
- {30, nullptr, "Unknown30"},
- {31, nullptr, "Unknown31"},
- {32, nullptr, "AddMatchingDataToRxEntry"},
- {33, nullptr, "RemoveMatchingDataFromRxEntry"},
- {34, nullptr, "GetScanResult"},
- {35, nullptr, "Unknown35"},
- {36, nullptr, "SetActionFrameWithBeacon"},
- {37, nullptr, "CancelActionFrameWithBeacon"},
- {38, nullptr, "CreateRxEntryForActionFrame"},
- {39, nullptr, "DeleteRxEntryForActionFrame"},
- {40, nullptr, "Unknown40"},
- {41, nullptr, "Unknown41"},
- {42, nullptr, "CancelGetActionFrame"},
- {43, nullptr, "GetRssi"},
- {44, nullptr, "Unknown44"},
- {45, nullptr, "Unknown45"},
- {46, nullptr, "Unknown46"},
- {47, nullptr, "Unknown47"},
- {48, nullptr, "Unknown48"},
- {49, nullptr, "Unknown49"},
- {50, nullptr, "Unknown50"},
- {51, nullptr, "Unknown51"},
- };
- // clang-format on
-
- RegisterHandlers(functions);
- }
-};
-
-class WLANLocalGetFrame final : public ServiceFramework<WLANLocalGetFrame> {
-public:
- explicit WLANLocalGetFrame(Core::System& system_) : ServiceFramework{system_, "wlan:lg"} {
- // clang-format off
- static const FunctionInfo functions[] = {
- {0, nullptr, "Unknown"},
- };
- // clang-format on
-
- RegisterHandlers(functions);
- }
-};
-
-class WLANSocketGetFrame final : public ServiceFramework<WLANSocketGetFrame> {
-public:
- explicit WLANSocketGetFrame(Core::System& system_) : ServiceFramework{system_, "wlan:sg"} {
- // clang-format off
- static const FunctionInfo functions[] = {
- {0, nullptr, "Unknown"},
- };
- // clang-format on
-
- RegisterHandlers(functions);
- }
-};
-
-class WLANSocketManager final : public ServiceFramework<WLANSocketManager> {
-public:
- explicit WLANSocketManager(Core::System& system_) : ServiceFramework{system_, "wlan:soc"} {
- // clang-format off
- static const FunctionInfo functions[] = {
- {0, nullptr, "Unknown0"},
- {1, nullptr, "Unknown1"},
- {2, nullptr, "Unknown2"},
- {3, nullptr, "Unknown3"},
- {4, nullptr, "Unknown4"},
- {5, nullptr, "Unknown5"},
- {6, nullptr, "GetMacAddress"},
- {7, nullptr, "SwitchTsfTimerFunction"},
- {8, nullptr, "Unknown8"},
- {9, nullptr, "Unknown9"},
- {10, nullptr, "Unknown10"},
- {11, nullptr, "Unknown11"},
- {12, nullptr, "Unknown12"},
- };
- // clang-format on
-
- RegisterHandlers(functions);
- }
-};
-
-void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
- std::make_shared<WLANInfra>(system)->InstallAsService(sm);
- std::make_shared<WLANLocal>(system)->InstallAsService(sm);
- std::make_shared<WLANLocalGetFrame>(system)->InstallAsService(sm);
- std::make_shared<WLANSocketGetFrame>(system)->InstallAsService(sm);
- std::make_shared<WLANSocketManager>(system)->InstallAsService(sm);
-}
-
-} // namespace Service::WLAN
diff --git a/src/core/hle/service/wlan/wlan.h b/src/core/hle/service/wlan/wlan.h
deleted file mode 100644
index 535c3bf0d..000000000
--- a/src/core/hle/service/wlan/wlan.h
+++ /dev/null
@@ -1,18 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#pragma once
-
-namespace Core {
-class System;
-}
-
-namespace Service::SM {
-class ServiceManager;
-}
-
-namespace Service::WLAN {
-
-void InstallInterfaces(SM::ServiceManager& sm, Core::System& system);
-
-} // namespace Service::WLAN
diff --git a/src/core/internal_network/network.cpp b/src/core/internal_network/network.cpp
index 282ea1ff9..75ac10a9c 100644
--- a/src/core/internal_network/network.cpp
+++ b/src/core/internal_network/network.cpp
@@ -109,6 +109,8 @@ Errno TranslateNativeError(int e) {
return Errno::AGAIN;
case WSAECONNREFUSED:
return Errno::CONNREFUSED;
+ case WSAECONNRESET:
+ return Errno::CONNRESET;
case WSAEHOSTUNREACH:
return Errno::HOSTUNREACH;
case WSAENETDOWN:
@@ -205,6 +207,8 @@ Errno TranslateNativeError(int e) {
return Errno::AGAIN;
case ECONNREFUSED:
return Errno::CONNREFUSED;
+ case ECONNRESET:
+ return Errno::CONNRESET;
case EHOSTUNREACH:
return Errno::HOSTUNREACH;
case ENETDOWN:
@@ -352,7 +356,7 @@ NetworkInstance::~NetworkInstance() {
std::optional<IPv4Address> GetHostIPv4Address() {
const auto network_interface = Network::GetSelectedNetworkInterface();
if (!network_interface.has_value()) {
- LOG_ERROR(Network, "GetSelectedNetworkInterface returned no interface");
+ LOG_DEBUG(Network, "GetSelectedNetworkInterface returned no interface");
return {};
}
@@ -550,7 +554,7 @@ std::pair<s32, Errno> Socket::RecvFrom(int flags, std::vector<u8>& message, Sock
return {-1, GetAndLogLastError()};
}
-std::pair<s32, Errno> Socket::Send(const std::vector<u8>& message, int flags) {
+std::pair<s32, Errno> Socket::Send(std::span<const u8> message, int flags) {
ASSERT(message.size() < static_cast<size_t>(std::numeric_limits<int>::max()));
ASSERT(flags == 0);
@@ -563,12 +567,12 @@ std::pair<s32, Errno> Socket::Send(const std::vector<u8>& message, int flags) {
return {-1, GetAndLogLastError()};
}
-std::pair<s32, Errno> Socket::SendTo(u32 flags, const std::vector<u8>& message,
+std::pair<s32, Errno> Socket::SendTo(u32 flags, std::span<const u8> message,
const SockAddrIn* addr) {
ASSERT(flags == 0);
const sockaddr* to = nullptr;
- const int tolen = addr ? sizeof(sockaddr) : 0;
+ const int to_len = addr ? sizeof(sockaddr) : 0;
sockaddr host_addr_in;
if (addr) {
@@ -577,7 +581,7 @@ std::pair<s32, Errno> Socket::SendTo(u32 flags, const std::vector<u8>& message,
}
const auto result = sendto(fd, reinterpret_cast<const char*>(message.data()),
- static_cast<int>(message.size()), 0, to, tolen);
+ static_cast<int>(message.size()), 0, to, to_len);
if (result != SOCKET_ERROR) {
return {static_cast<s32>(result), Errno::SUCCESS};
}
diff --git a/src/core/internal_network/network.h b/src/core/internal_network/network.h
index 36994c22e..1e09a007a 100644
--- a/src/core/internal_network/network.h
+++ b/src/core/internal_network/network.h
@@ -30,6 +30,7 @@ enum class Errno {
NOTCONN,
AGAIN,
CONNREFUSED,
+ CONNRESET,
HOSTUNREACH,
NETDOWN,
NETUNREACH,
diff --git a/src/core/internal_network/network_interface.cpp b/src/core/internal_network/network_interface.cpp
index 7b8e510a2..4c909a6d3 100644
--- a/src/core/internal_network/network_interface.cpp
+++ b/src/core/internal_network/network_interface.cpp
@@ -200,7 +200,7 @@ std::optional<NetworkInterface> GetSelectedNetworkInterface() {
});
if (res == network_interfaces.end()) {
- LOG_ERROR(Network, "Couldn't find selected interface \"{}\"", selected_network_interface);
+ LOG_DEBUG(Network, "Couldn't find selected interface \"{}\"", selected_network_interface);
return std::nullopt;
}
diff --git a/src/core/internal_network/socket_proxy.cpp b/src/core/internal_network/socket_proxy.cpp
index 1e1c42cea..7a77171c2 100644
--- a/src/core/internal_network/socket_proxy.cpp
+++ b/src/core/internal_network/socket_proxy.cpp
@@ -182,7 +182,7 @@ std::pair<s32, Errno> ProxySocket::ReceivePacket(int flags, std::vector<u8>& mes
return {static_cast<u32>(read_bytes), Errno::SUCCESS};
}
-std::pair<s32, Errno> ProxySocket::Send(const std::vector<u8>& message, int flags) {
+std::pair<s32, Errno> ProxySocket::Send(std::span<const u8> message, int flags) {
LOG_WARNING(Network, "(STUBBED) called");
ASSERT(message.size() < static_cast<size_t>(std::numeric_limits<int>::max()));
ASSERT(flags == 0);
@@ -200,7 +200,7 @@ void ProxySocket::SendPacket(ProxyPacket& packet) {
}
}
-std::pair<s32, Errno> ProxySocket::SendTo(u32 flags, const std::vector<u8>& message,
+std::pair<s32, Errno> ProxySocket::SendTo(u32 flags, std::span<const u8> message,
const SockAddrIn* addr) {
ASSERT(flags == 0);
diff --git a/src/core/internal_network/socket_proxy.h b/src/core/internal_network/socket_proxy.h
index f12b5f567..6e991fa38 100644
--- a/src/core/internal_network/socket_proxy.h
+++ b/src/core/internal_network/socket_proxy.h
@@ -4,6 +4,7 @@
#pragma once
#include <mutex>
+#include <span>
#include <vector>
#include <queue>
@@ -15,9 +16,6 @@ namespace Network {
class ProxySocket : public SocketBase {
public:
- YUZU_NON_COPYABLE(ProxySocket);
- YUZU_NON_MOVEABLE(ProxySocket);
-
explicit ProxySocket(RoomNetwork& room_network_) noexcept;
~ProxySocket() override;
@@ -48,11 +46,11 @@ public:
std::pair<s32, Errno> ReceivePacket(int flags, std::vector<u8>& message, SockAddrIn* addr,
std::size_t max_length);
- std::pair<s32, Errno> Send(const std::vector<u8>& message, int flags) override;
+ std::pair<s32, Errno> Send(std::span<const u8> message, int flags) override;
void SendPacket(ProxyPacket& packet);
- std::pair<s32, Errno> SendTo(u32 flags, const std::vector<u8>& message,
+ std::pair<s32, Errno> SendTo(u32 flags, std::span<const u8> message,
const SockAddrIn* addr) override;
Errno SetLinger(bool enable, u32 linger) override;
diff --git a/src/core/internal_network/sockets.h b/src/core/internal_network/sockets.h
index 2e328c645..11e479e50 100644
--- a/src/core/internal_network/sockets.h
+++ b/src/core/internal_network/sockets.h
@@ -5,6 +5,7 @@
#include <map>
#include <memory>
+#include <span>
#include <utility>
#if defined(_WIN32)
@@ -35,13 +36,10 @@ public:
SocketBase() = default;
explicit SocketBase(SOCKET fd_) : fd{fd_} {}
-
virtual ~SocketBase() = default;
- virtual SocketBase& operator=(const SocketBase&) = delete;
-
- // Avoid closing sockets implicitly
- virtual SocketBase& operator=(SocketBase&&) noexcept = delete;
+ YUZU_NON_COPYABLE(SocketBase);
+ YUZU_NON_MOVEABLE(SocketBase);
virtual Errno Initialize(Domain domain, Type type, Protocol protocol) = 0;
@@ -66,9 +64,9 @@ public:
virtual std::pair<s32, Errno> RecvFrom(int flags, std::vector<u8>& message,
SockAddrIn* addr) = 0;
- virtual std::pair<s32, Errno> Send(const std::vector<u8>& message, int flags) = 0;
+ virtual std::pair<s32, Errno> Send(std::span<const u8> message, int flags) = 0;
- virtual std::pair<s32, Errno> SendTo(u32 flags, const std::vector<u8>& message,
+ virtual std::pair<s32, Errno> SendTo(u32 flags, std::span<const u8> message,
const SockAddrIn* addr) = 0;
virtual Errno SetLinger(bool enable, u32 linger) = 0;
@@ -108,14 +106,8 @@ public:
~Socket() override;
- Socket(const Socket&) = delete;
- Socket& operator=(const Socket&) = delete;
-
Socket(Socket&& rhs) noexcept;
- // Avoid closing sockets implicitly
- Socket& operator=(Socket&&) noexcept = delete;
-
Errno Initialize(Domain domain, Type type, Protocol protocol) override;
Errno Close() override;
@@ -138,9 +130,9 @@ public:
std::pair<s32, Errno> RecvFrom(int flags, std::vector<u8>& message, SockAddrIn* addr) override;
- std::pair<s32, Errno> Send(const std::vector<u8>& message, int flags) override;
+ std::pair<s32, Errno> Send(std::span<const u8> message, int flags) override;
- std::pair<s32, Errno> SendTo(u32 flags, const std::vector<u8>& message,
+ std::pair<s32, Errno> SendTo(u32 flags, std::span<const u8> message,
const SockAddrIn* addr) override;
Errno SetLinger(bool enable, u32 linger) override;
diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp
index 192571d35..3be9b71cf 100644
--- a/src/core/loader/deconstructed_rom_directory.cpp
+++ b/src/core/loader/deconstructed_rom_directory.cpp
@@ -153,7 +153,7 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect
// Load NSO modules
modules.clear();
- const VAddr base_address{process.PageTable().GetCodeRegionStart()};
+ const VAddr base_address{GetInteger(process.PageTable().GetCodeRegionStart())};
VAddr next_load_addr{base_address};
const FileSys::PatchManager pm{metadata.GetTitleID(), system.GetFileSystemController(),
system.GetContentProvider()};
diff --git a/src/core/loader/kip.cpp b/src/core/loader/kip.cpp
index d8a1bf82a..709e2564f 100644
--- a/src/core/loader/kip.cpp
+++ b/src/core/loader/kip.cpp
@@ -96,7 +96,7 @@ AppLoader::LoadResult AppLoader_KIP::Load(Kernel::KProcess& process,
}
codeset.memory = std::move(program_image);
- const VAddr base_address = process.PageTable().GetCodeRegionStart();
+ const VAddr base_address = GetInteger(process.PageTable().GetCodeRegionStart());
process.LoadModule(std::move(codeset), base_address);
LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", kip->GetName(), base_address);
diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp
index 73d04d7ee..7be6cf5f3 100644
--- a/src/core/loader/nro.cpp
+++ b/src/core/loader/nro.cpp
@@ -33,7 +33,8 @@ static_assert(sizeof(NroSegmentHeader) == 0x8, "NroSegmentHeader has incorrect s
struct NroHeader {
INSERT_PADDING_BYTES(0x4);
u32_le module_header_offset;
- INSERT_PADDING_BYTES(0x8);
+ u32 magic_ext1;
+ u32 magic_ext2;
u32_le magic;
INSERT_PADDING_BYTES(0x4);
u32_le file_size;
@@ -124,6 +125,16 @@ FileType AppLoader_NRO::IdentifyType(const FileSys::VirtualFile& nro_file) {
return FileType::Error;
}
+bool AppLoader_NRO::IsHomebrew() {
+ // Read NSO header
+ NroHeader nro_header{};
+ if (sizeof(NroHeader) != file->ReadObject(&nro_header)) {
+ return false;
+ }
+ return nro_header.magic_ext1 == Common::MakeMagic('H', 'O', 'M', 'E') &&
+ nro_header.magic_ext2 == Common::MakeMagic('B', 'R', 'E', 'W');
+}
+
static constexpr u32 PageAlignSize(u32 size) {
return static_cast<u32>((size + Core::Memory::YUZU_PAGEMASK) & ~Core::Memory::YUZU_PAGEMASK);
}
diff --git a/src/core/loader/nro.h b/src/core/loader/nro.h
index ccb77b581..8de6eebc6 100644
--- a/src/core/loader/nro.h
+++ b/src/core/loader/nro.h
@@ -38,6 +38,8 @@ public:
*/
static FileType IdentifyType(const FileSys::VirtualFile& nro_file);
+ bool IsHomebrew();
+
FileType GetFileType() const override {
return IdentifyType(file);
}
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp
index 4c3b3c655..79639f5e4 100644
--- a/src/core/loader/nso.cpp
+++ b/src/core/loader/nso.cpp
@@ -145,7 +145,7 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::KProcess& process, Core::
// Apply cheats if they exist and the program has a valid title ID
if (pm) {
- system.SetCurrentProcessBuildID(nso_header.build_id);
+ system.SetApplicationProcessBuildID(nso_header.build_id);
const auto cheats = pm->CreateCheatList(nso_header.build_id);
if (!cheats.empty()) {
system.RegisterCheatList(cheats, nso_header.build_id, load_base, image_size);
@@ -167,7 +167,7 @@ AppLoader_NSO::LoadResult AppLoader_NSO::Load(Kernel::KProcess& process, Core::S
modules.clear();
// Load module
- const VAddr base_address = process.PageTable().GetCodeRegionStart();
+ const VAddr base_address = GetInteger(process.PageTable().GetCodeRegionStart());
if (!LoadModule(process, system, *file, base_address, true, true)) {
return {ResultStatus::ErrorLoadingNSO, {}};
}
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index 4e605fae4..514ba0d66 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -13,10 +13,12 @@
#include "common/swap.h"
#include "core/core.h"
#include "core/device_memory.h"
+#include "core/hardware_properties.h"
#include "core/hle/kernel/k_page_table.h"
#include "core/hle/kernel/k_process.h"
#include "core/memory.h"
#include "video_core/gpu.h"
+#include "video_core/rasterizer_download_area.h"
namespace Core::Memory {
@@ -35,31 +37,35 @@ struct Memory::Impl {
system.ArmInterface(core_id).PageTableChanged(*current_page_table, address_space_width);
}
- void MapMemoryRegion(Common::PageTable& page_table, VAddr base, u64 size, PAddr target) {
+ void MapMemoryRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size,
+ Common::PhysicalAddress target) {
ASSERT_MSG((size & YUZU_PAGEMASK) == 0, "non-page aligned size: {:016X}", size);
- ASSERT_MSG((base & YUZU_PAGEMASK) == 0, "non-page aligned base: {:016X}", base);
- ASSERT_MSG(target >= DramMemoryMap::Base, "Out of bounds target: {:016X}", target);
+ ASSERT_MSG((base & YUZU_PAGEMASK) == 0, "non-page aligned base: {:016X}", GetInteger(base));
+ ASSERT_MSG(target >= DramMemoryMap::Base, "Out of bounds target: {:016X}",
+ GetInteger(target));
MapPages(page_table, base / YUZU_PAGESIZE, size / YUZU_PAGESIZE, target,
Common::PageType::Memory);
if (Settings::IsFastmemEnabled()) {
- system.DeviceMemory().buffer.Map(base, target - DramMemoryMap::Base, size);
+ system.DeviceMemory().buffer.Map(GetInteger(base),
+ GetInteger(target) - DramMemoryMap::Base, size);
}
}
- void UnmapRegion(Common::PageTable& page_table, VAddr base, u64 size) {
+ void UnmapRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size) {
ASSERT_MSG((size & YUZU_PAGEMASK) == 0, "non-page aligned size: {:016X}", size);
- ASSERT_MSG((base & YUZU_PAGEMASK) == 0, "non-page aligned base: {:016X}", base);
+ ASSERT_MSG((base & YUZU_PAGEMASK) == 0, "non-page aligned base: {:016X}", GetInteger(base));
MapPages(page_table, base / YUZU_PAGESIZE, size / YUZU_PAGESIZE, 0,
Common::PageType::Unmapped);
if (Settings::IsFastmemEnabled()) {
- system.DeviceMemory().buffer.Unmap(base, size);
+ system.DeviceMemory().buffer.Unmap(GetInteger(base), size);
}
}
- [[nodiscard]] u8* GetPointerFromRasterizerCachedMemory(VAddr vaddr) const {
- const PAddr paddr{current_page_table->backing_addr[vaddr >> YUZU_PAGEBITS]};
+ [[nodiscard]] u8* GetPointerFromRasterizerCachedMemory(u64 vaddr) const {
+ const Common::PhysicalAddress paddr{
+ current_page_table->backing_addr[vaddr >> YUZU_PAGEBITS]};
if (!paddr) {
return {};
@@ -68,8 +74,9 @@ struct Memory::Impl {
return system.DeviceMemory().GetPointer<u8>(paddr) + vaddr;
}
- [[nodiscard]] u8* GetPointerFromDebugMemory(VAddr vaddr) const {
- const PAddr paddr{current_page_table->backing_addr[vaddr >> YUZU_PAGEBITS]};
+ [[nodiscard]] u8* GetPointerFromDebugMemory(u64 vaddr) const {
+ const Common::PhysicalAddress paddr{
+ current_page_table->backing_addr[vaddr >> YUZU_PAGEBITS]};
if (paddr == 0) {
return {};
@@ -78,11 +85,11 @@ struct Memory::Impl {
return system.DeviceMemory().GetPointer<u8>(paddr) + vaddr;
}
- u8 Read8(const VAddr addr) {
+ u8 Read8(const Common::ProcessAddress addr) {
return Read<u8>(addr);
}
- u16 Read16(const VAddr addr) {
+ u16 Read16(const Common::ProcessAddress addr) {
if ((addr & 1) == 0) {
return Read<u16_le>(addr);
} else {
@@ -92,7 +99,7 @@ struct Memory::Impl {
}
}
- u32 Read32(const VAddr addr) {
+ u32 Read32(const Common::ProcessAddress addr) {
if ((addr & 3) == 0) {
return Read<u32_le>(addr);
} else {
@@ -102,7 +109,7 @@ struct Memory::Impl {
}
}
- u64 Read64(const VAddr addr) {
+ u64 Read64(const Common::ProcessAddress addr) {
if ((addr & 7) == 0) {
return Read<u64_le>(addr);
} else {
@@ -112,11 +119,11 @@ struct Memory::Impl {
}
}
- void Write8(const VAddr addr, const u8 data) {
+ void Write8(const Common::ProcessAddress addr, const u8 data) {
Write<u8>(addr, data);
}
- void Write16(const VAddr addr, const u16 data) {
+ void Write16(const Common::ProcessAddress addr, const u16 data) {
if ((addr & 1) == 0) {
Write<u16_le>(addr, data);
} else {
@@ -125,7 +132,7 @@ struct Memory::Impl {
}
}
- void Write32(const VAddr addr, const u32 data) {
+ void Write32(const Common::ProcessAddress addr, const u32 data) {
if ((addr & 3) == 0) {
Write<u32_le>(addr, data);
} else {
@@ -134,7 +141,7 @@ struct Memory::Impl {
}
}
- void Write64(const VAddr addr, const u64 data) {
+ void Write64(const Common::ProcessAddress addr, const u64 data) {
if ((addr & 7) == 0) {
Write<u64_le>(addr, data);
} else {
@@ -143,23 +150,23 @@ struct Memory::Impl {
}
}
- bool WriteExclusive8(const VAddr addr, const u8 data, const u8 expected) {
+ bool WriteExclusive8(const Common::ProcessAddress addr, const u8 data, const u8 expected) {
return WriteExclusive<u8>(addr, data, expected);
}
- bool WriteExclusive16(const VAddr addr, const u16 data, const u16 expected) {
+ bool WriteExclusive16(const Common::ProcessAddress addr, const u16 data, const u16 expected) {
return WriteExclusive<u16_le>(addr, data, expected);
}
- bool WriteExclusive32(const VAddr addr, const u32 data, const u32 expected) {
+ bool WriteExclusive32(const Common::ProcessAddress addr, const u32 data, const u32 expected) {
return WriteExclusive<u32_le>(addr, data, expected);
}
- bool WriteExclusive64(const VAddr addr, const u64 data, const u64 expected) {
+ bool WriteExclusive64(const Common::ProcessAddress addr, const u64 data, const u64 expected) {
return WriteExclusive<u64_le>(addr, data, expected);
}
- std::string ReadCString(VAddr vaddr, std::size_t max_length) {
+ std::string ReadCString(Common::ProcessAddress vaddr, std::size_t max_length) {
std::string string;
string.reserve(max_length);
for (std::size_t i = 0; i < max_length; ++i) {
@@ -174,8 +181,9 @@ struct Memory::Impl {
return string;
}
- void WalkBlock(const Kernel::KProcess& process, const VAddr addr, const std::size_t size,
- auto on_unmapped, auto on_memory, auto on_rasterizer, auto increment) {
+ void WalkBlock(const Kernel::KProcess& process, const Common::ProcessAddress addr,
+ const std::size_t size, auto on_unmapped, auto on_memory, auto on_rasterizer,
+ auto increment) {
const auto& page_table = process.PageTable().PageTableImpl();
std::size_t remaining_size = size;
std::size_t page_index = addr >> YUZU_PAGEBITS;
@@ -185,7 +193,7 @@ struct Memory::Impl {
const std::size_t copy_amount =
std::min(static_cast<std::size_t>(YUZU_PAGESIZE) - page_offset, remaining_size);
const auto current_vaddr =
- static_cast<VAddr>((page_index << YUZU_PAGEBITS) + page_offset);
+ static_cast<u64>((page_index << YUZU_PAGEBITS) + page_offset);
const auto [pointer, type] = page_table.pointers[page_index].PointerType();
switch (type) {
@@ -220,24 +228,24 @@ struct Memory::Impl {
}
template <bool UNSAFE>
- void ReadBlockImpl(const Kernel::KProcess& process, const VAddr src_addr, void* dest_buffer,
- const std::size_t size) {
+ void ReadBlockImpl(const Kernel::KProcess& process, const Common::ProcessAddress src_addr,
+ void* dest_buffer, const std::size_t size) {
WalkBlock(
process, src_addr, size,
[src_addr, size, &dest_buffer](const std::size_t copy_amount,
- const VAddr current_vaddr) {
+ const Common::ProcessAddress current_vaddr) {
LOG_ERROR(HW_Memory,
"Unmapped ReadBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})",
- current_vaddr, src_addr, size);
+ GetInteger(current_vaddr), GetInteger(src_addr), size);
std::memset(dest_buffer, 0, copy_amount);
},
[&](const std::size_t copy_amount, const u8* const src_ptr) {
std::memcpy(dest_buffer, src_ptr, copy_amount);
},
- [&](const VAddr current_vaddr, const std::size_t copy_amount,
+ [&](const Common::ProcessAddress current_vaddr, const std::size_t copy_amount,
const u8* const host_ptr) {
if constexpr (!UNSAFE) {
- system.GPU().FlushRegion(current_vaddr, copy_amount);
+ HandleRasterizerDownload(GetInteger(current_vaddr), copy_amount);
}
std::memcpy(dest_buffer, host_ptr, copy_amount);
},
@@ -246,30 +254,34 @@ struct Memory::Impl {
});
}
- void ReadBlock(const VAddr src_addr, void* dest_buffer, const std::size_t size) {
- ReadBlockImpl<false>(*system.CurrentProcess(), src_addr, dest_buffer, size);
+ void ReadBlock(const Common::ProcessAddress src_addr, void* dest_buffer,
+ const std::size_t size) {
+ ReadBlockImpl<false>(*system.ApplicationProcess(), src_addr, dest_buffer, size);
}
- void ReadBlockUnsafe(const VAddr src_addr, void* dest_buffer, const std::size_t size) {
- ReadBlockImpl<true>(*system.CurrentProcess(), src_addr, dest_buffer, size);
+ void ReadBlockUnsafe(const Common::ProcessAddress src_addr, void* dest_buffer,
+ const std::size_t size) {
+ ReadBlockImpl<true>(*system.ApplicationProcess(), src_addr, dest_buffer, size);
}
template <bool UNSAFE>
- void WriteBlockImpl(const Kernel::KProcess& process, const VAddr dest_addr,
+ void WriteBlockImpl(const Kernel::KProcess& process, const Common::ProcessAddress dest_addr,
const void* src_buffer, const std::size_t size) {
WalkBlock(
process, dest_addr, size,
- [dest_addr, size](const std::size_t copy_amount, const VAddr current_vaddr) {
+ [dest_addr, size](const std::size_t copy_amount,
+ const Common::ProcessAddress current_vaddr) {
LOG_ERROR(HW_Memory,
"Unmapped WriteBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})",
- current_vaddr, dest_addr, size);
+ GetInteger(current_vaddr), GetInteger(dest_addr), size);
},
[&](const std::size_t copy_amount, u8* const dest_ptr) {
std::memcpy(dest_ptr, src_buffer, copy_amount);
},
- [&](const VAddr current_vaddr, const std::size_t copy_amount, u8* const host_ptr) {
+ [&](const Common::ProcessAddress current_vaddr, const std::size_t copy_amount,
+ u8* const host_ptr) {
if constexpr (!UNSAFE) {
- system.GPU().InvalidateRegion(current_vaddr, copy_amount);
+ system.GPU().InvalidateRegion(GetInteger(current_vaddr), copy_amount);
}
std::memcpy(host_ptr, src_buffer, copy_amount);
},
@@ -278,71 +290,77 @@ struct Memory::Impl {
});
}
- void WriteBlock(const VAddr dest_addr, const void* src_buffer, const std::size_t size) {
- WriteBlockImpl<false>(*system.CurrentProcess(), dest_addr, src_buffer, size);
+ void WriteBlock(const Common::ProcessAddress dest_addr, const void* src_buffer,
+ const std::size_t size) {
+ WriteBlockImpl<false>(*system.ApplicationProcess(), dest_addr, src_buffer, size);
}
- void WriteBlockUnsafe(const VAddr dest_addr, const void* src_buffer, const std::size_t size) {
- WriteBlockImpl<true>(*system.CurrentProcess(), dest_addr, src_buffer, size);
+ void WriteBlockUnsafe(const Common::ProcessAddress dest_addr, const void* src_buffer,
+ const std::size_t size) {
+ WriteBlockImpl<true>(*system.ApplicationProcess(), dest_addr, src_buffer, size);
}
- void ZeroBlock(const Kernel::KProcess& process, const VAddr dest_addr, const std::size_t size) {
+ void ZeroBlock(const Kernel::KProcess& process, const Common::ProcessAddress dest_addr,
+ const std::size_t size) {
WalkBlock(
process, dest_addr, size,
- [dest_addr, size](const std::size_t copy_amount, const VAddr current_vaddr) {
+ [dest_addr, size](const std::size_t copy_amount,
+ const Common::ProcessAddress current_vaddr) {
LOG_ERROR(HW_Memory,
"Unmapped ZeroBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})",
- current_vaddr, dest_addr, size);
+ GetInteger(current_vaddr), GetInteger(dest_addr), size);
},
[](const std::size_t copy_amount, u8* const dest_ptr) {
std::memset(dest_ptr, 0, copy_amount);
},
- [&](const VAddr current_vaddr, const std::size_t copy_amount, u8* const host_ptr) {
- system.GPU().InvalidateRegion(current_vaddr, copy_amount);
+ [&](const Common::ProcessAddress current_vaddr, const std::size_t copy_amount,
+ u8* const host_ptr) {
+ system.GPU().InvalidateRegion(GetInteger(current_vaddr), copy_amount);
std::memset(host_ptr, 0, copy_amount);
},
[](const std::size_t copy_amount) {});
}
- void CopyBlock(const Kernel::KProcess& process, VAddr dest_addr, VAddr src_addr,
- const std::size_t size) {
+ void CopyBlock(const Kernel::KProcess& process, Common::ProcessAddress dest_addr,
+ Common::ProcessAddress src_addr, const std::size_t size) {
WalkBlock(
process, dest_addr, size,
- [&](const std::size_t copy_amount, const VAddr current_vaddr) {
+ [&](const std::size_t copy_amount, const Common::ProcessAddress current_vaddr) {
LOG_ERROR(HW_Memory,
"Unmapped CopyBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})",
- current_vaddr, src_addr, size);
+ GetInteger(current_vaddr), GetInteger(src_addr), size);
ZeroBlock(process, dest_addr, copy_amount);
},
[&](const std::size_t copy_amount, const u8* const src_ptr) {
WriteBlockImpl<false>(process, dest_addr, src_ptr, copy_amount);
},
- [&](const VAddr current_vaddr, const std::size_t copy_amount, u8* const host_ptr) {
- system.GPU().FlushRegion(current_vaddr, copy_amount);
+ [&](const Common::ProcessAddress current_vaddr, const std::size_t copy_amount,
+ u8* const host_ptr) {
+ HandleRasterizerDownload(GetInteger(current_vaddr), copy_amount);
WriteBlockImpl<false>(process, dest_addr, host_ptr, copy_amount);
},
[&](const std::size_t copy_amount) {
- dest_addr += static_cast<VAddr>(copy_amount);
- src_addr += static_cast<VAddr>(copy_amount);
+ dest_addr += copy_amount;
+ src_addr += copy_amount;
});
}
template <typename Callback>
- Result PerformCacheOperation(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size,
- Callback&& cb) {
+ Result PerformCacheOperation(const Kernel::KProcess& process, Common::ProcessAddress dest_addr,
+ std::size_t size, Callback&& cb) {
class InvalidMemoryException : public std::exception {};
try {
WalkBlock(
process, dest_addr, size,
- [&](const std::size_t block_size, const VAddr current_vaddr) {
- LOG_ERROR(HW_Memory, "Unmapped cache maintenance @ {:#018X}", current_vaddr);
+ [&](const std::size_t block_size, const Common::ProcessAddress current_vaddr) {
+ LOG_ERROR(HW_Memory, "Unmapped cache maintenance @ {:#018X}",
+ GetInteger(current_vaddr));
throw InvalidMemoryException();
},
[&](const std::size_t block_size, u8* const host_ptr) {},
- [&](const VAddr current_vaddr, const std::size_t block_size, u8* const host_ptr) {
- cb(current_vaddr, block_size);
- },
+ [&](const Common::ProcessAddress current_vaddr, const std::size_t block_size,
+ u8* const host_ptr) { cb(current_vaddr, block_size); },
[](const std::size_t block_size) {});
} catch (InvalidMemoryException&) {
return Kernel::ResultInvalidCurrentMemory;
@@ -351,34 +369,40 @@ struct Memory::Impl {
return ResultSuccess;
}
- Result InvalidateDataCache(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size) {
- auto on_rasterizer = [&](const VAddr current_vaddr, const std::size_t block_size) {
+ Result InvalidateDataCache(const Kernel::KProcess& process, Common::ProcessAddress dest_addr,
+ std::size_t size) {
+ auto on_rasterizer = [&](const Common::ProcessAddress current_vaddr,
+ const std::size_t block_size) {
// dc ivac: Invalidate to point of coherency
// GPU flush -> CPU invalidate
- system.GPU().FlushRegion(current_vaddr, block_size);
+ HandleRasterizerDownload(GetInteger(current_vaddr), block_size);
};
return PerformCacheOperation(process, dest_addr, size, on_rasterizer);
}
- Result StoreDataCache(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size) {
- auto on_rasterizer = [&](const VAddr current_vaddr, const std::size_t block_size) {
+ Result StoreDataCache(const Kernel::KProcess& process, Common::ProcessAddress dest_addr,
+ std::size_t size) {
+ auto on_rasterizer = [&](const Common::ProcessAddress current_vaddr,
+ const std::size_t block_size) {
// dc cvac: Store to point of coherency
// CPU flush -> GPU invalidate
- system.GPU().InvalidateRegion(current_vaddr, block_size);
+ system.GPU().InvalidateRegion(GetInteger(current_vaddr), block_size);
};
return PerformCacheOperation(process, dest_addr, size, on_rasterizer);
}
- Result FlushDataCache(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size) {
- auto on_rasterizer = [&](const VAddr current_vaddr, const std::size_t block_size) {
+ Result FlushDataCache(const Kernel::KProcess& process, Common::ProcessAddress dest_addr,
+ std::size_t size) {
+ auto on_rasterizer = [&](const Common::ProcessAddress current_vaddr,
+ const std::size_t block_size) {
// dc civac: Store to point of coherency, and invalidate from cache
// CPU flush -> GPU invalidate
- system.GPU().InvalidateRegion(current_vaddr, block_size);
+ system.GPU().InvalidateRegion(GetInteger(current_vaddr), block_size);
};
return PerformCacheOperation(process, dest_addr, size, on_rasterizer);
}
- void MarkRegionDebug(VAddr vaddr, u64 size, bool debug) {
+ void MarkRegionDebug(u64 vaddr, u64 size, bool debug) {
if (vaddr == 0) {
return;
}
@@ -434,13 +458,14 @@ struct Memory::Impl {
}
}
- void RasterizerMarkRegionCached(VAddr vaddr, u64 size, bool cached) {
+ void RasterizerMarkRegionCached(u64 vaddr, u64 size, bool cached) {
if (vaddr == 0) {
return;
}
if (Settings::IsFastmemEnabled()) {
- const bool is_read_enable = !Settings::IsGPULevelExtreme() || !cached;
+ const bool is_read_enable =
+ !Settings::values.use_reactive_flushing.GetValue() || !cached;
system.DeviceMemory().buffer.Protect(vaddr, size, is_read_enable, !cached);
}
@@ -514,10 +539,12 @@ struct Memory::Impl {
* @param target The target address to begin mapping from.
* @param type The page type to map the memory as.
*/
- void MapPages(Common::PageTable& page_table, VAddr base, u64 size, PAddr target,
- Common::PageType type) {
- LOG_DEBUG(HW_Memory, "Mapping {:016X} onto {:016X}-{:016X}", target, base * YUZU_PAGESIZE,
- (base + size) * YUZU_PAGESIZE);
+ void MapPages(Common::PageTable& page_table, Common::ProcessAddress base_address, u64 size,
+ Common::PhysicalAddress target, Common::PageType type) {
+ auto base = GetInteger(base_address);
+
+ LOG_DEBUG(HW_Memory, "Mapping {:016X} onto {:016X}-{:016X}", GetInteger(target),
+ base * YUZU_PAGESIZE, (base + size) * YUZU_PAGESIZE);
// During boot, current_page_table might not be set yet, in which case we need not flush
if (system.IsPoweredOn()) {
@@ -530,7 +557,7 @@ struct Memory::Impl {
}
}
- const VAddr end = base + size;
+ const Common::ProcessAddress end = base + size;
ASSERT_MSG(end <= page_table.pointers.size(), "out of range mapping at {:016X}",
base + page_table.pointers.size());
@@ -548,7 +575,7 @@ struct Memory::Impl {
while (base != end) {
page_table.pointers[base].Store(
system.DeviceMemory().GetPointer<u8>(target) - (base << YUZU_PAGEBITS), type);
- page_table.backing_addr[base] = target - (base << YUZU_PAGEBITS);
+ page_table.backing_addr[base] = GetInteger(target) - (base << YUZU_PAGEBITS);
ASSERT_MSG(page_table.pointers[base].Pointer(),
"memory mapping base yield a nullptr within the table");
@@ -559,9 +586,9 @@ struct Memory::Impl {
}
}
- [[nodiscard]] u8* GetPointerImpl(VAddr vaddr, auto on_unmapped, auto on_rasterizer) const {
+ [[nodiscard]] u8* GetPointerImpl(u64 vaddr, auto on_unmapped, auto on_rasterizer) const {
// AARCH64 masks the upper 16 bit of all memory accesses
- vaddr &= 0xffffffffffffULL;
+ vaddr = vaddr & 0xffffffffffffULL;
if (vaddr >= 1uLL << current_page_table->GetAddressSpaceBits()) {
on_unmapped();
@@ -593,15 +620,18 @@ struct Memory::Impl {
return nullptr;
}
- [[nodiscard]] u8* GetPointer(const VAddr vaddr) const {
+ [[nodiscard]] u8* GetPointer(const Common::ProcessAddress vaddr) const {
return GetPointerImpl(
- vaddr, [vaddr]() { LOG_ERROR(HW_Memory, "Unmapped GetPointer @ 0x{:016X}", vaddr); },
+ GetInteger(vaddr),
+ [vaddr]() {
+ LOG_ERROR(HW_Memory, "Unmapped GetPointer @ 0x{:016X}", GetInteger(vaddr));
+ },
[]() {});
}
- [[nodiscard]] u8* GetPointerSilent(const VAddr vaddr) const {
+ [[nodiscard]] u8* GetPointerSilent(const Common::ProcessAddress vaddr) const {
return GetPointerImpl(
- vaddr, []() {}, []() {});
+ GetInteger(vaddr), []() {}, []() {});
}
/**
@@ -616,14 +646,15 @@ struct Memory::Impl {
* @returns The instance of T read from the specified virtual address.
*/
template <typename T>
- T Read(VAddr vaddr) {
+ T Read(Common::ProcessAddress vaddr) {
T result = 0;
const u8* const ptr = GetPointerImpl(
- vaddr,
+ GetInteger(vaddr),
[vaddr]() {
- LOG_ERROR(HW_Memory, "Unmapped Read{} @ 0x{:016X}", sizeof(T) * 8, vaddr);
+ LOG_ERROR(HW_Memory, "Unmapped Read{} @ 0x{:016X}", sizeof(T) * 8,
+ GetInteger(vaddr));
},
- [&]() { system.GPU().FlushRegion(vaddr, sizeof(T)); });
+ [&]() { HandleRasterizerDownload(GetInteger(vaddr), sizeof(T)); });
if (ptr) {
std::memcpy(&result, ptr, sizeof(T));
}
@@ -640,28 +671,28 @@ struct Memory::Impl {
* is undefined.
*/
template <typename T>
- void Write(VAddr vaddr, const T data) {
+ void Write(Common::ProcessAddress vaddr, const T data) {
u8* const ptr = GetPointerImpl(
- vaddr,
+ GetInteger(vaddr),
[vaddr, data]() {
LOG_ERROR(HW_Memory, "Unmapped Write{} @ 0x{:016X} = 0x{:016X}", sizeof(T) * 8,
- vaddr, static_cast<u64>(data));
+ GetInteger(vaddr), static_cast<u64>(data));
},
- [&]() { system.GPU().InvalidateRegion(vaddr, sizeof(T)); });
+ [&]() { system.GPU().InvalidateRegion(GetInteger(vaddr), sizeof(T)); });
if (ptr) {
std::memcpy(ptr, &data, sizeof(T));
}
}
template <typename T>
- bool WriteExclusive(VAddr vaddr, const T data, const T expected) {
+ bool WriteExclusive(Common::ProcessAddress vaddr, const T data, const T expected) {
u8* const ptr = GetPointerImpl(
- vaddr,
+ GetInteger(vaddr),
[vaddr, data]() {
LOG_ERROR(HW_Memory, "Unmapped WriteExclusive{} @ 0x{:016X} = 0x{:016X}",
- sizeof(T) * 8, vaddr, static_cast<u64>(data));
+ sizeof(T) * 8, GetInteger(vaddr), static_cast<u64>(data));
},
- [&]() { system.GPU().InvalidateRegion(vaddr, sizeof(T)); });
+ [&]() { system.GPU().InvalidateRegion(GetInteger(vaddr), sizeof(T)); });
if (ptr) {
const auto volatile_pointer = reinterpret_cast<volatile T*>(ptr);
return Common::AtomicCompareAndSwap(volatile_pointer, data, expected);
@@ -669,14 +700,14 @@ struct Memory::Impl {
return true;
}
- bool WriteExclusive128(VAddr vaddr, const u128 data, const u128 expected) {
+ bool WriteExclusive128(Common::ProcessAddress vaddr, const u128 data, const u128 expected) {
u8* const ptr = GetPointerImpl(
- vaddr,
+ GetInteger(vaddr),
[vaddr, data]() {
LOG_ERROR(HW_Memory, "Unmapped WriteExclusive128 @ 0x{:016X} = 0x{:016X}{:016X}",
- vaddr, static_cast<u64>(data[1]), static_cast<u64>(data[0]));
+ GetInteger(vaddr), static_cast<u64>(data[1]), static_cast<u64>(data[0]));
},
- [&]() { system.GPU().InvalidateRegion(vaddr, sizeof(u128)); });
+ [&]() { system.GPU().InvalidateRegion(GetInteger(vaddr), sizeof(u128)); });
if (ptr) {
const auto volatile_pointer = reinterpret_cast<volatile u64*>(ptr);
return Common::AtomicCompareAndSwap(volatile_pointer, data, expected);
@@ -684,7 +715,19 @@ struct Memory::Impl {
return true;
}
+ void HandleRasterizerDownload(VAddr address, size_t size) {
+ const size_t core = system.GetCurrentHostThreadID();
+ auto& current_area = rasterizer_areas[core];
+ const VAddr end_address = address + size;
+ if (current_area.start_address <= address && end_address <= current_area.end_address)
+ [[likely]] {
+ return;
+ }
+ current_area = system.GPU().OnCPURead(address, size);
+ }
+
Common::PageTable* current_page_table = nullptr;
+ std::array<VideoCore::RasterizerDownloadArea, Core::Hardware::NUM_CPU_CORES> rasterizer_areas{};
Core::System& system;
};
@@ -702,16 +745,17 @@ void Memory::SetCurrentPageTable(Kernel::KProcess& process, u32 core_id) {
impl->SetCurrentPageTable(process, core_id);
}
-void Memory::MapMemoryRegion(Common::PageTable& page_table, VAddr base, u64 size, PAddr target) {
+void Memory::MapMemoryRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size,
+ Common::PhysicalAddress target) {
impl->MapMemoryRegion(page_table, base, size, target);
}
-void Memory::UnmapRegion(Common::PageTable& page_table, VAddr base, u64 size) {
+void Memory::UnmapRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size) {
impl->UnmapRegion(page_table, base, size);
}
-bool Memory::IsValidVirtualAddress(const VAddr vaddr) const {
- const Kernel::KProcess& process = *system.CurrentProcess();
+bool Memory::IsValidVirtualAddress(const Common::ProcessAddress vaddr) const {
+ const Kernel::KProcess& process = *system.ApplicationProcess();
const auto& page_table = process.PageTable().PageTableImpl();
const size_t page = vaddr >> YUZU_PAGEBITS;
if (page >= page_table.pointers.size()) {
@@ -722,9 +766,9 @@ bool Memory::IsValidVirtualAddress(const VAddr vaddr) const {
type == Common::PageType::DebugMemory;
}
-bool Memory::IsValidVirtualAddressRange(VAddr base, u64 size) const {
- VAddr end = base + size;
- VAddr page = Common::AlignDown(base, YUZU_PAGESIZE);
+bool Memory::IsValidVirtualAddressRange(Common::ProcessAddress base, u64 size) const {
+ Common::ProcessAddress end = base + size;
+ Common::ProcessAddress page = Common::AlignDown(GetInteger(base), YUZU_PAGESIZE);
for (; page < end; page += YUZU_PAGESIZE) {
if (!IsValidVirtualAddress(page)) {
@@ -735,131 +779,121 @@ bool Memory::IsValidVirtualAddressRange(VAddr base, u64 size) const {
return true;
}
-u8* Memory::GetPointer(VAddr vaddr) {
+u8* Memory::GetPointer(Common::ProcessAddress vaddr) {
return impl->GetPointer(vaddr);
}
-u8* Memory::GetPointerSilent(VAddr vaddr) {
+u8* Memory::GetPointerSilent(Common::ProcessAddress vaddr) {
return impl->GetPointerSilent(vaddr);
}
-const u8* Memory::GetPointer(VAddr vaddr) const {
+const u8* Memory::GetPointer(Common::ProcessAddress vaddr) const {
return impl->GetPointer(vaddr);
}
-u8 Memory::Read8(const VAddr addr) {
+u8 Memory::Read8(const Common::ProcessAddress addr) {
return impl->Read8(addr);
}
-u16 Memory::Read16(const VAddr addr) {
+u16 Memory::Read16(const Common::ProcessAddress addr) {
return impl->Read16(addr);
}
-u32 Memory::Read32(const VAddr addr) {
+u32 Memory::Read32(const Common::ProcessAddress addr) {
return impl->Read32(addr);
}
-u64 Memory::Read64(const VAddr addr) {
+u64 Memory::Read64(const Common::ProcessAddress addr) {
return impl->Read64(addr);
}
-void Memory::Write8(VAddr addr, u8 data) {
+void Memory::Write8(Common::ProcessAddress addr, u8 data) {
impl->Write8(addr, data);
}
-void Memory::Write16(VAddr addr, u16 data) {
+void Memory::Write16(Common::ProcessAddress addr, u16 data) {
impl->Write16(addr, data);
}
-void Memory::Write32(VAddr addr, u32 data) {
+void Memory::Write32(Common::ProcessAddress addr, u32 data) {
impl->Write32(addr, data);
}
-void Memory::Write64(VAddr addr, u64 data) {
+void Memory::Write64(Common::ProcessAddress addr, u64 data) {
impl->Write64(addr, data);
}
-bool Memory::WriteExclusive8(VAddr addr, u8 data, u8 expected) {
+bool Memory::WriteExclusive8(Common::ProcessAddress addr, u8 data, u8 expected) {
return impl->WriteExclusive8(addr, data, expected);
}
-bool Memory::WriteExclusive16(VAddr addr, u16 data, u16 expected) {
+bool Memory::WriteExclusive16(Common::ProcessAddress addr, u16 data, u16 expected) {
return impl->WriteExclusive16(addr, data, expected);
}
-bool Memory::WriteExclusive32(VAddr addr, u32 data, u32 expected) {
+bool Memory::WriteExclusive32(Common::ProcessAddress addr, u32 data, u32 expected) {
return impl->WriteExclusive32(addr, data, expected);
}
-bool Memory::WriteExclusive64(VAddr addr, u64 data, u64 expected) {
+bool Memory::WriteExclusive64(Common::ProcessAddress addr, u64 data, u64 expected) {
return impl->WriteExclusive64(addr, data, expected);
}
-bool Memory::WriteExclusive128(VAddr addr, u128 data, u128 expected) {
+bool Memory::WriteExclusive128(Common::ProcessAddress addr, u128 data, u128 expected) {
return impl->WriteExclusive128(addr, data, expected);
}
-std::string Memory::ReadCString(VAddr vaddr, std::size_t max_length) {
+std::string Memory::ReadCString(Common::ProcessAddress vaddr, std::size_t max_length) {
return impl->ReadCString(vaddr, max_length);
}
-void Memory::ReadBlock(const Kernel::KProcess& process, const VAddr src_addr, void* dest_buffer,
+void Memory::ReadBlock(const Common::ProcessAddress src_addr, void* dest_buffer,
const std::size_t size) {
- impl->ReadBlockImpl<false>(process, src_addr, dest_buffer, size);
-}
-
-void Memory::ReadBlock(const VAddr src_addr, void* dest_buffer, const std::size_t size) {
impl->ReadBlock(src_addr, dest_buffer, size);
}
-void Memory::ReadBlockUnsafe(const VAddr src_addr, void* dest_buffer, const std::size_t size) {
+void Memory::ReadBlockUnsafe(const Common::ProcessAddress src_addr, void* dest_buffer,
+ const std::size_t size) {
impl->ReadBlockUnsafe(src_addr, dest_buffer, size);
}
-void Memory::WriteBlock(const Kernel::KProcess& process, VAddr dest_addr, const void* src_buffer,
- std::size_t size) {
- impl->WriteBlockImpl<false>(process, dest_addr, src_buffer, size);
-}
-
-void Memory::WriteBlock(const VAddr dest_addr, const void* src_buffer, const std::size_t size) {
+void Memory::WriteBlock(const Common::ProcessAddress dest_addr, const void* src_buffer,
+ const std::size_t size) {
impl->WriteBlock(dest_addr, src_buffer, size);
}
-void Memory::WriteBlockUnsafe(const VAddr dest_addr, const void* src_buffer,
+void Memory::WriteBlockUnsafe(const Common::ProcessAddress dest_addr, const void* src_buffer,
const std::size_t size) {
impl->WriteBlockUnsafe(dest_addr, src_buffer, size);
}
-void Memory::CopyBlock(const Kernel::KProcess& process, VAddr dest_addr, VAddr src_addr,
+void Memory::CopyBlock(Common::ProcessAddress dest_addr, Common::ProcessAddress src_addr,
const std::size_t size) {
- impl->CopyBlock(process, dest_addr, src_addr, size);
+ impl->CopyBlock(*system.ApplicationProcess(), dest_addr, src_addr, size);
}
-void Memory::ZeroBlock(const Kernel::KProcess& process, VAddr dest_addr, const std::size_t size) {
- impl->ZeroBlock(process, dest_addr, size);
+void Memory::ZeroBlock(Common::ProcessAddress dest_addr, const std::size_t size) {
+ impl->ZeroBlock(*system.ApplicationProcess(), dest_addr, size);
}
-Result Memory::InvalidateDataCache(const Kernel::KProcess& process, VAddr dest_addr,
- const std::size_t size) {
- return impl->InvalidateDataCache(process, dest_addr, size);
+Result Memory::InvalidateDataCache(Common::ProcessAddress dest_addr, const std::size_t size) {
+ return impl->InvalidateDataCache(*system.ApplicationProcess(), dest_addr, size);
}
-Result Memory::StoreDataCache(const Kernel::KProcess& process, VAddr dest_addr,
- const std::size_t size) {
- return impl->StoreDataCache(process, dest_addr, size);
+Result Memory::StoreDataCache(Common::ProcessAddress dest_addr, const std::size_t size) {
+ return impl->StoreDataCache(*system.ApplicationProcess(), dest_addr, size);
}
-Result Memory::FlushDataCache(const Kernel::KProcess& process, VAddr dest_addr,
- const std::size_t size) {
- return impl->FlushDataCache(process, dest_addr, size);
+Result Memory::FlushDataCache(Common::ProcessAddress dest_addr, const std::size_t size) {
+ return impl->FlushDataCache(*system.ApplicationProcess(), dest_addr, size);
}
-void Memory::RasterizerMarkRegionCached(VAddr vaddr, u64 size, bool cached) {
- impl->RasterizerMarkRegionCached(vaddr, size, cached);
+void Memory::RasterizerMarkRegionCached(Common::ProcessAddress vaddr, u64 size, bool cached) {
+ impl->RasterizerMarkRegionCached(GetInteger(vaddr), size, cached);
}
-void Memory::MarkRegionDebug(VAddr vaddr, u64 size, bool debug) {
- impl->MarkRegionDebug(vaddr, size, debug);
+void Memory::MarkRegionDebug(Common::ProcessAddress vaddr, u64 size, bool debug) {
+ impl->MarkRegionDebug(GetInteger(vaddr), size, debug);
}
} // namespace Core::Memory
diff --git a/src/core/memory.h b/src/core/memory.h
index 31fe699d8..72a0be813 100644
--- a/src/core/memory.h
+++ b/src/core/memory.h
@@ -6,7 +6,7 @@
#include <cstddef>
#include <memory>
#include <string>
-#include "common/common_types.h"
+#include "common/typed_address.h"
#include "core/hle/result.h"
namespace Common {
@@ -33,7 +33,7 @@ constexpr u64 YUZU_PAGESIZE = 1ULL << YUZU_PAGEBITS;
constexpr u64 YUZU_PAGEMASK = YUZU_PAGESIZE - 1;
/// Virtual user-space memory regions
-enum : VAddr {
+enum : u64 {
/// TLS (Thread-Local Storage) related.
TLS_ENTRY_SIZE = 0x200,
@@ -74,7 +74,8 @@ public:
* @param target Buffer with the memory backing the mapping. Must be of length at least
* `size`.
*/
- void MapMemoryRegion(Common::PageTable& page_table, VAddr base, u64 size, PAddr target);
+ void MapMemoryRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size,
+ Common::PhysicalAddress target);
/**
* Unmaps a region of the emulated process address space.
@@ -83,7 +84,7 @@ public:
* @param base The address to begin unmapping at.
* @param size The amount of bytes to unmap.
*/
- void UnmapRegion(Common::PageTable& page_table, VAddr base, u64 size);
+ void UnmapRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size);
/**
* Checks whether or not the supplied address is a valid virtual
@@ -93,7 +94,7 @@ public:
*
* @returns True if the given virtual address is valid, false otherwise.
*/
- [[nodiscard]] bool IsValidVirtualAddress(VAddr vaddr) const;
+ [[nodiscard]] bool IsValidVirtualAddress(Common::ProcessAddress vaddr) const;
/**
* Checks whether or not the supplied range of addresses are all valid
@@ -104,7 +105,7 @@ public:
*
* @returns True if all bytes in the given range are valid, false otherwise.
*/
- [[nodiscard]] bool IsValidVirtualAddressRange(VAddr base, u64 size) const;
+ [[nodiscard]] bool IsValidVirtualAddressRange(Common::ProcessAddress base, u64 size) const;
/**
* Gets a pointer to the given address.
@@ -114,11 +115,11 @@ public:
* @returns The pointer to the given address, if the address is valid.
* If the address is not valid, nullptr will be returned.
*/
- u8* GetPointer(VAddr vaddr);
- u8* GetPointerSilent(VAddr vaddr);
+ u8* GetPointer(Common::ProcessAddress vaddr);
+ u8* GetPointerSilent(Common::ProcessAddress vaddr);
template <typename T>
- T* GetPointer(VAddr vaddr) {
+ T* GetPointer(Common::ProcessAddress vaddr) {
return reinterpret_cast<T*>(GetPointer(vaddr));
}
@@ -130,10 +131,10 @@ public:
* @returns The pointer to the given address, if the address is valid.
* If the address is not valid, nullptr will be returned.
*/
- [[nodiscard]] const u8* GetPointer(VAddr vaddr) const;
+ [[nodiscard]] const u8* GetPointer(Common::ProcessAddress vaddr) const;
template <typename T>
- const T* GetPointer(VAddr vaddr) const {
+ const T* GetPointer(Common::ProcessAddress vaddr) const {
return reinterpret_cast<T*>(GetPointer(vaddr));
}
@@ -145,7 +146,7 @@ public:
*
* @returns the read 8-bit unsigned value.
*/
- u8 Read8(VAddr addr);
+ u8 Read8(Common::ProcessAddress addr);
/**
* Reads a 16-bit unsigned value from the current process' address space
@@ -155,7 +156,7 @@ public:
*
* @returns the read 16-bit unsigned value.
*/
- u16 Read16(VAddr addr);
+ u16 Read16(Common::ProcessAddress addr);
/**
* Reads a 32-bit unsigned value from the current process' address space
@@ -165,7 +166,7 @@ public:
*
* @returns the read 32-bit unsigned value.
*/
- u32 Read32(VAddr addr);
+ u32 Read32(Common::ProcessAddress addr);
/**
* Reads a 64-bit unsigned value from the current process' address space
@@ -175,7 +176,7 @@ public:
*
* @returns the read 64-bit value.
*/
- u64 Read64(VAddr addr);
+ u64 Read64(Common::ProcessAddress addr);
/**
* Writes an 8-bit unsigned integer to the given virtual address in
@@ -186,7 +187,7 @@ public:
*
* @post The memory at the given virtual address contains the specified data value.
*/
- void Write8(VAddr addr, u8 data);
+ void Write8(Common::ProcessAddress addr, u8 data);
/**
* Writes a 16-bit unsigned integer to the given virtual address in
@@ -197,7 +198,7 @@ public:
*
* @post The memory range [addr, sizeof(data)) contains the given data value.
*/
- void Write16(VAddr addr, u16 data);
+ void Write16(Common::ProcessAddress addr, u16 data);
/**
* Writes a 32-bit unsigned integer to the given virtual address in
@@ -208,7 +209,7 @@ public:
*
* @post The memory range [addr, sizeof(data)) contains the given data value.
*/
- void Write32(VAddr addr, u32 data);
+ void Write32(Common::ProcessAddress addr, u32 data);
/**
* Writes a 64-bit unsigned integer to the given virtual address in
@@ -219,7 +220,7 @@ public:
*
* @post The memory range [addr, sizeof(data)) contains the given data value.
*/
- void Write64(VAddr addr, u64 data);
+ void Write64(Common::ProcessAddress addr, u64 data);
/**
* Writes a 8-bit unsigned integer to the given virtual address in
@@ -232,7 +233,7 @@ public:
*
* @post The memory range [addr, sizeof(data)) contains the given data value.
*/
- bool WriteExclusive8(VAddr addr, u8 data, u8 expected);
+ bool WriteExclusive8(Common::ProcessAddress addr, u8 data, u8 expected);
/**
* Writes a 16-bit unsigned integer to the given virtual address in
@@ -245,7 +246,7 @@ public:
*
* @post The memory range [addr, sizeof(data)) contains the given data value.
*/
- bool WriteExclusive16(VAddr addr, u16 data, u16 expected);
+ bool WriteExclusive16(Common::ProcessAddress addr, u16 data, u16 expected);
/**
* Writes a 32-bit unsigned integer to the given virtual address in
@@ -258,7 +259,7 @@ public:
*
* @post The memory range [addr, sizeof(data)) contains the given data value.
*/
- bool WriteExclusive32(VAddr addr, u32 data, u32 expected);
+ bool WriteExclusive32(Common::ProcessAddress addr, u32 data, u32 expected);
/**
* Writes a 64-bit unsigned integer to the given virtual address in
@@ -271,7 +272,7 @@ public:
*
* @post The memory range [addr, sizeof(data)) contains the given data value.
*/
- bool WriteExclusive64(VAddr addr, u64 data, u64 expected);
+ bool WriteExclusive64(Common::ProcessAddress addr, u64 data, u64 expected);
/**
* Writes a 128-bit unsigned integer to the given virtual address in
@@ -284,7 +285,7 @@ public:
*
* @post The memory range [addr, sizeof(data)) contains the given data value.
*/
- bool WriteExclusive128(VAddr addr, u128 data, u128 expected);
+ bool WriteExclusive128(Common::ProcessAddress addr, u128 data, u128 expected);
/**
* Reads a null-terminated string from the given virtual address.
@@ -301,27 +302,7 @@ public:
*
* @returns The read string.
*/
- std::string ReadCString(VAddr vaddr, std::size_t max_length);
-
- /**
- * Reads a contiguous block of bytes from a specified process' address space.
- *
- * @param process The process to read the data from.
- * @param src_addr The virtual address to begin reading from.
- * @param dest_buffer The buffer to place the read bytes into.
- * @param size The amount of data to read, in bytes.
- *
- * @note If a size of 0 is specified, then this function reads nothing and
- * no attempts to access memory are made at all.
- *
- * @pre dest_buffer must be at least size bytes in length, otherwise a
- * buffer overrun will occur.
- *
- * @post The range [dest_buffer, size) contains the read bytes from the
- * process' address space.
- */
- void ReadBlock(const Kernel::KProcess& process, VAddr src_addr, void* dest_buffer,
- std::size_t size);
+ std::string ReadCString(Common::ProcessAddress vaddr, std::size_t max_length);
/**
* Reads a contiguous block of bytes from the current process' address space.
@@ -339,7 +320,7 @@ public:
* @post The range [dest_buffer, size) contains the read bytes from the
* current process' address space.
*/
- void ReadBlock(VAddr src_addr, void* dest_buffer, std::size_t size);
+ void ReadBlock(Common::ProcessAddress src_addr, void* dest_buffer, std::size_t size);
/**
* Reads a contiguous block of bytes from the current process' address space.
@@ -358,30 +339,7 @@ public:
* @post The range [dest_buffer, size) contains the read bytes from the
* current process' address space.
*/
- void ReadBlockUnsafe(VAddr src_addr, void* dest_buffer, std::size_t size);
-
- /**
- * Writes a range of bytes into a given process' address space at the specified
- * virtual address.
- *
- * @param process The process to write data into the address space of.
- * @param dest_addr The destination virtual address to begin writing the data at.
- * @param src_buffer The data to write into the process' address space.
- * @param size The size of the data to write, in bytes.
- *
- * @post The address range [dest_addr, size) in the process' address space
- * contains the data that was within src_buffer.
- *
- * @post If an attempt is made to write into an unmapped region of memory, the writes
- * will be ignored and an error will be logged.
- *
- * @post If a write is performed into a region of memory that is considered cached
- * rasterizer memory, will cause the currently active rasterizer to be notified
- * 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::KProcess& process, VAddr dest_addr, const void* src_buffer,
- std::size_t size);
+ void ReadBlockUnsafe(Common::ProcessAddress src_addr, void* dest_buffer, std::size_t size);
/**
* Writes a range of bytes into the current process' address space at the specified
@@ -402,7 +360,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(VAddr dest_addr, const void* src_buffer, std::size_t size);
+ void WriteBlock(Common::ProcessAddress dest_addr, const void* src_buffer, std::size_t size);
/**
* Writes a range of bytes into the current process' address space at the specified
@@ -420,13 +378,13 @@ public:
* will be ignored and an error will be logged.
*
*/
- void WriteBlockUnsafe(VAddr dest_addr, const void* src_buffer, std::size_t size);
+ void WriteBlockUnsafe(Common::ProcessAddress dest_addr, const void* src_buffer,
+ std::size_t size);
/**
* Copies data within a process' address space to another location within the
* same address space.
*
- * @param process The process that will have data copied within its address space.
* @param dest_addr The destination virtual address to begin copying the data into.
* @param src_addr The source virtual address to begin copying the data from.
* @param size The size of the data to copy, in bytes.
@@ -434,54 +392,50 @@ 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::KProcess& process, VAddr dest_addr, VAddr src_addr,
+ void CopyBlock(Common::ProcessAddress dest_addr, Common::ProcessAddress src_addr,
std::size_t size);
/**
* Zeros a range of bytes within the current process' address space at the specified
* virtual address.
*
- * @param process The process that will have data zeroed within its address space.
* @param dest_addr The destination virtual address to zero the data from.
* @param size The size of the range to zero out, in bytes.
*
* @post The range [dest_addr, size) within the process' address space contains the
* value 0.
*/
- void ZeroBlock(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size);
+ void ZeroBlock(Common::ProcessAddress dest_addr, std::size_t size);
/**
* Invalidates a range of bytes within the current process' address space at the specified
* virtual address.
*
- * @param process The process that will have data invalidated within its address space.
* @param dest_addr The destination virtual address to invalidate the data from.
* @param size The size of the range to invalidate, in bytes.
*
*/
- Result InvalidateDataCache(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size);
+ Result InvalidateDataCache(Common::ProcessAddress dest_addr, std::size_t size);
/**
* Stores a range of bytes within the current process' address space at the specified
* virtual address.
*
- * @param process The process that will have data stored within its address space.
* @param dest_addr The destination virtual address to store the data from.
* @param size The size of the range to store, in bytes.
*
*/
- Result StoreDataCache(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size);
+ Result StoreDataCache(Common::ProcessAddress dest_addr, std::size_t size);
/**
* Flushes a range of bytes within the current process' address space at the specified
* virtual address.
*
- * @param process The process that will have data flushed within its address space.
* @param dest_addr The destination virtual address to flush the data from.
* @param size The size of the range to flush, in bytes.
*
*/
- Result FlushDataCache(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size);
+ Result FlushDataCache(Common::ProcessAddress dest_addr, std::size_t size);
/**
* Marks each page within the specified address range as cached or uncached.
@@ -491,7 +445,7 @@ public:
* @param cached Whether or not any pages within the address range should be
* marked as cached or uncached.
*/
- void RasterizerMarkRegionCached(VAddr vaddr, u64 size, bool cached);
+ void RasterizerMarkRegionCached(Common::ProcessAddress vaddr, u64 size, bool cached);
/**
* Marks each page within the specified address range as debug or non-debug.
@@ -502,7 +456,7 @@ public:
* @param debug Whether or not any pages within the address range should be
* marked as debug or non-debug.
*/
- void MarkRegionDebug(VAddr vaddr, u64 size, bool debug);
+ void MarkRegionDebug(Common::ProcessAddress vaddr, u64 size, bool debug);
private:
Core::System& system;
diff --git a/src/core/memory/cheat_engine.cpp b/src/core/memory/cheat_engine.cpp
index ffdbacc18..8742dd164 100644
--- a/src/core/memory/cheat_engine.cpp
+++ b/src/core/memory/cheat_engine.cpp
@@ -39,16 +39,21 @@ StandardVmCallbacks::StandardVmCallbacks(System& system_, const CheatProcessMeta
StandardVmCallbacks::~StandardVmCallbacks() = default;
void StandardVmCallbacks::MemoryRead(VAddr address, void* data, u64 size) {
- system.Memory().ReadBlock(SanitizeAddress(address), data, size);
+ system.ApplicationMemory().ReadBlock(SanitizeAddress(address), data, size);
}
void StandardVmCallbacks::MemoryWrite(VAddr address, const void* data, u64 size) {
- system.Memory().WriteBlock(SanitizeAddress(address), data, size);
+ system.ApplicationMemory().WriteBlock(SanitizeAddress(address), data, size);
}
u64 StandardVmCallbacks::HidKeysDown() {
- const auto applet_resource =
- system.ServiceManager().GetService<Service::HID::Hid>("hid")->GetAppletResource();
+ const auto hid = system.ServiceManager().GetService<Service::HID::Hid>("hid");
+ if (hid == nullptr) {
+ LOG_WARNING(CheatEngine, "Attempted to read input state, but hid is not initialized!");
+ return 0;
+ }
+
+ const auto applet_resource = hid->GetAppletResource();
if (applet_resource == nullptr) {
LOG_WARNING(CheatEngine,
"Attempted to read input state, but applet resource is not initialized!");
@@ -191,22 +196,22 @@ void CheatEngine::Initialize() {
});
core_timing.ScheduleLoopingEvent(CHEAT_ENGINE_NS, CHEAT_ENGINE_NS, event);
- metadata.process_id = system.CurrentProcess()->GetProcessID();
- metadata.title_id = system.GetCurrentProcessProgramID();
+ metadata.process_id = system.ApplicationProcess()->GetProcessId();
+ metadata.title_id = system.GetApplicationProcessProgramID();
- const auto& page_table = system.CurrentProcess()->PageTable();
+ const auto& page_table = system.ApplicationProcess()->PageTable();
metadata.heap_extents = {
- .base = page_table.GetHeapRegionStart(),
+ .base = GetInteger(page_table.GetHeapRegionStart()),
.size = page_table.GetHeapRegionSize(),
};
metadata.address_space_extents = {
- .base = page_table.GetAddressSpaceStart(),
+ .base = GetInteger(page_table.GetAddressSpaceStart()),
.size = page_table.GetAddressSpaceSize(),
};
metadata.alias_extents = {
- .base = page_table.GetAliasCodeRegionStart(),
+ .base = GetInteger(page_table.GetAliasCodeRegionStart()),
.size = page_table.GetAliasCodeRegionSize(),
};
diff --git a/src/core/perf_stats.cpp b/src/core/perf_stats.cpp
index f09c176f8..1231c0dc8 100644
--- a/src/core/perf_stats.cpp
+++ b/src/core/perf_stats.cpp
@@ -126,8 +126,8 @@ double PerfStats::GetLastFrameTimeScale() const {
}
void SpeedLimiter::DoSpeedLimiting(microseconds current_system_time_us) {
- if (!Settings::values.use_speed_limit.GetValue() ||
- Settings::values.use_multi_core.GetValue()) {
+ if (Settings::values.use_multi_core.GetValue() ||
+ !Settings::values.use_speed_limit.GetValue()) {
return;
}
diff --git a/src/core/reporter.cpp b/src/core/reporter.cpp
index 77821e047..6c3dc7369 100644
--- a/src/core/reporter.cpp
+++ b/src/core/reporter.cpp
@@ -17,10 +17,10 @@
#include "common/settings.h"
#include "core/arm/arm_interface.h"
#include "core/core.h"
-#include "core/hle/kernel/hle_ipc.h"
#include "core/hle/kernel/k_page_table.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/result.h"
+#include "core/hle/service/hle_ipc.h"
#include "core/memory.h"
#include "core/reporter.h"
@@ -110,15 +110,15 @@ json GetProcessorStateData(const std::string& architecture, u64 entry_point, u64
}
json GetProcessorStateDataAuto(Core::System& system) {
- const auto* process{system.CurrentProcess()};
+ const auto* process{system.ApplicationProcess()};
auto& arm{system.CurrentArmInterface()};
Core::ARM_Interface::ThreadContext64 context{};
arm.SaveContext(context);
return GetProcessorStateData(process->Is64BitProcess() ? "AArch64" : "AArch32",
- process->PageTable().GetCodeRegionStart(), context.sp, context.pc,
- context.pstate, context.cpu_registers);
+ GetInteger(process->PageTable().GetCodeRegionStart()), context.sp,
+ context.pc, context.pstate, context.cpu_registers);
}
json GetBacktraceData(Core::System& system) {
@@ -170,7 +170,7 @@ json GetHLEBufferDescriptorData(const std::vector<DescriptorType>& buffer,
return buffer_out;
}
-json GetHLERequestContextData(Kernel::HLERequestContext& ctx, Core::Memory::Memory& memory) {
+json GetHLERequestContextData(Service::HLERequestContext& ctx, Core::Memory::Memory& memory) {
json out;
auto cmd_buf = json::array();
@@ -234,7 +234,7 @@ void Reporter::SaveSvcBreakReport(u32 type, bool signal_debugger, u64 info1, u64
}
const auto timestamp = GetTimestamp();
- const auto title_id = system.GetCurrentProcessProgramID();
+ const auto title_id = system.GetApplicationProcessProgramID();
auto out = GetFullDataAuto(timestamp, title_id, system);
auto break_out = json{
@@ -253,7 +253,7 @@ void Reporter::SaveSvcBreakReport(u32 type, bool signal_debugger, u64 info1, u64
SaveToFile(out, GetPath("svc_break_report", title_id, timestamp));
}
-void Reporter::SaveUnimplementedFunctionReport(Kernel::HLERequestContext& ctx, u32 command_id,
+void Reporter::SaveUnimplementedFunctionReport(Service::HLERequestContext& ctx, u32 command_id,
const std::string& name,
const std::string& service_name) const {
if (!IsReportingEnabled()) {
@@ -261,10 +261,10 @@ void Reporter::SaveUnimplementedFunctionReport(Kernel::HLERequestContext& ctx, u
}
const auto timestamp = GetTimestamp();
- const auto title_id = system.GetCurrentProcessProgramID();
+ const auto title_id = system.GetApplicationProcessProgramID();
auto out = GetFullDataAuto(timestamp, title_id, system);
- auto function_out = GetHLERequestContextData(ctx, system.Memory());
+ auto function_out = GetHLERequestContextData(ctx, system.ApplicationMemory());
function_out["command_id"] = command_id;
function_out["function_name"] = name;
function_out["service_name"] = service_name;
@@ -283,7 +283,7 @@ void Reporter::SaveUnimplementedAppletReport(
}
const auto timestamp = GetTimestamp();
- const auto title_id = system.GetCurrentProcessProgramID();
+ const auto title_id = system.GetApplicationProcessProgramID();
auto out = GetFullDataAuto(timestamp, title_id, system);
out["applet_common_args"] = {
@@ -312,7 +312,7 @@ void Reporter::SaveUnimplementedAppletReport(
}
void Reporter::SavePlayReport(PlayReportType type, u64 title_id,
- const std::vector<std::vector<u8>>& data,
+ const std::vector<std::span<const u8>>& data,
std::optional<u64> process_id, std::optional<u128> user_id) const {
if (!IsReportingEnabled()) {
return;
@@ -376,7 +376,7 @@ void Reporter::SaveUserReport() const {
}
const auto timestamp = GetTimestamp();
- const auto title_id = system.GetCurrentProcessProgramID();
+ const auto title_id = system.GetApplicationProcessProgramID();
SaveToFile(GetFullDataAuto(timestamp, title_id, system),
GetPath("user_report", title_id, timestamp));
diff --git a/src/core/reporter.h b/src/core/reporter.h
index 9fdb9d6c1..db1ca3ba0 100644
--- a/src/core/reporter.h
+++ b/src/core/reporter.h
@@ -5,15 +5,16 @@
#include <array>
#include <optional>
+#include <span>
#include <string>
#include <vector>
#include "common/common_types.h"
union Result;
-namespace Kernel {
+namespace Service {
class HLERequestContext;
-} // namespace Kernel
+} // namespace Service
namespace Service::LM {
struct LogMessage;
@@ -39,7 +40,7 @@ public:
const std::optional<std::vector<u8>>& resolved_buffer = {}) const;
// Used by HLE service handler
- void SaveUnimplementedFunctionReport(Kernel::HLERequestContext& ctx, u32 command_id,
+ void SaveUnimplementedFunctionReport(Service::HLERequestContext& ctx, u32 command_id,
const std::string& name,
const std::string& service_name) const;
@@ -56,7 +57,8 @@ public:
System,
};
- void SavePlayReport(PlayReportType type, u64 title_id, const std::vector<std::vector<u8>>& data,
+ void SavePlayReport(PlayReportType type, u64 title_id,
+ const std::vector<std::span<const u8>>& data,
std::optional<u64> process_id = {}, std::optional<u128> user_id = {}) const;
// Used by error applet
diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp
index 8d5f2be2f..7a2f3c90a 100644
--- a/src/core/telemetry_session.cpp
+++ b/src/core/telemetry_session.cpp
@@ -34,7 +34,7 @@ static u64 GenerateTelemetryId() {
mbedtls_entropy_context entropy;
mbedtls_entropy_init(&entropy);
mbedtls_ctr_drbg_context ctr_drbg;
- constexpr std::array<char, 18> personalization{{"yuzu Telemetry ID"}};
+ static constexpr std::array<char, 18> personalization{{"yuzu Telemetry ID"}};
mbedtls_ctr_drbg_init(&ctr_drbg);
ASSERT(mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
@@ -85,6 +85,20 @@ static const char* TranslateNvdecEmulation(Settings::NvdecEmulation backend) {
return "Unknown";
}
+static constexpr const char* TranslateVSyncMode(Settings::VSyncMode mode) {
+ switch (mode) {
+ case Settings::VSyncMode::Immediate:
+ return "Immediate";
+ case Settings::VSyncMode::Mailbox:
+ return "Mailbox";
+ case Settings::VSyncMode::FIFO:
+ return "FIFO";
+ case Settings::VSyncMode::FIFORelaxed:
+ return "FIFO Relaxed";
+ }
+ return "Unknown";
+}
+
u64 GetTelemetryId() {
u64 telemetry_id{};
const auto filename = Common::FS::GetYuzuPath(Common::FS::YuzuPath::ConfigDir) / "telemetry_id";
@@ -241,7 +255,8 @@ void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader,
AddField(field_type, "Renderer_NvdecEmulation",
TranslateNvdecEmulation(Settings::values.nvdec_emulation.GetValue()));
AddField(field_type, "Renderer_AccelerateASTC", Settings::values.accelerate_astc.GetValue());
- AddField(field_type, "Renderer_UseVsync", Settings::values.use_vsync.GetValue());
+ AddField(field_type, "Renderer_UseVsync",
+ TranslateVSyncMode(Settings::values.vsync_mode.GetValue()));
AddField(field_type, "Renderer_ShaderBackend",
static_cast<u32>(Settings::values.shader_backend.GetValue()));
AddField(field_type, "Renderer_UseAsynchronousShaders",