summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
authorGravatar Levi2021-01-10 22:09:56 -0700
committerGravatar Levi2021-01-10 22:09:56 -0700
commit7a3c884e39fccfbb498b855080bffabc9ce2e7f1 (patch)
tree5056f9406dec188439cb0deb87603498243a9412 /src/core
parentMore forgetting... duh (diff)
parentMerge pull request #5229 from Morph1984/fullscreen-opt (diff)
downloadyuzu-7a3c884e39fccfbb498b855080bffabc9ce2e7f1.tar.gz
yuzu-7a3c884e39fccfbb498b855080bffabc9ce2e7f1.tar.xz
yuzu-7a3c884e39fccfbb498b855080bffabc9ce2e7f1.zip
Merge remote-tracking branch 'upstream/master' into int-flags
Diffstat (limited to 'src/core')
-rw-r--r--src/core/CMakeLists.txt59
-rw-r--r--src/core/arm/arm_interface.cpp12
-rw-r--r--src/core/arm/arm_interface.h22
-rw-r--r--src/core/arm/cpu_interrupt_handler.h4
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_32.cpp28
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_32.h2
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_64.cpp60
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_64.h4
-rw-r--r--src/core/arm/unicorn/arm_unicorn.cpp295
-rw-r--r--src/core/arm/unicorn/arm_unicorn.h63
-rw-r--r--src/core/core.cpp169
-rw-r--r--src/core/core.h189
-rw-r--r--src/core/core_timing.h8
-rw-r--r--src/core/cpu_manager.cpp133
-rw-r--r--src/core/crypto/key_manager.cpp13
-rw-r--r--src/core/file_sys/card_image.cpp5
-rw-r--r--src/core/file_sys/card_image.h2
-rw-r--r--src/core/file_sys/common_funcs.h56
-rw-r--r--src/core/file_sys/content_archive.cpp31
-rw-r--r--src/core/file_sys/content_archive.h8
-rw-r--r--src/core/file_sys/fsmitm_romfsbuild.cpp10
-rw-r--r--src/core/file_sys/ips_layer.cpp2
-rw-r--r--src/core/file_sys/nca_metadata.cpp2
-rw-r--r--src/core/file_sys/nca_patch.cpp4
-rw-r--r--src/core/file_sys/nca_patch.h2
-rw-r--r--src/core/file_sys/patch_manager.cpp87
-rw-r--r--src/core/file_sys/patch_manager.h13
-rw-r--r--src/core/file_sys/registered_cache.cpp3
-rw-r--r--src/core/file_sys/registered_cache.h8
-rw-r--r--src/core/file_sys/romfs_factory.cpp28
-rw-r--r--src/core/file_sys/romfs_factory.h4
-rw-r--r--src/core/file_sys/savedata_factory.cpp18
-rw-r--r--src/core/file_sys/savedata_factory.h11
-rw-r--r--src/core/file_sys/submission_package.cpp92
-rw-r--r--src/core/file_sys/submission_package.h5
-rw-r--r--src/core/file_sys/system_archive/data/font_nintendo_extended.cpp555
-rw-r--r--src/core/file_sys/system_archive/data/font_nintendo_extended.h2
-rw-r--r--src/core/file_sys/system_archive/system_version.cpp12
-rw-r--r--src/core/file_sys/vfs.cpp32
-rw-r--r--src/core/file_sys/vfs.h44
-rw-r--r--src/core/file_sys/vfs_concat.cpp18
-rw-r--r--src/core/file_sys/vfs_concat.h2
-rw-r--r--src/core/file_sys/vfs_layered.cpp24
-rw-r--r--src/core/file_sys/vfs_layered.h18
-rw-r--r--src/core/file_sys/vfs_offset.cpp4
-rw-r--r--src/core/file_sys/vfs_offset.h6
-rw-r--r--src/core/file_sys/vfs_real.cpp24
-rw-r--r--src/core/file_sys/vfs_real.h24
-rw-r--r--src/core/file_sys/vfs_static.h2
-rw-r--r--src/core/file_sys/vfs_vector.cpp12
-rw-r--r--src/core/file_sys/vfs_vector.h26
-rw-r--r--src/core/file_sys/xts_archive.cpp6
-rw-r--r--src/core/file_sys/xts_archive.h6
-rw-r--r--src/core/frontend/applets/controller.cpp18
-rw-r--r--src/core/frontend/applets/controller.h12
-rw-r--r--src/core/frontend/applets/error.cpp7
-rw-r--r--src/core/frontend/applets/general_frontend.cpp68
-rw-r--r--src/core/frontend/applets/general_frontend.h51
-rw-r--r--src/core/frontend/applets/web_browser.cpp24
-rw-r--r--src/core/frontend/applets/web_browser.h20
-rw-r--r--src/core/frontend/emu_window.cpp10
-rw-r--r--src/core/frontend/emu_window.h4
-rw-r--r--src/core/frontend/framebuffer_layout.cpp8
-rw-r--r--src/core/frontend/input.h23
-rw-r--r--src/core/frontend/input_interpreter.cpp45
-rw-r--r--src/core/frontend/input_interpreter.h120
-rw-r--r--src/core/gdbstub/gdbstub.cpp1397
-rw-r--r--src/core/gdbstub/gdbstub.h114
-rw-r--r--src/core/hle/ipc_helpers.h95
-rw-r--r--src/core/hle/kernel/address_arbiter.cpp27
-rw-r--r--src/core/hle/kernel/address_arbiter.h3
-rw-r--r--src/core/hle/kernel/global_scheduler_context.cpp52
-rw-r--r--src/core/hle/kernel/global_scheduler_context.h81
-rw-r--r--src/core/hle/kernel/handle_table.cpp6
-rw-r--r--src/core/hle/kernel/hle_ipc.cpp41
-rw-r--r--src/core/hle/kernel/hle_ipc.h23
-rw-r--r--src/core/hle/kernel/k_affinity_mask.h58
-rw-r--r--src/core/hle/kernel/k_priority_queue.h451
-rw-r--r--src/core/hle/kernel/k_scheduler.cpp784
-rw-r--r--src/core/hle/kernel/k_scheduler.h201
-rw-r--r--src/core/hle/kernel/k_scheduler_lock.h75
-rw-r--r--src/core/hle/kernel/k_scoped_lock.h41
-rw-r--r--src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h50
-rw-r--r--src/core/hle/kernel/kernel.cpp201
-rw-r--r--src/core/hle/kernel/kernel.h39
-rw-r--r--src/core/hle/kernel/memory/address_space_info.cpp2
-rw-r--r--src/core/hle/kernel/memory/memory_block.h20
-rw-r--r--src/core/hle/kernel/memory/memory_block_manager.h4
-rw-r--r--src/core/hle/kernel/memory/page_table.cpp19
-rw-r--r--src/core/hle/kernel/mutex.cpp12
-rw-r--r--src/core/hle/kernel/physical_core.cpp52
-rw-r--r--src/core/hle/kernel/physical_core.h44
-rw-r--r--src/core/hle/kernel/process.cpp17
-rw-r--r--src/core/hle/kernel/process.h13
-rw-r--r--src/core/hle/kernel/process_capability.cpp2
-rw-r--r--src/core/hle/kernel/readable_event.cpp4
-rw-r--r--src/core/hle/kernel/resource_limit.cpp4
-rw-r--r--src/core/hle/kernel/scheduler.cpp849
-rw-r--r--src/core/hle/kernel/scheduler.h318
-rw-r--r--src/core/hle/kernel/server_session.cpp36
-rw-r--r--src/core/hle/kernel/server_session.h12
-rw-r--r--src/core/hle/kernel/service_thread.cpp110
-rw-r--r--src/core/hle/kernel/service_thread.h28
-rw-r--r--src/core/hle/kernel/svc.cpp149
-rw-r--r--src/core/hle/kernel/svc_types.h4
-rw-r--r--src/core/hle/kernel/synchronization.cpp11
-rw-r--r--src/core/hle/kernel/synchronization_object.h3
-rw-r--r--src/core/hle/kernel/thread.cpp120
-rw-r--r--src/core/hle/kernel/thread.h120
-rw-r--r--src/core/hle/kernel/time_manager.cpp26
-rw-r--r--src/core/hle/kernel/time_manager.h2
-rw-r--r--src/core/hle/result.h2
-rw-r--r--src/core/hle/service/acc/acc.cpp103
-rw-r--r--src/core/hle/service/acc/acc.h5
-rw-r--r--src/core/hle/service/am/am.cpp159
-rw-r--r--src/core/hle/service/am/am.h44
-rw-r--r--src/core/hle/service/am/applet_ae.cpp56
-rw-r--r--src/core/hle/service/am/applet_ae.h7
-rw-r--r--src/core/hle/service/am/applet_oe.cpp26
-rw-r--r--src/core/hle/service/am/applet_oe.h7
-rw-r--r--src/core/hle/service/am/applets/applets.cpp38
-rw-r--r--src/core/hle/service/am/applets/applets.h20
-rw-r--r--src/core/hle/service/am/applets/controller.cpp109
-rw-r--r--src/core/hle/service/am/applets/controller.h27
-rw-r--r--src/core/hle/service/am/applets/error.cpp8
-rw-r--r--src/core/hle/service/am/applets/general_backend.cpp28
-rw-r--r--src/core/hle/service/am/applets/general_backend.h3
-rw-r--r--src/core/hle/service/am/applets/profile_select.cpp6
-rw-r--r--src/core/hle/service/am/applets/profile_select.h1
-rw-r--r--src/core/hle/service/am/applets/software_keyboard.cpp14
-rw-r--r--src/core/hle/service/am/applets/software_keyboard.h1
-rw-r--r--src/core/hle/service/am/applets/web_browser.cpp792
-rw-r--r--src/core/hle/service/am/applets/web_browser.h80
-rw-r--r--src/core/hle/service/am/applets/web_types.h178
-rw-r--r--src/core/hle/service/am/idle.cpp2
-rw-r--r--src/core/hle/service/am/idle.h6
-rw-r--r--src/core/hle/service/am/omm.cpp2
-rw-r--r--src/core/hle/service/am/omm.h6
-rw-r--r--src/core/hle/service/am/spsm.cpp2
-rw-r--r--src/core/hle/service/am/spsm.h6
-rw-r--r--src/core/hle/service/am/tcap.cpp2
-rw-r--r--src/core/hle/service/am/tcap.h6
-rw-r--r--src/core/hle/service/aoc/aoc_u.cpp96
-rw-r--r--src/core/hle/service/aoc/aoc_u.h7
-rw-r--r--src/core/hle/service/apm/apm.cpp10
-rw-r--r--src/core/hle/service/apm/apm.h4
-rw-r--r--src/core/hle/service/apm/controller.cpp6
-rw-r--r--src/core/hle/service/apm/interface.cpp32
-rw-r--r--src/core/hle/service/apm/interface.h6
-rw-r--r--src/core/hle/service/audio/audctl.cpp2
-rw-r--r--src/core/hle/service/audio/audctl.h6
-rw-r--r--src/core/hle/service/audio/auddbg.cpp2
-rw-r--r--src/core/hle/service/audio/auddbg.h6
-rw-r--r--src/core/hle/service/audio/audin_a.cpp2
-rw-r--r--src/core/hle/service/audio/audin_a.h6
-rw-r--r--src/core/hle/service/audio/audin_u.cpp6
-rw-r--r--src/core/hle/service/audio/audin_u.h6
-rw-r--r--src/core/hle/service/audio/audio.cpp26
-rw-r--r--src/core/hle/service/audio/audout_a.cpp2
-rw-r--r--src/core/hle/service/audio/audout_a.h6
-rw-r--r--src/core/hle/service/audio/audout_u.cpp18
-rw-r--r--src/core/hle/service/audio/audout_u.h2
-rw-r--r--src/core/hle/service/audio/audrec_a.cpp2
-rw-r--r--src/core/hle/service/audio/audrec_a.h6
-rw-r--r--src/core/hle/service/audio/audrec_u.cpp5
-rw-r--r--src/core/hle/service/audio/audrec_u.h6
-rw-r--r--src/core/hle/service/audio/audren_a.cpp2
-rw-r--r--src/core/hle/service/audio/audren_a.h6
-rw-r--r--src/core/hle/service/audio/audren_u.cpp22
-rw-r--r--src/core/hle/service/audio/audren_u.h1
-rw-r--r--src/core/hle/service/audio/codecctl.cpp5
-rw-r--r--src/core/hle/service/audio/codecctl.h6
-rw-r--r--src/core/hle/service/audio/hwopus.cpp9
-rw-r--r--src/core/hle/service/audio/hwopus.h6
-rw-r--r--src/core/hle/service/bcat/backend/backend.cpp2
-rw-r--r--src/core/hle/service/bcat/backend/boxcat.cpp22
-rw-r--r--src/core/hle/service/bcat/module.cpp41
-rw-r--r--src/core/hle/service/bcat/module.h3
-rw-r--r--src/core/hle/service/bpc/bpc.cpp10
-rw-r--r--src/core/hle/service/bpc/bpc.h6
-rw-r--r--src/core/hle/service/btdrv/btdrv.cpp7
-rw-r--r--src/core/hle/service/btm/btm.cpp23
-rw-r--r--src/core/hle/service/caps/caps.cpp14
-rw-r--r--src/core/hle/service/caps/caps.h6
-rw-r--r--src/core/hle/service/caps/caps_a.cpp5
-rw-r--r--src/core/hle/service/caps/caps_a.h6
-rw-r--r--src/core/hle/service/caps/caps_c.cpp21
-rw-r--r--src/core/hle/service/caps/caps_c.h9
-rw-r--r--src/core/hle/service/caps/caps_sc.cpp2
-rw-r--r--src/core/hle/service/caps/caps_sc.h6
-rw-r--r--src/core/hle/service/caps/caps_ss.cpp2
-rw-r--r--src/core/hle/service/caps/caps_ss.h6
-rw-r--r--src/core/hle/service/caps/caps_su.cpp9
-rw-r--r--src/core/hle/service/caps/caps_su.h6
-rw-r--r--src/core/hle/service/caps/caps_u.cpp46
-rw-r--r--src/core/hle/service/caps/caps_u.h8
-rw-r--r--src/core/hle/service/erpt/erpt.cpp10
-rw-r--r--src/core/hle/service/erpt/erpt.h6
-rw-r--r--src/core/hle/service/es/es.cpp6
-rw-r--r--src/core/hle/service/es/es.h6
-rw-r--r--src/core/hle/service/eupld/eupld.cpp10
-rw-r--r--src/core/hle/service/eupld/eupld.h6
-rw-r--r--src/core/hle/service/fatal/fatal.cpp10
-rw-r--r--src/core/hle/service/fatal/fatal.h4
-rw-r--r--src/core/hle/service/fatal/fatal_p.cpp4
-rw-r--r--src/core/hle/service/fatal/fatal_p.h2
-rw-r--r--src/core/hle/service/fatal/fatal_u.cpp4
-rw-r--r--src/core/hle/service/fatal/fatal_u.h2
-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.cpp60
-rw-r--r--src/core/hle/service/filesystem/filesystem.h4
-rw-r--r--src/core/hle/service/filesystem/fsp_ldr.cpp2
-rw-r--r--src/core/hle/service/filesystem/fsp_ldr.h6
-rw-r--r--src/core/hle/service/filesystem/fsp_pr.cpp2
-rw-r--r--src/core/hle/service/filesystem/fsp_pr.h6
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.cpp114
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.h7
-rw-r--r--src/core/hle/service/friend/friend.cpp17
-rw-r--r--src/core/hle/service/friend/friend.h4
-rw-r--r--src/core/hle/service/friend/interface.cpp4
-rw-r--r--src/core/hle/service/friend/interface.h2
-rw-r--r--src/core/hle/service/glue/arp.cpp14
-rw-r--r--src/core/hle/service/glue/arp.h6
-rw-r--r--src/core/hle/service/glue/bgtc.cpp4
-rw-r--r--src/core/hle/service/glue/bgtc.h8
-rw-r--r--src/core/hle/service/glue/glue.cpp4
-rw-r--r--src/core/hle/service/grc/grc.cpp6
-rw-r--r--src/core/hle/service/grc/grc.h6
-rw-r--r--src/core/hle/service/hid/controllers/controller_base.h4
-rw-r--r--src/core/hle/service/hid/controllers/keyboard.cpp4
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp621
-rw-r--r--src/core/hle/service/hid/controllers/npad.h157
-rw-r--r--src/core/hle/service/hid/hid.cpp797
-rw-r--r--src/core/hle/service/hid/hid.h50
-rw-r--r--src/core/hle/service/hid/irs.cpp4
-rw-r--r--src/core/hle/service/hid/irs.h10
-rw-r--r--src/core/hle/service/hid/xcd.cpp2
-rw-r--r--src/core/hle/service/hid/xcd.h6
-rw-r--r--src/core/hle/service/lbl/lbl.cpp6
-rw-r--r--src/core/hle/service/lbl/lbl.h6
-rw-r--r--src/core/hle/service/ldn/ldn.cpp29
-rw-r--r--src/core/hle/service/ldn/ldn.h6
-rw-r--r--src/core/hle/service/ldr/ldr.cpp41
-rw-r--r--src/core/hle/service/ldr/ldr.h4
-rw-r--r--src/core/hle/service/lm/lm.cpp19
-rw-r--r--src/core/hle/service/mig/mig.cpp6
-rw-r--r--src/core/hle/service/mig/mig.h6
-rw-r--r--src/core/hle/service/mii/manager.cpp6
-rw-r--r--src/core/hle/service/mii/mii.cpp19
-rw-r--r--src/core/hle/service/mii/mii.h6
-rw-r--r--src/core/hle/service/mm/mm_u.cpp7
-rw-r--r--src/core/hle/service/mm/mm_u.h10
-rw-r--r--src/core/hle/service/ncm/ncm.cpp22
-rw-r--r--src/core/hle/service/ncm/ncm.h6
-rw-r--r--src/core/hle/service/nfc/nfc.cpp34
-rw-r--r--src/core/hle/service/nfc/nfc.h6
-rw-r--r--src/core/hle/service/nfp/nfp.cpp9
-rw-r--r--src/core/hle/service/nfp/nfp.h4
-rw-r--r--src/core/hle/service/nfp/nfp_user.cpp4
-rw-r--r--src/core/hle/service/nfp/nfp_user.h2
-rw-r--r--src/core/hle/service/nifm/nifm.cpp37
-rw-r--r--src/core/hle/service/nifm/nifm.h8
-rw-r--r--src/core/hle/service/nim/nim.cpp48
-rw-r--r--src/core/hle/service/nim/nim.h8
-rw-r--r--src/core/hle/service/npns/npns.cpp10
-rw-r--r--src/core/hle/service/npns/npns.h6
-rw-r--r--src/core/hle/service/ns/ns.cpp76
-rw-r--r--src/core/hle/service/ns/ns.h40
-rw-r--r--src/core/hle/service/ns/pl_u.cpp55
-rw-r--r--src/core/hle/service/ns/pl_u.h22
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdevice.h36
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp21
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdisp_disp0.h8
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp165
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h109
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp121
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl.h113
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp192
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h55
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp294
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_gpu.h169
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp73
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec.h33
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp244
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h170
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp42
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h18
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_vic.cpp65
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_vic.h37
-rw-r--r--src/core/hle/service/nvdrv/devices/nvmap.cpp119
-rw-r--r--src/core/hle/service/nvdrv/devices/nvmap.h69
-rw-r--r--src/core/hle/service/nvdrv/interface.cpp200
-rw-r--r--src/core/hle/service/nvdrv/interface.h10
-rw-r--r--src/core/hle/service/nvdrv/nvdata.h86
-rw-r--r--src/core/hle/service/nvdrv/nvdrv.cpp131
-rw-r--r--src/core/hle/service/nvdrv/nvdrv.h39
-rw-r--r--src/core/hle/service/nvdrv/nvmemp.cpp2
-rw-r--r--src/core/hle/service/nvdrv/nvmemp.h6
-rw-r--r--src/core/hle/service/nvdrv/syncpoint_manager.cpp39
-rw-r--r--src/core/hle/service/nvdrv/syncpoint_manager.h85
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue.cpp168
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue.h23
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.cpp38
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.h9
-rw-r--r--src/core/hle/service/olsc/olsc.cpp69
-rw-r--r--src/core/hle/service/olsc/olsc.h20
-rw-r--r--src/core/hle/service/pcie/pcie.cpp8
-rw-r--r--src/core/hle/service/pcie/pcie.h6
-rw-r--r--src/core/hle/service/pctl/module.cpp21
-rw-r--r--src/core/hle/service/pctl/module.h9
-rw-r--r--src/core/hle/service/pctl/pctl.cpp4
-rw-r--r--src/core/hle/service/pctl/pctl.h6
-rw-r--r--src/core/hle/service/pcv/pcv.cpp14
-rw-r--r--src/core/hle/service/pcv/pcv.h6
-rw-r--r--src/core/hle/service/pm/pm.cpp24
-rw-r--r--src/core/hle/service/prepo/prepo.cpp10
-rw-r--r--src/core/hle/service/prepo/prepo.h8
-rw-r--r--src/core/hle/service/psc/psc.cpp14
-rw-r--r--src/core/hle/service/psc/psc.h6
-rw-r--r--src/core/hle/service/ptm/psm.cpp6
-rw-r--r--src/core/hle/service/ptm/psm.h6
-rw-r--r--src/core/hle/service/service.cpp134
-rw-r--r--src/core/hle/service/service.h55
-rw-r--r--src/core/hle/service/set/set.cpp3
-rw-r--r--src/core/hle/service/set/set.h6
-rw-r--r--src/core/hle/service/set/set_cal.cpp2
-rw-r--r--src/core/hle/service/set/set_cal.h6
-rw-r--r--src/core/hle/service/set/set_fd.cpp2
-rw-r--r--src/core/hle/service/set/set_fd.h6
-rw-r--r--src/core/hle/service/set/set_sys.cpp8
-rw-r--r--src/core/hle/service/set/set_sys.h6
-rw-r--r--src/core/hle/service/set/settings.cpp11
-rw-r--r--src/core/hle/service/set/settings.h10
-rw-r--r--src/core/hle/service/sm/controller.cpp2
-rw-r--r--src/core/hle/service/sm/controller.h6
-rw-r--r--src/core/hle/service/sm/sm.cpp14
-rw-r--r--src/core/hle/service/sm/sm.h8
-rw-r--r--src/core/hle/service/sockets/blocking_worker.h161
-rw-r--r--src/core/hle/service/sockets/bsd.cpp140
-rw-r--r--src/core/hle/service/sockets/bsd.h13
-rw-r--r--src/core/hle/service/sockets/ethc.cpp4
-rw-r--r--src/core/hle/service/sockets/ethc.h8
-rw-r--r--src/core/hle/service/sockets/nsd.cpp2
-rw-r--r--src/core/hle/service/sockets/nsd.h7
-rw-r--r--src/core/hle/service/sockets/sfdnsres.cpp38
-rw-r--r--src/core/hle/service/sockets/sfdnsres.h6
-rw-r--r--src/core/hle/service/sockets/sockets.cpp12
-rw-r--r--src/core/hle/service/sockets/sockets.h23
-rw-r--r--src/core/hle/service/sockets/sockets_translate.cpp59
-rw-r--r--src/core/hle/service/sockets/sockets_translate.h4
-rw-r--r--src/core/hle/service/spl/csrng.cpp3
-rw-r--r--src/core/hle/service/spl/csrng.h6
-rw-r--r--src/core/hle/service/spl/module.cpp11
-rw-r--r--src/core/hle/service/spl/module.h9
-rw-r--r--src/core/hle/service/spl/spl.cpp3
-rw-r--r--src/core/hle/service/spl/spl.h6
-rw-r--r--src/core/hle/service/ssl/ssl.cpp14
-rw-r--r--src/core/hle/service/ssl/ssl.h6
-rw-r--r--src/core/hle/service/time/interface.cpp2
-rw-r--r--src/core/hle/service/time/time.cpp46
-rw-r--r--src/core/hle/service/time/time.h13
-rw-r--r--src/core/hle/service/time/time_manager.cpp359
-rw-r--r--src/core/hle/service/time/time_manager.h85
-rw-r--r--src/core/hle/service/time/time_zone_content_manager.cpp5
-rw-r--r--src/core/hle/service/time/time_zone_content_manager.h4
-rw-r--r--src/core/hle/service/time/time_zone_manager.cpp21
-rw-r--r--src/core/hle/service/time/time_zone_service.cpp5
-rw-r--r--src/core/hle/service/time/time_zone_service.h7
-rw-r--r--src/core/hle/service/usb/usb.cpp39
-rw-r--r--src/core/hle/service/usb/usb.h6
-rw-r--r--src/core/hle/service/vi/vi.cpp199
-rw-r--r--src/core/hle/service/vi/vi.h12
-rw-r--r--src/core/hle/service/vi/vi_m.cpp6
-rw-r--r--src/core/hle/service/vi/vi_m.h8
-rw-r--r--src/core/hle/service/vi/vi_s.cpp6
-rw-r--r--src/core/hle/service/vi/vi_s.h8
-rw-r--r--src/core/hle/service/vi/vi_u.cpp6
-rw-r--r--src/core/hle/service/vi/vi_u.h8
-rw-r--r--src/core/hle/service/wlan/wlan.cpp22
-rw-r--r--src/core/hle/service/wlan/wlan.h6
-rw-r--r--src/core/loader/deconstructed_rom_directory.cpp9
-rw-r--r--src/core/loader/deconstructed_rom_directory.h2
-rw-r--r--src/core/loader/elf.h2
-rw-r--r--src/core/loader/kip.cpp5
-rw-r--r--src/core/loader/kip.h2
-rw-r--r--src/core/loader/loader.cpp33
-rw-r--r--src/core/loader/loader.h12
-rw-r--r--src/core/loader/nax.h2
-rw-r--r--src/core/loader/nca.h2
-rw-r--r--src/core/loader/nro.cpp8
-rw-r--r--src/core/loader/nro.h2
-rw-r--r--src/core/loader/nso.cpp9
-rw-r--r--src/core/loader/nso.h4
-rw-r--r--src/core/loader/nsp.cpp22
-rw-r--r--src/core/loader/nsp.h16
-rw-r--r--src/core/loader/xci.cpp19
-rw-r--r--src/core/loader/xci.h16
-rw-r--r--src/core/memory.cpp211
-rw-r--r--src/core/memory.h34
-rw-r--r--src/core/memory/cheat_engine.cpp3
-rw-r--r--src/core/network/network.cpp84
-rw-r--r--src/core/network/network.h24
-rw-r--r--src/core/network/sockets.h4
-rw-r--r--src/core/settings.cpp53
-rw-r--r--src/core/settings.h87
-rw-r--r--src/core/telemetry_session.cpp13
-rw-r--r--src/core/telemetry_session.h18
408 files changed, 10451 insertions, 8483 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index d0c405ec7..893df433a 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -1,9 +1,3 @@
1if (YUZU_ENABLE_BOXCAT)
2 set(BCAT_BOXCAT_ADDITIONAL_SOURCES hle/service/bcat/backend/boxcat.cpp hle/service/bcat/backend/boxcat.h)
3else()
4 set(BCAT_BOXCAT_ADDITIONAL_SOURCES)
5endif()
6
7add_library(core STATIC 1add_library(core STATIC
8 arm/arm_interface.h 2 arm/arm_interface.h
9 arm/arm_interface.cpp 3 arm/arm_interface.cpp
@@ -19,8 +13,6 @@ add_library(core STATIC
19 arm/dynarmic/arm_exclusive_monitor.h 13 arm/dynarmic/arm_exclusive_monitor.h
20 arm/exclusive_monitor.cpp 14 arm/exclusive_monitor.cpp
21 arm/exclusive_monitor.h 15 arm/exclusive_monitor.h
22 arm/unicorn/arm_unicorn.cpp
23 arm/unicorn/arm_unicorn.h
24 constants.cpp 16 constants.cpp
25 constants.h 17 constants.h
26 core.cpp 18 core.cpp
@@ -49,6 +41,7 @@ add_library(core STATIC
49 file_sys/bis_factory.h 41 file_sys/bis_factory.h
50 file_sys/card_image.cpp 42 file_sys/card_image.cpp
51 file_sys/card_image.h 43 file_sys/card_image.h
44 file_sys/common_funcs.h
52 file_sys/content_archive.cpp 45 file_sys/content_archive.cpp
53 file_sys/content_archive.h 46 file_sys/content_archive.h
54 file_sys/control_metadata.cpp 47 file_sys/control_metadata.cpp
@@ -142,9 +135,9 @@ add_library(core STATIC
142 frontend/emu_window.h 135 frontend/emu_window.h
143 frontend/framebuffer_layout.cpp 136 frontend/framebuffer_layout.cpp
144 frontend/framebuffer_layout.h 137 frontend/framebuffer_layout.h
138 frontend/input_interpreter.cpp
139 frontend/input_interpreter.h
145 frontend/input.h 140 frontend/input.h
146 gdbstub/gdbstub.cpp
147 gdbstub/gdbstub.h
148 hardware_interrupt_manager.cpp 141 hardware_interrupt_manager.cpp
149 hardware_interrupt_manager.h 142 hardware_interrupt_manager.h
150 hle/ipc.h 143 hle/ipc.h
@@ -158,10 +151,19 @@ add_library(core STATIC
158 hle/kernel/code_set.cpp 151 hle/kernel/code_set.cpp
159 hle/kernel/code_set.h 152 hle/kernel/code_set.h
160 hle/kernel/errors.h 153 hle/kernel/errors.h
154 hle/kernel/global_scheduler_context.cpp
155 hle/kernel/global_scheduler_context.h
161 hle/kernel/handle_table.cpp 156 hle/kernel/handle_table.cpp
162 hle/kernel/handle_table.h 157 hle/kernel/handle_table.h
163 hle/kernel/hle_ipc.cpp 158 hle/kernel/hle_ipc.cpp
164 hle/kernel/hle_ipc.h 159 hle/kernel/hle_ipc.h
160 hle/kernel/k_affinity_mask.h
161 hle/kernel/k_priority_queue.h
162 hle/kernel/k_scheduler.cpp
163 hle/kernel/k_scheduler.h
164 hle/kernel/k_scheduler_lock.h
165 hle/kernel/k_scoped_lock.h
166 hle/kernel/k_scoped_scheduler_lock_and_sleep.h
165 hle/kernel/kernel.cpp 167 hle/kernel/kernel.cpp
166 hle/kernel/kernel.h 168 hle/kernel/kernel.h
167 hle/kernel/memory/address_space_info.cpp 169 hle/kernel/memory/address_space_info.cpp
@@ -196,12 +198,12 @@ add_library(core STATIC
196 hle/kernel/readable_event.h 198 hle/kernel/readable_event.h
197 hle/kernel/resource_limit.cpp 199 hle/kernel/resource_limit.cpp
198 hle/kernel/resource_limit.h 200 hle/kernel/resource_limit.h
199 hle/kernel/scheduler.cpp
200 hle/kernel/scheduler.h
201 hle/kernel/server_port.cpp 201 hle/kernel/server_port.cpp
202 hle/kernel/server_port.h 202 hle/kernel/server_port.h
203 hle/kernel/server_session.cpp 203 hle/kernel/server_session.cpp
204 hle/kernel/server_session.h 204 hle/kernel/server_session.h
205 hle/kernel/service_thread.cpp
206 hle/kernel/service_thread.h
205 hle/kernel/session.cpp 207 hle/kernel/session.cpp
206 hle/kernel/session.h 208 hle/kernel/session.h
207 hle/kernel/shared_memory.cpp 209 hle/kernel/shared_memory.cpp
@@ -303,7 +305,6 @@ add_library(core STATIC
303 hle/service/audio/hwopus.h 305 hle/service/audio/hwopus.h
304 hle/service/bcat/backend/backend.cpp 306 hle/service/bcat/backend/backend.cpp
305 hle/service/bcat/backend/backend.h 307 hle/service/bcat/backend/backend.h
306 ${BCAT_BOXCAT_ADDITIONAL_SOURCES}
307 hle/service/bcat/bcat.cpp 308 hle/service/bcat/bcat.cpp
308 hle/service/bcat/bcat.h 309 hle/service/bcat/bcat.h
309 hle/service/bcat/module.cpp 310 hle/service/bcat/module.cpp
@@ -446,6 +447,8 @@ add_library(core STATIC
446 hle/service/nvdrv/devices/nvhost_gpu.h 447 hle/service/nvdrv/devices/nvhost_gpu.h
447 hle/service/nvdrv/devices/nvhost_nvdec.cpp 448 hle/service/nvdrv/devices/nvhost_nvdec.cpp
448 hle/service/nvdrv/devices/nvhost_nvdec.h 449 hle/service/nvdrv/devices/nvhost_nvdec.h
450 hle/service/nvdrv/devices/nvhost_nvdec_common.cpp
451 hle/service/nvdrv/devices/nvhost_nvdec_common.h
449 hle/service/nvdrv/devices/nvhost_nvjpg.cpp 452 hle/service/nvdrv/devices/nvhost_nvjpg.cpp
450 hle/service/nvdrv/devices/nvhost_nvjpg.h 453 hle/service/nvdrv/devices/nvhost_nvjpg.h
451 hle/service/nvdrv/devices/nvhost_vic.cpp 454 hle/service/nvdrv/devices/nvhost_vic.cpp
@@ -459,10 +462,14 @@ add_library(core STATIC
459 hle/service/nvdrv/nvdrv.h 462 hle/service/nvdrv/nvdrv.h
460 hle/service/nvdrv/nvmemp.cpp 463 hle/service/nvdrv/nvmemp.cpp
461 hle/service/nvdrv/nvmemp.h 464 hle/service/nvdrv/nvmemp.h
465 hle/service/nvdrv/syncpoint_manager.cpp
466 hle/service/nvdrv/syncpoint_manager.h
462 hle/service/nvflinger/buffer_queue.cpp 467 hle/service/nvflinger/buffer_queue.cpp
463 hle/service/nvflinger/buffer_queue.h 468 hle/service/nvflinger/buffer_queue.h
464 hle/service/nvflinger/nvflinger.cpp 469 hle/service/nvflinger/nvflinger.cpp
465 hle/service/nvflinger/nvflinger.h 470 hle/service/nvflinger/nvflinger.h
471 hle/service/olsc/olsc.cpp
472 hle/service/olsc/olsc.h
466 hle/service/pcie/pcie.cpp 473 hle/service/pcie/pcie.cpp
467 hle/service/pcie/pcie.h 474 hle/service/pcie/pcie.h
468 hle/service/pctl/module.cpp 475 hle/service/pctl/module.cpp
@@ -495,7 +502,6 @@ add_library(core STATIC
495 hle/service/sm/controller.h 502 hle/service/sm/controller.h
496 hle/service/sm/sm.cpp 503 hle/service/sm/sm.cpp
497 hle/service/sm/sm.h 504 hle/service/sm/sm.h
498 hle/service/sockets/blocking_worker.h
499 hle/service/sockets/bsd.cpp 505 hle/service/sockets/bsd.cpp
500 hle/service/sockets/bsd.h 506 hle/service/sockets/bsd.h
501 hle/service/sockets/ethc.cpp 507 hle/service/sockets/ethc.cpp
@@ -608,6 +614,13 @@ add_library(core STATIC
608 tools/freezer.h 614 tools/freezer.h
609) 615)
610 616
617if (YUZU_ENABLE_BOXCAT)
618 target_sources(core PRIVATE
619 hle/service/bcat/backend/boxcat.cpp
620 hle/service/bcat/backend/boxcat.h
621 )
622endif()
623
611if (MSVC) 624if (MSVC)
612 target_compile_options(core PRIVATE 625 target_compile_options(core PRIVATE
613 # 'expression' : signed/unsigned mismatch 626 # 'expression' : signed/unsigned mismatch
@@ -622,13 +635,29 @@ if (MSVC)
622 /we4267 635 /we4267
623 # 'context' : truncation from 'type1' to 'type2' 636 # 'context' : truncation from 'type1' to 'type2'
624 /we4305 637 /we4305
638 # 'function' : not all control paths return a value
639 /we4715
640 )
641else()
642 target_compile_options(core PRIVATE
643 -Werror=conversion
644 -Werror=ignored-qualifiers
645 -Werror=implicit-fallthrough
646 -Werror=reorder
647 -Werror=sign-compare
648 -Werror=unused-variable
649
650 $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-parameter>
651 $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-variable>
652
653 -Wno-sign-conversion
625 ) 654 )
626endif() 655endif()
627 656
628create_target_directory_groups(core) 657create_target_directory_groups(core)
629 658
630target_link_libraries(core PUBLIC common PRIVATE audio_core video_core) 659target_link_libraries(core PUBLIC common PRIVATE audio_core video_core)
631target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt::fmt nlohmann_json::nlohmann_json mbedtls opus unicorn zip) 660target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt::fmt nlohmann_json::nlohmann_json mbedtls opus zip)
632 661
633if (YUZU_ENABLE_BOXCAT) 662if (YUZU_ENABLE_BOXCAT)
634 target_compile_definitions(core PRIVATE -DYUZU_ENABLE_BOXCAT) 663 target_compile_definitions(core PRIVATE -DYUZU_ENABLE_BOXCAT)
diff --git a/src/core/arm/arm_interface.cpp b/src/core/arm/arm_interface.cpp
index d2295ed90..0951e1976 100644
--- a/src/core/arm/arm_interface.cpp
+++ b/src/core/arm/arm_interface.cpp
@@ -147,10 +147,18 @@ std::vector<ARM_Interface::BacktraceEntry> ARM_Interface::GetBacktraceFromContex
147 auto fp = ctx.cpu_registers[29]; 147 auto fp = ctx.cpu_registers[29];
148 auto lr = ctx.cpu_registers[30]; 148 auto lr = ctx.cpu_registers[30];
149 while (true) { 149 while (true) {
150 out.push_back({"", 0, lr, 0}); 150 out.push_back({
151 if (!fp) { 151 .module = "",
152 .address = 0,
153 .original_address = lr,
154 .offset = 0,
155 .name = {},
156 });
157
158 if (fp == 0) {
152 break; 159 break;
153 } 160 }
161
154 lr = memory.Read64(fp + 8) - 4; 162 lr = memory.Read64(fp + 8) - 4;
155 fp = memory.Read64(fp); 163 fp = memory.Read64(fp);
156 } 164 }
diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h
index 1f24051e4..70098c526 100644
--- a/src/core/arm/arm_interface.h
+++ b/src/core/arm/arm_interface.h
@@ -64,15 +64,25 @@ public:
64 /// Step CPU by one instruction 64 /// Step CPU by one instruction
65 virtual void Step() = 0; 65 virtual void Step() = 0;
66 66
67 /// Exits execution from a callback, the callback must rewind the stack
68 virtual void ExceptionalExit() = 0;
69
67 /// Clear all instruction cache 70 /// Clear all instruction cache
68 virtual void ClearInstructionCache() = 0; 71 virtual void ClearInstructionCache() = 0;
69 72
70 /// Notifies CPU emulation that the current page table has changed. 73 /**
71 /// 74 * Clear instruction cache range
72 /// @param new_page_table The new page table. 75 * @param addr Start address of the cache range to clear
73 /// @param new_address_space_size_in_bits The new usable size of the address space in bits. 76 * @param size Size of the cache range to clear, starting at addr
74 /// This can be either 32, 36, or 39 on official software. 77 */
75 /// 78 virtual void InvalidateCacheRange(VAddr addr, std::size_t size) = 0;
79
80 /**
81 * Notifies CPU emulation that the current page table has changed.
82 * @param new_page_table The new page table.
83 * @param new_address_space_size_in_bits The new usable size of the address space in bits.
84 * This can be either 32, 36, or 39 on official software.
85 */
76 virtual void PageTableChanged(Common::PageTable& new_page_table, 86 virtual void PageTableChanged(Common::PageTable& new_page_table,
77 std::size_t new_address_space_size_in_bits) = 0; 87 std::size_t new_address_space_size_in_bits) = 0;
78 88
diff --git a/src/core/arm/cpu_interrupt_handler.h b/src/core/arm/cpu_interrupt_handler.h
index 71e582f79..c20c280f1 100644
--- a/src/core/arm/cpu_interrupt_handler.h
+++ b/src/core/arm/cpu_interrupt_handler.h
@@ -21,8 +21,8 @@ public:
21 CPUInterruptHandler(const CPUInterruptHandler&) = delete; 21 CPUInterruptHandler(const CPUInterruptHandler&) = delete;
22 CPUInterruptHandler& operator=(const CPUInterruptHandler&) = delete; 22 CPUInterruptHandler& operator=(const CPUInterruptHandler&) = delete;
23 23
24 CPUInterruptHandler(CPUInterruptHandler&&) = default; 24 CPUInterruptHandler(CPUInterruptHandler&&) = delete;
25 CPUInterruptHandler& operator=(CPUInterruptHandler&&) = default; 25 CPUInterruptHandler& operator=(CPUInterruptHandler&&) = delete;
26 26
27 bool IsInterrupted() const { 27 bool IsInterrupted() const {
28 return is_interrupted; 28 return is_interrupted;
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
index b5f28a86e..6c4c8e9e4 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
@@ -7,6 +7,7 @@
7#include <dynarmic/A32/a32.h> 7#include <dynarmic/A32/a32.h>
8#include <dynarmic/A32/config.h> 8#include <dynarmic/A32/config.h>
9#include <dynarmic/A32/context.h> 9#include <dynarmic/A32/context.h>
10#include "common/assert.h"
10#include "common/logging/log.h" 11#include "common/logging/log.h"
11#include "common/page_table.h" 12#include "common/page_table.h"
12#include "core/arm/cpu_interrupt_handler.h" 13#include "core/arm/cpu_interrupt_handler.h"
@@ -70,15 +71,8 @@ public:
70 } 71 }
71 72
72 void ExceptionRaised(u32 pc, Dynarmic::A32::Exception exception) override { 73 void ExceptionRaised(u32 pc, Dynarmic::A32::Exception exception) override {
73 switch (exception) {
74 case Dynarmic::A32::Exception::UndefinedInstruction:
75 case Dynarmic::A32::Exception::UnpredictableInstruction:
76 break;
77 case Dynarmic::A32::Exception::Breakpoint:
78 break;
79 }
80 LOG_CRITICAL(Core_ARM, "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X})", 74 LOG_CRITICAL(Core_ARM, "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X})",
81 static_cast<std::size_t>(exception), pc, MemoryReadCode(pc)); 75 exception, pc, MemoryReadCode(pc));
82 UNIMPLEMENTED(); 76 UNIMPLEMENTED();
83 } 77 }
84 78
@@ -132,6 +126,7 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable&
132 config.page_table = reinterpret_cast<std::array<std::uint8_t*, NUM_PAGE_TABLE_ENTRIES>*>( 126 config.page_table = reinterpret_cast<std::array<std::uint8_t*, NUM_PAGE_TABLE_ENTRIES>*>(
133 page_table.pointers.data()); 127 page_table.pointers.data());
134 config.absolute_offset_page_table = true; 128 config.absolute_offset_page_table = true;
129 config.page_table_pointer_mask_bits = Common::PageTable::ATTRIBUTE_BITS;
135 config.detect_misaligned_access_via_page_table = 16 | 32 | 64 | 128; 130 config.detect_misaligned_access_via_page_table = 16 | 32 | 64 | 128;
136 config.only_detect_misalignment_via_page_table_on_page_boundary = true; 131 config.only_detect_misalignment_via_page_table_on_page_boundary = true;
137 132
@@ -179,6 +174,9 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable&
179 if (Settings::values.cpuopt_unsafe_reduce_fp_error) { 174 if (Settings::values.cpuopt_unsafe_reduce_fp_error) {
180 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_ReducedErrorFP; 175 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_ReducedErrorFP;
181 } 176 }
177 if (Settings::values.cpuopt_unsafe_inaccurate_nan) {
178 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN;
179 }
182 } 180 }
183 181
184 return std::make_unique<Dynarmic::A32::Jit>(config); 182 return std::make_unique<Dynarmic::A32::Jit>(config);
@@ -188,6 +186,10 @@ void ARM_Dynarmic_32::Run() {
188 jit->Run(); 186 jit->Run();
189} 187}
190 188
189void ARM_Dynarmic_32::ExceptionalExit() {
190 jit->ExceptionalExit();
191}
192
191void ARM_Dynarmic_32::Step() { 193void ARM_Dynarmic_32::Step() {
192 jit->Step(); 194 jit->Step();
193} 195}
@@ -281,7 +283,17 @@ void ARM_Dynarmic_32::ClearInstructionCache() {
281 jit->ClearCache(); 283 jit->ClearCache();
282} 284}
283 285
286void ARM_Dynarmic_32::InvalidateCacheRange(VAddr addr, std::size_t size) {
287 if (!jit) {
288 return;
289 }
290 jit->InvalidateCacheRange(static_cast<u32>(addr), size);
291}
292
284void ARM_Dynarmic_32::ClearExclusiveState() { 293void ARM_Dynarmic_32::ClearExclusiveState() {
294 if (!jit) {
295 return;
296 }
285 jit->ClearExclusiveState(); 297 jit->ClearExclusiveState();
286} 298}
287 299
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.h b/src/core/arm/dynarmic/arm_dynarmic_32.h
index 2bab31b92..35e9ced48 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_32.h
+++ b/src/core/arm/dynarmic/arm_dynarmic_32.h
@@ -42,6 +42,7 @@ public:
42 u32 GetPSTATE() const override; 42 u32 GetPSTATE() const override;
43 void SetPSTATE(u32 pstate) override; 43 void SetPSTATE(u32 pstate) override;
44 void Run() override; 44 void Run() override;
45 void ExceptionalExit() override;
45 void Step() override; 46 void Step() override;
46 VAddr GetTlsAddress() const override; 47 VAddr GetTlsAddress() const override;
47 void SetTlsAddress(VAddr address) override; 48 void SetTlsAddress(VAddr address) override;
@@ -58,6 +59,7 @@ public:
58 void ClearExclusiveState() override; 59 void ClearExclusiveState() override;
59 60
60 void ClearInstructionCache() override; 61 void ClearInstructionCache() override;
62 void InvalidateCacheRange(VAddr addr, std::size_t size) override;
61 void PageTableChanged(Common::PageTable& new_page_table, 63 void PageTableChanged(Common::PageTable& new_page_table,
62 std::size_t new_address_space_size_in_bits) override; 64 std::size_t new_address_space_size_in_bits) override;
63 65
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
index ce9968724..4c5ebca22 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
@@ -6,6 +6,7 @@
6#include <memory> 6#include <memory>
7#include <dynarmic/A64/a64.h> 7#include <dynarmic/A64/a64.h>
8#include <dynarmic/A64/config.h> 8#include <dynarmic/A64/config.h>
9#include "common/assert.h"
9#include "common/logging/log.h" 10#include "common/logging/log.h"
10#include "common/page_table.h" 11#include "common/page_table.h"
11#include "core/arm/cpu_interrupt_handler.h" 12#include "core/arm/cpu_interrupt_handler.h"
@@ -13,11 +14,9 @@
13#include "core/arm/dynarmic/arm_exclusive_monitor.h" 14#include "core/arm/dynarmic/arm_exclusive_monitor.h"
14#include "core/core.h" 15#include "core/core.h"
15#include "core/core_timing.h" 16#include "core/core_timing.h"
16#include "core/core_timing_util.h"
17#include "core/gdbstub/gdbstub.h"
18#include "core/hardware_properties.h" 17#include "core/hardware_properties.h"
18#include "core/hle/kernel/k_scheduler.h"
19#include "core/hle/kernel/process.h" 19#include "core/hle/kernel/process.h"
20#include "core/hle/kernel/scheduler.h"
21#include "core/hle/kernel/svc.h" 20#include "core/hle/kernel/svc.h"
22#include "core/memory.h" 21#include "core/memory.h"
23#include "core/settings.h" 22#include "core/settings.h"
@@ -82,16 +81,9 @@ public:
82 } 81 }
83 82
84 void InterpreterFallback(u64 pc, std::size_t num_instructions) override { 83 void InterpreterFallback(u64 pc, std::size_t num_instructions) override {
85 LOG_INFO(Core_ARM, "Unicorn fallback @ 0x{:X} for {} instructions (instr = {:08X})", pc, 84 LOG_ERROR(Core_ARM,
86 num_instructions, MemoryReadCode(pc)); 85 "Unimplemented instruction @ 0x{:X} for {} instructions (instr = {:08X})", pc,
87 86 num_instructions, MemoryReadCode(pc));
88 ARM_Interface::ThreadContext64 ctx;
89 parent.SaveContext(ctx);
90 parent.inner_unicorn.LoadContext(ctx);
91 parent.inner_unicorn.ExecuteInstructions(num_instructions);
92 parent.inner_unicorn.SaveContext(ctx);
93 parent.LoadContext(ctx);
94 num_interpreted_instructions += num_instructions;
95 } 87 }
96 88
97 void ExceptionRaised(u64 pc, Dynarmic::A64::Exception exception) override { 89 void ExceptionRaised(u64 pc, Dynarmic::A64::Exception exception) override {
@@ -103,16 +95,6 @@ public:
103 case Dynarmic::A64::Exception::Yield: 95 case Dynarmic::A64::Exception::Yield:
104 return; 96 return;
105 case Dynarmic::A64::Exception::Breakpoint: 97 case Dynarmic::A64::Exception::Breakpoint:
106 if (GDBStub::IsServerEnabled()) {
107 parent.jit->HaltExecution();
108 parent.SetPC(pc);
109 Kernel::Thread* const thread = parent.system.CurrentScheduler().GetCurrentThread();
110 parent.SaveContext(thread->GetContext64());
111 GDBStub::Break();
112 GDBStub::SendTrap(thread, 5);
113 return;
114 }
115 [[fallthrough]];
116 default: 98 default:
117 ASSERT_MSG(false, "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X})", 99 ASSERT_MSG(false, "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X})",
118 static_cast<std::size_t>(exception), pc, MemoryReadCode(pc)); 100 static_cast<std::size_t>(exception), pc, MemoryReadCode(pc));
@@ -127,18 +109,17 @@ public:
127 if (parent.uses_wall_clock) { 109 if (parent.uses_wall_clock) {
128 return; 110 return;
129 } 111 }
112
130 // Divide the number of ticks by the amount of CPU cores. TODO(Subv): This yields only a 113 // Divide the number of ticks by the amount of CPU cores. TODO(Subv): This yields only a
131 // rough approximation of the amount of executed ticks in the system, it may be thrown off 114 // rough approximation of the amount of executed ticks in the system, it may be thrown off
132 // if not all cores are doing a similar amount of work. Instead of doing this, we should 115 // if not all cores are doing a similar amount of work. Instead of doing this, we should
133 // device a way so that timing is consistent across all cores without increasing the ticks 4 116 // device a way so that timing is consistent across all cores without increasing the ticks 4
134 // times. 117 // times.
135 u64 amortized_ticks = 118 u64 amortized_ticks = ticks / Core::Hardware::NUM_CPU_CORES;
136 (ticks - num_interpreted_instructions) / Core::Hardware::NUM_CPU_CORES;
137 // Always execute at least one tick. 119 // Always execute at least one tick.
138 amortized_ticks = std::max<u64>(amortized_ticks, 1); 120 amortized_ticks = std::max<u64>(amortized_ticks, 1);
139 121
140 parent.system.CoreTiming().AddTicks(amortized_ticks); 122 parent.system.CoreTiming().AddTicks(amortized_ticks);
141 num_interpreted_instructions = 0;
142 } 123 }
143 124
144 u64 GetTicksRemaining() override { 125 u64 GetTicksRemaining() override {
@@ -156,7 +137,6 @@ public:
156 } 137 }
157 138
158 ARM_Dynarmic_64& parent; 139 ARM_Dynarmic_64& parent;
159 std::size_t num_interpreted_instructions = 0;
160 u64 tpidrro_el0 = 0; 140 u64 tpidrro_el0 = 0;
161 u64 tpidr_el0 = 0; 141 u64 tpidr_el0 = 0;
162 static constexpr u64 minimum_run_cycles = 1000U; 142 static constexpr u64 minimum_run_cycles = 1000U;
@@ -172,6 +152,7 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable&
172 // Memory 152 // Memory
173 config.page_table = reinterpret_cast<void**>(page_table.pointers.data()); 153 config.page_table = reinterpret_cast<void**>(page_table.pointers.data());
174 config.page_table_address_space_bits = address_space_bits; 154 config.page_table_address_space_bits = address_space_bits;
155 config.page_table_pointer_mask_bits = Common::PageTable::ATTRIBUTE_BITS;
175 config.silently_mirror_page_table = false; 156 config.silently_mirror_page_table = false;
176 config.absolute_offset_page_table = true; 157 config.absolute_offset_page_table = true;
177 config.detect_misaligned_access_via_page_table = 16 | 32 | 64 | 128; 158 config.detect_misaligned_access_via_page_table = 16 | 32 | 64 | 128;
@@ -231,6 +212,9 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable&
231 if (Settings::values.cpuopt_unsafe_reduce_fp_error) { 212 if (Settings::values.cpuopt_unsafe_reduce_fp_error) {
232 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_ReducedErrorFP; 213 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_ReducedErrorFP;
233 } 214 }
215 if (Settings::values.cpuopt_unsafe_inaccurate_nan) {
216 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN;
217 }
234 } 218 }
235 219
236 return std::make_shared<Dynarmic::A64::Jit>(config); 220 return std::make_shared<Dynarmic::A64::Jit>(config);
@@ -240,6 +224,10 @@ void ARM_Dynarmic_64::Run() {
240 jit->Run(); 224 jit->Run();
241} 225}
242 226
227void ARM_Dynarmic_64::ExceptionalExit() {
228 jit->ExceptionalExit();
229}
230
243void ARM_Dynarmic_64::Step() { 231void ARM_Dynarmic_64::Step() {
244 cb->InterpreterFallback(jit->GetPC(), 1); 232 cb->InterpreterFallback(jit->GetPC(), 1);
245} 233}
@@ -248,12 +236,8 @@ ARM_Dynarmic_64::ARM_Dynarmic_64(System& system, CPUInterrupts& interrupt_handle
248 bool uses_wall_clock, ExclusiveMonitor& exclusive_monitor, 236 bool uses_wall_clock, ExclusiveMonitor& exclusive_monitor,
249 std::size_t core_index) 237 std::size_t core_index)
250 : ARM_Interface{system, interrupt_handlers, uses_wall_clock}, 238 : ARM_Interface{system, interrupt_handlers, uses_wall_clock},
251 cb(std::make_unique<DynarmicCallbacks64>(*this)), inner_unicorn{system, interrupt_handlers, 239 cb(std::make_unique<DynarmicCallbacks64>(*this)), core_index{core_index},
252 uses_wall_clock, 240 exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)} {}
253 ARM_Unicorn::Arch::AArch64,
254 core_index},
255 core_index{core_index}, exclusive_monitor{
256 dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)} {}
257 241
258ARM_Dynarmic_64::~ARM_Dynarmic_64() = default; 242ARM_Dynarmic_64::~ARM_Dynarmic_64() = default;
259 243
@@ -342,7 +326,17 @@ void ARM_Dynarmic_64::ClearInstructionCache() {
342 jit->ClearCache(); 326 jit->ClearCache();
343} 327}
344 328
329void ARM_Dynarmic_64::InvalidateCacheRange(VAddr addr, std::size_t size) {
330 if (!jit) {
331 return;
332 }
333 jit->InvalidateCacheRange(addr, size);
334}
335
345void ARM_Dynarmic_64::ClearExclusiveState() { 336void ARM_Dynarmic_64::ClearExclusiveState() {
337 if (!jit) {
338 return;
339 }
346 jit->ClearExclusiveState(); 340 jit->ClearExclusiveState();
347} 341}
348 342
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.h b/src/core/arm/dynarmic/arm_dynarmic_64.h
index 403c55961..329b59a32 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_64.h
+++ b/src/core/arm/dynarmic/arm_dynarmic_64.h
@@ -12,7 +12,6 @@
12#include "common/hash.h" 12#include "common/hash.h"
13#include "core/arm/arm_interface.h" 13#include "core/arm/arm_interface.h"
14#include "core/arm/exclusive_monitor.h" 14#include "core/arm/exclusive_monitor.h"
15#include "core/arm/unicorn/arm_unicorn.h"
16 15
17namespace Core::Memory { 16namespace Core::Memory {
18class Memory; 17class Memory;
@@ -41,6 +40,7 @@ public:
41 void SetPSTATE(u32 pstate) override; 40 void SetPSTATE(u32 pstate) override;
42 void Run() override; 41 void Run() override;
43 void Step() override; 42 void Step() override;
43 void ExceptionalExit() override;
44 VAddr GetTlsAddress() const override; 44 VAddr GetTlsAddress() const override;
45 void SetTlsAddress(VAddr address) override; 45 void SetTlsAddress(VAddr address) override;
46 void SetTPIDR_EL0(u64 value) override; 46 void SetTPIDR_EL0(u64 value) override;
@@ -56,6 +56,7 @@ public:
56 void ClearExclusiveState() override; 56 void ClearExclusiveState() override;
57 57
58 void ClearInstructionCache() override; 58 void ClearInstructionCache() override;
59 void InvalidateCacheRange(VAddr addr, std::size_t size) override;
59 void PageTableChanged(Common::PageTable& new_page_table, 60 void PageTableChanged(Common::PageTable& new_page_table,
60 std::size_t new_address_space_size_in_bits) override; 61 std::size_t new_address_space_size_in_bits) override;
61 62
@@ -71,7 +72,6 @@ private:
71 std::unique_ptr<DynarmicCallbacks64> cb; 72 std::unique_ptr<DynarmicCallbacks64> cb;
72 JitCacheType jit_cache; 73 JitCacheType jit_cache;
73 std::shared_ptr<Dynarmic::A64::Jit> jit; 74 std::shared_ptr<Dynarmic::A64::Jit> jit;
74 ARM_Unicorn inner_unicorn;
75 75
76 std::size_t core_index; 76 std::size_t core_index;
77 DynarmicExclusiveMonitor& exclusive_monitor; 77 DynarmicExclusiveMonitor& exclusive_monitor;
diff --git a/src/core/arm/unicorn/arm_unicorn.cpp b/src/core/arm/unicorn/arm_unicorn.cpp
deleted file mode 100644
index 1df3f3ed1..000000000
--- a/src/core/arm/unicorn/arm_unicorn.cpp
+++ /dev/null
@@ -1,295 +0,0 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <algorithm>
6#include <unicorn/arm64.h>
7#include "common/assert.h"
8#include "common/microprofile.h"
9#include "core/arm/cpu_interrupt_handler.h"
10#include "core/arm/unicorn/arm_unicorn.h"
11#include "core/core.h"
12#include "core/core_timing.h"
13#include "core/hle/kernel/scheduler.h"
14#include "core/hle/kernel/svc.h"
15#include "core/memory.h"
16
17namespace Core {
18
19// Load Unicorn DLL once on Windows using RAII
20#ifdef _MSC_VER
21#include <unicorn_dynload.h>
22struct LoadDll {
23private:
24 LoadDll() {
25 ASSERT(uc_dyn_load(NULL, 0));
26 }
27 ~LoadDll() {
28 ASSERT(uc_dyn_free());
29 }
30 static LoadDll g_load_dll;
31};
32LoadDll LoadDll::g_load_dll;
33#endif
34
35#define CHECKED(expr) \
36 do { \
37 if (auto _cerr = (expr)) { \
38 ASSERT_MSG(false, "Call " #expr " failed with error: {} ({})\n", _cerr, \
39 uc_strerror(_cerr)); \
40 } \
41 } while (0)
42
43static void CodeHook(uc_engine* uc, uint64_t address, uint32_t size, void* user_data) {
44 GDBStub::BreakpointAddress bkpt =
45 GDBStub::GetNextBreakpointFromAddress(address, GDBStub::BreakpointType::Execute);
46 if (GDBStub::IsMemoryBreak() ||
47 (bkpt.type != GDBStub::BreakpointType::None && address == bkpt.address)) {
48 auto core = static_cast<ARM_Unicorn*>(user_data);
49 core->RecordBreak(bkpt);
50 uc_emu_stop(uc);
51 }
52}
53
54static bool UnmappedMemoryHook(uc_engine* uc, uc_mem_type type, u64 addr, int size, u64 value,
55 void* user_data) {
56 auto* const system = static_cast<System*>(user_data);
57
58 ARM_Interface::ThreadContext64 ctx{};
59 system->CurrentArmInterface().SaveContext(ctx);
60 ASSERT_MSG(false, "Attempted to read from unmapped memory: 0x{:X}, pc=0x{:X}, lr=0x{:X}", addr,
61 ctx.pc, ctx.cpu_registers[30]);
62
63 return false;
64}
65
66ARM_Unicorn::ARM_Unicorn(System& system, CPUInterrupts& interrupt_handlers, bool uses_wall_clock,
67 Arch architecture, std::size_t core_index)
68 : ARM_Interface{system, interrupt_handlers, uses_wall_clock}, core_index{core_index} {
69 const auto arch = architecture == Arch::AArch32 ? UC_ARCH_ARM : UC_ARCH_ARM64;
70 CHECKED(uc_open(arch, UC_MODE_ARM, &uc));
71
72 auto fpv = 3 << 20;
73 CHECKED(uc_reg_write(uc, UC_ARM64_REG_CPACR_EL1, &fpv));
74
75 uc_hook hook{};
76 CHECKED(uc_hook_add(uc, &hook, UC_HOOK_INTR, (void*)InterruptHook, this, 0, UINT64_MAX));
77 CHECKED(uc_hook_add(uc, &hook, UC_HOOK_MEM_INVALID, (void*)UnmappedMemoryHook, &system, 0,
78 UINT64_MAX));
79 if (GDBStub::IsServerEnabled()) {
80 CHECKED(uc_hook_add(uc, &hook, UC_HOOK_CODE, (void*)CodeHook, this, 0, UINT64_MAX));
81 last_bkpt_hit = false;
82 }
83}
84
85ARM_Unicorn::~ARM_Unicorn() {
86 CHECKED(uc_close(uc));
87}
88
89void ARM_Unicorn::SetPC(u64 pc) {
90 CHECKED(uc_reg_write(uc, UC_ARM64_REG_PC, &pc));
91}
92
93u64 ARM_Unicorn::GetPC() const {
94 u64 val{};
95 CHECKED(uc_reg_read(uc, UC_ARM64_REG_PC, &val));
96 return val;
97}
98
99u64 ARM_Unicorn::GetReg(int regn) const {
100 u64 val{};
101 auto treg = UC_ARM64_REG_SP;
102 if (regn <= 28) {
103 treg = (uc_arm64_reg)(UC_ARM64_REG_X0 + regn);
104 } else if (regn < 31) {
105 treg = (uc_arm64_reg)(UC_ARM64_REG_X29 + regn - 29);
106 }
107 CHECKED(uc_reg_read(uc, treg, &val));
108 return val;
109}
110
111void ARM_Unicorn::SetReg(int regn, u64 val) {
112 auto treg = UC_ARM64_REG_SP;
113 if (regn <= 28) {
114 treg = (uc_arm64_reg)(UC_ARM64_REG_X0 + regn);
115 } else if (regn < 31) {
116 treg = (uc_arm64_reg)(UC_ARM64_REG_X29 + regn - 29);
117 }
118 CHECKED(uc_reg_write(uc, treg, &val));
119}
120
121u128 ARM_Unicorn::GetVectorReg(int /*index*/) const {
122 UNIMPLEMENTED();
123 static constexpr u128 res{};
124 return res;
125}
126
127void ARM_Unicorn::SetVectorReg(int /*index*/, u128 /*value*/) {
128 UNIMPLEMENTED();
129}
130
131u32 ARM_Unicorn::GetPSTATE() const {
132 u64 nzcv{};
133 CHECKED(uc_reg_read(uc, UC_ARM64_REG_NZCV, &nzcv));
134 return static_cast<u32>(nzcv);
135}
136
137void ARM_Unicorn::SetPSTATE(u32 pstate) {
138 u64 nzcv = pstate;
139 CHECKED(uc_reg_write(uc, UC_ARM64_REG_NZCV, &nzcv));
140}
141
142VAddr ARM_Unicorn::GetTlsAddress() const {
143 u64 base{};
144 CHECKED(uc_reg_read(uc, UC_ARM64_REG_TPIDRRO_EL0, &base));
145 return base;
146}
147
148void ARM_Unicorn::SetTlsAddress(VAddr base) {
149 CHECKED(uc_reg_write(uc, UC_ARM64_REG_TPIDRRO_EL0, &base));
150}
151
152u64 ARM_Unicorn::GetTPIDR_EL0() const {
153 u64 value{};
154 CHECKED(uc_reg_read(uc, UC_ARM64_REG_TPIDR_EL0, &value));
155 return value;
156}
157
158void ARM_Unicorn::SetTPIDR_EL0(u64 value) {
159 CHECKED(uc_reg_write(uc, UC_ARM64_REG_TPIDR_EL0, &value));
160}
161
162void ARM_Unicorn::ChangeProcessorID(std::size_t new_core_id) {
163 core_index = new_core_id;
164}
165
166void ARM_Unicorn::Run() {
167 if (GDBStub::IsServerEnabled()) {
168 ExecuteInstructions(std::max(4000000U, 0U));
169 } else {
170 while (true) {
171 if (interrupt_handlers[core_index].IsInterrupted()) {
172 return;
173 }
174 ExecuteInstructions(10);
175 }
176 }
177}
178
179void ARM_Unicorn::Step() {
180 ExecuteInstructions(1);
181}
182
183MICROPROFILE_DEFINE(ARM_Jit_Unicorn, "ARM JIT", "Unicorn", MP_RGB(255, 64, 64));
184
185void ARM_Unicorn::ExecuteInstructions(std::size_t num_instructions) {
186 MICROPROFILE_SCOPE(ARM_Jit_Unicorn);
187
188 // Temporarily map the code page for Unicorn
189 u64 map_addr{GetPC() & ~Memory::PAGE_MASK};
190 std::vector<u8> page_buffer(Memory::PAGE_SIZE);
191 system.Memory().ReadBlock(map_addr, page_buffer.data(), page_buffer.size());
192
193 CHECKED(uc_mem_map_ptr(uc, map_addr, page_buffer.size(),
194 UC_PROT_READ | UC_PROT_WRITE | UC_PROT_EXEC, page_buffer.data()));
195 CHECKED(uc_emu_start(uc, GetPC(), 1ULL << 63, 0, num_instructions));
196 CHECKED(uc_mem_unmap(uc, map_addr, page_buffer.size()));
197 if (GDBStub::IsServerEnabled()) {
198 if (last_bkpt_hit && last_bkpt.type == GDBStub::BreakpointType::Execute) {
199 uc_reg_write(uc, UC_ARM64_REG_PC, &last_bkpt.address);
200 }
201
202 Kernel::Thread* const thread = system.CurrentScheduler().GetCurrentThread();
203 SaveContext(thread->GetContext64());
204 if (last_bkpt_hit || GDBStub::IsMemoryBreak() || GDBStub::GetCpuStepFlag()) {
205 last_bkpt_hit = false;
206 GDBStub::Break();
207 GDBStub::SendTrap(thread, 5);
208 }
209 }
210}
211
212void ARM_Unicorn::SaveContext(ThreadContext64& ctx) {
213 int uregs[32];
214 void* tregs[32];
215
216 CHECKED(uc_reg_read(uc, UC_ARM64_REG_SP, &ctx.sp));
217 CHECKED(uc_reg_read(uc, UC_ARM64_REG_PC, &ctx.pc));
218 CHECKED(uc_reg_read(uc, UC_ARM64_REG_NZCV, &ctx.pstate));
219
220 for (auto i = 0; i < 29; ++i) {
221 uregs[i] = UC_ARM64_REG_X0 + i;
222 tregs[i] = &ctx.cpu_registers[i];
223 }
224 uregs[29] = UC_ARM64_REG_X29;
225 tregs[29] = (void*)&ctx.cpu_registers[29];
226 uregs[30] = UC_ARM64_REG_X30;
227 tregs[30] = (void*)&ctx.cpu_registers[30];
228
229 CHECKED(uc_reg_read_batch(uc, uregs, tregs, 31));
230
231 for (int i = 0; i < 32; ++i) {
232 uregs[i] = UC_ARM64_REG_Q0 + i;
233 tregs[i] = &ctx.vector_registers[i];
234 }
235
236 CHECKED(uc_reg_read_batch(uc, uregs, tregs, 32));
237}
238
239void ARM_Unicorn::LoadContext(const ThreadContext64& ctx) {
240 int uregs[32];
241 void* tregs[32];
242
243 CHECKED(uc_reg_write(uc, UC_ARM64_REG_SP, &ctx.sp));
244 CHECKED(uc_reg_write(uc, UC_ARM64_REG_PC, &ctx.pc));
245 CHECKED(uc_reg_write(uc, UC_ARM64_REG_NZCV, &ctx.pstate));
246
247 for (int i = 0; i < 29; ++i) {
248 uregs[i] = UC_ARM64_REG_X0 + i;
249 tregs[i] = (void*)&ctx.cpu_registers[i];
250 }
251 uregs[29] = UC_ARM64_REG_X29;
252 tregs[29] = (void*)&ctx.cpu_registers[29];
253 uregs[30] = UC_ARM64_REG_X30;
254 tregs[30] = (void*)&ctx.cpu_registers[30];
255
256 CHECKED(uc_reg_write_batch(uc, uregs, tregs, 31));
257
258 for (auto i = 0; i < 32; ++i) {
259 uregs[i] = UC_ARM64_REG_Q0 + i;
260 tregs[i] = (void*)&ctx.vector_registers[i];
261 }
262
263 CHECKED(uc_reg_write_batch(uc, uregs, tregs, 32));
264}
265
266void ARM_Unicorn::PrepareReschedule() {
267 CHECKED(uc_emu_stop(uc));
268}
269
270void ARM_Unicorn::ClearExclusiveState() {}
271
272void ARM_Unicorn::ClearInstructionCache() {}
273
274void ARM_Unicorn::RecordBreak(GDBStub::BreakpointAddress bkpt) {
275 last_bkpt = bkpt;
276 last_bkpt_hit = true;
277}
278
279void ARM_Unicorn::InterruptHook(uc_engine* uc, u32 int_no, void* user_data) {
280 u32 esr{};
281 CHECKED(uc_reg_read(uc, UC_ARM64_REG_ESR, &esr));
282
283 const auto ec = esr >> 26;
284 const auto iss = esr & 0xFFFFFF;
285
286 auto* const arm_instance = static_cast<ARM_Unicorn*>(user_data);
287
288 switch (ec) {
289 case 0x15: // SVC
290 Kernel::Svc::Call(arm_instance->system, iss);
291 break;
292 }
293}
294
295} // namespace Core
diff --git a/src/core/arm/unicorn/arm_unicorn.h b/src/core/arm/unicorn/arm_unicorn.h
deleted file mode 100644
index 810aff311..000000000
--- a/src/core/arm/unicorn/arm_unicorn.h
+++ /dev/null
@@ -1,63 +0,0 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <unicorn/unicorn.h>
8#include "common/common_types.h"
9#include "core/arm/arm_interface.h"
10#include "core/gdbstub/gdbstub.h"
11
12namespace Core {
13
14class System;
15
16class ARM_Unicorn final : public ARM_Interface {
17public:
18 enum class Arch {
19 AArch32, // 32-bit ARM
20 AArch64, // 64-bit ARM
21 };
22
23 explicit ARM_Unicorn(System& system, CPUInterrupts& interrupt_handlers, bool uses_wall_clock,
24 Arch architecture, std::size_t core_index);
25 ~ARM_Unicorn() override;
26
27 void SetPC(u64 pc) override;
28 u64 GetPC() const override;
29 u64 GetReg(int index) const override;
30 void SetReg(int index, u64 value) override;
31 u128 GetVectorReg(int index) const override;
32 void SetVectorReg(int index, u128 value) override;
33 u32 GetPSTATE() const override;
34 void SetPSTATE(u32 pstate) override;
35 VAddr GetTlsAddress() const override;
36 void SetTlsAddress(VAddr address) override;
37 void SetTPIDR_EL0(u64 value) override;
38 u64 GetTPIDR_EL0() const override;
39 void ChangeProcessorID(std::size_t new_core_id) override;
40 void PrepareReschedule() override;
41 void ClearExclusiveState() override;
42 void ExecuteInstructions(std::size_t num_instructions);
43 void Run() override;
44 void Step() override;
45 void ClearInstructionCache() override;
46 void PageTableChanged(Common::PageTable&, std::size_t) override {}
47 void RecordBreak(GDBStub::BreakpointAddress bkpt);
48
49 void SaveContext(ThreadContext32& ctx) override {}
50 void SaveContext(ThreadContext64& ctx) override;
51 void LoadContext(const ThreadContext32& ctx) override {}
52 void LoadContext(const ThreadContext64& ctx) override;
53
54private:
55 static void InterruptHook(uc_engine* uc, u32 int_no, void* user_data);
56
57 uc_engine* uc{};
58 GDBStub::BreakpointAddress last_bkpt{};
59 bool last_bkpt_hit = false;
60 std::size_t core_index;
61};
62
63} // namespace Core
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 81e8cc338..1a2002dec 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -25,13 +25,12 @@
25#include "core/file_sys/sdmc_factory.h" 25#include "core/file_sys/sdmc_factory.h"
26#include "core/file_sys/vfs_concat.h" 26#include "core/file_sys/vfs_concat.h"
27#include "core/file_sys/vfs_real.h" 27#include "core/file_sys/vfs_real.h"
28#include "core/gdbstub/gdbstub.h"
29#include "core/hardware_interrupt_manager.h" 28#include "core/hardware_interrupt_manager.h"
30#include "core/hle/kernel/client_port.h" 29#include "core/hle/kernel/client_port.h"
30#include "core/hle/kernel/k_scheduler.h"
31#include "core/hle/kernel/kernel.h" 31#include "core/hle/kernel/kernel.h"
32#include "core/hle/kernel/physical_core.h" 32#include "core/hle/kernel/physical_core.h"
33#include "core/hle/kernel/process.h" 33#include "core/hle/kernel/process.h"
34#include "core/hle/kernel/scheduler.h"
35#include "core/hle/kernel/thread.h" 34#include "core/hle/kernel/thread.h"
36#include "core/hle/service/am/applets/applets.h" 35#include "core/hle/service/am/applets/applets.h"
37#include "core/hle/service/apm/controller.h" 36#include "core/hle/service/apm/controller.h"
@@ -40,6 +39,7 @@
40#include "core/hle/service/lm/manager.h" 39#include "core/hle/service/lm/manager.h"
41#include "core/hle/service/service.h" 40#include "core/hle/service/service.h"
42#include "core/hle/service/sm/sm.h" 41#include "core/hle/service/sm/sm.h"
42#include "core/hle/service/time/time_manager.h"
43#include "core/loader/loader.h" 43#include "core/loader/loader.h"
44#include "core/memory.h" 44#include "core/memory.h"
45#include "core/memory/cheat_engine.h" 45#include "core/memory/cheat_engine.h"
@@ -91,37 +91,47 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
91 std::string dir_name; 91 std::string dir_name;
92 std::string filename; 92 std::string filename;
93 Common::SplitPath(path, &dir_name, &filename, nullptr); 93 Common::SplitPath(path, &dir_name, &filename, nullptr);
94
94 if (filename == "00") { 95 if (filename == "00") {
95 const auto dir = vfs->OpenDirectory(dir_name, FileSys::Mode::Read); 96 const auto dir = vfs->OpenDirectory(dir_name, FileSys::Mode::Read);
96 std::vector<FileSys::VirtualFile> concat; 97 std::vector<FileSys::VirtualFile> concat;
97 for (u8 i = 0; i < 0x10; ++i) { 98
98 auto next = dir->GetFile(fmt::format("{:02X}", i)); 99 for (u32 i = 0; i < 0x10; ++i) {
99 if (next != nullptr) 100 const auto file_name = fmt::format("{:02X}", i);
101 auto next = dir->GetFile(file_name);
102
103 if (next != nullptr) {
100 concat.push_back(std::move(next)); 104 concat.push_back(std::move(next));
101 else { 105 } else {
102 next = dir->GetFile(fmt::format("{:02x}", i)); 106 next = dir->GetFile(file_name);
103 if (next != nullptr) 107
104 concat.push_back(std::move(next)); 108 if (next == nullptr) {
105 else
106 break; 109 break;
110 }
111
112 concat.push_back(std::move(next));
107 } 113 }
108 } 114 }
109 115
110 if (concat.empty()) 116 if (concat.empty()) {
111 return nullptr; 117 return nullptr;
118 }
112 119
113 return FileSys::ConcatenatedVfsFile::MakeConcatenatedFile(concat, dir->GetName()); 120 return FileSys::ConcatenatedVfsFile::MakeConcatenatedFile(std::move(concat),
121 dir->GetName());
114 } 122 }
115 123
116 if (Common::FS::IsDirectory(path)) 124 if (Common::FS::IsDirectory(path)) {
117 return vfs->OpenFile(path + "/" + "main", FileSys::Mode::Read); 125 return vfs->OpenFile(path + "/main", FileSys::Mode::Read);
126 }
118 127
119 return vfs->OpenFile(path, FileSys::Mode::Read); 128 return vfs->OpenFile(path, FileSys::Mode::Read);
120} 129}
130
121struct System::Impl { 131struct System::Impl {
122 explicit Impl(System& system) 132 explicit Impl(System& system)
123 : kernel{system}, fs_controller{system}, memory{system}, 133 : kernel{system}, fs_controller{system}, memory{system},
124 cpu_manager{system}, reporter{system}, applet_manager{system} {} 134 cpu_manager{system}, reporter{system}, applet_manager{system}, time_manager{system} {}
125 135
126 ResultStatus Run() { 136 ResultStatus Run() {
127 status = ResultStatus::Success; 137 status = ResultStatus::Success;
@@ -144,12 +154,12 @@ struct System::Impl {
144 } 154 }
145 155
146 ResultStatus Init(System& system, Frontend::EmuWindow& emu_window) { 156 ResultStatus Init(System& system, Frontend::EmuWindow& emu_window) {
147 LOG_DEBUG(HW_Memory, "initialized OK"); 157 LOG_DEBUG(Core, "initialized OK");
148 158
149 device_memory = std::make_unique<Core::DeviceMemory>(); 159 device_memory = std::make_unique<Core::DeviceMemory>();
150 160
151 is_multicore = Settings::values.use_multi_core.GetValue(); 161 is_multicore = Settings::values.use_multi_core.GetValue();
152 is_async_gpu = is_multicore || Settings::values.use_asynchronous_gpu_emulation.GetValue(); 162 is_async_gpu = Settings::values.use_asynchronous_gpu_emulation.GetValue();
153 163
154 kernel.SetMulticore(is_multicore); 164 kernel.SetMulticore(is_multicore);
155 cpu_manager.SetMulticore(is_multicore); 165 cpu_manager.SetMulticore(is_multicore);
@@ -178,17 +188,19 @@ struct System::Impl {
178 arp_manager.ResetAll(); 188 arp_manager.ResetAll();
179 189
180 telemetry_session = std::make_unique<Core::TelemetrySession>(); 190 telemetry_session = std::make_unique<Core::TelemetrySession>();
181 service_manager = std::make_shared<Service::SM::ServiceManager>(kernel);
182 191
183 Service::Init(service_manager, system);
184 GDBStub::DeferStart();
185
186 interrupt_manager = std::make_unique<Core::Hardware::InterruptManager>(system);
187 gpu_core = VideoCore::CreateGPU(emu_window, system); 192 gpu_core = VideoCore::CreateGPU(emu_window, system);
188 if (!gpu_core) { 193 if (!gpu_core) {
189 return ResultStatus::ErrorVideoCore; 194 return ResultStatus::ErrorVideoCore;
190 } 195 }
191 196
197 service_manager = std::make_shared<Service::SM::ServiceManager>(kernel);
198 services = std::make_unique<Service::Services>(service_manager, system);
199 interrupt_manager = std::make_unique<Hardware::InterruptManager>(system);
200
201 // Initialize time manager, which must happen after kernel is created
202 time_manager.Initialize();
203
192 is_powered_on = true; 204 is_powered_on = true;
193 exit_lock = false; 205 exit_lock = false;
194 206
@@ -202,9 +214,11 @@ struct System::Impl {
202 return ResultStatus::Success; 214 return ResultStatus::Success;
203 } 215 }
204 216
205 ResultStatus Load(System& system, Frontend::EmuWindow& emu_window, 217 ResultStatus Load(System& system, Frontend::EmuWindow& emu_window, const std::string& filepath,
206 const std::string& filepath) { 218 std::size_t program_index) {
207 app_loader = Loader::GetLoader(GetGameFileFromPath(virtual_filesystem, filepath)); 219 app_loader = Loader::GetLoader(system, GetGameFileFromPath(virtual_filesystem, filepath),
220 program_index);
221
208 if (!app_loader) { 222 if (!app_loader) {
209 LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath); 223 LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath);
210 return ResultStatus::ErrorGetLoader; 224 return ResultStatus::ErrorGetLoader;
@@ -218,12 +232,12 @@ struct System::Impl {
218 return init_result; 232 return init_result;
219 } 233 }
220 234
221 telemetry_session->AddInitialInfo(*app_loader); 235 telemetry_session->AddInitialInfo(*app_loader, fs_controller, *content_provider);
222 auto main_process = 236 auto main_process =
223 Kernel::Process::Create(system, "main", Kernel::Process::ProcessType::Userland); 237 Kernel::Process::Create(system, "main", Kernel::Process::ProcessType::Userland);
224 const auto [load_result, load_parameters] = app_loader->Load(*main_process, system); 238 const auto [load_result, load_parameters] = app_loader->Load(*main_process, system);
225 if (load_result != Loader::ResultStatus::Success) { 239 if (load_result != Loader::ResultStatus::Success) {
226 LOG_CRITICAL(Core, "Failed to load ROM (Error {})!", static_cast<int>(load_result)); 240 LOG_CRITICAL(Core, "Failed to load ROM (Error {})!", load_result);
227 Shutdown(); 241 Shutdown();
228 242
229 return static_cast<ResultStatus>(static_cast<u32>(ResultStatus::ErrorLoader) + 243 return static_cast<ResultStatus>(static_cast<u32>(ResultStatus::ErrorLoader) +
@@ -231,6 +245,7 @@ struct System::Impl {
231 } 245 }
232 AddGlueRegistrationForProcess(*app_loader, *main_process); 246 AddGlueRegistrationForProcess(*app_loader, *main_process);
233 kernel.MakeCurrentProcess(main_process.get()); 247 kernel.MakeCurrentProcess(main_process.get());
248 kernel.InitializeCores();
234 249
235 // Initialize cheat engine 250 // Initialize cheat engine
236 if (cheat_engine) { 251 if (cheat_engine) {
@@ -252,8 +267,7 @@ struct System::Impl {
252 267
253 u64 title_id{0}; 268 u64 title_id{0};
254 if (app_loader->ReadProgramId(title_id) != Loader::ResultStatus::Success) { 269 if (app_loader->ReadProgramId(title_id) != Loader::ResultStatus::Success) {
255 LOG_ERROR(Core, "Failed to find title id for ROM (Error {})", 270 LOG_ERROR(Core, "Failed to find title id for ROM (Error {})", load_result);
256 static_cast<u32>(load_result));
257 } 271 }
258 perf_stats = std::make_unique<PerfStats>(title_id); 272 perf_stats = std::make_unique<PerfStats>(title_id);
259 // Reset counters and set time origin to current frame 273 // Reset counters and set time origin to current frame
@@ -289,19 +303,17 @@ struct System::Impl {
289 } 303 }
290 304
291 // Shutdown emulation session 305 // Shutdown emulation session
292 GDBStub::Shutdown(); 306 services.reset();
293 Service::Shutdown();
294 service_manager.reset(); 307 service_manager.reset();
295 cheat_engine.reset(); 308 cheat_engine.reset();
296 telemetry_session.reset(); 309 telemetry_session.reset();
297 device_memory.reset();
298 310
299 // Close all CPU/threading state 311 // Close all CPU/threading state
300 cpu_manager.Shutdown(); 312 cpu_manager.Shutdown();
301 313
302 // Shutdown kernel and core timing 314 // Shutdown kernel and core timing
303 kernel.Shutdown();
304 core_timing.Shutdown(); 315 core_timing.Shutdown();
316 kernel.Shutdown();
305 317
306 // Close app loader 318 // Close app loader
307 app_loader.reset(); 319 app_loader.reset();
@@ -332,7 +344,7 @@ struct System::Impl {
332 Service::Glue::ApplicationLaunchProperty launch{}; 344 Service::Glue::ApplicationLaunchProperty launch{};
333 launch.title_id = process.GetTitleID(); 345 launch.title_id = process.GetTitleID();
334 346
335 FileSys::PatchManager pm{launch.title_id}; 347 FileSys::PatchManager pm{launch.title_id, fs_controller, *content_provider};
336 launch.version = pm.GetGameVersion().value_or(0); 348 launch.version = pm.GetGameVersion().value_or(0);
337 349
338 // TODO(DarkLordZach): When FSController/Game Card Support is added, if 350 // TODO(DarkLordZach): When FSController/Game Card Support is added, if
@@ -387,10 +399,14 @@ struct System::Impl {
387 /// Service State 399 /// Service State
388 Service::Glue::ARPManager arp_manager; 400 Service::Glue::ARPManager arp_manager;
389 Service::LM::Manager lm_manager{reporter}; 401 Service::LM::Manager lm_manager{reporter};
402 Service::Time::TimeManager time_manager;
390 403
391 /// Service manager 404 /// Service manager
392 std::shared_ptr<Service::SM::ServiceManager> service_manager; 405 std::shared_ptr<Service::SM::ServiceManager> service_manager;
393 406
407 /// Services
408 std::unique_ptr<Service::Services> services;
409
394 /// Telemetry session for this emulation session 410 /// Telemetry session for this emulation session
395 std::unique_ptr<Core::TelemetrySession> telemetry_session; 411 std::unique_ptr<Core::TelemetrySession> telemetry_session;
396 412
@@ -406,6 +422,8 @@ struct System::Impl {
406 bool is_multicore{}; 422 bool is_multicore{};
407 bool is_async_gpu{}; 423 bool is_async_gpu{};
408 424
425 ExecuteProgramCallback execute_program_callback;
426
409 std::array<u64, Core::Hardware::NUM_CPU_CORES> dynarmic_ticks{}; 427 std::array<u64, Core::Hardware::NUM_CPU_CORES> dynarmic_ticks{};
410 std::array<MicroProfileToken, Core::Hardware::NUM_CPU_CORES> microprofile_dynarmic{}; 428 std::array<MicroProfileToken, Core::Hardware::NUM_CPU_CORES> microprofile_dynarmic{};
411}; 429};
@@ -437,8 +455,17 @@ void System::InvalidateCpuInstructionCaches() {
437 impl->kernel.InvalidateAllInstructionCaches(); 455 impl->kernel.InvalidateAllInstructionCaches();
438} 456}
439 457
440System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath) { 458void System::InvalidateCpuInstructionCacheRange(VAddr addr, std::size_t size) {
441 return impl->Load(*this, emu_window, filepath); 459 impl->kernel.InvalidateCpuInstructionCacheRange(addr, size);
460}
461
462void System::Shutdown() {
463 impl->Shutdown();
464}
465
466System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath,
467 std::size_t program_index) {
468 return impl->Load(*this, emu_window, filepath, program_index);
442} 469}
443 470
444bool System::IsPoweredOn() const { 471bool System::IsPoweredOn() const {
@@ -466,11 +493,11 @@ const TelemetrySession& System::TelemetrySession() const {
466} 493}
467 494
468ARM_Interface& System::CurrentArmInterface() { 495ARM_Interface& System::CurrentArmInterface() {
469 return impl->kernel.CurrentScheduler().GetCurrentThread()->ArmInterface(); 496 return impl->kernel.CurrentPhysicalCore().ArmInterface();
470} 497}
471 498
472const ARM_Interface& System::CurrentArmInterface() const { 499const ARM_Interface& System::CurrentArmInterface() const {
473 return impl->kernel.CurrentScheduler().GetCurrentThread()->ArmInterface(); 500 return impl->kernel.CurrentPhysicalCore().ArmInterface();
474} 501}
475 502
476std::size_t System::CurrentCoreIndex() const { 503std::size_t System::CurrentCoreIndex() const {
@@ -479,14 +506,6 @@ std::size_t System::CurrentCoreIndex() const {
479 return core; 506 return core;
480} 507}
481 508
482Kernel::Scheduler& System::CurrentScheduler() {
483 return impl->kernel.CurrentScheduler();
484}
485
486const Kernel::Scheduler& System::CurrentScheduler() const {
487 return impl->kernel.CurrentScheduler();
488}
489
490Kernel::PhysicalCore& System::CurrentPhysicalCore() { 509Kernel::PhysicalCore& System::CurrentPhysicalCore() {
491 return impl->kernel.CurrentPhysicalCore(); 510 return impl->kernel.CurrentPhysicalCore();
492} 511}
@@ -495,22 +514,14 @@ const Kernel::PhysicalCore& System::CurrentPhysicalCore() const {
495 return impl->kernel.CurrentPhysicalCore(); 514 return impl->kernel.CurrentPhysicalCore();
496} 515}
497 516
498Kernel::Scheduler& System::Scheduler(std::size_t core_index) {
499 return impl->kernel.Scheduler(core_index);
500}
501
502const Kernel::Scheduler& System::Scheduler(std::size_t core_index) const {
503 return impl->kernel.Scheduler(core_index);
504}
505
506/// Gets the global scheduler 517/// Gets the global scheduler
507Kernel::GlobalScheduler& System::GlobalScheduler() { 518Kernel::GlobalSchedulerContext& System::GlobalSchedulerContext() {
508 return impl->kernel.GlobalScheduler(); 519 return impl->kernel.GlobalSchedulerContext();
509} 520}
510 521
511/// Gets the global scheduler 522/// Gets the global scheduler
512const Kernel::GlobalScheduler& System::GlobalScheduler() const { 523const Kernel::GlobalSchedulerContext& System::GlobalSchedulerContext() const {
513 return impl->kernel.GlobalScheduler(); 524 return impl->kernel.GlobalSchedulerContext();
514} 525}
515 526
516Kernel::Process* System::CurrentProcess() { 527Kernel::Process* System::CurrentProcess() {
@@ -530,15 +541,11 @@ const Kernel::Process* System::CurrentProcess() const {
530} 541}
531 542
532ARM_Interface& System::ArmInterface(std::size_t core_index) { 543ARM_Interface& System::ArmInterface(std::size_t core_index) {
533 auto* thread = impl->kernel.Scheduler(core_index).GetCurrentThread(); 544 return impl->kernel.PhysicalCore(core_index).ArmInterface();
534 ASSERT(thread && !thread->IsHLEThread());
535 return thread->ArmInterface();
536} 545}
537 546
538const ARM_Interface& System::ArmInterface(std::size_t core_index) const { 547const ARM_Interface& System::ArmInterface(std::size_t core_index) const {
539 auto* thread = impl->kernel.Scheduler(core_index).GetCurrentThread(); 548 return impl->kernel.PhysicalCore(core_index).ArmInterface();
540 ASSERT(thread && !thread->IsHLEThread());
541 return thread->ArmInterface();
542} 549}
543 550
544ExclusiveMonitor& System::Monitor() { 551ExclusiveMonitor& System::Monitor() {
@@ -625,7 +632,11 @@ const std::string& System::GetStatusDetails() const {
625 return impl->status_details; 632 return impl->status_details;
626} 633}
627 634
628Loader::AppLoader& System::GetAppLoader() const { 635Loader::AppLoader& System::GetAppLoader() {
636 return *impl->app_loader;
637}
638
639const Loader::AppLoader& System::GetAppLoader() const {
629 return *impl->app_loader; 640 return *impl->app_loader;
630} 641}
631 642
@@ -717,6 +728,14 @@ const Service::LM::Manager& System::GetLogManager() const {
717 return impl->lm_manager; 728 return impl->lm_manager;
718} 729}
719 730
731Service::Time::TimeManager& System::GetTimeManager() {
732 return impl->time_manager;
733}
734
735const Service::Time::TimeManager& System::GetTimeManager() const {
736 return impl->time_manager;
737}
738
720void System::SetExitLock(bool locked) { 739void System::SetExitLock(bool locked) {
721 impl->exit_lock = locked; 740 impl->exit_lock = locked;
722} 741}
@@ -733,14 +752,6 @@ const System::CurrentBuildProcessID& System::GetCurrentProcessBuildID() const {
733 return impl->build_id; 752 return impl->build_id;
734} 753}
735 754
736System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) {
737 return impl->Init(*this, emu_window);
738}
739
740void System::Shutdown() {
741 impl->Shutdown();
742}
743
744Service::SM::ServiceManager& System::ServiceManager() { 755Service::SM::ServiceManager& System::ServiceManager() {
745 return *impl->service_manager; 756 return *impl->service_manager;
746} 757}
@@ -771,4 +782,16 @@ bool System::IsMulticore() const {
771 return impl->is_multicore; 782 return impl->is_multicore;
772} 783}
773 784
785void System::RegisterExecuteProgramCallback(ExecuteProgramCallback&& callback) {
786 impl->execute_program_callback = std::move(callback);
787}
788
789void System::ExecuteProgram(std::size_t program_index) {
790 if (impl->execute_program_callback) {
791 impl->execute_program_callback(program_index);
792 } else {
793 LOG_CRITICAL(Core, "execute_program_callback must be initialized by the frontend");
794 }
795}
796
774} // namespace Core 797} // namespace Core
diff --git a/src/core/core.h b/src/core/core.h
index 83ded63a5..579a774e4 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -5,6 +5,7 @@
5#pragma once 5#pragma once
6 6
7#include <cstddef> 7#include <cstddef>
8#include <functional>
8#include <memory> 9#include <memory>
9#include <string> 10#include <string>
10#include <vector> 11#include <vector>
@@ -25,11 +26,11 @@ class VfsFilesystem;
25} // namespace FileSys 26} // namespace FileSys
26 27
27namespace Kernel { 28namespace Kernel {
28class GlobalScheduler; 29class GlobalSchedulerContext;
29class KernelCore; 30class KernelCore;
30class PhysicalCore; 31class PhysicalCore;
31class Process; 32class Process;
32class Scheduler; 33class KScheduler;
33} // namespace Kernel 34} // namespace Kernel
34 35
35namespace Loader { 36namespace Loader {
@@ -69,6 +70,10 @@ namespace SM {
69class ServiceManager; 70class ServiceManager;
70} // namespace SM 71} // namespace SM
71 72
73namespace Time {
74class TimeManager;
75} // namespace Time
76
72} // namespace Service 77} // namespace Service
73 78
74namespace Tegra { 79namespace Tegra {
@@ -120,7 +125,7 @@ public:
120 * Gets the instance of the System singleton class. 125 * Gets the instance of the System singleton class.
121 * @returns Reference to the instance of the System singleton class. 126 * @returns Reference to the instance of the System singleton class.
122 */ 127 */
123 static System& GetInstance() { 128 [[deprecated("Use of the global system instance is deprecated")]] static System& GetInstance() {
124 return s_instance; 129 return s_instance;
125 } 130 }
126 131
@@ -140,19 +145,19 @@ public:
140 * Run the OS and Application 145 * Run the OS and Application
141 * This function will start emulation and run the relevant devices 146 * This function will start emulation and run the relevant devices
142 */ 147 */
143 ResultStatus Run(); 148 [[nodiscard]] ResultStatus Run();
144 149
145 /** 150 /**
146 * Pause the OS and Application 151 * Pause the OS and Application
147 * This function will pause emulation and stop the relevant devices 152 * This function will pause emulation and stop the relevant devices
148 */ 153 */
149 ResultStatus Pause(); 154 [[nodiscard]] ResultStatus Pause();
150 155
151 /** 156 /**
152 * Step the CPU one instruction 157 * Step the CPU one instruction
153 * @return Result status, indicating whether or not the operation succeeded. 158 * @return Result status, indicating whether or not the operation succeeded.
154 */ 159 */
155 ResultStatus SingleStep(); 160 [[nodiscard]] ResultStatus SingleStep();
156 161
157 /** 162 /**
158 * Invalidate the CPU instruction caches 163 * Invalidate the CPU instruction caches
@@ -161,6 +166,8 @@ public:
161 */ 166 */
162 void InvalidateCpuInstructionCaches(); 167 void InvalidateCpuInstructionCaches();
163 168
169 void InvalidateCpuInstructionCacheRange(VAddr addr, std::size_t size);
170
164 /// Shutdown the emulated system. 171 /// Shutdown the emulated system.
165 void Shutdown(); 172 void Shutdown();
166 173
@@ -169,22 +176,24 @@ public:
169 * @param emu_window Reference to the host-system window used for video output and keyboard 176 * @param emu_window Reference to the host-system window used for video output and keyboard
170 * input. 177 * input.
171 * @param filepath String path to the executable application to load on the host file system. 178 * @param filepath String path to the executable application to load on the host file system.
179 * @param program_index Specifies the index within the container of the program to launch.
172 * @returns ResultStatus code, indicating if the operation succeeded. 180 * @returns ResultStatus code, indicating if the operation succeeded.
173 */ 181 */
174 ResultStatus Load(Frontend::EmuWindow& emu_window, const std::string& filepath); 182 [[nodiscard]] ResultStatus Load(Frontend::EmuWindow& emu_window, const std::string& filepath,
183 std::size_t program_index = 0);
175 184
176 /** 185 /**
177 * Indicates if the emulated system is powered on (all subsystems initialized and able to run an 186 * Indicates if the emulated system is powered on (all subsystems initialized and able to run an
178 * application). 187 * application).
179 * @returns True if the emulated system is powered on, otherwise false. 188 * @returns True if the emulated system is powered on, otherwise false.
180 */ 189 */
181 bool IsPoweredOn() const; 190 [[nodiscard]] bool IsPoweredOn() const;
182 191
183 /// Gets a reference to the telemetry session for this emulation session. 192 /// Gets a reference to the telemetry session for this emulation session.
184 Core::TelemetrySession& TelemetrySession(); 193 [[nodiscard]] Core::TelemetrySession& TelemetrySession();
185 194
186 /// Gets a reference to the telemetry session for this emulation session. 195 /// Gets a reference to the telemetry session for this emulation session.
187 const Core::TelemetrySession& TelemetrySession() const; 196 [[nodiscard]] const Core::TelemetrySession& TelemetrySession() const;
188 197
189 /// Prepare the core emulation for a reschedule 198 /// Prepare the core emulation for a reschedule
190 void PrepareReschedule(); 199 void PrepareReschedule();
@@ -193,181 +202,166 @@ public:
193 void PrepareReschedule(u32 core_index); 202 void PrepareReschedule(u32 core_index);
194 203
195 /// Gets and resets core performance statistics 204 /// Gets and resets core performance statistics
196 PerfStatsResults GetAndResetPerfStats(); 205 [[nodiscard]] PerfStatsResults GetAndResetPerfStats();
197 206
198 /// Gets an ARM interface to the CPU core that is currently running 207 /// Gets an ARM interface to the CPU core that is currently running
199 ARM_Interface& CurrentArmInterface(); 208 [[nodiscard]] ARM_Interface& CurrentArmInterface();
200 209
201 /// Gets an ARM interface to the CPU core that is currently running 210 /// Gets an ARM interface to the CPU core that is currently running
202 const ARM_Interface& CurrentArmInterface() const; 211 [[nodiscard]] const ARM_Interface& CurrentArmInterface() const;
203 212
204 /// Gets the index of the currently running CPU core 213 /// Gets the index of the currently running CPU core
205 std::size_t CurrentCoreIndex() const; 214 [[nodiscard]] std::size_t CurrentCoreIndex() const;
206
207 /// Gets the scheduler for the CPU core that is currently running
208 Kernel::Scheduler& CurrentScheduler();
209
210 /// Gets the scheduler for the CPU core that is currently running
211 const Kernel::Scheduler& CurrentScheduler() const;
212 215
213 /// Gets the physical core for the CPU core that is currently running 216 /// Gets the physical core for the CPU core that is currently running
214 Kernel::PhysicalCore& CurrentPhysicalCore(); 217 [[nodiscard]] Kernel::PhysicalCore& CurrentPhysicalCore();
215 218
216 /// Gets the physical core for the CPU core that is currently running 219 /// Gets the physical core for the CPU core that is currently running
217 const Kernel::PhysicalCore& CurrentPhysicalCore() const; 220 [[nodiscard]] const Kernel::PhysicalCore& CurrentPhysicalCore() const;
218 221
219 /// Gets a reference to an ARM interface for the CPU core with the specified index 222 /// Gets a reference to an ARM interface for the CPU core with the specified index
220 ARM_Interface& ArmInterface(std::size_t core_index); 223 [[nodiscard]] ARM_Interface& ArmInterface(std::size_t core_index);
221 224
222 /// Gets a const reference to an ARM interface from the CPU core with the specified index 225 /// Gets a const reference to an ARM interface from the CPU core with the specified index
223 const ARM_Interface& ArmInterface(std::size_t core_index) const; 226 [[nodiscard]] const ARM_Interface& ArmInterface(std::size_t core_index) const;
224 227
225 CpuManager& GetCpuManager(); 228 /// Gets a reference to the underlying CPU manager.
229 [[nodiscard]] CpuManager& GetCpuManager();
226 230
227 const CpuManager& GetCpuManager() const; 231 /// Gets a const reference to the underlying CPU manager
232 [[nodiscard]] const CpuManager& GetCpuManager() const;
228 233
229 /// Gets a reference to the exclusive monitor 234 /// Gets a reference to the exclusive monitor
230 ExclusiveMonitor& Monitor(); 235 [[nodiscard]] ExclusiveMonitor& Monitor();
231 236
232 /// Gets a constant reference to the exclusive monitor 237 /// Gets a constant reference to the exclusive monitor
233 const ExclusiveMonitor& Monitor() const; 238 [[nodiscard]] const ExclusiveMonitor& Monitor() const;
234 239
235 /// Gets a mutable reference to the system memory instance. 240 /// Gets a mutable reference to the system memory instance.
236 Core::Memory::Memory& Memory(); 241 [[nodiscard]] Core::Memory::Memory& Memory();
237 242
238 /// Gets a constant reference to the system memory instance. 243 /// Gets a constant reference to the system memory instance.
239 const Core::Memory::Memory& Memory() const; 244 [[nodiscard]] const Core::Memory::Memory& Memory() const;
240 245
241 /// Gets a mutable reference to the GPU interface 246 /// Gets a mutable reference to the GPU interface
242 Tegra::GPU& GPU(); 247 [[nodiscard]] Tegra::GPU& GPU();
243 248
244 /// Gets an immutable reference to the GPU interface. 249 /// Gets an immutable reference to the GPU interface.
245 const Tegra::GPU& GPU() const; 250 [[nodiscard]] const Tegra::GPU& GPU() const;
246 251
247 /// Gets a mutable reference to the renderer. 252 /// Gets a mutable reference to the renderer.
248 VideoCore::RendererBase& Renderer(); 253 [[nodiscard]] VideoCore::RendererBase& Renderer();
249 254
250 /// Gets an immutable reference to the renderer. 255 /// Gets an immutable reference to the renderer.
251 const VideoCore::RendererBase& Renderer() const; 256 [[nodiscard]] const VideoCore::RendererBase& Renderer() const;
252
253 /// Gets the scheduler for the CPU core with the specified index
254 Kernel::Scheduler& Scheduler(std::size_t core_index);
255
256 /// Gets the scheduler for the CPU core with the specified index
257 const Kernel::Scheduler& Scheduler(std::size_t core_index) const;
258 257
259 /// Gets the global scheduler 258 /// Gets the global scheduler
260 Kernel::GlobalScheduler& GlobalScheduler(); 259 [[nodiscard]] Kernel::GlobalSchedulerContext& GlobalSchedulerContext();
261 260
262 /// Gets the global scheduler 261 /// Gets the global scheduler
263 const Kernel::GlobalScheduler& GlobalScheduler() const; 262 [[nodiscard]] const Kernel::GlobalSchedulerContext& GlobalSchedulerContext() const;
264 263
265 /// Gets the manager for the guest device memory 264 /// Gets the manager for the guest device memory
266 Core::DeviceMemory& DeviceMemory(); 265 [[nodiscard]] Core::DeviceMemory& DeviceMemory();
267 266
268 /// Gets the manager for the guest device memory 267 /// Gets the manager for the guest device memory
269 const Core::DeviceMemory& DeviceMemory() const; 268 [[nodiscard]] const Core::DeviceMemory& DeviceMemory() const;
270 269
271 /// Provides a pointer to the current process 270 /// Provides a pointer to the current process
272 Kernel::Process* CurrentProcess(); 271 [[nodiscard]] Kernel::Process* CurrentProcess();
273 272
274 /// Provides a constant pointer to the current process. 273 /// Provides a constant pointer to the current process.
275 const Kernel::Process* CurrentProcess() const; 274 [[nodiscard]] const Kernel::Process* CurrentProcess() const;
276 275
277 /// Provides a reference to the core timing instance. 276 /// Provides a reference to the core timing instance.
278 Timing::CoreTiming& CoreTiming(); 277 [[nodiscard]] Timing::CoreTiming& CoreTiming();
279 278
280 /// Provides a constant reference to the core timing instance. 279 /// Provides a constant reference to the core timing instance.
281 const Timing::CoreTiming& CoreTiming() const; 280 [[nodiscard]] const Timing::CoreTiming& CoreTiming() const;
282 281
283 /// Provides a reference to the interrupt manager instance. 282 /// Provides a reference to the interrupt manager instance.
284 Core::Hardware::InterruptManager& InterruptManager(); 283 [[nodiscard]] Core::Hardware::InterruptManager& InterruptManager();
285 284
286 /// Provides a constant reference to the interrupt manager instance. 285 /// Provides a constant reference to the interrupt manager instance.
287 const Core::Hardware::InterruptManager& InterruptManager() const; 286 [[nodiscard]] const Core::Hardware::InterruptManager& InterruptManager() const;
288 287
289 /// Provides a reference to the kernel instance. 288 /// Provides a reference to the kernel instance.
290 Kernel::KernelCore& Kernel(); 289 [[nodiscard]] Kernel::KernelCore& Kernel();
291 290
292 /// Provides a constant reference to the kernel instance. 291 /// Provides a constant reference to the kernel instance.
293 const Kernel::KernelCore& Kernel() const; 292 [[nodiscard]] const Kernel::KernelCore& Kernel() const;
294 293
295 /// Provides a reference to the internal PerfStats instance. 294 /// Provides a reference to the internal PerfStats instance.
296 Core::PerfStats& GetPerfStats(); 295 [[nodiscard]] Core::PerfStats& GetPerfStats();
297 296
298 /// Provides a constant reference to the internal PerfStats instance. 297 /// Provides a constant reference to the internal PerfStats instance.
299 const Core::PerfStats& GetPerfStats() const; 298 [[nodiscard]] const Core::PerfStats& GetPerfStats() const;
300 299
301 /// Provides a reference to the frame limiter; 300 /// Provides a reference to the frame limiter;
302 Core::FrameLimiter& FrameLimiter(); 301 [[nodiscard]] Core::FrameLimiter& FrameLimiter();
303 302
304 /// Provides a constant referent to the frame limiter 303 /// Provides a constant referent to the frame limiter
305 const Core::FrameLimiter& FrameLimiter() const; 304 [[nodiscard]] const Core::FrameLimiter& FrameLimiter() const;
306 305
307 /// Gets the name of the current game 306 /// Gets the name of the current game
308 Loader::ResultStatus GetGameName(std::string& out) const; 307 [[nodiscard]] Loader::ResultStatus GetGameName(std::string& out) const;
309 308
310 void SetStatus(ResultStatus new_status, const char* details); 309 void SetStatus(ResultStatus new_status, const char* details);
311 310
312 const std::string& GetStatusDetails() const; 311 [[nodiscard]] const std::string& GetStatusDetails() const;
313 312
314 Loader::AppLoader& GetAppLoader() const; 313 [[nodiscard]] Loader::AppLoader& GetAppLoader();
314 [[nodiscard]] const Loader::AppLoader& GetAppLoader() const;
315 315
316 Service::SM::ServiceManager& ServiceManager(); 316 [[nodiscard]] Service::SM::ServiceManager& ServiceManager();
317 const Service::SM::ServiceManager& ServiceManager() const; 317 [[nodiscard]] const Service::SM::ServiceManager& ServiceManager() const;
318 318
319 void SetFilesystem(FileSys::VirtualFilesystem vfs); 319 void SetFilesystem(FileSys::VirtualFilesystem vfs);
320 320
321 FileSys::VirtualFilesystem GetFilesystem() const; 321 [[nodiscard]] FileSys::VirtualFilesystem GetFilesystem() const;
322 322
323 void RegisterCheatList(const std::vector<Memory::CheatEntry>& list, 323 void RegisterCheatList(const std::vector<Memory::CheatEntry>& list,
324 const std::array<u8, 0x20>& build_id, VAddr main_region_begin, 324 const std::array<u8, 0x20>& build_id, VAddr main_region_begin,
325 u64 main_region_size); 325 u64 main_region_size);
326 326
327 void SetAppletFrontendSet(Service::AM::Applets::AppletFrontendSet&& set); 327 void SetAppletFrontendSet(Service::AM::Applets::AppletFrontendSet&& set);
328
329 void SetDefaultAppletFrontendSet(); 328 void SetDefaultAppletFrontendSet();
330 329
331 Service::AM::Applets::AppletManager& GetAppletManager(); 330 [[nodiscard]] Service::AM::Applets::AppletManager& GetAppletManager();
332 331 [[nodiscard]] const Service::AM::Applets::AppletManager& GetAppletManager() const;
333 const Service::AM::Applets::AppletManager& GetAppletManager() const;
334 332
335 void SetContentProvider(std::unique_ptr<FileSys::ContentProviderUnion> provider); 333 void SetContentProvider(std::unique_ptr<FileSys::ContentProviderUnion> provider);
336 334
337 FileSys::ContentProvider& GetContentProvider(); 335 [[nodiscard]] FileSys::ContentProvider& GetContentProvider();
338 336 [[nodiscard]] const FileSys::ContentProvider& GetContentProvider() const;
339 const FileSys::ContentProvider& GetContentProvider() const;
340 337
341 Service::FileSystem::FileSystemController& GetFileSystemController(); 338 [[nodiscard]] Service::FileSystem::FileSystemController& GetFileSystemController();
342 339 [[nodiscard]] const Service::FileSystem::FileSystemController& GetFileSystemController() const;
343 const Service::FileSystem::FileSystemController& GetFileSystemController() const;
344 340
345 void RegisterContentProvider(FileSys::ContentProviderUnionSlot slot, 341 void RegisterContentProvider(FileSys::ContentProviderUnionSlot slot,
346 FileSys::ContentProvider* provider); 342 FileSys::ContentProvider* provider);
347 343
348 void ClearContentProvider(FileSys::ContentProviderUnionSlot slot); 344 void ClearContentProvider(FileSys::ContentProviderUnionSlot slot);
349 345
350 const Reporter& GetReporter() const; 346 [[nodiscard]] const Reporter& GetReporter() const;
351
352 Service::Glue::ARPManager& GetARPManager();
353
354 const Service::Glue::ARPManager& GetARPManager() const;
355 347
356 Service::APM::Controller& GetAPMController(); 348 [[nodiscard]] Service::Glue::ARPManager& GetARPManager();
349 [[nodiscard]] const Service::Glue::ARPManager& GetARPManager() const;
357 350
358 const Service::APM::Controller& GetAPMController() const; 351 [[nodiscard]] Service::APM::Controller& GetAPMController();
352 [[nodiscard]] const Service::APM::Controller& GetAPMController() const;
359 353
360 Service::LM::Manager& GetLogManager(); 354 [[nodiscard]] Service::LM::Manager& GetLogManager();
355 [[nodiscard]] const Service::LM::Manager& GetLogManager() const;
361 356
362 const Service::LM::Manager& GetLogManager() const; 357 [[nodiscard]] Service::Time::TimeManager& GetTimeManager();
358 [[nodiscard]] const Service::Time::TimeManager& GetTimeManager() const;
363 359
364 void SetExitLock(bool locked); 360 void SetExitLock(bool locked);
365 361 [[nodiscard]] bool GetExitLock() const;
366 bool GetExitLock() const;
367 362
368 void SetCurrentProcessBuildID(const CurrentBuildProcessID& id); 363 void SetCurrentProcessBuildID(const CurrentBuildProcessID& id);
369 364 [[nodiscard]] const CurrentBuildProcessID& GetCurrentProcessBuildID() const;
370 const CurrentBuildProcessID& GetCurrentProcessBuildID() const;
371 365
372 /// Register a host thread as an emulated CPU Core. 366 /// Register a host thread as an emulated CPU Core.
373 void RegisterCoreThread(std::size_t id); 367 void RegisterCoreThread(std::size_t id);
@@ -382,18 +376,27 @@ public:
382 void ExitDynarmicProfile(); 376 void ExitDynarmicProfile();
383 377
384 /// Tells if system is running on multicore. 378 /// Tells if system is running on multicore.
385 bool IsMulticore() const; 379 [[nodiscard]] bool IsMulticore() const;
386 380
387private: 381 /// Type used for the frontend to designate a callback for System to re-launch the application
388 System(); 382 /// using a specified program index.
383 using ExecuteProgramCallback = std::function<void(std::size_t)>;
389 384
390 /** 385 /**
391 * Initialize the emulated system. 386 * Registers a callback from the frontend for System to re-launch the application using a
392 * @param emu_window Reference to the host-system window used for video output and keyboard 387 * specified program index.
393 * input. 388 * @param callback Callback from the frontend to relaunch the application.
394 * @return ResultStatus code, indicating if the operation succeeded.
395 */ 389 */
396 ResultStatus Init(Frontend::EmuWindow& emu_window); 390 void RegisterExecuteProgramCallback(ExecuteProgramCallback&& callback);
391
392 /**
393 * Instructs the frontend to re-launch the application using the specified program_index.
394 * @param program_index Specifies the index within the application of the program to launch.
395 */
396 void ExecuteProgram(std::size_t program_index);
397
398private:
399 System();
397 400
398 struct Impl; 401 struct Impl;
399 std::unique_ptr<Impl> impl; 402 std::unique_ptr<Impl> impl;
diff --git a/src/core/core_timing.h b/src/core/core_timing.h
index b0b6036e4..77ff4c6fe 100644
--- a/src/core/core_timing.h
+++ b/src/core/core_timing.h
@@ -27,8 +27,8 @@ using TimedCallback =
27 27
28/// Contains the characteristics of a particular event. 28/// Contains the characteristics of a particular event.
29struct EventType { 29struct EventType {
30 EventType(TimedCallback&& callback, std::string&& name) 30 explicit EventType(TimedCallback&& callback_, std::string&& name_)
31 : callback{std::move(callback)}, name{std::move(name)} {} 31 : callback{std::move(callback_)}, name{std::move(name_)} {}
32 32
33 /// The event's callback function. 33 /// The event's callback function.
34 TimedCallback callback; 34 TimedCallback callback;
@@ -67,8 +67,8 @@ public:
67 void Shutdown(); 67 void Shutdown();
68 68
69 /// Sets if emulation is multicore or single core, must be set before Initialize 69 /// Sets if emulation is multicore or single core, must be set before Initialize
70 void SetMulticore(bool is_multicore) { 70 void SetMulticore(bool is_multicore_) {
71 this->is_multicore = is_multicore; 71 is_multicore = is_multicore_;
72 } 72 }
73 73
74 /// Check if it's using host timing. 74 /// Check if it's using host timing.
diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp
index 688b99eba..373395047 100644
--- a/src/core/cpu_manager.cpp
+++ b/src/core/cpu_manager.cpp
@@ -4,15 +4,15 @@
4 4
5#include "common/fiber.h" 5#include "common/fiber.h"
6#include "common/microprofile.h" 6#include "common/microprofile.h"
7#include "common/scope_exit.h"
7#include "common/thread.h" 8#include "common/thread.h"
8#include "core/arm/exclusive_monitor.h" 9#include "core/arm/exclusive_monitor.h"
9#include "core/core.h" 10#include "core/core.h"
10#include "core/core_timing.h" 11#include "core/core_timing.h"
11#include "core/cpu_manager.h" 12#include "core/cpu_manager.h"
12#include "core/gdbstub/gdbstub.h" 13#include "core/hle/kernel/k_scheduler.h"
13#include "core/hle/kernel/kernel.h" 14#include "core/hle/kernel/kernel.h"
14#include "core/hle/kernel/physical_core.h" 15#include "core/hle/kernel/physical_core.h"
15#include "core/hle/kernel/scheduler.h"
16#include "core/hle/kernel/thread.h" 16#include "core/hle/kernel/thread.h"
17#include "video_core/gpu.h" 17#include "video_core/gpu.h"
18 18
@@ -109,28 +109,26 @@ void* CpuManager::GetStartFuncParamater() {
109 109
110void CpuManager::MultiCoreRunGuestThread() { 110void CpuManager::MultiCoreRunGuestThread() {
111 auto& kernel = system.Kernel(); 111 auto& kernel = system.Kernel();
112 { 112 kernel.CurrentScheduler()->OnThreadStart();
113 auto& sched = kernel.CurrentScheduler(); 113 auto* thread = kernel.CurrentScheduler()->GetCurrentThread();
114 sched.OnThreadStart(); 114 auto& host_context = thread->GetHostContext();
115 } 115 host_context->SetRewindPoint(GuestRewindFunction, this);
116 MultiCoreRunGuestLoop(); 116 MultiCoreRunGuestLoop();
117} 117}
118 118
119void CpuManager::MultiCoreRunGuestLoop() { 119void CpuManager::MultiCoreRunGuestLoop() {
120 auto& kernel = system.Kernel(); 120 auto& kernel = system.Kernel();
121 auto* thread = kernel.CurrentScheduler().GetCurrentThread(); 121
122 while (true) { 122 while (true) {
123 auto* physical_core = &kernel.CurrentPhysicalCore(); 123 auto* physical_core = &kernel.CurrentPhysicalCore();
124 auto& arm_interface = thread->ArmInterface();
125 system.EnterDynarmicProfile(); 124 system.EnterDynarmicProfile();
126 while (!physical_core->IsInterrupted()) { 125 while (!physical_core->IsInterrupted()) {
127 arm_interface.Run(); 126 physical_core->Run();
128 physical_core = &kernel.CurrentPhysicalCore(); 127 physical_core = &kernel.CurrentPhysicalCore();
129 } 128 }
130 system.ExitDynarmicProfile(); 129 system.ExitDynarmicProfile();
131 arm_interface.ClearExclusiveState(); 130 physical_core->ArmInterface().ClearExclusiveState();
132 auto& scheduler = kernel.CurrentScheduler(); 131 kernel.CurrentScheduler()->RescheduleCurrentCore();
133 scheduler.TryDoContextSwitch();
134 } 132 }
135} 133}
136 134
@@ -139,25 +137,21 @@ void CpuManager::MultiCoreRunIdleThread() {
139 while (true) { 137 while (true) {
140 auto& physical_core = kernel.CurrentPhysicalCore(); 138 auto& physical_core = kernel.CurrentPhysicalCore();
141 physical_core.Idle(); 139 physical_core.Idle();
142 auto& scheduler = kernel.CurrentScheduler(); 140 kernel.CurrentScheduler()->RescheduleCurrentCore();
143 scheduler.TryDoContextSwitch();
144 } 141 }
145} 142}
146 143
147void CpuManager::MultiCoreRunSuspendThread() { 144void CpuManager::MultiCoreRunSuspendThread() {
148 auto& kernel = system.Kernel(); 145 auto& kernel = system.Kernel();
149 { 146 kernel.CurrentScheduler()->OnThreadStart();
150 auto& sched = kernel.CurrentScheduler();
151 sched.OnThreadStart();
152 }
153 while (true) { 147 while (true) {
154 auto core = kernel.GetCurrentHostThreadID(); 148 auto core = kernel.GetCurrentHostThreadID();
155 auto& scheduler = kernel.CurrentScheduler(); 149 auto& scheduler = *kernel.CurrentScheduler();
156 Kernel::Thread* current_thread = scheduler.GetCurrentThread(); 150 Kernel::Thread* current_thread = scheduler.GetCurrentThread();
157 Common::Fiber::YieldTo(current_thread->GetHostContext(), core_data[core].host_context); 151 Common::Fiber::YieldTo(current_thread->GetHostContext(), core_data[core].host_context);
158 ASSERT(scheduler.ContextSwitchPending()); 152 ASSERT(scheduler.ContextSwitchPending());
159 ASSERT(core == kernel.GetCurrentHostThreadID()); 153 ASSERT(core == kernel.GetCurrentHostThreadID());
160 scheduler.TryDoContextSwitch(); 154 scheduler.RescheduleCurrentCore();
161 } 155 }
162} 156}
163 157
@@ -205,32 +199,31 @@ void CpuManager::MultiCorePause(bool paused) {
205 199
206void CpuManager::SingleCoreRunGuestThread() { 200void CpuManager::SingleCoreRunGuestThread() {
207 auto& kernel = system.Kernel(); 201 auto& kernel = system.Kernel();
208 { 202 kernel.CurrentScheduler()->OnThreadStart();
209 auto& sched = kernel.CurrentScheduler(); 203 auto* thread = kernel.CurrentScheduler()->GetCurrentThread();
210 sched.OnThreadStart(); 204 auto& host_context = thread->GetHostContext();
211 } 205 host_context->SetRewindPoint(GuestRewindFunction, this);
212 SingleCoreRunGuestLoop(); 206 SingleCoreRunGuestLoop();
213} 207}
214 208
215void CpuManager::SingleCoreRunGuestLoop() { 209void CpuManager::SingleCoreRunGuestLoop() {
216 auto& kernel = system.Kernel(); 210 auto& kernel = system.Kernel();
217 auto* thread = kernel.CurrentScheduler().GetCurrentThread(); 211 auto* thread = kernel.CurrentScheduler()->GetCurrentThread();
218 while (true) { 212 while (true) {
219 auto* physical_core = &kernel.CurrentPhysicalCore(); 213 auto* physical_core = &kernel.CurrentPhysicalCore();
220 auto& arm_interface = thread->ArmInterface();
221 system.EnterDynarmicProfile(); 214 system.EnterDynarmicProfile();
222 if (!physical_core->IsInterrupted()) { 215 if (!physical_core->IsInterrupted()) {
223 arm_interface.Run(); 216 physical_core->Run();
224 physical_core = &kernel.CurrentPhysicalCore(); 217 physical_core = &kernel.CurrentPhysicalCore();
225 } 218 }
226 system.ExitDynarmicProfile(); 219 system.ExitDynarmicProfile();
227 thread->SetPhantomMode(true); 220 thread->SetPhantomMode(true);
228 system.CoreTiming().Advance(); 221 system.CoreTiming().Advance();
229 thread->SetPhantomMode(false); 222 thread->SetPhantomMode(false);
230 arm_interface.ClearExclusiveState(); 223 physical_core->ArmInterface().ClearExclusiveState();
231 PreemptSingleCore(); 224 PreemptSingleCore();
232 auto& scheduler = kernel.Scheduler(current_core); 225 auto& scheduler = kernel.Scheduler(current_core);
233 scheduler.TryDoContextSwitch(); 226 scheduler.RescheduleCurrentCore();
234 } 227 }
235} 228}
236 229
@@ -242,51 +235,53 @@ void CpuManager::SingleCoreRunIdleThread() {
242 system.CoreTiming().AddTicks(1000U); 235 system.CoreTiming().AddTicks(1000U);
243 idle_count++; 236 idle_count++;
244 auto& scheduler = physical_core.Scheduler(); 237 auto& scheduler = physical_core.Scheduler();
245 scheduler.TryDoContextSwitch(); 238 scheduler.RescheduleCurrentCore();
246 } 239 }
247} 240}
248 241
249void CpuManager::SingleCoreRunSuspendThread() { 242void CpuManager::SingleCoreRunSuspendThread() {
250 auto& kernel = system.Kernel(); 243 auto& kernel = system.Kernel();
251 { 244 kernel.CurrentScheduler()->OnThreadStart();
252 auto& sched = kernel.CurrentScheduler();
253 sched.OnThreadStart();
254 }
255 while (true) { 245 while (true) {
256 auto core = kernel.GetCurrentHostThreadID(); 246 auto core = kernel.GetCurrentHostThreadID();
257 auto& scheduler = kernel.CurrentScheduler(); 247 auto& scheduler = *kernel.CurrentScheduler();
258 Kernel::Thread* current_thread = scheduler.GetCurrentThread(); 248 Kernel::Thread* current_thread = scheduler.GetCurrentThread();
259 Common::Fiber::YieldTo(current_thread->GetHostContext(), core_data[0].host_context); 249 Common::Fiber::YieldTo(current_thread->GetHostContext(), core_data[0].host_context);
260 ASSERT(scheduler.ContextSwitchPending()); 250 ASSERT(scheduler.ContextSwitchPending());
261 ASSERT(core == kernel.GetCurrentHostThreadID()); 251 ASSERT(core == kernel.GetCurrentHostThreadID());
262 scheduler.TryDoContextSwitch(); 252 scheduler.RescheduleCurrentCore();
263 } 253 }
264} 254}
265 255
266void CpuManager::PreemptSingleCore(bool from_running_enviroment) { 256void CpuManager::PreemptSingleCore(bool from_running_enviroment) {
267 std::size_t old_core = current_core; 257 {
268 auto& scheduler = system.Kernel().Scheduler(old_core); 258 auto& scheduler = system.Kernel().Scheduler(current_core);
269 Kernel::Thread* current_thread = scheduler.GetCurrentThread(); 259 Kernel::Thread* current_thread = scheduler.GetCurrentThread();
270 if (idle_count >= 4 || from_running_enviroment) { 260 if (idle_count >= 4 || from_running_enviroment) {
271 if (!from_running_enviroment) { 261 if (!from_running_enviroment) {
272 system.CoreTiming().Idle(); 262 system.CoreTiming().Idle();
273 idle_count = 0; 263 idle_count = 0;
264 }
265 current_thread->SetPhantomMode(true);
266 system.CoreTiming().Advance();
267 current_thread->SetPhantomMode(false);
274 } 268 }
275 current_thread->SetPhantomMode(true); 269 current_core.store((current_core + 1) % Core::Hardware::NUM_CPU_CORES);
276 system.CoreTiming().Advance(); 270 system.CoreTiming().ResetTicks();
277 current_thread->SetPhantomMode(false); 271 scheduler.Unload(scheduler.GetCurrentThread());
272
273 auto& next_scheduler = system.Kernel().Scheduler(current_core);
274 Common::Fiber::YieldTo(current_thread->GetHostContext(), next_scheduler.ControlContext());
278 } 275 }
279 current_core.store((current_core + 1) % Core::Hardware::NUM_CPU_CORES); 276
280 system.CoreTiming().ResetTicks(); 277 // May have changed scheduler
281 scheduler.Unload(); 278 {
282 auto& next_scheduler = system.Kernel().Scheduler(current_core); 279 auto& scheduler = system.Kernel().Scheduler(current_core);
283 Common::Fiber::YieldTo(current_thread->GetHostContext(), next_scheduler.ControlContext()); 280 scheduler.Reload(scheduler.GetCurrentThread());
284 /// May have changed scheduler 281 auto* currrent_thread2 = scheduler.GetCurrentThread();
285 auto& current_scheduler = system.Kernel().Scheduler(current_core); 282 if (!currrent_thread2->IsIdleThread()) {
286 current_scheduler.Reload(); 283 idle_count = 0;
287 auto* currrent_thread2 = current_scheduler.GetCurrentThread(); 284 }
288 if (!currrent_thread2->IsIdleThread()) {
289 idle_count = 0;
290 } 285 }
291} 286}
292 287
@@ -343,6 +338,16 @@ void CpuManager::RunThread(std::size_t core) {
343 data.initialized = true; 338 data.initialized = true;
344 const bool sc_sync = !is_async_gpu && !is_multicore; 339 const bool sc_sync = !is_async_gpu && !is_multicore;
345 bool sc_sync_first_use = sc_sync; 340 bool sc_sync_first_use = sc_sync;
341
342 // Cleanup
343 SCOPE_EXIT({
344 data.host_context->Exit();
345 data.enter_barrier.reset();
346 data.exit_barrier.reset();
347 data.initialized = false;
348 MicroProfileOnThreadExit();
349 });
350
346 /// Running 351 /// Running
347 while (running_mode) { 352 while (running_mode) {
348 data.is_running = false; 353 data.is_running = false;
@@ -351,8 +356,13 @@ void CpuManager::RunThread(std::size_t core) {
351 system.GPU().ObtainContext(); 356 system.GPU().ObtainContext();
352 sc_sync_first_use = false; 357 sc_sync_first_use = false;
353 } 358 }
354 auto& scheduler = system.Kernel().CurrentScheduler(); 359
355 Kernel::Thread* current_thread = scheduler.GetCurrentThread(); 360 // Abort if emulation was killed before the session really starts
361 if (!system.IsPoweredOn()) {
362 return;
363 }
364
365 auto current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread();
356 data.is_running = true; 366 data.is_running = true;
357 Common::Fiber::YieldTo(data.host_context, current_thread->GetHostContext()); 367 Common::Fiber::YieldTo(data.host_context, current_thread->GetHostContext());
358 data.is_running = false; 368 data.is_running = false;
@@ -360,11 +370,6 @@ void CpuManager::RunThread(std::size_t core) {
360 data.exit_barrier->Wait(); 370 data.exit_barrier->Wait();
361 data.is_paused = false; 371 data.is_paused = false;
362 } 372 }
363 /// Time to cleanup
364 data.host_context->Exit();
365 data.enter_barrier.reset();
366 data.exit_barrier.reset();
367 data.initialized = false;
368} 373}
369 374
370} // namespace Core 375} // namespace Core
diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp
index 65d246050..cebe2ce37 100644
--- a/src/core/crypto/key_manager.cpp
+++ b/src/core/crypto/key_manager.cpp
@@ -143,6 +143,7 @@ u64 GetSignatureTypeDataSize(SignatureType type) {
143 return 0x3C; 143 return 0x3C;
144 } 144 }
145 UNREACHABLE(); 145 UNREACHABLE();
146 return 0;
146} 147}
147 148
148u64 GetSignatureTypePaddingSize(SignatureType type) { 149u64 GetSignatureTypePaddingSize(SignatureType type) {
@@ -157,6 +158,7 @@ u64 GetSignatureTypePaddingSize(SignatureType type) {
157 return 0x40; 158 return 0x40;
158 } 159 }
159 UNREACHABLE(); 160 UNREACHABLE();
161 return 0;
160} 162}
161 163
162SignatureType Ticket::GetSignatureType() const { 164SignatureType Ticket::GetSignatureType() const {
@@ -169,8 +171,7 @@ SignatureType Ticket::GetSignatureType() const {
169 if (const auto* ticket = std::get_if<ECDSATicket>(&data)) { 171 if (const auto* ticket = std::get_if<ECDSATicket>(&data)) {
170 return ticket->sig_type; 172 return ticket->sig_type;
171 } 173 }
172 174 throw std::bad_variant_access{};
173 UNREACHABLE();
174} 175}
175 176
176TicketData& Ticket::GetData() { 177TicketData& Ticket::GetData() {
@@ -183,8 +184,7 @@ TicketData& Ticket::GetData() {
183 if (auto* ticket = std::get_if<ECDSATicket>(&data)) { 184 if (auto* ticket = std::get_if<ECDSATicket>(&data)) {
184 return ticket->data; 185 return ticket->data;
185 } 186 }
186 187 throw std::bad_variant_access{};
187 UNREACHABLE();
188} 188}
189 189
190const TicketData& Ticket::GetData() const { 190const TicketData& Ticket::GetData() const {
@@ -197,8 +197,7 @@ const TicketData& Ticket::GetData() const {
197 if (const auto* ticket = std::get_if<ECDSATicket>(&data)) { 197 if (const auto* ticket = std::get_if<ECDSATicket>(&data)) {
198 return ticket->data; 198 return ticket->data;
199 } 199 }
200 200 throw std::bad_variant_access{};
201 UNREACHABLE();
202} 201}
203 202
204u64 Ticket::GetSize() const { 203u64 Ticket::GetSize() const {
@@ -411,7 +410,7 @@ Loader::ResultStatus DeriveSDKeys(std::array<Key256, 2>& sd_keys, KeyManager& ke
411 // Combine sources and seed 410 // Combine sources and seed
412 for (auto& source : sd_key_sources) { 411 for (auto& source : sd_key_sources) {
413 for (std::size_t i = 0; i < source.size(); ++i) { 412 for (std::size_t i = 0; i < source.size(); ++i) {
414 source[i] ^= sd_seed[i & 0xF]; 413 source[i] = static_cast<u8>(source[i] ^ sd_seed[i & 0xF]);
415 } 414 }
416 } 415 }
417 416
diff --git a/src/core/file_sys/card_image.cpp b/src/core/file_sys/card_image.cpp
index 956da68f7..8dee5590b 100644
--- a/src/core/file_sys/card_image.cpp
+++ b/src/core/file_sys/card_image.cpp
@@ -29,7 +29,7 @@ constexpr std::array partition_names{
29 "logo", 29 "logo",
30}; 30};
31 31
32XCI::XCI(VirtualFile file_) 32XCI::XCI(VirtualFile file_, std::size_t program_index)
33 : file(std::move(file_)), program_nca_status{Loader::ResultStatus::ErrorXCIMissingProgramNCA}, 33 : file(std::move(file_)), program_nca_status{Loader::ResultStatus::ErrorXCIMissingProgramNCA},
34 partitions(partition_names.size()), 34 partitions(partition_names.size()),
35 partitions_raw(partition_names.size()), keys{Core::Crypto::KeyManager::Instance()} { 35 partitions_raw(partition_names.size()), keys{Core::Crypto::KeyManager::Instance()} {
@@ -62,7 +62,8 @@ XCI::XCI(VirtualFile file_)
62 } 62 }
63 63
64 secure_partition = std::make_shared<NSP>( 64 secure_partition = std::make_shared<NSP>(
65 main_hfs.GetFile(partition_names[static_cast<std::size_t>(XCIPartition::Secure)])); 65 main_hfs.GetFile(partition_names[static_cast<std::size_t>(XCIPartition::Secure)]),
66 program_index);
66 67
67 ncas = secure_partition->GetNCAsCollapsed(); 68 ncas = secure_partition->GetNCAsCollapsed();
68 program = 69 program =
diff --git a/src/core/file_sys/card_image.h b/src/core/file_sys/card_image.h
index 2d0a0f285..4960e90fe 100644
--- a/src/core/file_sys/card_image.h
+++ b/src/core/file_sys/card_image.h
@@ -78,7 +78,7 @@ enum class XCIPartition : u8 { Update, Normal, Secure, Logo };
78 78
79class XCI : public ReadOnlyVfsDirectory { 79class XCI : public ReadOnlyVfsDirectory {
80public: 80public:
81 explicit XCI(VirtualFile file); 81 explicit XCI(VirtualFile file, std::size_t program_index = 0);
82 ~XCI() override; 82 ~XCI() override;
83 83
84 Loader::ResultStatus GetStatus() const; 84 Loader::ResultStatus GetStatus() const;
diff --git a/src/core/file_sys/common_funcs.h b/src/core/file_sys/common_funcs.h
new file mode 100644
index 000000000..7ed97aa50
--- /dev/null
+++ b/src/core/file_sys/common_funcs.h
@@ -0,0 +1,56 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "common/common_types.h"
8
9namespace FileSys {
10
11constexpr u64 AOC_TITLE_ID_MASK = 0x7FF;
12constexpr u64 AOC_TITLE_ID_OFFSET = 0x1000;
13constexpr u64 BASE_TITLE_ID_MASK = 0xFFFFFFFFFFFFE000;
14
15/**
16 * Gets the base title ID from a given title ID.
17 *
18 * @param title_id The title ID.
19 * @returns The base title ID.
20 */
21[[nodiscard]] constexpr u64 GetBaseTitleID(u64 title_id) {
22 return title_id & BASE_TITLE_ID_MASK;
23}
24
25/**
26 * Gets the base title ID with a program index offset from a given title ID.
27 *
28 * @param title_id The title ID.
29 * @param program_index The program index.
30 * @returns The base title ID with a program index offset.
31 */
32[[nodiscard]] constexpr u64 GetBaseTitleIDWithProgramIndex(u64 title_id, u64 program_index) {
33 return GetBaseTitleID(title_id) + program_index;
34}
35
36/**
37 * Gets the AOC (Add-On Content) base title ID from a given title ID.
38 *
39 * @param title_id The title ID.
40 * @returns The AOC base title ID.
41 */
42[[nodiscard]] constexpr u64 GetAOCBaseTitleID(u64 title_id) {
43 return GetBaseTitleID(title_id) + AOC_TITLE_ID_OFFSET;
44}
45
46/**
47 * Gets the AOC (Add-On Content) ID from a given AOC title ID.
48 *
49 * @param aoc_title_id The AOC title ID.
50 * @returns The AOC ID.
51 */
52[[nodiscard]] constexpr u64 GetAOCID(u64 aoc_title_id) {
53 return aoc_title_id & AOC_TITLE_ID_MASK;
54}
55
56} // namespace FileSys
diff --git a/src/core/file_sys/content_archive.cpp b/src/core/file_sys/content_archive.cpp
index 76af47ff9..a6c0337fa 100644
--- a/src/core/file_sys/content_archive.cpp
+++ b/src/core/file_sys/content_archive.cpp
@@ -410,8 +410,9 @@ u8 NCA::GetCryptoRevision() const {
410std::optional<Core::Crypto::Key128> NCA::GetKeyAreaKey(NCASectionCryptoType type) const { 410std::optional<Core::Crypto::Key128> NCA::GetKeyAreaKey(NCASectionCryptoType type) const {
411 const auto master_key_id = GetCryptoRevision(); 411 const auto master_key_id = GetCryptoRevision();
412 412
413 if (!keys.HasKey(Core::Crypto::S128KeyType::KeyArea, master_key_id, header.key_index)) 413 if (!keys.HasKey(Core::Crypto::S128KeyType::KeyArea, master_key_id, header.key_index)) {
414 return {}; 414 return std::nullopt;
415 }
415 416
416 std::vector<u8> key_area(header.key_area.begin(), header.key_area.end()); 417 std::vector<u8> key_area(header.key_area.begin(), header.key_area.end());
417 Core::Crypto::AESCipher<Core::Crypto::Key128> cipher( 418 Core::Crypto::AESCipher<Core::Crypto::Key128> cipher(
@@ -420,15 +421,17 @@ std::optional<Core::Crypto::Key128> NCA::GetKeyAreaKey(NCASectionCryptoType type
420 cipher.Transcode(key_area.data(), key_area.size(), key_area.data(), Core::Crypto::Op::Decrypt); 421 cipher.Transcode(key_area.data(), key_area.size(), key_area.data(), Core::Crypto::Op::Decrypt);
421 422
422 Core::Crypto::Key128 out; 423 Core::Crypto::Key128 out;
423 if (type == NCASectionCryptoType::XTS) 424 if (type == NCASectionCryptoType::XTS) {
424 std::copy(key_area.begin(), key_area.begin() + 0x10, out.begin()); 425 std::copy(key_area.begin(), key_area.begin() + 0x10, out.begin());
425 else if (type == NCASectionCryptoType::CTR || type == NCASectionCryptoType::BKTR) 426 } else if (type == NCASectionCryptoType::CTR || type == NCASectionCryptoType::BKTR) {
426 std::copy(key_area.begin() + 0x20, key_area.begin() + 0x30, out.begin()); 427 std::copy(key_area.begin() + 0x20, key_area.begin() + 0x30, out.begin());
427 else 428 } else {
428 LOG_CRITICAL(Crypto, "Called GetKeyAreaKey on invalid NCASectionCryptoType type={:02X}", 429 LOG_CRITICAL(Crypto, "Called GetKeyAreaKey on invalid NCASectionCryptoType type={:02X}",
429 static_cast<u8>(type)); 430 type);
431 }
432
430 u128 out_128{}; 433 u128 out_128{};
431 memcpy(out_128.data(), out.data(), 16); 434 std::memcpy(out_128.data(), out.data(), sizeof(u128));
432 LOG_TRACE(Crypto, "called with crypto_rev={:02X}, kak_index={:02X}, key={:016X}{:016X}", 435 LOG_TRACE(Crypto, "called with crypto_rev={:02X}, kak_index={:02X}, key={:016X}{:016X}",
433 master_key_id, header.key_index, out_128[1], out_128[0]); 436 master_key_id, header.key_index, out_128[1], out_128[0]);
434 437
@@ -507,7 +510,7 @@ VirtualFile NCA::Decrypt(const NCASectionHeader& s_header, VirtualFile in, u64 s
507 // TODO(DarkLordZach): Find a test case for XTS-encrypted NCAs 510 // TODO(DarkLordZach): Find a test case for XTS-encrypted NCAs
508 default: 511 default:
509 LOG_ERROR(Crypto, "called with unhandled crypto type={:02X}", 512 LOG_ERROR(Crypto, "called with unhandled crypto type={:02X}",
510 static_cast<u8>(s_header.raw.header.crypto_type)); 513 s_header.raw.header.crypto_type);
511 return nullptr; 514 return nullptr;
512 } 515 }
513} 516}
@@ -516,15 +519,17 @@ Loader::ResultStatus NCA::GetStatus() const {
516 return status; 519 return status;
517} 520}
518 521
519std::vector<std::shared_ptr<VfsFile>> NCA::GetFiles() const { 522std::vector<VirtualFile> NCA::GetFiles() const {
520 if (status != Loader::ResultStatus::Success) 523 if (status != Loader::ResultStatus::Success) {
521 return {}; 524 return {};
525 }
522 return files; 526 return files;
523} 527}
524 528
525std::vector<std::shared_ptr<VfsDirectory>> NCA::GetSubdirectories() const { 529std::vector<VirtualDir> NCA::GetSubdirectories() const {
526 if (status != Loader::ResultStatus::Success) 530 if (status != Loader::ResultStatus::Success) {
527 return {}; 531 return {};
532 }
528 return dirs; 533 return dirs;
529} 534}
530 535
@@ -532,7 +537,7 @@ std::string NCA::GetName() const {
532 return file->GetName(); 537 return file->GetName();
533} 538}
534 539
535std::shared_ptr<VfsDirectory> NCA::GetParentDirectory() const { 540VirtualDir NCA::GetParentDirectory() const {
536 return file->GetContainingDirectory(); 541 return file->GetContainingDirectory();
537} 542}
538 543
diff --git a/src/core/file_sys/content_archive.h b/src/core/file_sys/content_archive.h
index 69292232a..e9eccdea3 100644
--- a/src/core/file_sys/content_archive.h
+++ b/src/core/file_sys/content_archive.h
@@ -82,7 +82,7 @@ struct NCAHeader {
82}; 82};
83static_assert(sizeof(NCAHeader) == 0x400, "NCAHeader has incorrect size."); 83static_assert(sizeof(NCAHeader) == 0x400, "NCAHeader has incorrect size.");
84 84
85inline bool IsDirectoryExeFS(const std::shared_ptr<VfsDirectory>& pfs) { 85inline bool IsDirectoryExeFS(const VirtualDir& pfs) {
86 // According to switchbrew, an exefs must only contain these two files: 86 // According to switchbrew, an exefs must only contain these two files:
87 return pfs->GetFile("main") != nullptr && pfs->GetFile("main.npdm") != nullptr; 87 return pfs->GetFile("main") != nullptr && pfs->GetFile("main.npdm") != nullptr;
88} 88}
@@ -104,10 +104,10 @@ public:
104 104
105 Loader::ResultStatus GetStatus() const; 105 Loader::ResultStatus GetStatus() const;
106 106
107 std::vector<std::shared_ptr<VfsFile>> GetFiles() const override; 107 std::vector<VirtualFile> GetFiles() const override;
108 std::vector<std::shared_ptr<VfsDirectory>> GetSubdirectories() const override; 108 std::vector<VirtualDir> GetSubdirectories() const override;
109 std::string GetName() const override; 109 std::string GetName() const override;
110 std::shared_ptr<VfsDirectory> GetParentDirectory() const override; 110 VirtualDir GetParentDirectory() const override;
111 111
112 NCAContentType GetType() const; 112 NCAContentType GetType() const;
113 u64 GetTitleId() const; 113 u64 GetTitleId() const;
diff --git a/src/core/file_sys/fsmitm_romfsbuild.cpp b/src/core/file_sys/fsmitm_romfsbuild.cpp
index 2aff2708a..c52fafb6f 100644
--- a/src/core/file_sys/fsmitm_romfsbuild.cpp
+++ b/src/core/file_sys/fsmitm_romfsbuild.cpp
@@ -266,8 +266,9 @@ std::multimap<u64, VirtualFile> RomFSBuildContext::Build() {
266 cur_file->offset = file_partition_size; 266 cur_file->offset = file_partition_size;
267 file_partition_size += cur_file->size; 267 file_partition_size += cur_file->size;
268 cur_file->entry_offset = entry_offset; 268 cur_file->entry_offset = entry_offset;
269 entry_offset += sizeof(RomFSFileEntry) + 269 entry_offset +=
270 Common::AlignUp(cur_file->path_len - cur_file->cur_path_ofs, 4); 270 static_cast<u32>(sizeof(RomFSFileEntry) +
271 Common::AlignUp(cur_file->path_len - cur_file->cur_path_ofs, 4));
271 prev_file = cur_file; 272 prev_file = cur_file;
272 } 273 }
273 // Assign deferred parent/sibling ownership. 274 // Assign deferred parent/sibling ownership.
@@ -284,8 +285,9 @@ std::multimap<u64, VirtualFile> RomFSBuildContext::Build() {
284 for (const auto& it : directories) { 285 for (const auto& it : directories) {
285 cur_dir = it.second; 286 cur_dir = it.second;
286 cur_dir->entry_offset = entry_offset; 287 cur_dir->entry_offset = entry_offset;
287 entry_offset += sizeof(RomFSDirectoryEntry) + 288 entry_offset +=
288 Common::AlignUp(cur_dir->path_len - cur_dir->cur_path_ofs, 4); 289 static_cast<u32>(sizeof(RomFSDirectoryEntry) +
290 Common::AlignUp(cur_dir->path_len - cur_dir->cur_path_ofs, 4));
289 } 291 }
290 // Assign deferred parent/sibling ownership. 292 // Assign deferred parent/sibling ownership.
291 for (auto it = directories.rbegin(); it->second != root; ++it) { 293 for (auto it = directories.rbegin(); it->second != root; ++it) {
diff --git a/src/core/file_sys/ips_layer.cpp b/src/core/file_sys/ips_layer.cpp
index dd779310f..a6101f1c0 100644
--- a/src/core/file_sys/ips_layer.cpp
+++ b/src/core/file_sys/ips_layer.cpp
@@ -299,7 +299,7 @@ void IPSwitchCompiler::Parse() {
299 patch_text->GetName(), offset, Common::HexToString(replace)); 299 patch_text->GetName(), offset, Common::HexToString(replace));
300 } 300 }
301 301
302 patch.records.insert_or_assign(offset, std::move(replace)); 302 patch.records.insert_or_assign(static_cast<u32>(offset), std::move(replace));
303 } 303 }
304 304
305 patches.push_back(std::move(patch)); 305 patches.push_back(std::move(patch));
diff --git a/src/core/file_sys/nca_metadata.cpp b/src/core/file_sys/nca_metadata.cpp
index 2d1476e3a..3596541b2 100644
--- a/src/core/file_sys/nca_metadata.cpp
+++ b/src/core/file_sys/nca_metadata.cpp
@@ -108,7 +108,7 @@ std::vector<u8> CNMT::Serialize() const {
108 memcpy(out.data() + sizeof(CNMTHeader), &opt_header, sizeof(OptionalHeader)); 108 memcpy(out.data() + sizeof(CNMTHeader), &opt_header, sizeof(OptionalHeader));
109 } 109 }
110 110
111 auto offset = header.table_offset; 111 u64_le offset = header.table_offset;
112 112
113 for (const auto& rec : content_records) { 113 for (const auto& rec : content_records) {
114 memcpy(out.data() + offset + sizeof(CNMTHeader), &rec, sizeof(ContentRecord)); 114 memcpy(out.data() + offset + sizeof(CNMTHeader), &rec, sizeof(ContentRecord));
diff --git a/src/core/file_sys/nca_patch.cpp b/src/core/file_sys/nca_patch.cpp
index 5990a2fd5..a65ec6798 100644
--- a/src/core/file_sys/nca_patch.cpp
+++ b/src/core/file_sys/nca_patch.cpp
@@ -51,8 +51,8 @@ std::pair<std::size_t, std::size_t> SearchBucketEntry(u64 offset, const BlockTyp
51 low = mid + 1; 51 low = mid + 1;
52 } 52 }
53 } 53 }
54
55 UNREACHABLE_MSG("Offset could not be found in BKTR block."); 54 UNREACHABLE_MSG("Offset could not be found in BKTR block.");
55 return {0, 0};
56} 56}
57} // Anonymous namespace 57} // Anonymous namespace
58 58
@@ -191,7 +191,7 @@ bool BKTR::Resize(std::size_t new_size) {
191 return false; 191 return false;
192} 192}
193 193
194std::shared_ptr<VfsDirectory> BKTR::GetContainingDirectory() const { 194VirtualDir BKTR::GetContainingDirectory() const {
195 return base_romfs->GetContainingDirectory(); 195 return base_romfs->GetContainingDirectory();
196} 196}
197 197
diff --git a/src/core/file_sys/nca_patch.h b/src/core/file_sys/nca_patch.h
index 60c544f8e..503cf473e 100644
--- a/src/core/file_sys/nca_patch.h
+++ b/src/core/file_sys/nca_patch.h
@@ -106,7 +106,7 @@ public:
106 106
107 bool Resize(std::size_t new_size) override; 107 bool Resize(std::size_t new_size) override;
108 108
109 std::shared_ptr<VfsDirectory> GetContainingDirectory() const override; 109 VirtualDir GetContainingDirectory() const override;
110 110
111 bool IsWritable() const override; 111 bool IsWritable() const override;
112 112
diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp
index b9c09b456..7c3284df8 100644
--- a/src/core/file_sys/patch_manager.cpp
+++ b/src/core/file_sys/patch_manager.cpp
@@ -12,6 +12,7 @@
12#include "common/logging/log.h" 12#include "common/logging/log.h"
13#include "common/string_util.h" 13#include "common/string_util.h"
14#include "core/core.h" 14#include "core/core.h"
15#include "core/file_sys/common_funcs.h"
15#include "core/file_sys/content_archive.h" 16#include "core/file_sys/content_archive.h"
16#include "core/file_sys/control_metadata.h" 17#include "core/file_sys/control_metadata.h"
17#include "core/file_sys/ips_layer.h" 18#include "core/file_sys/ips_layer.h"
@@ -29,8 +30,7 @@
29namespace FileSys { 30namespace FileSys {
30namespace { 31namespace {
31 32
32constexpr u64 SINGLE_BYTE_MODULUS = 0x100; 33constexpr u32 SINGLE_BYTE_MODULUS = 0x100;
33constexpr u64 DLC_BASE_TITLE_ID_MASK = 0xFFFFFFFFFFFFE000;
34 34
35constexpr std::array<const char*, 14> EXEFS_FILE_NAMES{ 35constexpr std::array<const char*, 14> EXEFS_FILE_NAMES{
36 "main", "main.npdm", "rtld", "sdk", "subsdk0", "subsdk1", "subsdk2", 36 "main", "main.npdm", "rtld", "sdk", "subsdk0", "subsdk1", "subsdk2",
@@ -112,7 +112,10 @@ bool IsDirValidAndNonEmpty(const VirtualDir& dir) {
112} 112}
113} // Anonymous namespace 113} // Anonymous namespace
114 114
115PatchManager::PatchManager(u64 title_id) : title_id(title_id) {} 115PatchManager::PatchManager(u64 title_id_,
116 const Service::FileSystem::FileSystemController& fs_controller_,
117 const ContentProvider& content_provider_)
118 : title_id{title_id_}, fs_controller{fs_controller_}, content_provider{content_provider_} {}
116 119
117PatchManager::~PatchManager() = default; 120PatchManager::~PatchManager() = default;
118 121
@@ -128,34 +131,30 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
128 131
129 if (Settings::values.dump_exefs) { 132 if (Settings::values.dump_exefs) {
130 LOG_INFO(Loader, "Dumping ExeFS for title_id={:016X}", title_id); 133 LOG_INFO(Loader, "Dumping ExeFS for title_id={:016X}", title_id);
131 const auto dump_dir = 134 const auto dump_dir = fs_controller.GetModificationDumpRoot(title_id);
132 Core::System::GetInstance().GetFileSystemController().GetModificationDumpRoot(title_id);
133 if (dump_dir != nullptr) { 135 if (dump_dir != nullptr) {
134 const auto exefs_dir = GetOrCreateDirectoryRelative(dump_dir, "/exefs"); 136 const auto exefs_dir = GetOrCreateDirectoryRelative(dump_dir, "/exefs");
135 VfsRawCopyD(exefs, exefs_dir); 137 VfsRawCopyD(exefs, exefs_dir);
136 } 138 }
137 } 139 }
138 140
139 const auto& installed = Core::System::GetInstance().GetContentProvider();
140
141 const auto& disabled = Settings::values.disabled_addons[title_id]; 141 const auto& disabled = Settings::values.disabled_addons[title_id];
142 const auto update_disabled = 142 const auto update_disabled =
143 std::find(disabled.cbegin(), disabled.cend(), "Update") != disabled.cend(); 143 std::find(disabled.cbegin(), disabled.cend(), "Update") != disabled.cend();
144 144
145 // Game Updates 145 // Game Updates
146 const auto update_tid = GetUpdateTitleID(title_id); 146 const auto update_tid = GetUpdateTitleID(title_id);
147 const auto update = installed.GetEntry(update_tid, ContentRecordType::Program); 147 const auto update = content_provider.GetEntry(update_tid, ContentRecordType::Program);
148 148
149 if (!update_disabled && update != nullptr && update->GetExeFS() != nullptr && 149 if (!update_disabled && update != nullptr && update->GetExeFS() != nullptr &&
150 update->GetStatus() == Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) { 150 update->GetStatus() == Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) {
151 LOG_INFO(Loader, " ExeFS: Update ({}) applied successfully", 151 LOG_INFO(Loader, " ExeFS: Update ({}) applied successfully",
152 FormatTitleVersion(installed.GetEntryVersion(update_tid).value_or(0))); 152 FormatTitleVersion(content_provider.GetEntryVersion(update_tid).value_or(0)));
153 exefs = update->GetExeFS(); 153 exefs = update->GetExeFS();
154 } 154 }
155 155
156 // LayeredExeFS 156 // LayeredExeFS
157 const auto load_dir = 157 const auto load_dir = fs_controller.GetModificationLoadRoot(title_id);
158 Core::System::GetInstance().GetFileSystemController().GetModificationLoadRoot(title_id);
159 if (load_dir != nullptr && load_dir->GetSize() > 0) { 158 if (load_dir != nullptr && load_dir->GetSize() > 0) {
160 auto patch_dirs = load_dir->GetSubdirectories(); 159 auto patch_dirs = load_dir->GetSubdirectories();
161 std::sort( 160 std::sort(
@@ -241,8 +240,7 @@ std::vector<u8> PatchManager::PatchNSO(const std::vector<u8>& nso, const std::st
241 if (Settings::values.dump_nso) { 240 if (Settings::values.dump_nso) {
242 LOG_INFO(Loader, "Dumping NSO for name={}, build_id={}, title_id={:016X}", name, build_id, 241 LOG_INFO(Loader, "Dumping NSO for name={}, build_id={}, title_id={:016X}", name, build_id,
243 title_id); 242 title_id);
244 const auto dump_dir = 243 const auto dump_dir = fs_controller.GetModificationDumpRoot(title_id);
245 Core::System::GetInstance().GetFileSystemController().GetModificationDumpRoot(title_id);
246 if (dump_dir != nullptr) { 244 if (dump_dir != nullptr) {
247 const auto nso_dir = GetOrCreateDirectoryRelative(dump_dir, "/nso"); 245 const auto nso_dir = GetOrCreateDirectoryRelative(dump_dir, "/nso");
248 const auto file = nso_dir->CreateFile(fmt::format("{}-{}.nso", name, build_id)); 246 const auto file = nso_dir->CreateFile(fmt::format("{}-{}.nso", name, build_id));
@@ -254,8 +252,7 @@ std::vector<u8> PatchManager::PatchNSO(const std::vector<u8>& nso, const std::st
254 252
255 LOG_INFO(Loader, "Patching NSO for name={}, build_id={}", name, build_id); 253 LOG_INFO(Loader, "Patching NSO for name={}, build_id={}", name, build_id);
256 254
257 const auto load_dir = 255 const auto load_dir = fs_controller.GetModificationLoadRoot(title_id);
258 Core::System::GetInstance().GetFileSystemController().GetModificationLoadRoot(title_id);
259 if (load_dir == nullptr) { 256 if (load_dir == nullptr) {
260 LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id); 257 LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id);
261 return nso; 258 return nso;
@@ -298,8 +295,7 @@ bool PatchManager::HasNSOPatch(const BuildID& build_id_) const {
298 295
299 LOG_INFO(Loader, "Querying NSO patch existence for build_id={}", build_id); 296 LOG_INFO(Loader, "Querying NSO patch existence for build_id={}", build_id);
300 297
301 const auto load_dir = 298 const auto load_dir = fs_controller.GetModificationLoadRoot(title_id);
302 Core::System::GetInstance().GetFileSystemController().GetModificationLoadRoot(title_id);
303 if (load_dir == nullptr) { 299 if (load_dir == nullptr) {
304 LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id); 300 LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id);
305 return false; 301 return false;
@@ -313,8 +309,8 @@ bool PatchManager::HasNSOPatch(const BuildID& build_id_) const {
313} 309}
314 310
315std::vector<Core::Memory::CheatEntry> PatchManager::CreateCheatList( 311std::vector<Core::Memory::CheatEntry> PatchManager::CreateCheatList(
316 const Core::System& system, const BuildID& build_id_) const { 312 const BuildID& build_id_) const {
317 const auto load_dir = system.GetFileSystemController().GetModificationLoadRoot(title_id); 313 const auto load_dir = fs_controller.GetModificationLoadRoot(title_id);
318 if (load_dir == nullptr) { 314 if (load_dir == nullptr) {
319 LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id); 315 LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id);
320 return {}; 316 return {};
@@ -347,9 +343,9 @@ std::vector<Core::Memory::CheatEntry> PatchManager::CreateCheatList(
347 return out; 343 return out;
348} 344}
349 345
350static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType type) { 346static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType type,
351 const auto load_dir = 347 const Service::FileSystem::FileSystemController& fs_controller) {
352 Core::System::GetInstance().GetFileSystemController().GetModificationLoadRoot(title_id); 348 const auto load_dir = fs_controller.GetModificationLoadRoot(title_id);
353 if ((type != ContentRecordType::Program && type != ContentRecordType::Data) || 349 if ((type != ContentRecordType::Program && type != ContentRecordType::Data) ||
354 load_dir == nullptr || load_dir->GetSize() <= 0) { 350 load_dir == nullptr || load_dir->GetSize() <= 0) {
355 return; 351 return;
@@ -411,19 +407,19 @@ VirtualFile PatchManager::PatchRomFS(VirtualFile romfs, u64 ivfc_offset, Content
411 const auto log_string = fmt::format("Patching RomFS for title_id={:016X}, type={:02X}", 407 const auto log_string = fmt::format("Patching RomFS for title_id={:016X}, type={:02X}",
412 title_id, static_cast<u8>(type)); 408 title_id, static_cast<u8>(type));
413 409
414 if (type == ContentRecordType::Program || type == ContentRecordType::Data) 410 if (type == ContentRecordType::Program || type == ContentRecordType::Data) {
415 LOG_INFO(Loader, "{}", log_string); 411 LOG_INFO(Loader, "{}", log_string);
416 else 412 } else {
417 LOG_DEBUG(Loader, "{}", log_string); 413 LOG_DEBUG(Loader, "{}", log_string);
414 }
418 415
419 if (romfs == nullptr) 416 if (romfs == nullptr) {
420 return romfs; 417 return romfs;
421 418 }
422 const auto& installed = Core::System::GetInstance().GetContentProvider();
423 419
424 // Game Updates 420 // Game Updates
425 const auto update_tid = GetUpdateTitleID(title_id); 421 const auto update_tid = GetUpdateTitleID(title_id);
426 const auto update = installed.GetEntryRaw(update_tid, type); 422 const auto update = content_provider.GetEntryRaw(update_tid, type);
427 423
428 const auto& disabled = Settings::values.disabled_addons[title_id]; 424 const auto& disabled = Settings::values.disabled_addons[title_id];
429 const auto update_disabled = 425 const auto update_disabled =
@@ -434,7 +430,7 @@ VirtualFile PatchManager::PatchRomFS(VirtualFile romfs, u64 ivfc_offset, Content
434 if (new_nca->GetStatus() == Loader::ResultStatus::Success && 430 if (new_nca->GetStatus() == Loader::ResultStatus::Success &&
435 new_nca->GetRomFS() != nullptr) { 431 new_nca->GetRomFS() != nullptr) {
436 LOG_INFO(Loader, " RomFS: Update ({}) applied successfully", 432 LOG_INFO(Loader, " RomFS: Update ({}) applied successfully",
437 FormatTitleVersion(installed.GetEntryVersion(update_tid).value_or(0))); 433 FormatTitleVersion(content_provider.GetEntryVersion(update_tid).value_or(0)));
438 romfs = new_nca->GetRomFS(); 434 romfs = new_nca->GetRomFS();
439 } 435 }
440 } else if (!update_disabled && update_raw != nullptr) { 436 } else if (!update_disabled && update_raw != nullptr) {
@@ -447,7 +443,7 @@ VirtualFile PatchManager::PatchRomFS(VirtualFile romfs, u64 ivfc_offset, Content
447 } 443 }
448 444
449 // LayeredFS 445 // LayeredFS
450 ApplyLayeredFS(romfs, title_id, type); 446 ApplyLayeredFS(romfs, title_id, type, fs_controller);
451 447
452 return romfs; 448 return romfs;
453} 449}
@@ -458,12 +454,11 @@ PatchManager::PatchVersionNames PatchManager::GetPatchVersionNames(VirtualFile u
458 } 454 }
459 455
460 std::map<std::string, std::string, std::less<>> out; 456 std::map<std::string, std::string, std::less<>> out;
461 const auto& installed = Core::System::GetInstance().GetContentProvider();
462 const auto& disabled = Settings::values.disabled_addons[title_id]; 457 const auto& disabled = Settings::values.disabled_addons[title_id];
463 458
464 // Game Updates 459 // Game Updates
465 const auto update_tid = GetUpdateTitleID(title_id); 460 const auto update_tid = GetUpdateTitleID(title_id);
466 PatchManager update{update_tid}; 461 PatchManager update{update_tid, fs_controller, content_provider};
467 const auto metadata = update.GetControlMetadata(); 462 const auto metadata = update.GetControlMetadata();
468 const auto& nacp = metadata.first; 463 const auto& nacp = metadata.first;
469 464
@@ -474,8 +469,8 @@ PatchManager::PatchVersionNames PatchManager::GetPatchVersionNames(VirtualFile u
474 if (nacp != nullptr) { 469 if (nacp != nullptr) {
475 out.insert_or_assign(update_label, nacp->GetVersionString()); 470 out.insert_or_assign(update_label, nacp->GetVersionString());
476 } else { 471 } else {
477 if (installed.HasEntry(update_tid, ContentRecordType::Program)) { 472 if (content_provider.HasEntry(update_tid, ContentRecordType::Program)) {
478 const auto meta_ver = installed.GetEntryVersion(update_tid); 473 const auto meta_ver = content_provider.GetEntryVersion(update_tid);
479 if (meta_ver.value_or(0) == 0) { 474 if (meta_ver.value_or(0) == 0) {
480 out.insert_or_assign(update_label, ""); 475 out.insert_or_assign(update_label, "");
481 } else { 476 } else {
@@ -487,8 +482,7 @@ PatchManager::PatchVersionNames PatchManager::GetPatchVersionNames(VirtualFile u
487 } 482 }
488 483
489 // General Mods (LayeredFS and IPS) 484 // General Mods (LayeredFS and IPS)
490 const auto mod_dir = 485 const auto mod_dir = fs_controller.GetModificationLoadRoot(title_id);
491 Core::System::GetInstance().GetFileSystemController().GetModificationLoadRoot(title_id);
492 if (mod_dir != nullptr && mod_dir->GetSize() > 0) { 486 if (mod_dir != nullptr && mod_dir->GetSize() > 0) {
493 for (const auto& mod : mod_dir->GetSubdirectories()) { 487 for (const auto& mod : mod_dir->GetSubdirectories()) {
494 std::string types; 488 std::string types;
@@ -532,13 +526,15 @@ PatchManager::PatchVersionNames PatchManager::GetPatchVersionNames(VirtualFile u
532 } 526 }
533 527
534 // DLC 528 // DLC
535 const auto dlc_entries = installed.ListEntriesFilter(TitleType::AOC, ContentRecordType::Data); 529 const auto dlc_entries =
530 content_provider.ListEntriesFilter(TitleType::AOC, ContentRecordType::Data);
536 std::vector<ContentProviderEntry> dlc_match; 531 std::vector<ContentProviderEntry> dlc_match;
537 dlc_match.reserve(dlc_entries.size()); 532 dlc_match.reserve(dlc_entries.size());
538 std::copy_if(dlc_entries.begin(), dlc_entries.end(), std::back_inserter(dlc_match), 533 std::copy_if(dlc_entries.begin(), dlc_entries.end(), std::back_inserter(dlc_match),
539 [this, &installed](const ContentProviderEntry& entry) { 534 [this](const ContentProviderEntry& entry) {
540 return (entry.title_id & DLC_BASE_TITLE_ID_MASK) == title_id && 535 return GetBaseTitleID(entry.title_id) == title_id &&
541 installed.GetEntry(entry)->GetStatus() == Loader::ResultStatus::Success; 536 content_provider.GetEntry(entry)->GetStatus() ==
537 Loader::ResultStatus::Success;
542 }); 538 });
543 if (!dlc_match.empty()) { 539 if (!dlc_match.empty()) {
544 // Ensure sorted so DLC IDs show in order. 540 // Ensure sorted so DLC IDs show in order.
@@ -559,19 +555,16 @@ PatchManager::PatchVersionNames PatchManager::GetPatchVersionNames(VirtualFile u
559} 555}
560 556
561std::optional<u32> PatchManager::GetGameVersion() const { 557std::optional<u32> PatchManager::GetGameVersion() const {
562 const auto& installed = Core::System::GetInstance().GetContentProvider();
563 const auto update_tid = GetUpdateTitleID(title_id); 558 const auto update_tid = GetUpdateTitleID(title_id);
564 if (installed.HasEntry(update_tid, ContentRecordType::Program)) { 559 if (content_provider.HasEntry(update_tid, ContentRecordType::Program)) {
565 return installed.GetEntryVersion(update_tid); 560 return content_provider.GetEntryVersion(update_tid);
566 } 561 }
567 562
568 return installed.GetEntryVersion(title_id); 563 return content_provider.GetEntryVersion(title_id);
569} 564}
570 565
571PatchManager::Metadata PatchManager::GetControlMetadata() const { 566PatchManager::Metadata PatchManager::GetControlMetadata() const {
572 const auto& installed = Core::System::GetInstance().GetContentProvider(); 567 const auto base_control_nca = content_provider.GetEntry(title_id, ContentRecordType::Control);
573
574 const auto base_control_nca = installed.GetEntry(title_id, ContentRecordType::Control);
575 if (base_control_nca == nullptr) { 568 if (base_control_nca == nullptr) {
576 return {}; 569 return {};
577 } 570 }
diff --git a/src/core/file_sys/patch_manager.h b/src/core/file_sys/patch_manager.h
index 1f28c6241..fb1853035 100644
--- a/src/core/file_sys/patch_manager.h
+++ b/src/core/file_sys/patch_manager.h
@@ -17,8 +17,13 @@ namespace Core {
17class System; 17class System;
18} 18}
19 19
20namespace Service::FileSystem {
21class FileSystemController;
22}
23
20namespace FileSys { 24namespace FileSys {
21 25
26class ContentProvider;
22class NCA; 27class NCA;
23class NACP; 28class NACP;
24 29
@@ -29,7 +34,9 @@ public:
29 using Metadata = std::pair<std::unique_ptr<NACP>, VirtualFile>; 34 using Metadata = std::pair<std::unique_ptr<NACP>, VirtualFile>;
30 using PatchVersionNames = std::map<std::string, std::string, std::less<>>; 35 using PatchVersionNames = std::map<std::string, std::string, std::less<>>;
31 36
32 explicit PatchManager(u64 title_id); 37 explicit PatchManager(u64 title_id_,
38 const Service::FileSystem::FileSystemController& fs_controller_,
39 const ContentProvider& content_provider_);
33 ~PatchManager(); 40 ~PatchManager();
34 41
35 [[nodiscard]] u64 GetTitleID() const; 42 [[nodiscard]] u64 GetTitleID() const;
@@ -50,7 +57,7 @@ public:
50 57
51 // Creates a CheatList object with all 58 // Creates a CheatList object with all
52 [[nodiscard]] std::vector<Core::Memory::CheatEntry> CreateCheatList( 59 [[nodiscard]] std::vector<Core::Memory::CheatEntry> CreateCheatList(
53 const Core::System& system, const BuildID& build_id) const; 60 const BuildID& build_id) const;
54 61
55 // Currently tracked RomFS patches: 62 // Currently tracked RomFS patches:
56 // - Game Updates 63 // - Game Updates
@@ -80,6 +87,8 @@ private:
80 const std::string& build_id) const; 87 const std::string& build_id) const;
81 88
82 u64 title_id; 89 u64 title_id;
90 const Service::FileSystem::FileSystemController& fs_controller;
91 const ContentProvider& content_provider;
83}; 92};
84 93
85} // namespace FileSys 94} // namespace FileSys
diff --git a/src/core/file_sys/registered_cache.cpp b/src/core/file_sys/registered_cache.cpp
index da01002d5..431302f55 100644
--- a/src/core/file_sys/registered_cache.cpp
+++ b/src/core/file_sys/registered_cache.cpp
@@ -105,7 +105,8 @@ ContentRecordType GetCRTypeFromNCAType(NCAContentType type) {
105 // TODO(DarkLordZach): Peek at NCA contents to differentiate Manual and Legal. 105 // TODO(DarkLordZach): Peek at NCA contents to differentiate Manual and Legal.
106 return ContentRecordType::HtmlDocument; 106 return ContentRecordType::HtmlDocument;
107 default: 107 default:
108 UNREACHABLE_MSG("Invalid NCAContentType={:02X}", static_cast<u8>(type)); 108 UNREACHABLE_MSG("Invalid NCAContentType={:02X}", type);
109 return ContentRecordType{};
109 } 110 }
110} 111}
111 112
diff --git a/src/core/file_sys/registered_cache.h b/src/core/file_sys/registered_cache.h
index 5b414b0f0..b08a1687a 100644
--- a/src/core/file_sys/registered_cache.h
+++ b/src/core/file_sys/registered_cache.h
@@ -67,18 +67,18 @@ public:
67 virtual void Refresh() = 0; 67 virtual void Refresh() = 0;
68 68
69 virtual bool HasEntry(u64 title_id, ContentRecordType type) const = 0; 69 virtual bool HasEntry(u64 title_id, ContentRecordType type) const = 0;
70 virtual bool HasEntry(ContentProviderEntry entry) const; 70 bool HasEntry(ContentProviderEntry entry) const;
71 71
72 virtual std::optional<u32> GetEntryVersion(u64 title_id) const = 0; 72 virtual std::optional<u32> GetEntryVersion(u64 title_id) const = 0;
73 73
74 virtual VirtualFile GetEntryUnparsed(u64 title_id, ContentRecordType type) const = 0; 74 virtual VirtualFile GetEntryUnparsed(u64 title_id, ContentRecordType type) const = 0;
75 virtual VirtualFile GetEntryUnparsed(ContentProviderEntry entry) const; 75 VirtualFile GetEntryUnparsed(ContentProviderEntry entry) const;
76 76
77 virtual VirtualFile GetEntryRaw(u64 title_id, ContentRecordType type) const = 0; 77 virtual VirtualFile GetEntryRaw(u64 title_id, ContentRecordType type) const = 0;
78 virtual VirtualFile GetEntryRaw(ContentProviderEntry entry) const; 78 VirtualFile GetEntryRaw(ContentProviderEntry entry) const;
79 79
80 virtual std::unique_ptr<NCA> GetEntry(u64 title_id, ContentRecordType type) const = 0; 80 virtual std::unique_ptr<NCA> GetEntry(u64 title_id, ContentRecordType type) const = 0;
81 virtual std::unique_ptr<NCA> GetEntry(ContentProviderEntry entry) const; 81 std::unique_ptr<NCA> GetEntry(ContentProviderEntry entry) const;
82 82
83 virtual std::vector<ContentProviderEntry> ListEntries() const; 83 virtual std::vector<ContentProviderEntry> ListEntries() const;
84 84
diff --git a/src/core/file_sys/romfs_factory.cpp b/src/core/file_sys/romfs_factory.cpp
index e967a254e..f4e16e4be 100644
--- a/src/core/file_sys/romfs_factory.cpp
+++ b/src/core/file_sys/romfs_factory.cpp
@@ -7,6 +7,7 @@
7#include "common/common_types.h" 7#include "common/common_types.h"
8#include "common/logging/log.h" 8#include "common/logging/log.h"
9#include "core/file_sys/card_image.h" 9#include "core/file_sys/card_image.h"
10#include "core/file_sys/common_funcs.h"
10#include "core/file_sys/content_archive.h" 11#include "core/file_sys/content_archive.h"
11#include "core/file_sys/nca_metadata.h" 12#include "core/file_sys/nca_metadata.h"
12#include "core/file_sys/patch_manager.h" 13#include "core/file_sys/patch_manager.h"
@@ -37,14 +38,37 @@ void RomFSFactory::SetPackedUpdate(VirtualFile update_raw) {
37} 38}
38 39
39ResultVal<VirtualFile> RomFSFactory::OpenCurrentProcess(u64 current_process_title_id) const { 40ResultVal<VirtualFile> RomFSFactory::OpenCurrentProcess(u64 current_process_title_id) const {
40 if (!updatable) 41 if (!updatable) {
41 return MakeResult<VirtualFile>(file); 42 return MakeResult<VirtualFile>(file);
43 }
42 44
43 const PatchManager patch_manager(current_process_title_id); 45 const PatchManager patch_manager{current_process_title_id, filesystem_controller,
46 content_provider};
44 return MakeResult<VirtualFile>( 47 return MakeResult<VirtualFile>(
45 patch_manager.PatchRomFS(file, ivfc_offset, ContentRecordType::Program, update_raw)); 48 patch_manager.PatchRomFS(file, ivfc_offset, ContentRecordType::Program, update_raw));
46} 49}
47 50
51ResultVal<VirtualFile> RomFSFactory::OpenPatchedRomFS(u64 title_id, ContentRecordType type) const {
52 auto nca = content_provider.GetEntry(title_id, type);
53
54 if (nca == nullptr) {
55 // TODO: Find the right error code to use here
56 return RESULT_UNKNOWN;
57 }
58
59 const PatchManager patch_manager{title_id, filesystem_controller, content_provider};
60
61 return MakeResult<VirtualFile>(
62 patch_manager.PatchRomFS(nca->GetRomFS(), nca->GetBaseIVFCOffset(), type));
63}
64
65ResultVal<VirtualFile> RomFSFactory::OpenPatchedRomFSWithProgramIndex(
66 u64 title_id, u8 program_index, ContentRecordType type) const {
67 const auto res_title_id = GetBaseTitleIDWithProgramIndex(title_id, program_index);
68
69 return OpenPatchedRomFS(res_title_id, type);
70}
71
48ResultVal<VirtualFile> RomFSFactory::Open(u64 title_id, StorageId storage, 72ResultVal<VirtualFile> RomFSFactory::Open(u64 title_id, StorageId storage,
49 ContentRecordType type) const { 73 ContentRecordType type) const {
50 const std::shared_ptr<NCA> res = GetEntry(title_id, storage, type); 74 const std::shared_ptr<NCA> res = GetEntry(title_id, storage, type);
diff --git a/src/core/file_sys/romfs_factory.h b/src/core/file_sys/romfs_factory.h
index ec704dfa8..96dd0d578 100644
--- a/src/core/file_sys/romfs_factory.h
+++ b/src/core/file_sys/romfs_factory.h
@@ -42,6 +42,10 @@ public:
42 42
43 void SetPackedUpdate(VirtualFile update_raw); 43 void SetPackedUpdate(VirtualFile update_raw);
44 [[nodiscard]] ResultVal<VirtualFile> OpenCurrentProcess(u64 current_process_title_id) const; 44 [[nodiscard]] ResultVal<VirtualFile> OpenCurrentProcess(u64 current_process_title_id) const;
45 [[nodiscard]] ResultVal<VirtualFile> OpenPatchedRomFS(u64 title_id,
46 ContentRecordType type) const;
47 [[nodiscard]] ResultVal<VirtualFile> OpenPatchedRomFSWithProgramIndex(
48 u64 title_id, u8 program_index, ContentRecordType type) const;
45 [[nodiscard]] ResultVal<VirtualFile> Open(u64 title_id, StorageId storage, 49 [[nodiscard]] ResultVal<VirtualFile> Open(u64 title_id, StorageId storage,
46 ContentRecordType type) const; 50 ContentRecordType type) const;
47 51
diff --git a/src/core/file_sys/savedata_factory.cpp b/src/core/file_sys/savedata_factory.cpp
index ba4efee3a..b7bfe0928 100644
--- a/src/core/file_sys/savedata_factory.cpp
+++ b/src/core/file_sys/savedata_factory.cpp
@@ -70,7 +70,8 @@ std::string SaveDataAttribute::DebugInfo() const {
70 static_cast<u8>(rank), index); 70 static_cast<u8>(rank), index);
71} 71}
72 72
73SaveDataFactory::SaveDataFactory(VirtualDir save_directory) : dir(std::move(save_directory)) { 73SaveDataFactory::SaveDataFactory(Core::System& system_, VirtualDir save_directory_)
74 : dir{std::move(save_directory_)}, system{system_} {
74 // Delete all temporary storages 75 // Delete all temporary storages
75 // On hardware, it is expected that temporary storage be empty at first use. 76 // On hardware, it is expected that temporary storage be empty at first use.
76 dir->DeleteSubdirectoryRecursive("temp"); 77 dir->DeleteSubdirectoryRecursive("temp");
@@ -83,7 +84,7 @@ ResultVal<VirtualDir> SaveDataFactory::Create(SaveDataSpaceId space,
83 PrintSaveDataAttributeWarnings(meta); 84 PrintSaveDataAttributeWarnings(meta);
84 85
85 const auto save_directory = 86 const auto save_directory =
86 GetFullPath(space, meta.type, meta.title_id, meta.user_id, meta.save_id); 87 GetFullPath(system, space, meta.type, meta.title_id, meta.user_id, meta.save_id);
87 88
88 auto out = dir->CreateDirectoryRelative(save_directory); 89 auto out = dir->CreateDirectoryRelative(save_directory);
89 90
@@ -100,7 +101,7 @@ ResultVal<VirtualDir> SaveDataFactory::Open(SaveDataSpaceId space,
100 const SaveDataAttribute& meta) const { 101 const SaveDataAttribute& meta) const {
101 102
102 const auto save_directory = 103 const auto save_directory =
103 GetFullPath(space, meta.type, meta.title_id, meta.user_id, meta.save_id); 104 GetFullPath(system, space, meta.type, meta.title_id, meta.user_id, meta.save_id);
104 105
105 auto out = dir->GetDirectoryRelative(save_directory); 106 auto out = dir->GetDirectoryRelative(save_directory);
106 107
@@ -135,13 +136,14 @@ std::string SaveDataFactory::GetSaveDataSpaceIdPath(SaveDataSpaceId space) {
135 } 136 }
136} 137}
137 138
138std::string SaveDataFactory::GetFullPath(SaveDataSpaceId space, SaveDataType type, u64 title_id, 139std::string SaveDataFactory::GetFullPath(Core::System& system, SaveDataSpaceId space,
139 u128 user_id, u64 save_id) { 140 SaveDataType type, u64 title_id, u128 user_id,
141 u64 save_id) {
140 // According to switchbrew, if a save is of type SaveData and the title id field is 0, it should 142 // According to switchbrew, if a save is of type SaveData and the title id field is 0, it should
141 // be interpreted as the title id of the current process. 143 // be interpreted as the title id of the current process.
142 if (type == SaveDataType::SaveData || type == SaveDataType::DeviceSaveData) { 144 if (type == SaveDataType::SaveData || type == SaveDataType::DeviceSaveData) {
143 if (title_id == 0) { 145 if (title_id == 0) {
144 title_id = Core::System::GetInstance().CurrentProcess()->GetTitleID(); 146 title_id = system.CurrentProcess()->GetTitleID();
145 } 147 }
146 } 148 }
147 149
@@ -167,7 +169,7 @@ std::string SaveDataFactory::GetFullPath(SaveDataSpaceId space, SaveDataType typ
167 169
168SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id, 170SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id,
169 u128 user_id) const { 171 u128 user_id) const {
170 const auto path = GetFullPath(SaveDataSpaceId::NandUser, type, title_id, user_id, 0); 172 const auto path = GetFullPath(system, SaveDataSpaceId::NandUser, type, title_id, user_id, 0);
171 const auto dir = GetOrCreateDirectoryRelative(this->dir, path); 173 const auto dir = GetOrCreateDirectoryRelative(this->dir, path);
172 174
173 const auto size_file = dir->GetFile(SAVE_DATA_SIZE_FILENAME); 175 const auto size_file = dir->GetFile(SAVE_DATA_SIZE_FILENAME);
@@ -182,7 +184,7 @@ SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id,
182 184
183void SaveDataFactory::WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id, 185void SaveDataFactory::WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id,
184 SaveDataSize new_value) const { 186 SaveDataSize new_value) const {
185 const auto path = GetFullPath(SaveDataSpaceId::NandUser, type, title_id, user_id, 0); 187 const auto path = GetFullPath(system, SaveDataSpaceId::NandUser, type, title_id, user_id, 0);
186 const auto dir = GetOrCreateDirectoryRelative(this->dir, path); 188 const auto dir = GetOrCreateDirectoryRelative(this->dir, path);
187 189
188 const auto size_file = dir->CreateFile(SAVE_DATA_SIZE_FILENAME); 190 const auto size_file = dir->CreateFile(SAVE_DATA_SIZE_FILENAME);
diff --git a/src/core/file_sys/savedata_factory.h b/src/core/file_sys/savedata_factory.h
index 6625bbbd8..17f774baa 100644
--- a/src/core/file_sys/savedata_factory.h
+++ b/src/core/file_sys/savedata_factory.h
@@ -12,6 +12,10 @@
12#include "core/file_sys/vfs.h" 12#include "core/file_sys/vfs.h"
13#include "core/hle/result.h" 13#include "core/hle/result.h"
14 14
15namespace Core {
16class System;
17}
18
15namespace FileSys { 19namespace FileSys {
16 20
17enum class SaveDataSpaceId : u8 { 21enum class SaveDataSpaceId : u8 {
@@ -84,7 +88,7 @@ struct SaveDataSize {
84/// File system interface to the SaveData archive 88/// File system interface to the SaveData archive
85class SaveDataFactory { 89class SaveDataFactory {
86public: 90public:
87 explicit SaveDataFactory(VirtualDir dir); 91 explicit SaveDataFactory(Core::System& system_, VirtualDir save_directory_);
88 ~SaveDataFactory(); 92 ~SaveDataFactory();
89 93
90 ResultVal<VirtualDir> Create(SaveDataSpaceId space, const SaveDataAttribute& meta) const; 94 ResultVal<VirtualDir> Create(SaveDataSpaceId space, const SaveDataAttribute& meta) const;
@@ -93,8 +97,8 @@ public:
93 VirtualDir GetSaveDataSpaceDirectory(SaveDataSpaceId space) const; 97 VirtualDir GetSaveDataSpaceDirectory(SaveDataSpaceId space) const;
94 98
95 static std::string GetSaveDataSpaceIdPath(SaveDataSpaceId space); 99 static std::string GetSaveDataSpaceIdPath(SaveDataSpaceId space);
96 static std::string GetFullPath(SaveDataSpaceId space, SaveDataType type, u64 title_id, 100 static std::string GetFullPath(Core::System& system, SaveDataSpaceId space, SaveDataType type,
97 u128 user_id, u64 save_id); 101 u64 title_id, u128 user_id, u64 save_id);
98 102
99 SaveDataSize ReadSaveDataSize(SaveDataType type, u64 title_id, u128 user_id) const; 103 SaveDataSize ReadSaveDataSize(SaveDataType type, u64 title_id, u128 user_id) const;
100 void WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id, 104 void WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id,
@@ -102,6 +106,7 @@ public:
102 106
103private: 107private:
104 VirtualDir dir; 108 VirtualDir dir;
109 Core::System& system;
105}; 110};
106 111
107} // namespace FileSys 112} // namespace FileSys
diff --git a/src/core/file_sys/submission_package.cpp b/src/core/file_sys/submission_package.cpp
index aab957bf2..c05735ddd 100644
--- a/src/core/file_sys/submission_package.cpp
+++ b/src/core/file_sys/submission_package.cpp
@@ -19,41 +19,9 @@
19#include "core/loader/loader.h" 19#include "core/loader/loader.h"
20 20
21namespace FileSys { 21namespace FileSys {
22namespace {
23void SetTicketKeys(const std::vector<VirtualFile>& files) {
24 auto& keys = Core::Crypto::KeyManager::Instance();
25 22
26 for (const auto& ticket_file : files) { 23NSP::NSP(VirtualFile file_, std::size_t program_index)
27 if (ticket_file == nullptr) { 24 : file(std::move(file_)), program_index(program_index), status{Loader::ResultStatus::Success},
28 continue;
29 }
30
31 if (ticket_file->GetExtension() != "tik") {
32 continue;
33 }
34
35 if (ticket_file->GetSize() <
36 Core::Crypto::TICKET_FILE_TITLEKEY_OFFSET + sizeof(Core::Crypto::Key128)) {
37 continue;
38 }
39
40 Core::Crypto::Key128 key{};
41 ticket_file->Read(key.data(), key.size(), Core::Crypto::TICKET_FILE_TITLEKEY_OFFSET);
42
43 // We get the name without the extension in order to create the rights ID.
44 std::string name_only(ticket_file->GetName());
45 name_only.erase(name_only.size() - 4);
46
47 const auto rights_id_raw = Common::HexStringToArray<16>(name_only);
48 u128 rights_id;
49 std::memcpy(rights_id.data(), rights_id_raw.data(), sizeof(u128));
50 keys.SetKey(Core::Crypto::S128KeyType::Titlekey, key, rights_id[1], rights_id[0]);
51 }
52}
53} // Anonymous namespace
54
55NSP::NSP(VirtualFile file_)
56 : file(std::move(file_)), status{Loader::ResultStatus::Success},
57 pfs(std::make_shared<PartitionFilesystem>(file)), keys{Core::Crypto::KeyManager::Instance()} { 25 pfs(std::make_shared<PartitionFilesystem>(file)), keys{Core::Crypto::KeyManager::Instance()} {
58 if (pfs->GetStatus() != Loader::ResultStatus::Success) { 26 if (pfs->GetStatus() != Loader::ResultStatus::Success) {
59 status = pfs->GetStatus(); 27 status = pfs->GetStatus();
@@ -178,7 +146,7 @@ std::shared_ptr<NCA> NSP::GetNCA(u64 title_id, ContentRecordType type, TitleType
178 if (extracted) 146 if (extracted)
179 LOG_WARNING(Service_FS, "called on an NSP that is of type extracted."); 147 LOG_WARNING(Service_FS, "called on an NSP that is of type extracted.");
180 148
181 const auto title_id_iter = ncas.find(title_id); 149 const auto title_id_iter = ncas.find(title_id + program_index);
182 if (title_id_iter == ncas.end()) 150 if (title_id_iter == ncas.end())
183 return nullptr; 151 return nullptr;
184 152
@@ -232,6 +200,35 @@ VirtualDir NSP::GetParentDirectory() const {
232 return file->GetContainingDirectory(); 200 return file->GetContainingDirectory();
233} 201}
234 202
203void NSP::SetTicketKeys(const std::vector<VirtualFile>& files) {
204 for (const auto& ticket_file : files) {
205 if (ticket_file == nullptr) {
206 continue;
207 }
208
209 if (ticket_file->GetExtension() != "tik") {
210 continue;
211 }
212
213 if (ticket_file->GetSize() <
214 Core::Crypto::TICKET_FILE_TITLEKEY_OFFSET + sizeof(Core::Crypto::Key128)) {
215 continue;
216 }
217
218 Core::Crypto::Key128 key{};
219 ticket_file->Read(key.data(), key.size(), Core::Crypto::TICKET_FILE_TITLEKEY_OFFSET);
220
221 // We get the name without the extension in order to create the rights ID.
222 std::string name_only(ticket_file->GetName());
223 name_only.erase(name_only.size() - 4);
224
225 const auto rights_id_raw = Common::HexStringToArray<16>(name_only);
226 u128 rights_id;
227 std::memcpy(rights_id.data(), rights_id_raw.data(), sizeof(u128));
228 keys.SetKey(Core::Crypto::S128KeyType::Titlekey, key, rights_id[1], rights_id[0]);
229 }
230}
231
235void NSP::InitializeExeFSAndRomFS(const std::vector<VirtualFile>& files) { 232void NSP::InitializeExeFSAndRomFS(const std::vector<VirtualFile>& files) {
236 exefs = pfs; 233 exefs = pfs;
237 234
@@ -286,12 +283,31 @@ void NSP::ReadNCAs(const std::vector<VirtualFile>& files) {
286 } 283 }
287 284
288 auto next_nca = std::make_shared<NCA>(std::move(next_file), nullptr, 0); 285 auto next_nca = std::make_shared<NCA>(std::move(next_file), nullptr, 0);
286
289 if (next_nca->GetType() == NCAContentType::Program) { 287 if (next_nca->GetType() == NCAContentType::Program) {
290 program_status[next_nca->GetTitleId()] = next_nca->GetStatus(); 288 program_status[next_nca->GetTitleId()] = next_nca->GetStatus();
291 } 289 }
292 if (next_nca->GetStatus() == Loader::ResultStatus::Success || 290
293 (next_nca->GetStatus() == Loader::ResultStatus::ErrorMissingBKTRBaseRomFS && 291 if (next_nca->GetStatus() != Loader::ResultStatus::Success &&
294 (next_nca->GetTitleId() & 0x800) != 0)) { 292 next_nca->GetStatus() != Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) {
293 continue;
294 }
295
296 // If the last 3 hexadecimal digits of the CNMT TitleID is 0x800 or is missing the
297 // BKTRBaseRomFS, this is an update NCA. Otherwise, this is a base NCA.
298 if ((cnmt.GetTitleID() & 0x800) != 0 ||
299 next_nca->GetStatus() == Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) {
300 // If the last 3 hexadecimal digits of the NCA's TitleID is between 0x1 and
301 // 0x7FF, this is a multi-program update NCA. Otherwise, this is a regular
302 // update NCA.
303 if ((next_nca->GetTitleId() & 0x7FF) != 0 &&
304 (next_nca->GetTitleId() & 0x800) == 0) {
305 ncas[next_nca->GetTitleId()][{cnmt.GetType(), rec.type}] =
306 std::move(next_nca);
307 } else {
308 ncas[cnmt.GetTitleID()][{cnmt.GetType(), rec.type}] = std::move(next_nca);
309 }
310 } else {
295 ncas[next_nca->GetTitleId()][{cnmt.GetType(), rec.type}] = std::move(next_nca); 311 ncas[next_nca->GetTitleId()][{cnmt.GetType(), rec.type}] = std::move(next_nca);
296 } 312 }
297 } 313 }
diff --git a/src/core/file_sys/submission_package.h b/src/core/file_sys/submission_package.h
index 2db5e46b8..54581a6f3 100644
--- a/src/core/file_sys/submission_package.h
+++ b/src/core/file_sys/submission_package.h
@@ -27,7 +27,7 @@ enum class ContentRecordType : u8;
27 27
28class NSP : public ReadOnlyVfsDirectory { 28class NSP : public ReadOnlyVfsDirectory {
29public: 29public:
30 explicit NSP(VirtualFile file); 30 explicit NSP(VirtualFile file, std::size_t program_index = 0);
31 ~NSP() override; 31 ~NSP() override;
32 32
33 Loader::ResultStatus GetStatus() const; 33 Loader::ResultStatus GetStatus() const;
@@ -63,11 +63,14 @@ public:
63 VirtualDir GetParentDirectory() const override; 63 VirtualDir GetParentDirectory() const override;
64 64
65private: 65private:
66 void SetTicketKeys(const std::vector<VirtualFile>& files);
66 void InitializeExeFSAndRomFS(const std::vector<VirtualFile>& files); 67 void InitializeExeFSAndRomFS(const std::vector<VirtualFile>& files);
67 void ReadNCAs(const std::vector<VirtualFile>& files); 68 void ReadNCAs(const std::vector<VirtualFile>& files);
68 69
69 VirtualFile file; 70 VirtualFile file;
70 71
72 const std::size_t program_index;
73
71 bool extracted = false; 74 bool extracted = false;
72 Loader::ResultStatus status; 75 Loader::ResultStatus status;
73 std::map<u64, Loader::ResultStatus> program_status; 76 std::map<u64, Loader::ResultStatus> program_status;
diff --git a/src/core/file_sys/system_archive/data/font_nintendo_extended.cpp b/src/core/file_sys/system_archive/data/font_nintendo_extended.cpp
index 69d62ce8f..29ef110a6 100644
--- a/src/core/file_sys/system_archive/data/font_nintendo_extended.cpp
+++ b/src/core/file_sys/system_archive/data/font_nintendo_extended.cpp
@@ -6,191 +6,384 @@
6 6
7namespace FileSys::SystemArchive::SharedFontData { 7namespace FileSys::SystemArchive::SharedFontData {
8 8
9const std::array<unsigned char, 2932> FONT_NINTENDO_EXTENDED{{ 9const std::array<unsigned char, 6024> FONT_NINTENDO_EXTENDED{{
10 0x00, 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x80, 0x00, 0x03, 0x00, 0x70, 0x44, 0x53, 0x49, 0x47, 10 0x00, 0x01, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x80, 0x00, 0x03, 0x00, 0x60, 0x4F, 0x53, 0x2F, 0x32,
11 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0b, 0x6c, 0x00, 0x00, 0x00, 0x08, 0x4f, 0x53, 0x2f, 0x32, 11 0x34, 0x00, 0x1E, 0x26, 0x00, 0x00, 0x01, 0x68, 0x00, 0x00, 0x00, 0x60, 0x63, 0x6D, 0x61, 0x70,
12 0x33, 0x86, 0x1d, 0x9b, 0x00, 0x00, 0x01, 0x78, 0x00, 0x00, 0x00, 0x60, 0x63, 0x6d, 0x61, 0x70, 12 0xC1, 0xE7, 0xC8, 0xF3, 0x00, 0x00, 0x02, 0x0C, 0x00, 0x00, 0x01, 0x72, 0x63, 0x76, 0x74, 0x20,
13 0xc2, 0x06, 0x20, 0xde, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x63, 0x76, 0x74, 0x20, 13 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0C, 0x00, 0x00, 0x00, 0x06, 0x66, 0x70, 0x67, 0x6D,
14 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x04, 0x2c, 0x00, 0x00, 0x00, 0x06, 0x66, 0x70, 0x67, 0x6d, 14 0x06, 0x59, 0x9C, 0x37, 0x00, 0x00, 0x03, 0x80, 0x00, 0x00, 0x01, 0x73, 0x67, 0x61, 0x73, 0x70,
15 0x06, 0x59, 0x9c, 0x37, 0x00, 0x00, 0x02, 0xa0, 0x00, 0x00, 0x01, 0x73, 0x67, 0x61, 0x73, 0x70, 15 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x17, 0x80, 0x00, 0x00, 0x00, 0x08, 0x67, 0x6C, 0x79, 0x66,
16 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x0b, 0x64, 0x00, 0x00, 0x00, 0x08, 0x67, 0x6c, 0x79, 0x66, 16 0x50, 0x0B, 0xEA, 0xFA, 0x00, 0x00, 0x05, 0x50, 0x00, 0x00, 0x0F, 0x04, 0x68, 0x65, 0x61, 0x64,
17 0x10, 0x31, 0x88, 0x00, 0x00, 0x00, 0x04, 0x34, 0x00, 0x00, 0x04, 0x64, 0x68, 0x65, 0x61, 0x64, 17 0x18, 0x65, 0x81, 0x09, 0x00, 0x00, 0x00, 0xEC, 0x00, 0x00, 0x00, 0x36, 0x68, 0x68, 0x65, 0x61,
18 0x15, 0x9d, 0xef, 0x91, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x36, 0x68, 0x68, 0x65, 0x61, 18 0x09, 0x88, 0x03, 0x86, 0x00, 0x00, 0x01, 0x24, 0x00, 0x00, 0x00, 0x24, 0x68, 0x6D, 0x74, 0x78,
19 0x09, 0x60, 0x03, 0x71, 0x00, 0x00, 0x01, 0x34, 0x00, 0x00, 0x00, 0x24, 0x68, 0x6d, 0x74, 0x78, 19 0x0A, 0xF0, 0x01, 0x94, 0x00, 0x00, 0x01, 0xC8, 0x00, 0x00, 0x00, 0x42, 0x6C, 0x6F, 0x63, 0x61,
20 0x0d, 0x2e, 0x03, 0xa7, 0x00, 0x00, 0x01, 0xd8, 0x00, 0x00, 0x00, 0x26, 0x6c, 0x6f, 0x63, 0x61, 20 0x34, 0x80, 0x30, 0x6E, 0x00, 0x00, 0x05, 0x14, 0x00, 0x00, 0x00, 0x3A, 0x6D, 0x61, 0x78, 0x70,
21 0x05, 0xc0, 0x04, 0x6c, 0x00, 0x00, 0x08, 0x98, 0x00, 0x00, 0x00, 0x1e, 0x6d, 0x61, 0x78, 0x70, 21 0x02, 0x2C, 0x00, 0x72, 0x00, 0x00, 0x01, 0x48, 0x00, 0x00, 0x00, 0x20, 0x6E, 0x61, 0x6D, 0x65,
22 0x02, 0x1c, 0x00, 0x5f, 0x00, 0x00, 0x01, 0x58, 0x00, 0x00, 0x00, 0x20, 0x6e, 0x61, 0x6d, 0x65, 22 0xDB, 0xC5, 0x42, 0x4D, 0x00, 0x00, 0x14, 0x54, 0x00, 0x00, 0x01, 0xFE, 0x70, 0x6F, 0x73, 0x74,
23 0x7c, 0xe0, 0x84, 0x5c, 0x00, 0x00, 0x08, 0xb8, 0x00, 0x00, 0x02, 0x09, 0x70, 0x6f, 0x73, 0x74, 23 0xF4, 0xB4, 0xAC, 0xAB, 0x00, 0x00, 0x16, 0x54, 0x00, 0x00, 0x01, 0x2A, 0x70, 0x72, 0x65, 0x70,
24 0x47, 0x4e, 0x74, 0x19, 0x00, 0x00, 0x0a, 0xc4, 0x00, 0x00, 0x00, 0x9e, 0x70, 0x72, 0x65, 0x70, 24 0x1C, 0xFC, 0x7D, 0x9C, 0x00, 0x00, 0x04, 0xF4, 0x00, 0x00, 0x00, 0x16, 0x00, 0x01, 0x00, 0x00,
25 0x1c, 0xfc, 0x7d, 0x9c, 0x00, 0x00, 0x04, 0x14, 0x00, 0x00, 0x00, 0x16, 0x00, 0x01, 0x00, 0x00, 25 0x00, 0x01, 0x00, 0x00, 0xC9, 0x16, 0x5B, 0x71, 0x5F, 0x0F, 0x3C, 0xF5, 0x00, 0x0B, 0x04, 0x00,
26 0x00, 0x01, 0x00, 0x00, 0x7c, 0xc7, 0xb1, 0x63, 0x5f, 0x0f, 0x3c, 0xf5, 0x00, 0x1b, 0x03, 0xe8, 26 0x00, 0x00, 0x00, 0x00, 0xD9, 0x44, 0x2F, 0x5D, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x02, 0x0D, 0xA7,
27 0x00, 0x00, 0x00, 0x00, 0xd9, 0x44, 0x2f, 0x5d, 0x00, 0x00, 0x00, 0x00, 0xd9, 0x45, 0x7b, 0x69, 27 0x00, 0x14, 0xFF, 0x98, 0x03, 0xEC, 0x03, 0x70, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, 0x00,
28 0x00, 0x00, 0x00, 0x00, 0x03, 0xe6, 0x03, 0xe8, 0x00, 0x00, 0x00, 0x06, 0x00, 0x02, 0x00, 0x00, 28 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0x9A, 0xFF, 0x80, 0x02, 0x00, 0x04, 0x00,
29 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0x84, 0xff, 0x83, 0x01, 0xf4, 0x03, 0xe8, 29 0x00, 0x00, 0x00, 0x00, 0x03, 0xEC, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
30 0x00, 0x00, 0x00, 0x00, 0x03, 0xe6, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 30 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x71,
31 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x5e, 31 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00,
32 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 32 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0xC4, 0x01, 0x90, 0x00, 0x05,
33 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x74, 0x01, 0x90, 0x00, 0x05, 33 0x00, 0x04, 0x00, 0xD2, 0x00, 0xD2, 0x00, 0x00, 0x01, 0x26, 0x00, 0xD2, 0x00, 0xD2, 0x00, 0x00,
34 0x00, 0x04, 0x00, 0xcd, 0x00, 0xcd, 0x00, 0x00, 0x01, 0x1f, 0x00, 0xcd, 0x00, 0xcd, 0x00, 0x00, 34 0x03, 0xDA, 0x00, 0x68, 0x02, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
35 0x03, 0xc3, 0x00, 0x66, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
36 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 35 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
37 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x00, 0xc0, 0x00, 0x00, 0xe0, 0xe9, 0x03, 0x84, 0xff, 0x83, 36 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x00, 0xC0, 0x00, 0x0D, 0xE0, 0xF0, 0x03, 0x9A, 0xFF, 0x80,
38 0x01, 0xf4, 0x02, 0xee, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0xe8, 37 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
39 0x02, 0xbc, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x03, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 38 0x02, 0xCD, 0x00, 0x00, 0x00, 0x20, 0x00, 0x01, 0x04, 0x00, 0x00, 0xA4, 0x00, 0x00, 0x00, 0x00,
40 0x00, 0xfa, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x03, 0xe8, 0x00, 0xeb, 0x01, 0x21, 0x00, 0xff, 39 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14,
41 0x00, 0xff, 0x01, 0x3d, 0x01, 0x17, 0x00, 0x42, 0x00, 0x1c, 0x00, 0x3e, 0x00, 0x17, 0x00, 0x00, 40 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14,
42 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x68, 0x00, 0x01, 0x00, 0x00, 41 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14,
43 0x00, 0x00, 0x00, 0x1c, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x68, 0x00, 0x06, 0x00, 0x4c, 42 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
44 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 43 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6C,
44 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x04, 0x00, 0x50, 0x00, 0x00, 0x00, 0x10,
45 0x00, 0x10, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x20, 0xE0, 0xA9, 0xE0, 0xB4,
46 0xE0, 0xE9, 0xE0, 0xF0, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x20, 0xE0, 0xA0,
47 0xE0, 0xB3, 0xE0, 0xE0, 0xE0, 0xEF, 0xFF, 0xFF, 0x00, 0x01, 0xFF, 0xF5, 0xFF, 0xE3, 0x1F, 0x64,
48 0x1F, 0x5B, 0x1F, 0x30, 0x1F, 0x2B, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
49 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x01, 0x00,
50 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
51 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0x00,
45 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 52 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
46 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
47 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 53 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
48 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x04, 0x00, 0x38, 0x00, 0x00, 0x00, 0x0a,
49 0x00, 0x08, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x20, 0xe0, 0xe9, 0xff, 0xff,
50 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x20, 0xe0, 0xe0, 0xff, 0xff, 0x00, 0x01, 0xff, 0xf5,
51 0xff, 0xe3, 0x1f, 0x24, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
52 0xb8, 0x00, 0x00, 0x2c, 0x4b, 0xb8, 0x00, 0x09, 0x50, 0x58, 0xb1, 0x01, 0x01, 0x8e, 0x59, 0xb8,
53 0x01, 0xff, 0x85, 0xb8, 0x00, 0x44, 0x1d, 0xb9, 0x00, 0x09, 0x00, 0x03, 0x5f, 0x5e, 0x2d, 0xb8,
54 0x00, 0x01, 0x2c, 0x20, 0x20, 0x45, 0x69, 0x44, 0xb0, 0x01, 0x60, 0x2d, 0xb8, 0x00, 0x02, 0x2c,
55 0xb8, 0x00, 0x01, 0x2a, 0x21, 0x2d, 0xb8, 0x00, 0x03, 0x2c, 0x20, 0x46, 0xb0, 0x03, 0x25, 0x46,
56 0x52, 0x58, 0x23, 0x59, 0x20, 0x8a, 0x20, 0x8a, 0x49, 0x64, 0x8a, 0x20, 0x46, 0x20, 0x68, 0x61,
57 0x64, 0xb0, 0x04, 0x25, 0x46, 0x20, 0x68, 0x61, 0x64, 0x52, 0x58, 0x23, 0x65, 0x8a, 0x59, 0x2f,
58 0x20, 0xb0, 0x00, 0x53, 0x58, 0x69, 0x20, 0xb0, 0x00, 0x54, 0x58, 0x21, 0xb0, 0x40, 0x59, 0x1b,
59 0x69, 0x20, 0xb0, 0x00, 0x54, 0x58, 0x21, 0xb0, 0x40, 0x65, 0x59, 0x59, 0x3a, 0x2d, 0xb8, 0x00,
60 0x04, 0x2c, 0x20, 0x46, 0xb0, 0x04, 0x25, 0x46, 0x52, 0x58, 0x23, 0x8a, 0x59, 0x20, 0x46, 0x20,
61 0x6a, 0x61, 0x64, 0xb0, 0x04, 0x25, 0x46, 0x20, 0x6a, 0x61, 0x64, 0x52, 0x58, 0x23, 0x8a, 0x59,
62 0x2f, 0xfd, 0x2d, 0xb8, 0x00, 0x05, 0x2c, 0x4b, 0x20, 0xb0, 0x03, 0x26, 0x50, 0x58, 0x51, 0x58,
63 0xb0, 0x80, 0x44, 0x1b, 0xb0, 0x40, 0x44, 0x59, 0x1b, 0x21, 0x21, 0x20, 0x45, 0xb0, 0xc0, 0x50,
64 0x58, 0xb0, 0xc0, 0x44, 0x1b, 0x21, 0x59, 0x59, 0x2d, 0xb8, 0x00, 0x06, 0x2c, 0x20, 0x20, 0x45,
65 0x69, 0x44, 0xb0, 0x01, 0x60, 0x20, 0x20, 0x45, 0x7d, 0x69, 0x18, 0x44, 0xb0, 0x01, 0x60, 0x2d,
66 0xb8, 0x00, 0x07, 0x2c, 0xb8, 0x00, 0x06, 0x2a, 0x2d, 0xb8, 0x00, 0x08, 0x2c, 0x4b, 0x20, 0xb0,
67 0x03, 0x26, 0x53, 0x58, 0xb0, 0x40, 0x1b, 0xb0, 0x00, 0x59, 0x8a, 0x8a, 0x20, 0xb0, 0x03, 0x26,
68 0x53, 0x58, 0x23, 0x21, 0xb0, 0x80, 0x8a, 0x8a, 0x1b, 0x8a, 0x23, 0x59, 0x20, 0xb0, 0x03, 0x26,
69 0x53, 0x58, 0x23, 0x21, 0xb8, 0x00, 0xc0, 0x8a, 0x8a, 0x1b, 0x8a, 0x23, 0x59, 0x20, 0xb0, 0x03,
70 0x26, 0x53, 0x58, 0x23, 0x21, 0xb8, 0x01, 0x00, 0x8a, 0x8a, 0x1b, 0x8a, 0x23, 0x59, 0x20, 0xb0,
71 0x03, 0x26, 0x53, 0x58, 0x23, 0x21, 0xb8, 0x01, 0x40, 0x8a, 0x8a, 0x1b, 0x8a, 0x23, 0x59, 0x20,
72 0xb8, 0x00, 0x03, 0x26, 0x53, 0x58, 0xb0, 0x03, 0x25, 0x45, 0xb8, 0x01, 0x80, 0x50, 0x58, 0x23,
73 0x21, 0xb8, 0x01, 0x80, 0x23, 0x21, 0x1b, 0xb0, 0x03, 0x25, 0x45, 0x23, 0x21, 0x23, 0x21, 0x59,
74 0x1b, 0x21, 0x59, 0x44, 0x2d, 0xb8, 0x00, 0x09, 0x2c, 0x4b, 0x53, 0x58, 0x45, 0x44, 0x1b, 0x21,
75 0x21, 0x59, 0x2d, 0x00, 0xb8, 0x00, 0x00, 0x2b, 0x00, 0xba, 0x00, 0x01, 0x00, 0x01, 0x00, 0x07,
76 0x2b, 0xb8, 0x00, 0x00, 0x20, 0x45, 0x7d, 0x69, 0x18, 0x44, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00,
77 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x03, 0xe6, 0x03, 0xe8, 0x00, 0x06,
78 0x00, 0x00, 0x35, 0x01, 0x33, 0x15, 0x01, 0x23, 0x35, 0x03, 0x52, 0x94, 0xfc, 0xa6, 0x8c, 0x90,
79 0x03, 0x58, 0x86, 0xfc, 0xa0, 0x8e, 0x00, 0x00, 0x00, 0x02, 0x00, 0xeb, 0x00, 0xcc, 0x02, 0xfb,
80 0x03, 0x1e, 0x00, 0x08, 0x00, 0x0f, 0x00, 0x00, 0x01, 0x33, 0x13, 0x23, 0x27, 0x23, 0x07, 0x23,
81 0x13, 0x17, 0x07, 0x06, 0x15, 0x33, 0x27, 0x07, 0x01, 0xbc, 0x6d, 0xd2, 0x7c, 0x26, 0xcc, 0x26,
82 0x7c, 0xd1, 0x35, 0x40, 0x02, 0x89, 0x45, 0x02, 0x03, 0x1e, 0xfd, 0xae, 0x77, 0x77, 0x02, 0x52,
83 0x9b, 0xcc, 0x08, 0x04, 0xda, 0x02, 0x00, 0x00, 0x00, 0x03, 0x01, 0x21, 0x00, 0xcc, 0x02, 0xc5,
84 0x03, 0x1e, 0x00, 0x15, 0x00, 0x1f, 0x00, 0x2b, 0x00, 0x00, 0x25, 0x11, 0x33, 0x32, 0x1e, 0x02,
85 0x15, 0x14, 0x0e, 0x02, 0x07, 0x1e, 0x01, 0x15, 0x14, 0x0e, 0x02, 0x2b, 0x01, 0x13, 0x33, 0x32,
86 0x36, 0x35, 0x34, 0x26, 0x2b, 0x01, 0x1d, 0x01, 0x33, 0x32, 0x3e, 0x02, 0x35, 0x34, 0x26, 0x2b,
87 0x01, 0x15, 0x01, 0x21, 0xea, 0x25, 0x3f, 0x2e, 0x1a, 0x0e, 0x15, 0x1b, 0x0e, 0x2d, 0x2d, 0x1a,
88 0x2e, 0x3f, 0x25, 0xf8, 0x76, 0x62, 0x20, 0x2a, 0x28, 0x22, 0x62, 0x76, 0x10, 0x18, 0x11, 0x09,
89 0x22, 0x22, 0x74, 0xcc, 0x02, 0x52, 0x18, 0x2b, 0x3c, 0x24, 0x1d, 0x1f, 0x17, 0x17, 0x14, 0x0f,
90 0x48, 0x2f, 0x24, 0x3f, 0x2e, 0x1a, 0x01, 0x5b, 0x29, 0x20, 0x20, 0x2b, 0x94, 0xf8, 0x0e, 0x16,
91 0x1c, 0x0e, 0x1f, 0x31, 0x9e, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xff, 0x00, 0xcc, 0x02, 0xe7,
92 0x03, 0x1e, 0x00, 0x0c, 0x00, 0x00, 0x01, 0x33, 0x17, 0x37, 0x33, 0x03, 0x13, 0x23, 0x27, 0x07,
93 0x23, 0x13, 0x03, 0x01, 0x04, 0x86, 0x69, 0x69, 0x86, 0xa3, 0xa8, 0x88, 0x6c, 0x6c, 0x88, 0xa8,
94 0xa3, 0x03, 0x1e, 0xcb, 0xcb, 0xfe, 0xda, 0xfe, 0xd4, 0xcf, 0xcf, 0x01, 0x2c, 0x01, 0x26, 0x00,
95 0x00, 0x01, 0x00, 0xff, 0x00, 0xcc, 0x02, 0xe7, 0x03, 0x1e, 0x00, 0x0f, 0x00, 0x00, 0x01, 0x03,
96 0x33, 0x17, 0x32, 0x15, 0x1e, 0x01, 0x15, 0x1b, 0x01, 0x33, 0x03, 0x15, 0x23, 0x35, 0x01, 0xb8,
97 0xb9, 0x7e, 0x01, 0x01, 0x01, 0x03, 0x70, 0x75, 0x7f, 0xb9, 0x76, 0x01, 0xa3, 0x01, 0x7b, 0x01,
98 0x01, 0x01, 0x05, 0x02, 0xff, 0x00, 0x01, 0x0a, 0xfe, 0x85, 0xd7, 0xd7, 0x00, 0x01, 0x01, 0x3d,
99 0x00, 0xcc, 0x02, 0xa9, 0x03, 0x1e, 0x00, 0x06, 0x00, 0x00, 0x25, 0x11, 0x33, 0x11, 0x33, 0x15,
100 0x21, 0x01, 0x3d, 0x75, 0xf7, 0xfe, 0x94, 0xcc, 0x02, 0x52, 0xfe, 0x10, 0x62, 0x00, 0x00, 0x00,
101 0x00, 0x02, 0x01, 0x17, 0x00, 0xbc, 0x02, 0xcf, 0x03, 0x0e, 0x00, 0x15, 0x00, 0x21, 0x00, 0x00,
102 0x25, 0x11, 0x33, 0x32, 0x1e, 0x02, 0x1d, 0x01, 0x0e, 0x03, 0x1d, 0x01, 0x17, 0x15, 0x23, 0x27,
103 0x23, 0x15, 0x23, 0x13, 0x33, 0x32, 0x3e, 0x02, 0x35, 0x34, 0x26, 0x2b, 0x01, 0x15, 0x01, 0x17,
104 0xf4, 0x27, 0x40, 0x2e, 0x19, 0x01, 0x1f, 0x24, 0x1e, 0x78, 0x7d, 0x6a, 0x5c, 0x75, 0x76, 0x72,
105 0x12, 0x19, 0x11, 0x08, 0x26, 0x26, 0x6a, 0xbc, 0x02, 0x52, 0x1d, 0x31, 0x42, 0x25, 0x16, 0x18,
106 0x32, 0x2a, 0x1b, 0x02, 0x01, 0xef, 0x06, 0xd7, 0xd7, 0x01, 0x3f, 0x10, 0x1a, 0x1e, 0x0f, 0x23,
107 0x36, 0xb0, 0x00, 0x00, 0x00, 0x02, 0x00, 0x42, 0x00, 0xbc, 0x03, 0xa4, 0x03, 0x0e, 0x00, 0x0a,
108 0x00, 0x11, 0x00, 0x00, 0x13, 0x35, 0x21, 0x15, 0x01, 0x21, 0x15, 0x21, 0x35, 0x01, 0x21, 0x01,
109 0x11, 0x33, 0x11, 0x33, 0x15, 0x21, 0x42, 0x01, 0xa7, 0xfe, 0xeb, 0x01, 0x1b, 0xfe, 0x53, 0x01,
110 0x15, 0xfe, 0xeb, 0x01, 0xf7, 0x75, 0xf6, 0xfe, 0x95, 0x02, 0xac, 0x62, 0x45, 0xfe, 0x55, 0x62,
111 0x47, 0x01, 0xa9, 0xfe, 0x10, 0x02, 0x52, 0xfe, 0x10, 0x62, 0x00, 0x00, 0x00, 0x03, 0x00, 0x1c,
112 0x00, 0xbc, 0x03, 0xca, 0x03, 0x0e, 0x00, 0x0a, 0x00, 0x21, 0x00, 0x2f, 0x00, 0x00, 0x13, 0x35,
113 0x21, 0x15, 0x01, 0x21, 0x15, 0x21, 0x35, 0x01, 0x21, 0x01, 0x11, 0x33, 0x32, 0x1e, 0x02, 0x15,
114 0x14, 0x06, 0x07, 0x0e, 0x03, 0x15, 0x17, 0x15, 0x23, 0x27, 0x23, 0x15, 0x23, 0x13, 0x33, 0x32,
115 0x3e, 0x02, 0x35, 0x34, 0x2e, 0x02, 0x2b, 0x01, 0x15, 0x1c, 0x01, 0xa7, 0xfe, 0xeb, 0x01, 0x1b,
116 0xfe, 0x53, 0x01, 0x15, 0xfe, 0xeb, 0x01, 0xf7, 0xf3, 0x27, 0x41, 0x2d, 0x19, 0x1c, 0x20, 0x01,
117 0x0d, 0x0e, 0x0a, 0x78, 0x7d, 0x69, 0x5c, 0x75, 0x76, 0x71, 0x11, 0x1a, 0x12, 0x09, 0x0a, 0x14,
118 0x1d, 0x13, 0x69, 0x02, 0xac, 0x62, 0x45, 0xfe, 0x55, 0x62, 0x47, 0x01, 0xa9, 0xfe, 0x10, 0x02,
119 0x52, 0x1d, 0x31, 0x42, 0x25, 0x2b, 0x44, 0x1d, 0x01, 0x08, 0x09, 0x07, 0x01, 0xf1, 0x06, 0xd7,
120 0xd7, 0x01, 0x3f, 0x11, 0x19, 0x1f, 0x0e, 0x11, 0x20, 0x19, 0x0f, 0xb0, 0x00, 0x02, 0x00, 0x3e,
121 0x00, 0xb3, 0x03, 0xa8, 0x03, 0x17, 0x00, 0x3a, 0x00, 0x41, 0x00, 0x00, 0x13, 0x34, 0x3e, 0x02,
122 0x33, 0x32, 0x1e, 0x02, 0x15, 0x23, 0x27, 0x34, 0x27, 0x2e, 0x01, 0x23, 0x22, 0x0e, 0x02, 0x15,
123 0x14, 0x16, 0x15, 0x1e, 0x05, 0x15, 0x14, 0x0e, 0x02, 0x23, 0x22, 0x2e, 0x02, 0x35, 0x33, 0x1e,
124 0x01, 0x33, 0x32, 0x3e, 0x02, 0x35, 0x34, 0x2e, 0x04, 0x35, 0x01, 0x11, 0x33, 0x11, 0x33, 0x15,
125 0x21, 0x50, 0x24, 0x3b, 0x4a, 0x27, 0x28, 0x4b, 0x39, 0x22, 0x73, 0x01, 0x01, 0x08, 0x2b, 0x29,
126 0x10, 0x20, 0x19, 0x0f, 0x01, 0x0b, 0x35, 0x41, 0x46, 0x3b, 0x25, 0x23, 0x3a, 0x4b, 0x27, 0x2b,
127 0x50, 0x3f, 0x26, 0x74, 0x05, 0x34, 0x33, 0x10, 0x20, 0x1a, 0x11, 0x2c, 0x42, 0x4d, 0x42, 0x2c,
128 0x01, 0xef, 0x73, 0xf6, 0xfe, 0x97, 0x02, 0x70, 0x2a, 0x3f, 0x2a, 0x14, 0x18, 0x2e, 0x44, 0x2c,
129 0x02, 0x03, 0x01, 0x27, 0x27, 0x07, 0x10, 0x1a, 0x12, 0x02, 0x0b, 0x02, 0x1f, 0x22, 0x19, 0x17,
130 0x27, 0x3f, 0x34, 0x2c, 0x3e, 0x28, 0x13, 0x1a, 0x32, 0x48, 0x2e, 0x30, 0x30, 0x06, 0x0f, 0x1a,
131 0x13, 0x21, 0x27, 0x1e, 0x1b, 0x29, 0x3e, 0x31, 0xfe, 0x4c, 0x02, 0x53, 0xfe, 0x10, 0x63, 0x00,
132 0x00, 0x03, 0x00, 0x17, 0x00, 0xb3, 0x03, 0xce, 0x03, 0x17, 0x00, 0x38, 0x00, 0x4f, 0x00, 0x5d,
133 0x00, 0x00, 0x13, 0x34, 0x3e, 0x02, 0x33, 0x32, 0x1e, 0x02, 0x15, 0x23, 0x27, 0x34, 0x23, 0x2e,
134 0x01, 0x23, 0x22, 0x0e, 0x02, 0x15, 0x14, 0x1e, 0x04, 0x15, 0x14, 0x0e, 0x02, 0x23, 0x22, 0x2e,
135 0x02, 0x35, 0x33, 0x1e, 0x01, 0x33, 0x32, 0x3e, 0x02, 0x35, 0x34, 0x26, 0x27, 0x2e, 0x03, 0x35,
136 0x01, 0x11, 0x33, 0x32, 0x1e, 0x02, 0x15, 0x14, 0x06, 0x07, 0x30, 0x0e, 0x02, 0x31, 0x17, 0x15,
137 0x23, 0x27, 0x23, 0x15, 0x23, 0x13, 0x33, 0x32, 0x3e, 0x02, 0x35, 0x34, 0x2e, 0x02, 0x2b, 0x01,
138 0x15, 0x2a, 0x24, 0x3a, 0x4a, 0x26, 0x29, 0x4b, 0x39, 0x23, 0x73, 0x01, 0x01, 0x08, 0x2a, 0x2a,
139 0x10, 0x1f, 0x1a, 0x10, 0x2c, 0x42, 0x4d, 0x42, 0x2c, 0x23, 0x39, 0x4b, 0x27, 0x2b, 0x51, 0x3f,
140 0x27, 0x75, 0x05, 0x34, 0x33, 0x10, 0x20, 0x1a, 0x10, 0x1f, 0x1c, 0x25, 0x53, 0x47, 0x2e, 0x01,
141 0xed, 0xf3, 0x27, 0x41, 0x2d, 0x19, 0x1c, 0x20, 0x0c, 0x0e, 0x0c, 0x78, 0x7d, 0x68, 0x5d, 0x75,
142 0x76, 0x71, 0x11, 0x1a, 0x12, 0x09, 0x0a, 0x14, 0x1d, 0x13, 0x69, 0x02, 0x71, 0x2a, 0x3e, 0x2a,
143 0x14, 0x18, 0x2e, 0x44, 0x2c, 0x02, 0x02, 0x27, 0x29, 0x07, 0x11, 0x1a, 0x12, 0x1d, 0x24, 0x1c,
144 0x1d, 0x2b, 0x40, 0x32, 0x2c, 0x3f, 0x29, 0x13, 0x1a, 0x31, 0x49, 0x2e, 0x30, 0x30, 0x06, 0x0f,
145 0x19, 0x13, 0x1e, 0x22, 0x0b, 0x0e, 0x20, 0x2f, 0x43, 0x30, 0xfe, 0x4b, 0x02, 0x52, 0x1d, 0x32,
146 0x42, 0x25, 0x2c, 0x42, 0x1d, 0x08, 0x0a, 0x08, 0xf1, 0x06, 0xd7, 0xd7, 0x01, 0x3f, 0x11, 0x19,
147 0x1f, 0x0e, 0x11, 0x20, 0x19, 0x0f, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x12, 0x00, 0x12,
148 0x00, 0x12, 0x00, 0x32, 0x00, 0x72, 0x00, 0x8e, 0x00, 0xac, 0x00, 0xbe, 0x00, 0xf0, 0x01, 0x14,
149 0x01, 0x5c, 0x01, 0xb6, 0x02, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0xa2, 0x00, 0x01,
150 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
151 0x00, 0x02, 0x00, 0x07, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x2f,
152 0x00, 0x17, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x12, 0x00, 0x46, 0x00, 0x01,
153 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x58, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
154 0x00, 0x06, 0x00, 0x12, 0x00, 0x65, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, 0x00, 0x01, 0x00, 0x20,
155 0x00, 0x77, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, 0x00, 0x02, 0x00, 0x0e, 0x00, 0x97, 0x00, 0x03,
156 0x00, 0x01, 0x04, 0x09, 0x00, 0x03, 0x00, 0x5e, 0x00, 0xa5, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09,
157 0x00, 0x04, 0x00, 0x24, 0x01, 0x03, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, 0x00, 0x05, 0x00, 0x1a,
158 0x01, 0x27, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, 0x00, 0x06, 0x00, 0x24, 0x01, 0x41, 0x00, 0x03,
159 0x00, 0x01, 0x04, 0x09, 0x00, 0x11, 0x00, 0x02, 0x01, 0x65, 0x59, 0x75, 0x7a, 0x75, 0x4f, 0x53,
160 0x53, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x67, 0x75, 0x6c, 0x61,
161 0x72, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x31, 0x2e, 0x30, 0x30, 0x30, 0x3b, 0x3b,
162 0x59, 0x75, 0x7a, 0x75, 0x4f, 0x53, 0x53, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e,
163 0x2d, 0x52, 0x3b, 0x32, 0x30, 0x31, 0x39, 0x3b, 0x46, 0x4c, 0x56, 0x49, 0x2d, 0x36, 0x31, 0x34,
164 0x59, 0x75, 0x7a, 0x75, 0x4f, 0x53, 0x53, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e,
165 0x20, 0x52, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x31, 0x2e, 0x30, 0x30, 0x30, 0x59,
166 0x75, 0x7a, 0x75, 0x4f, 0x53, 0x53, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x2d,
167 0x52, 0x00, 0x59, 0x00, 0x75, 0x00, 0x7a, 0x00, 0x75, 0x00, 0x4f, 0x00, 0x53, 0x00, 0x53, 0x00,
168 0x45, 0x00, 0x78, 0x00, 0x74, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6f, 0x00,
169 0x6e, 0x00, 0x52, 0x00, 0x65, 0x00, 0x67, 0x00, 0x75, 0x00, 0x6c, 0x00, 0x61, 0x00, 0x72, 0x00,
170 0x56, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x20, 0x00,
171 0x31, 0x00, 0x2e, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x3b, 0x00, 0x3b, 0x00, 0x59, 0x00,
172 0x75, 0x00, 0x7a, 0x00, 0x75, 0x00, 0x4f, 0x00, 0x53, 0x00, 0x53, 0x00, 0x45, 0x00, 0x78, 0x00,
173 0x74, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x2d, 0x00,
174 0x52, 0x00, 0x3b, 0x00, 0x32, 0x00, 0x30, 0x00, 0x31, 0x00, 0x39, 0x00, 0x3b, 0x00, 0x46, 0x00,
175 0x4c, 0x00, 0x56, 0x00, 0x49, 0x00, 0x2d, 0x00, 0x36, 0x00, 0x31, 0x00, 0x34, 0x00, 0x59, 0x00,
176 0x75, 0x00, 0x7a, 0x00, 0x75, 0x00, 0x4f, 0x00, 0x53, 0x00, 0x53, 0x00, 0x45, 0x00, 0x78, 0x00,
177 0x74, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x20, 0x00,
178 0x52, 0x00, 0x56, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00,
179 0x20, 0x00, 0x31, 0x00, 0x2e, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x59, 0x00, 0x75, 0x00,
180 0x7a, 0x00, 0x75, 0x00, 0x4f, 0x00, 0x53, 0x00, 0x53, 0x00, 0x45, 0x00, 0x78, 0x00, 0x74, 0x00,
181 0x65, 0x00, 0x6e, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x2d, 0x00, 0x52, 0x00,
182 0x52, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x9c, 0x00, 0x32,
183 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 54 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
184 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x01, 0x02, 0x01, 0x03, 0x00, 0x03, 0x01, 0x04, 55 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
185 0x01, 0x05, 0x01, 0x06, 0x01, 0x07, 0x01, 0x08, 0x01, 0x09, 0x01, 0x0a, 0x01, 0x0b, 0x01, 0x0c, 56 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
186 0x01, 0x0d, 0x07, 0x75, 0x6e, 0x69, 0x30, 0x30, 0x30, 0x30, 0x07, 0x75, 0x6e, 0x69, 0x30, 0x30, 57 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
187 0x30, 0x44, 0x07, 0x75, 0x6e, 0x69, 0x45, 0x30, 0x45, 0x30, 0x07, 0x75, 0x6e, 0x69, 0x45, 0x30, 58 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
188 0x45, 0x31, 0x07, 0x75, 0x6e, 0x69, 0x45, 0x30, 0x45, 0x32, 0x07, 0x75, 0x6e, 0x69, 0x45, 0x30, 59 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
189 0x45, 0x33, 0x07, 0x75, 0x6e, 0x69, 0x45, 0x30, 0x45, 0x34, 0x07, 0x75, 0x6e, 0x69, 0x45, 0x30, 60 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
190 0x45, 0x35, 0x07, 0x75, 0x6e, 0x69, 0x45, 0x30, 0x45, 0x36, 0x07, 0x75, 0x6e, 0x69, 0x45, 0x30, 61 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
191 0x45, 0x37, 0x07, 0x75, 0x6e, 0x69, 0x45, 0x30, 0x45, 0x38, 0x07, 0x75, 0x6e, 0x69, 0x45, 0x30, 62 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
192 0x45, 0x39, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0xff, 0xff, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x01, 63 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
193 0x00, 0x00, 0x00, 0x00, 64 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
65 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
66 0xB8, 0x00, 0x00, 0x2C, 0x4B, 0xB8, 0x00, 0x09, 0x50, 0x58, 0xB1, 0x01, 0x01, 0x8E, 0x59, 0xB8,
67 0x01, 0xFF, 0x85, 0xB8, 0x00, 0x44, 0x1D, 0xB9, 0x00, 0x09, 0x00, 0x03, 0x5F, 0x5E, 0x2D, 0xB8,
68 0x00, 0x01, 0x2C, 0x20, 0x20, 0x45, 0x69, 0x44, 0xB0, 0x01, 0x60, 0x2D, 0xB8, 0x00, 0x02, 0x2C,
69 0xB8, 0x00, 0x01, 0x2A, 0x21, 0x2D, 0xB8, 0x00, 0x03, 0x2C, 0x20, 0x46, 0xB0, 0x03, 0x25, 0x46,
70 0x52, 0x58, 0x23, 0x59, 0x20, 0x8A, 0x20, 0x8A, 0x49, 0x64, 0x8A, 0x20, 0x46, 0x20, 0x68, 0x61,
71 0x64, 0xB0, 0x04, 0x25, 0x46, 0x20, 0x68, 0x61, 0x64, 0x52, 0x58, 0x23, 0x65, 0x8A, 0x59, 0x2F,
72 0x20, 0xB0, 0x00, 0x53, 0x58, 0x69, 0x20, 0xB0, 0x00, 0x54, 0x58, 0x21, 0xB0, 0x40, 0x59, 0x1B,
73 0x69, 0x20, 0xB0, 0x00, 0x54, 0x58, 0x21, 0xB0, 0x40, 0x65, 0x59, 0x59, 0x3A, 0x2D, 0xB8, 0x00,
74 0x04, 0x2C, 0x20, 0x46, 0xB0, 0x04, 0x25, 0x46, 0x52, 0x58, 0x23, 0x8A, 0x59, 0x20, 0x46, 0x20,
75 0x6A, 0x61, 0x64, 0xB0, 0x04, 0x25, 0x46, 0x20, 0x6A, 0x61, 0x64, 0x52, 0x58, 0x23, 0x8A, 0x59,
76 0x2F, 0xFD, 0x2D, 0xB8, 0x00, 0x05, 0x2C, 0x4B, 0x20, 0xB0, 0x03, 0x26, 0x50, 0x58, 0x51, 0x58,
77 0xB0, 0x80, 0x44, 0x1B, 0xB0, 0x40, 0x44, 0x59, 0x1B, 0x21, 0x21, 0x20, 0x45, 0xB0, 0xC0, 0x50,
78 0x58, 0xB0, 0xC0, 0x44, 0x1B, 0x21, 0x59, 0x59, 0x2D, 0xB8, 0x00, 0x06, 0x2C, 0x20, 0x20, 0x45,
79 0x69, 0x44, 0xB0, 0x01, 0x60, 0x20, 0x20, 0x45, 0x7D, 0x69, 0x18, 0x44, 0xB0, 0x01, 0x60, 0x2D,
80 0xB8, 0x00, 0x07, 0x2C, 0xB8, 0x00, 0x06, 0x2A, 0x2D, 0xB8, 0x00, 0x08, 0x2C, 0x4B, 0x20, 0xB0,
81 0x03, 0x26, 0x53, 0x58, 0xB0, 0x40, 0x1B, 0xB0, 0x00, 0x59, 0x8A, 0x8A, 0x20, 0xB0, 0x03, 0x26,
82 0x53, 0x58, 0x23, 0x21, 0xB0, 0x80, 0x8A, 0x8A, 0x1B, 0x8A, 0x23, 0x59, 0x20, 0xB0, 0x03, 0x26,
83 0x53, 0x58, 0x23, 0x21, 0xB8, 0x00, 0xC0, 0x8A, 0x8A, 0x1B, 0x8A, 0x23, 0x59, 0x20, 0xB0, 0x03,
84 0x26, 0x53, 0x58, 0x23, 0x21, 0xB8, 0x01, 0x00, 0x8A, 0x8A, 0x1B, 0x8A, 0x23, 0x59, 0x20, 0xB0,
85 0x03, 0x26, 0x53, 0x58, 0x23, 0x21, 0xB8, 0x01, 0x40, 0x8A, 0x8A, 0x1B, 0x8A, 0x23, 0x59, 0x20,
86 0xB8, 0x00, 0x03, 0x26, 0x53, 0x58, 0xB0, 0x03, 0x25, 0x45, 0xB8, 0x01, 0x80, 0x50, 0x58, 0x23,
87 0x21, 0xB8, 0x01, 0x80, 0x23, 0x21, 0x1B, 0xB0, 0x03, 0x25, 0x45, 0x23, 0x21, 0x23, 0x21, 0x59,
88 0x1B, 0x21, 0x59, 0x44, 0x2D, 0xB8, 0x00, 0x09, 0x2C, 0x4B, 0x53, 0x58, 0x45, 0x44, 0x1B, 0x21,
89 0x21, 0x59, 0x2D, 0x00, 0xB8, 0x00, 0x00, 0x2B, 0x00, 0xBA, 0x00, 0x01, 0x00, 0x01, 0x00, 0x07,
90 0x2B, 0xB8, 0x00, 0x00, 0x20, 0x45, 0x7D, 0x69, 0x18, 0x44, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00,
91 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x70,
92 0x00, 0xDC, 0x01, 0x34, 0x01, 0x7C, 0x01, 0xA2, 0x01, 0xF4, 0x02, 0x3C, 0x02, 0xA8, 0x03, 0x4C,
93 0x03, 0xE2, 0x04, 0x20, 0x04, 0x58, 0x04, 0x9A, 0x04, 0xEE, 0x05, 0x32, 0x05, 0x64, 0x05, 0x80,
94 0x05, 0xC6, 0x05, 0xF6, 0x06, 0x54, 0x06, 0xB2, 0x07, 0x38, 0x07, 0x60, 0x07, 0x82, 0x00, 0x00,
95 0x00, 0x02, 0x00, 0xA4, 0xFF, 0xFF, 0x03, 0x5C, 0x03, 0x09, 0x00, 0x03, 0x00, 0x07, 0x00, 0x00,
96 0x13, 0x11, 0x21, 0x11, 0x25, 0x21, 0x11, 0x21, 0xCD, 0x02, 0x66, 0xFD, 0x71, 0x02, 0xB8, 0xFD,
97 0x48, 0x02, 0xE0, 0xFD, 0x48, 0x02, 0xB8, 0x29, 0xFC, 0xF6, 0x00, 0x00, 0x00, 0x04, 0x00, 0x14,
98 0xFF, 0x98, 0x03, 0xEC, 0x03, 0x70, 0x00, 0x0F, 0x00, 0x1F, 0x00, 0x2F, 0x00, 0x39, 0x00, 0x00,
99 0x00, 0x22, 0x0E, 0x02, 0x14, 0x1E, 0x02, 0x32, 0x3E, 0x02, 0x34, 0x2E, 0x01, 0x24, 0x32, 0x1E,
100 0x02, 0x14, 0x0E, 0x02, 0x22, 0x2E, 0x02, 0x34, 0x3E, 0x01, 0x13, 0x12, 0x37, 0x33, 0x13, 0x12,
101 0x15, 0x16, 0x23, 0x2F, 0x01, 0x23, 0x07, 0x23, 0x22, 0x26, 0x25, 0x30, 0x27, 0x26, 0x2F, 0x01,
102 0x06, 0x07, 0x06, 0x32, 0x02, 0x5A, 0xB4, 0xA4, 0x77, 0x46, 0x46, 0x77, 0xA4, 0xB4, 0xA4, 0x77,
103 0x46, 0x46, 0x77, 0xFE, 0x9E, 0xC8, 0xB7, 0x83, 0x4E, 0x4E, 0x83, 0xB7, 0xC8, 0xB7, 0x83, 0x4E,
104 0x4E, 0x83, 0x23, 0x6C, 0x5E, 0x6D, 0x68, 0x68, 0x01, 0x39, 0x38, 0x2E, 0xD1, 0x2B, 0x37, 0x33,
105 0x04, 0x01, 0x48, 0x1D, 0x1C, 0x0A, 0x05, 0x01, 0x45, 0x01, 0x89, 0x03, 0x3F, 0x46, 0x77, 0xA4,
106 0xB4, 0xA4, 0x77, 0x46, 0x46, 0x77, 0xA4, 0xB4, 0xA4, 0x77, 0x77, 0x4E, 0x83, 0xB7, 0xC8, 0xB7,
107 0x83, 0x4E, 0x4E, 0x83, 0xB7, 0xC8, 0xB7, 0x83, 0xFD, 0x64, 0x01, 0x1A, 0xEB, 0xFE, 0xFE, 0xFE,
108 0xFD, 0x03, 0x01, 0x01, 0x77, 0x78, 0x01, 0xCF, 0x4C, 0x4C, 0x1C, 0x0C, 0x02, 0xBE, 0x02, 0x00,
109 0x00, 0x05, 0x00, 0x14, 0xFF, 0x98, 0x03, 0xEC, 0x03, 0x70, 0x00, 0x0F, 0x00, 0x1B, 0x00, 0x2F,
110 0x00, 0x3A, 0x00, 0x44, 0x00, 0x00, 0x12, 0x14, 0x1E, 0x02, 0x32, 0x3E, 0x02, 0x34, 0x2E, 0x02,
111 0x22, 0x0E, 0x01, 0x02, 0x10, 0x3E, 0x01, 0x20, 0x1E, 0x01, 0x10, 0x0E, 0x01, 0x20, 0x26, 0x01,
112 0x16, 0x17, 0x14, 0x06, 0x07, 0x06, 0x2B, 0x01, 0x19, 0x01, 0x17, 0x32, 0x17, 0x16, 0x17, 0x16,
113 0x07, 0x06, 0x0F, 0x01, 0x36, 0x37, 0x34, 0x2E, 0x01, 0x27, 0x23, 0x15, 0x33, 0x32, 0x27, 0x32,
114 0x37, 0x36, 0x26, 0x27, 0x26, 0x2B, 0x01, 0x15, 0x45, 0x46, 0x77, 0xA4, 0xB4, 0xA4, 0x77, 0x46,
115 0x46, 0x77, 0xA4, 0xB4, 0xA4, 0x77, 0x77, 0x84, 0xE2, 0x01, 0x0C, 0xE2, 0x84, 0x84, 0xE2, 0xFE,
116 0xF4, 0xE2, 0x01, 0xF7, 0x61, 0x01, 0x4E, 0x3E, 0x29, 0xAF, 0x4E, 0x81, 0x8B, 0x1D, 0x3C, 0x1F,
117 0x19, 0x04, 0x06, 0x39, 0x57, 0x44, 0x01, 0x1B, 0x2D, 0x51, 0x46, 0x46, 0x47, 0x66, 0x70, 0x16,
118 0x1F, 0x01, 0x2C, 0x08, 0x4B, 0x4C, 0x01, 0xDE, 0xB4, 0xA4, 0x77, 0x46, 0x46, 0x77, 0xA4, 0xB4,
119 0xA4, 0x77, 0x46, 0x46, 0x77, 0xFE, 0x7C, 0x01, 0x0C, 0xE2, 0x84, 0x84, 0xE2, 0xFE, 0xF4, 0xE2,
120 0x84, 0x84, 0x01, 0x6D, 0x21, 0x5B, 0x40, 0x50, 0x05, 0x03, 0x01, 0x03, 0x01, 0x05, 0x01, 0x05,
121 0x09, 0x30, 0x25, 0x29, 0x40, 0x21, 0xC2, 0x06, 0x3E, 0x1A, 0x21, 0x0B, 0x01, 0x8C, 0xE1, 0x0A,
122 0x0E, 0x54, 0x0B, 0x02, 0x79, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x14, 0xFF, 0x98, 0x03, 0xEC,
123 0x03, 0x70, 0x00, 0x0F, 0x00, 0x1B, 0x00, 0x38, 0x00, 0x00, 0x12, 0x14, 0x1E, 0x02, 0x32, 0x3E,
124 0x02, 0x34, 0x2E, 0x02, 0x22, 0x0E, 0x01, 0x02, 0x10, 0x3E, 0x01, 0x20, 0x1E, 0x01, 0x10, 0x0E,
125 0x01, 0x20, 0x26, 0x36, 0x34, 0x3F, 0x01, 0x27, 0x26, 0x27, 0x33, 0x17, 0x16, 0x33, 0x36, 0x3F,
126 0x02, 0x32, 0x14, 0x06, 0x16, 0x12, 0x14, 0x2B, 0x01, 0x27, 0x26, 0x06, 0x0F, 0x01, 0x23, 0x45,
127 0x46, 0x77, 0xA4, 0xB4, 0xA4, 0x77, 0x46, 0x46, 0x77, 0xA4, 0xB4, 0xA4, 0x77, 0x77, 0x84, 0xE2,
128 0x01, 0x0C, 0xE2, 0x84, 0x84, 0xE2, 0xFE, 0xF4, 0xE2, 0x7B, 0x58, 0x58, 0x4D, 0x4F, 0x05, 0x7A,
129 0x34, 0x34, 0x02, 0x01, 0x33, 0x32, 0x3C, 0x3C, 0xA1, 0x01, 0xB0, 0x3E, 0x3F, 0x39, 0x3B, 0x02,
130 0x3A, 0x38, 0x3F, 0x01, 0xDE, 0xB4, 0xA4, 0x77, 0x46, 0x46, 0x77, 0xA4, 0xB4, 0xA4, 0x77, 0x46,
131 0x46, 0x77, 0xFE, 0x7C, 0x01, 0x0C, 0xE2, 0x84, 0x84, 0xE2, 0xFE, 0xF4, 0xE2, 0x84, 0x84, 0x60,
132 0x02, 0x87, 0x88, 0x79, 0x7A, 0x06, 0x54, 0x54, 0x01, 0x53, 0x53, 0x01, 0x01, 0xFB, 0x04, 0xFE,
133 0xF8, 0x02, 0x5B, 0x5A, 0x03, 0x59, 0x59, 0x00, 0x00, 0x03, 0x00, 0x14, 0xFF, 0x98, 0x03, 0xEC,
134 0x03, 0x70, 0x00, 0x0F, 0x00, 0x1B, 0x00, 0x2B, 0x00, 0x00, 0x00, 0x22, 0x0E, 0x02, 0x14, 0x1E,
135 0x02, 0x32, 0x3E, 0x02, 0x34, 0x2E, 0x01, 0x24, 0x20, 0x1E, 0x01, 0x10, 0x0E, 0x01, 0x20, 0x2E,
136 0x01, 0x10, 0x36, 0x01, 0x35, 0x27, 0x26, 0x34, 0x3B, 0x01, 0x17, 0x16, 0x36, 0x3F, 0x01, 0x33,
137 0x03, 0x15, 0x23, 0x02, 0x5A, 0xB4, 0xA4, 0x77, 0x46, 0x46, 0x77, 0xA4, 0xB4, 0xA4, 0x77, 0x46,
138 0x46, 0x77, 0xFE, 0x7C, 0x01, 0x0C, 0xE2, 0x84, 0x84, 0xE2, 0xFE, 0xF4, 0xE2, 0x84, 0x84, 0x01,
139 0x36, 0x5E, 0x5F, 0x3C, 0x3D, 0x3D, 0x3D, 0x03, 0x3B, 0x3B, 0x77, 0xBE, 0x68, 0x03, 0x3F, 0x46,
140 0x77, 0xA4, 0xB4, 0xA4, 0x77, 0x46, 0x46, 0x77, 0xA4, 0xB4, 0xA4, 0x77, 0x77, 0x84, 0xE2, 0xFE,
141 0xF4, 0xE2, 0x84, 0x84, 0xE2, 0x01, 0x0C, 0xE2, 0xFD, 0xF9, 0x6E, 0x96, 0x95, 0x01, 0x67, 0x67,
142 0x03, 0x66, 0x65, 0xFE, 0xD3, 0xDA, 0x00, 0x00, 0x00, 0x03, 0x00, 0x14, 0xFF, 0xBD, 0x03, 0xEC,
143 0x03, 0x4B, 0x00, 0x06, 0x00, 0x0C, 0x00, 0x12, 0x00, 0x00, 0x01, 0x21, 0x22, 0x15, 0x30, 0x11,
144 0x21, 0x17, 0x21, 0x11, 0x10, 0x25, 0x21, 0x01, 0x11, 0x33, 0x11, 0x21, 0x15, 0x03, 0xBB, 0xFD,
145 0x77, 0xED, 0x03, 0x76, 0x31, 0xFC, 0x28, 0x01, 0x1E, 0x02, 0xBA, 0xFD, 0x5C, 0x68, 0x01, 0x08,
146 0x03, 0x1A, 0xEE, 0xFD, 0xC2, 0x31, 0x02, 0x6F, 0x01, 0x1E, 0x01, 0xFD, 0x36, 0x02, 0x07, 0xFE,
147 0x50, 0x57, 0x00, 0x00, 0x00, 0x04, 0x00, 0x14, 0xFF, 0xBD, 0x03, 0xEC, 0x03, 0x4B, 0x00, 0x06,
148 0x00, 0x0C, 0x00, 0x27, 0x00, 0x32, 0x00, 0x00, 0x05, 0x11, 0x34, 0x27, 0x30, 0x21, 0x11, 0x07,
149 0x11, 0x21, 0x20, 0x19, 0x01, 0x25, 0x11, 0x33, 0x32, 0x17, 0x16, 0x17, 0x16, 0x17, 0x16, 0x07,
150 0x06, 0x07, 0x06, 0x07, 0x1E, 0x02, 0x15, 0x07, 0x23, 0x27, 0x2E, 0x01, 0x2F, 0x01, 0x15, 0x13,
151 0x36, 0x35, 0x34, 0x27, 0x26, 0x27, 0x23, 0x15, 0x33, 0x36, 0x03, 0xBB, 0xED, 0xFD, 0x77, 0x31,
152 0x02, 0xBA, 0x01, 0x1E, 0xFD, 0x2A, 0x77, 0x76, 0x15, 0x49, 0x20, 0x35, 0x08, 0x04, 0x06, 0x13,
153 0x66, 0x0C, 0x01, 0x1F, 0x2E, 0x65, 0x3D, 0x3D, 0x2A, 0x56, 0x28, 0x2E, 0x19, 0x99, 0x3C, 0x20,
154 0x10, 0x56, 0x4F, 0x46, 0x47, 0x12, 0x02, 0x3E, 0xED, 0x01, 0xFC, 0xD4, 0x31, 0x03, 0x8E, 0xFE,
155 0xE1, 0xFD, 0x91, 0xC4, 0x02, 0x07, 0x01, 0x04, 0x13, 0x21, 0x44, 0x1D, 0x19, 0x58, 0x15, 0x02,
156 0x01, 0x13, 0x2D, 0xA2, 0x01, 0x01, 0x3D, 0x81, 0x1A, 0x01, 0x01, 0xDA, 0x01, 0x2D, 0x08, 0x3A,
157 0x29, 0x0F, 0x08, 0x01, 0x85, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x14, 0xFF, 0xF5, 0x03, 0xEC,
158 0x03, 0x13, 0x00, 0x09, 0x00, 0x11, 0x00, 0x26, 0x00, 0x32, 0x00, 0x00, 0x37, 0x21, 0x34, 0x10,
159 0x35, 0x34, 0x27, 0x21, 0x04, 0x11, 0x23, 0x10, 0x25, 0x21, 0x16, 0x15, 0x11, 0x21, 0x37, 0x35,
160 0x37, 0x36, 0x22, 0x2B, 0x01, 0x3D, 0x01, 0x3B, 0x01, 0x1D, 0x01, 0x0F, 0x01, 0x3B, 0x01, 0x1D,
161 0x01, 0x2B, 0x01, 0x25, 0x35, 0x3B, 0x01, 0x1D, 0x01, 0x3B, 0x01, 0x1D, 0x01, 0x2B, 0x01, 0x45,
162 0x03, 0x76, 0x45, 0xFE, 0x2D, 0xFE, 0xA2, 0x31, 0x01, 0x8F, 0x01, 0xD3, 0x76, 0xFC, 0x28, 0xA7,
163 0x68, 0x68, 0x01, 0x5B, 0x5D, 0x90, 0x91, 0x6C, 0x6D, 0x71, 0x70, 0xA0, 0xA0, 0x01, 0x75, 0x27,
164 0x28, 0x63, 0x63, 0x8B, 0x8A, 0x27, 0x69, 0x01, 0xA4, 0x69, 0x44, 0x01, 0x02, 0xFE, 0xA4, 0x01,
165 0x8C, 0x03, 0x01, 0x75, 0xFD, 0x58, 0xBB, 0x24, 0x80, 0x80, 0x21, 0x21, 0x1F, 0x1E, 0x85, 0x86,
166 0x20, 0x22, 0xC3, 0xC3, 0xA1, 0xA3, 0x20, 0x22, 0x00, 0x05, 0x00, 0x14, 0xFF, 0xF5, 0x03, 0xEC,
167 0x03, 0x13, 0x00, 0x08, 0x00, 0x10, 0x00, 0x2B, 0x00, 0x37, 0x00, 0x44, 0x00, 0x00, 0x37, 0x21,
168 0x11, 0x10, 0x25, 0x30, 0x21, 0x06, 0x15, 0x03, 0x11, 0x34, 0x37, 0x21, 0x04, 0x19, 0x01, 0x01,
169 0x35, 0x17, 0x32, 0x17, 0x16, 0x17, 0x16, 0x07, 0x06, 0x07, 0x06, 0x17, 0x16, 0x17, 0x16, 0x17,
170 0x16, 0x23, 0x2F, 0x01, 0x2E, 0x01, 0x2F, 0x01, 0x15, 0x23, 0x37, 0x32, 0x36, 0x37, 0x36, 0x35,
171 0x26, 0x27, 0x26, 0x2B, 0x01, 0x15, 0x05, 0x35, 0x37, 0x36, 0x26, 0x2B, 0x01, 0x35, 0x21, 0x15,
172 0x03, 0x17, 0x15, 0x45, 0x03, 0x76, 0xFE, 0xA2, 0xFE, 0x2D, 0x45, 0x31, 0x76, 0x01, 0xD3, 0x01,
173 0x8F, 0xFE, 0x1E, 0x65, 0x6F, 0x15, 0x46, 0x10, 0x05, 0x04, 0x0D, 0x4F, 0x09, 0x09, 0x1F, 0x1D,
174 0x3A, 0x06, 0x01, 0x30, 0x2F, 0x22, 0x37, 0x1E, 0x29, 0x14, 0x4E, 0x82, 0x34, 0x19, 0x0E, 0x13,
175 0x0A, 0x22, 0x07, 0x38, 0x37, 0xFE, 0x3E, 0x68, 0x68, 0x01, 0x5C, 0x5C, 0x01, 0x20, 0xD8, 0xE1,
176 0x27, 0x01, 0x5D, 0x01, 0x5B, 0x03, 0x01, 0x44, 0xFD, 0x58, 0x02, 0xA8, 0x75, 0x01, 0x03, 0xFE,
177 0x74, 0xFE, 0x71, 0x01, 0x5C, 0xC5, 0x01, 0x04, 0x0C, 0x43, 0x15, 0x1D, 0x44, 0x10, 0x04, 0x06,
178 0x14, 0x2B, 0x56, 0x10, 0x01, 0x01, 0x34, 0x52, 0x1C, 0x01, 0x01, 0xA5, 0xE3, 0x04, 0x06, 0x0A,
179 0x20, 0x2C, 0x04, 0x01, 0x65, 0xE3, 0x47, 0x80, 0x80, 0x01, 0x42, 0x3D, 0xFE, 0xF5, 0x01, 0x41,
180 0x00, 0x04, 0x00, 0x14, 0x00, 0x52, 0x03, 0xEC, 0x02, 0xB6, 0x00, 0x08, 0x00, 0x16, 0x00, 0x64,
181 0x00, 0x70, 0x00, 0x00, 0x25, 0x11, 0x21, 0x22, 0x15, 0x30, 0x15, 0x14, 0x33, 0x11, 0x21, 0x32,
182 0x15, 0x11, 0x14, 0x27, 0x21, 0x22, 0x26, 0x3D, 0x01, 0x34, 0x36, 0x13, 0x26, 0x27, 0x26, 0x27,
183 0x26, 0x37, 0x33, 0x36, 0x37, 0x36, 0x33, 0x16, 0x17, 0x16, 0x17, 0x16, 0x37, 0x36, 0x37, 0x36,
184 0x35, 0x34, 0x27, 0x26, 0x27, 0x26, 0x27, 0x26, 0x27, 0x26, 0x27, 0x26, 0x34, 0x37, 0x36, 0x37,
185 0x36, 0x37, 0x36, 0x17, 0x16, 0x17, 0x16, 0x17, 0x16, 0x17, 0x16, 0x0F, 0x01, 0x22, 0x06, 0x23,
186 0x27, 0x26, 0x27, 0x26, 0x23, 0x22, 0x07, 0x06, 0x07, 0x06, 0x17, 0x16, 0x17, 0x16, 0x17, 0x16,
187 0x17, 0x16, 0x17, 0x16, 0x07, 0x06, 0x07, 0x06, 0x27, 0x37, 0x35, 0x3B, 0x01, 0x1D, 0x01, 0x3B,
188 0x01, 0x1D, 0x01, 0x2B, 0x01, 0x03, 0xBB, 0xFD, 0x2A, 0xA0, 0xA0, 0x02, 0xEE, 0x19, 0x19, 0xFD,
189 0x12, 0x57, 0x7A, 0x7A, 0xCA, 0x38, 0x1D, 0x16, 0x08, 0x03, 0x01, 0x02, 0x0F, 0x0C, 0x1E, 0x01,
190 0x02, 0x04, 0x0C, 0x2B, 0x0F, 0x0E, 0x18, 0x0C, 0x09, 0x04, 0x15, 0x32, 0x23, 0x12, 0x1C, 0x0E,
191 0x09, 0x03, 0x01, 0x01, 0x09, 0x21, 0x0F, 0x14, 0x2E, 0x2A, 0x13, 0x0F, 0x0C, 0x08, 0x0B, 0x05,
192 0x02, 0x01, 0x02, 0x03, 0x36, 0x03, 0x02, 0x03, 0x08, 0x0D, 0x23, 0x16, 0x0E, 0x10, 0x01, 0x01,
193 0x07, 0x0B, 0x32, 0x25, 0x13, 0x26, 0x0F, 0x09, 0x01, 0x01, 0x0F, 0x11, 0x24, 0x21, 0x2A, 0xE3,
194 0x20, 0x20, 0x52, 0x50, 0x71, 0x71, 0x84, 0x02, 0x00, 0xAF, 0xA2, 0xAF, 0x02, 0x32, 0x19, 0xFD,
195 0xCE, 0x19, 0x01, 0x84, 0x5C, 0xA2, 0x5C, 0x85, 0xFE, 0x29, 0x04, 0x1E, 0x18, 0x26, 0x0F, 0x01,
196 0x02, 0x01, 0x03, 0x05, 0x0B, 0x29, 0x06, 0x02, 0x03, 0x04, 0x11, 0x0B, 0x0D, 0x0A, 0x06, 0x12,
197 0x0D, 0x0A, 0x07, 0x0C, 0x18, 0x0D, 0x10, 0x06, 0x18, 0x05, 0x27, 0x14, 0x09, 0x03, 0x0A, 0x0D,
198 0x06, 0x09, 0x09, 0x0D, 0x0F, 0x14, 0x0C, 0x06, 0x03, 0x02, 0x04, 0x10, 0x0A, 0x11, 0x08, 0x09,
199 0x0E, 0x0C, 0x07, 0x0C, 0x0C, 0x0A, 0x07, 0x0F, 0x20, 0x11, 0x18, 0x1E, 0x1A, 0x1E, 0x0C, 0x0B,
200 0x03, 0xAA, 0xA5, 0x89, 0x8A, 0x1C, 0x1B, 0x00, 0x00, 0x05, 0x00, 0x14, 0x00, 0x53, 0x03, 0xEC,
201 0x02, 0xB6, 0x00, 0x08, 0x00, 0x16, 0x00, 0x2E, 0x00, 0x38, 0x00, 0x65, 0x00, 0x00, 0x01, 0x30,
202 0x21, 0x11, 0x21, 0x32, 0x3D, 0x01, 0x34, 0x27, 0x32, 0x16, 0x1D, 0x01, 0x14, 0x06, 0x23, 0x21,
203 0x26, 0x35, 0x11, 0x34, 0x33, 0x01, 0x11, 0x33, 0x32, 0x17, 0x16, 0x17, 0x16, 0x07, 0x06, 0x07,
204 0x17, 0x1E, 0x01, 0x1F, 0x01, 0x23, 0x2A, 0x01, 0x2E, 0x01, 0x23, 0x27, 0x15, 0x37, 0x32, 0x37,
205 0x36, 0x27, 0x2E, 0x01, 0x2B, 0x01, 0x15, 0x05, 0x26, 0x27, 0x37, 0x32, 0x3F, 0x01, 0x16, 0x17,
206 0x1E, 0x01, 0x37, 0x36, 0x27, 0x2E, 0x04, 0x37, 0x3E, 0x01, 0x33, 0x32, 0x17, 0x16, 0x17, 0x14,
207 0x06, 0x27, 0x26, 0x27, 0x26, 0x0E, 0x01, 0x1E, 0x02, 0x17, 0x16, 0x06, 0x07, 0x06, 0x07, 0x06,
208 0x03, 0x1B, 0xFD, 0x2A, 0x02, 0xD6, 0xA0, 0xA0, 0x57, 0x7A, 0x7A, 0x57, 0xFD, 0x12, 0x19, 0x19,
209 0x01, 0xD3, 0x47, 0x44, 0x11, 0x3E, 0x18, 0x21, 0x0B, 0x0C, 0x43, 0x04, 0x17, 0x1C, 0x1E, 0x16,
210 0x26, 0x26, 0x03, 0x4D, 0x18, 0x1E, 0x11, 0x25, 0x3A, 0x0C, 0x22, 0x08, 0x03, 0x1B, 0x3E, 0x29,
211 0xFE, 0xAC, 0x0D, 0x04, 0x02, 0x02, 0x1E, 0x1D, 0x03, 0x02, 0x0C, 0x4C, 0x13, 0x20, 0x07, 0x04,
212 0x1B, 0x56, 0x2D, 0x1C, 0x01, 0x02, 0x44, 0x35, 0x49, 0x1F, 0x10, 0x03, 0x41, 0x01, 0x06, 0x0A,
213 0x16, 0x3C, 0x18, 0x0C, 0x16, 0x5D, 0x15, 0x33, 0x03, 0x2B, 0x1E, 0x34, 0x59, 0x02, 0x84, 0xFE,
214 0x00, 0xAF, 0xA2, 0xAF, 0x32, 0x85, 0x5C, 0xA2, 0x5C, 0x84, 0x01, 0x17, 0x02, 0x32, 0x19, 0xFE,
215 0x2F, 0x01, 0x45, 0x01, 0x02, 0x19, 0x22, 0x32, 0x39, 0x0B, 0x08, 0x0F, 0x27, 0x2F, 0x24, 0x75,
216 0x12, 0x01, 0x88, 0xBB, 0x04, 0x09, 0x2A, 0x0F, 0x0D, 0x53, 0x8A, 0x17, 0x1E, 0x04, 0x03, 0x03,
217 0x0C, 0x04, 0x26, 0x0E, 0x0C, 0x14, 0x1A, 0x0E, 0x0E, 0x16, 0x16, 0x2C, 0x1A, 0x2D, 0x2D, 0x2A,
218 0x16, 0x1D, 0x06, 0x04, 0x01, 0x1A, 0x09, 0x11, 0x09, 0x17, 0x18, 0x0D, 0x17, 0x0C, 0x1B, 0x71,
219 0x1B, 0x12, 0x01, 0x03, 0x00, 0x03, 0x00, 0x14, 0xFF, 0x98, 0x03, 0xEC, 0x03, 0x70, 0x00, 0x0F,
220 0x00, 0x1B, 0x00, 0x27, 0x00, 0x00, 0x00, 0x22, 0x0E, 0x02, 0x14, 0x1E, 0x02, 0x32, 0x3E, 0x02,
221 0x34, 0x2E, 0x01, 0x24, 0x20, 0x1E, 0x01, 0x10, 0x0E, 0x01, 0x20, 0x2E, 0x01, 0x10, 0x36, 0x13,
222 0x33, 0x35, 0x33, 0x15, 0x33, 0x15, 0x23, 0x15, 0x23, 0x35, 0x23, 0x02, 0x5A, 0xB4, 0xA4, 0x77,
223 0x46, 0x46, 0x77, 0xA4, 0xB4, 0xA4, 0x77, 0x46, 0x46, 0x77, 0xFE, 0x7C, 0x01, 0x0C, 0xE2, 0x84,
224 0x84, 0xE2, 0xFE, 0xF4, 0xE2, 0x84, 0x84, 0x7C, 0xC5, 0x4E, 0xC5, 0xC4, 0x50, 0xC4, 0x03, 0x3F,
225 0x46, 0x77, 0xA4, 0xB4, 0xA4, 0x77, 0x46, 0x46, 0x77, 0xA4, 0xB4, 0xA4, 0x77, 0x77, 0x84, 0xE2,
226 0xFE, 0xF4, 0xE2, 0x84, 0x84, 0xE2, 0x01, 0x0C, 0xE2, 0xFE, 0xC0, 0xC4, 0xC5, 0x4E, 0xC5, 0xC5,
227 0x00, 0x03, 0x00, 0x14, 0xFF, 0x98, 0x03, 0xEC, 0x03, 0x70, 0x00, 0x0F, 0x00, 0x1B, 0x00, 0x1F,
228 0x00, 0x00, 0x00, 0x22, 0x0E, 0x02, 0x14, 0x1E, 0x02, 0x32, 0x3E, 0x02, 0x34, 0x2E, 0x01, 0x24,
229 0x20, 0x1E, 0x01, 0x10, 0x0E, 0x01, 0x20, 0x2E, 0x01, 0x10, 0x36, 0x13, 0x35, 0x21, 0x15, 0x02,
230 0x5A, 0xB4, 0xA4, 0x77, 0x46, 0x46, 0x77, 0xA4, 0xB4, 0xA4, 0x77, 0x46, 0x46, 0x77, 0xFE, 0x7C,
231 0x01, 0x0C, 0xE2, 0x84, 0x84, 0xE2, 0xFE, 0xF4, 0xE2, 0x84, 0x84, 0x7C, 0x01, 0xD8, 0x03, 0x3F,
232 0x46, 0x77, 0xA4, 0xB4, 0xA4, 0x77, 0x46, 0x46, 0x77, 0xA4, 0xB4, 0xA4, 0x77, 0x77, 0x84, 0xE2,
233 0xFE, 0xF4, 0xE2, 0x84, 0x84, 0xE2, 0x01, 0x0C, 0xE2, 0xFE, 0x71, 0x4E, 0x4E, 0x00, 0x00, 0x00,
234 0x00, 0x03, 0x00, 0x14, 0xFF, 0x98, 0x03, 0xEC, 0x03, 0x70, 0x00, 0x0B, 0x00, 0x1B, 0x00, 0x25,
235 0x00, 0x00, 0x00, 0x20, 0x0E, 0x01, 0x10, 0x1E, 0x01, 0x20, 0x3E, 0x01, 0x10, 0x26, 0x01, 0x12,
236 0x37, 0x33, 0x13, 0x12, 0x15, 0x16, 0x23, 0x2F, 0x01, 0x23, 0x07, 0x23, 0x22, 0x26, 0x25, 0x30,
237 0x27, 0x26, 0x2F, 0x01, 0x06, 0x07, 0x06, 0x32, 0x02, 0x86, 0xFE, 0xF4, 0xE2, 0x84, 0x84, 0xE2,
238 0x01, 0x0C, 0xE2, 0x84, 0x84, 0xFD, 0xA0, 0x6C, 0x5E, 0x6D, 0x68, 0x68, 0x01, 0x39, 0x38, 0x2E,
239 0xD1, 0x2B, 0x37, 0x33, 0x04, 0x01, 0x48, 0x1D, 0x1C, 0x0A, 0x05, 0x01, 0x45, 0x01, 0x89, 0x03,
240 0x70, 0x84, 0xE2, 0xFE, 0xF4, 0xE2, 0x84, 0x84, 0xE2, 0x01, 0x0C, 0xE2, 0xFD, 0x9A, 0x01, 0x1A,
241 0xEB, 0xFE, 0xFE, 0xFE, 0xFD, 0x03, 0x01, 0x01, 0x77, 0x78, 0x01, 0xCF, 0x4C, 0x4C, 0x1C, 0x0C,
242 0x02, 0xBE, 0x02, 0x00, 0x00, 0x04, 0x00, 0x14, 0xFF, 0x98, 0x03, 0xEC, 0x03, 0x70, 0x00, 0x0B,
243 0x00, 0x20, 0x00, 0x2B, 0x00, 0x35, 0x00, 0x00, 0x36, 0x10, 0x3E, 0x01, 0x20, 0x1E, 0x01, 0x10,
244 0x0E, 0x01, 0x20, 0x26, 0x01, 0x30, 0x37, 0x36, 0x37, 0x36, 0x27, 0x26, 0x27, 0x26, 0x23, 0x27,
245 0x19, 0x01, 0x33, 0x32, 0x37, 0x3E, 0x01, 0x35, 0x26, 0x07, 0x06, 0x2B, 0x01, 0x35, 0x33, 0x1E,
246 0x02, 0x15, 0x06, 0x27, 0x23, 0x35, 0x33, 0x16, 0x17, 0x16, 0x14, 0x07, 0x06, 0x14, 0x84, 0xE2,
247 0x01, 0x0C, 0xE2, 0x84, 0x84, 0xE2, 0xFE, 0xF4, 0xE2, 0x01, 0xF7, 0x0A, 0x3A, 0x05, 0x04, 0x19,
248 0x20, 0x3B, 0x1D, 0x8B, 0x81, 0x4E, 0xAF, 0x29, 0x3E, 0x4E, 0x01, 0xAE, 0x0D, 0x47, 0x46, 0x46,
249 0x52, 0x2C, 0x1B, 0x01, 0xB7, 0x27, 0x4C, 0x4C, 0x07, 0x2C, 0x1E, 0x16, 0xFE, 0x01, 0x0C, 0xE2,
250 0x84, 0x84, 0xE2, 0xFE, 0xF4, 0xE2, 0x84, 0x84, 0x01, 0x6D, 0x06, 0x21, 0x40, 0x2A, 0x24, 0x30,
251 0x09, 0x05, 0x01, 0xFE, 0xFB, 0xFE, 0xFD, 0x03, 0x05, 0x4F, 0x41, 0x5B, 0x9B, 0x01, 0x8C, 0x01,
252 0x0B, 0x21, 0x1A, 0x3E, 0xDA, 0x79, 0x01, 0x01, 0x0B, 0x54, 0x0E, 0x0A, 0x00, 0x02, 0x00, 0x14,
253 0xFF, 0x98, 0x03, 0xEC, 0x03, 0x70, 0x00, 0x0B, 0x00, 0x29, 0x00, 0x00, 0x36, 0x10, 0x3E, 0x01,
254 0x20, 0x1E, 0x01, 0x10, 0x0E, 0x01, 0x20, 0x26, 0x36, 0x14, 0x3B, 0x01, 0x37, 0x36, 0x37, 0x36,
255 0x1F, 0x01, 0x33, 0x32, 0x34, 0x02, 0x26, 0x36, 0x34, 0x23, 0x0F, 0x01, 0x06, 0x07, 0x22, 0x2F,
256 0x01, 0x23, 0x16, 0x1F, 0x01, 0x07, 0x14, 0x84, 0xE2, 0x01, 0x0C, 0xE2, 0x84, 0x84, 0xE2, 0xFE,
257 0xF4, 0xE2, 0x7B, 0x3D, 0x3F, 0x38, 0x3A, 0x01, 0x02, 0x3A, 0x39, 0x3F, 0x3E, 0xB0, 0x01, 0xA1,
258 0x3C, 0x3C, 0x32, 0x33, 0x01, 0x02, 0x34, 0x34, 0x7A, 0x05, 0x4F, 0x4D, 0x58, 0xFE, 0x01, 0x0C,
259 0xE2, 0x84, 0x84, 0xE2, 0xFE, 0xF4, 0xE2, 0x84, 0x84, 0x62, 0x02, 0x59, 0x59, 0x02, 0x01, 0x5A,
260 0x5B, 0x02, 0x01, 0x08, 0x04, 0xFB, 0x01, 0x01, 0x53, 0x53, 0x01, 0x54, 0x54, 0x06, 0x7A, 0x79,
261 0x88, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x14, 0xFF, 0x98, 0x03, 0xEC, 0x03, 0x70, 0x00, 0x0B,
262 0x00, 0x1B, 0x00, 0x00, 0x00, 0x20, 0x1E, 0x01, 0x10, 0x0E, 0x01, 0x20, 0x2E, 0x01, 0x10, 0x36,
263 0x01, 0x15, 0x33, 0x35, 0x13, 0x23, 0x07, 0x0E, 0x01, 0x2F, 0x01, 0x23, 0x22, 0x16, 0x1F, 0x01,
264 0x01, 0x7A, 0x01, 0x0C, 0xE2, 0x84, 0x84, 0xE2, 0xFE, 0xF4, 0xE2, 0x84, 0x84, 0x01, 0x36, 0x68,
265 0xBE, 0x77, 0x3B, 0x3C, 0x02, 0x3D, 0x3D, 0x3D, 0x3D, 0x01, 0x5F, 0x5E, 0x03, 0x70, 0x84, 0xE2,
266 0xFE, 0xF4, 0xE2, 0x84, 0x84, 0xE2, 0x01, 0x0C, 0xE2, 0xFD, 0xF9, 0x6D, 0xDA, 0x01, 0x2D, 0x65,
267 0x66, 0x03, 0x67, 0x67, 0x01, 0x95, 0x96, 0x00, 0x00, 0x02, 0x00, 0x14, 0xFF, 0xBF, 0x03, 0xEC,
268 0x03, 0x4A, 0x00, 0x05, 0x00, 0x0B, 0x00, 0x00, 0x05, 0x21, 0x11, 0x10, 0x05, 0x21, 0x01, 0x21,
269 0x35, 0x21, 0x11, 0x23, 0x03, 0xEC, 0xFC, 0x28, 0x01, 0x14, 0x02, 0xC4, 0xFD, 0x5C, 0x01, 0x70,
270 0xFE, 0xF8, 0x68, 0x41, 0x02, 0x77, 0x01, 0x14, 0x01, 0xFD, 0x38, 0x57, 0x01, 0xB0, 0x00, 0x00,
271 0x00, 0x03, 0x00, 0x14, 0xFF, 0xBF, 0x03, 0xEC, 0x03, 0x49, 0x00, 0x05, 0x00, 0x20, 0x00, 0x2B,
272 0x00, 0x00, 0x17, 0x11, 0x21, 0x20, 0x19, 0x01, 0x25, 0x33, 0x35, 0x17, 0x1E, 0x01, 0x1F, 0x01,
273 0x33, 0x37, 0x2E, 0x02, 0x27, 0x34, 0x37, 0x36, 0x37, 0x36, 0x27, 0x26, 0x27, 0x26, 0x27, 0x26,
274 0x2B, 0x01, 0x05, 0x06, 0x2B, 0x01, 0x35, 0x33, 0x16, 0x17, 0x16, 0x15, 0x14, 0x14, 0x02, 0xC4,
275 0x01, 0x14, 0xFD, 0x2A, 0x69, 0x19, 0x2E, 0x28, 0x56, 0x2A, 0x3D, 0x3D, 0x01, 0x65, 0x2C, 0x20,
276 0x0D, 0x66, 0x13, 0x06, 0x04, 0x09, 0x34, 0x20, 0x49, 0x15, 0x76, 0x77, 0x01, 0x02, 0x0C, 0x47,
277 0x46, 0x4F, 0x56, 0x10, 0x20, 0x41, 0x03, 0x8A, 0xFE, 0xED, 0xFD, 0x89, 0xC2, 0xDA, 0x01, 0x01,
278 0x1A, 0x81, 0x3D, 0x01, 0x01, 0xA3, 0x2C, 0x13, 0x01, 0x02, 0x13, 0x5A, 0x1A, 0x1C, 0x44, 0x21,
279 0x13, 0x04, 0x01, 0xDA, 0x02, 0x85, 0x01, 0x08, 0x0F, 0x29, 0x3A, 0x00, 0x00, 0x03, 0x00, 0x14,
280 0xFF, 0xFB, 0x03, 0xEC, 0x03, 0x0E, 0x00, 0x08, 0x00, 0x15, 0x00, 0x1B, 0x00, 0x00, 0x05, 0x21,
281 0x11, 0x10, 0x21, 0x30, 0x21, 0x32, 0x15, 0x01, 0x21, 0x35, 0x23, 0x13, 0x35, 0x21, 0x15, 0x33,
282 0x32, 0x22, 0x0F, 0x01, 0x05, 0x21, 0x35, 0x23, 0x11, 0x23, 0x03, 0xEC, 0xFC, 0x28, 0x01, 0x8A,
283 0x01, 0xEC, 0x62, 0xFC, 0xCF, 0x01, 0x40, 0xE1, 0xD9, 0xFE, 0xDF, 0x5D, 0x5C, 0x01, 0x67, 0x68,
284 0x01, 0x75, 0x01, 0x15, 0xC6, 0x4F, 0x05, 0x01, 0x89, 0x01, 0x8A, 0x63, 0xFD, 0xE1, 0x42, 0x01,
285 0x0B, 0x3D, 0x42, 0x80, 0x80, 0x48, 0x42, 0x01, 0x44, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x14,
286 0xFF, 0xFB, 0x03, 0xEC, 0x03, 0x0E, 0x00, 0x07, 0x00, 0x22, 0x00, 0x2F, 0x00, 0x3C, 0x00, 0x00,
287 0x17, 0x11, 0x34, 0x37, 0x21, 0x20, 0x19, 0x01, 0x01, 0x15, 0x33, 0x35, 0x17, 0x1E, 0x01, 0x1F,
288 0x02, 0x32, 0x35, 0x26, 0x27, 0x26, 0x27, 0x26, 0x37, 0x36, 0x37, 0x36, 0x27, 0x26, 0x27, 0x26,
289 0x23, 0x27, 0x17, 0x30, 0x23, 0x35, 0x33, 0x32, 0x17, 0x16, 0x17, 0x14, 0x07, 0x0E, 0x01, 0x05,
290 0x21, 0x35, 0x27, 0x13, 0x35, 0x21, 0x15, 0x33, 0x32, 0x14, 0x0F, 0x01, 0x14, 0x62, 0x01, 0xEC,
291 0x01, 0x8A, 0xFE, 0x1E, 0x4E, 0x14, 0x29, 0x1E, 0x37, 0x22, 0x2F, 0x2F, 0x06, 0x3A, 0x1D, 0x1F,
292 0x09, 0x09, 0x4E, 0x0E, 0x04, 0x05, 0x0F, 0x47, 0x15, 0x6F, 0x65, 0x82, 0x34, 0x37, 0x38, 0x07,
293 0x23, 0x09, 0x13, 0x0D, 0x1A, 0xFD, 0xD6, 0x01, 0x40, 0xE1, 0xD8, 0xFE, 0xE0, 0x5C, 0x5C, 0x67,
294 0x68, 0x05, 0x02, 0xB0, 0x62, 0x01, 0xFE, 0x76, 0xFE, 0x77, 0x01, 0x56, 0xC5, 0xA5, 0x01, 0x01,
295 0x1C, 0x52, 0x34, 0x01, 0x01, 0x0E, 0x58, 0x2C, 0x13, 0x06, 0x04, 0x0F, 0x45, 0x1E, 0x14, 0x42,
296 0x0D, 0x04, 0x01, 0xA7, 0x65, 0x01, 0x04, 0x2C, 0x21, 0x09, 0x07, 0x03, 0xE3, 0x41, 0x01, 0x01,
297 0x0B, 0x3D, 0x42, 0x01, 0x80, 0x80, 0x00, 0x00, 0x00, 0x03, 0x00, 0x14, 0x00, 0x5D, 0x03, 0xEC,
298 0x02, 0xAB, 0x00, 0x08, 0x00, 0x37, 0x00, 0x3D, 0x00, 0x00, 0x13, 0x30, 0x21, 0x11, 0x21, 0x22,
299 0x3D, 0x01, 0x34, 0x05, 0x37, 0x34, 0x27, 0x26, 0x27, 0x26, 0x07, 0x06, 0x07, 0x0E, 0x01, 0x17,
300 0x1E, 0x01, 0x17, 0x16, 0x14, 0x07, 0x06, 0x26, 0x27, 0x26, 0x27, 0x22, 0x06, 0x07, 0x22, 0x17,
301 0x1E, 0x01, 0x17, 0x16, 0x37, 0x36, 0x27, 0x26, 0x27, 0x2E, 0x02, 0x37, 0x36, 0x33, 0x32, 0x1F,
302 0x02, 0x33, 0x35, 0x23, 0x11, 0x23, 0xD6, 0x03, 0x16, 0xFC, 0xEA, 0xC2, 0x01, 0xC6, 0x02, 0x01,
303 0x0C, 0x3A, 0x2B, 0x2D, 0x13, 0x10, 0x2B, 0x01, 0x33, 0x17, 0x55, 0x15, 0x04, 0x09, 0x14, 0x58,
304 0x0C, 0x04, 0x02, 0x02, 0x26, 0x14, 0x01, 0x03, 0x08, 0x33, 0x38, 0x5F, 0x20, 0x10, 0x01, 0x03,
305 0x3C, 0x12, 0x59, 0x11, 0x01, 0x02, 0x39, 0x2C, 0x09, 0x02, 0x9D, 0xE2, 0xA2, 0x40, 0x02, 0xAB,
306 0xFD, 0xB2, 0xD2, 0xAA, 0xD2, 0xDC, 0x03, 0x07, 0x0B, 0x38, 0x10, 0x0C, 0x09, 0x04, 0x08, 0x19,
307 0x6C, 0x17, 0x0B, 0x17, 0x11, 0x07, 0x17, 0x0A, 0x1A, 0x0A, 0x29, 0x0C, 0x04, 0x04, 0x02, 0x10,
308 0x25, 0x37, 0x04, 0x06, 0x37, 0x1D, 0x1C, 0x3F, 0x19, 0x08, 0x16, 0x13, 0x0B, 0x1F, 0x2B, 0x04,
309 0xE9, 0x37, 0x01, 0x13, 0x00, 0x04, 0x00, 0x14, 0x00, 0x5D, 0x03, 0xEC, 0x02, 0xAB, 0x00, 0x07,
310 0x00, 0x1F, 0x00, 0x2A, 0x00, 0x58, 0x00, 0x00, 0x01, 0x32, 0x1D, 0x01, 0x14, 0x23, 0x21, 0x11,
311 0x01, 0x33, 0x35, 0x17, 0x1E, 0x03, 0x3B, 0x01, 0x27, 0x2E, 0x01, 0x2F, 0x01, 0x36, 0x37, 0x36,
312 0x27, 0x26, 0x27, 0x26, 0x2B, 0x01, 0x17, 0x30, 0x23, 0x35, 0x33, 0x32, 0x16, 0x17, 0x16, 0x07,
313 0x06, 0x05, 0x16, 0x37, 0x36, 0x37, 0x3E, 0x01, 0x27, 0x2E, 0x03, 0x3E, 0x01, 0x17, 0x16, 0x17,
314 0x30, 0x37, 0x36, 0x27, 0x26, 0x27, 0x26, 0x27, 0x22, 0x06, 0x07, 0x06, 0x1E, 0x03, 0x17, 0x16,
315 0x07, 0x06, 0x26, 0x27, 0x26, 0x27, 0x07, 0x06, 0x23, 0x07, 0x16, 0x03, 0x2A, 0xC2, 0xC2, 0xFC,
316 0xEA, 0x01, 0xEC, 0x41, 0x11, 0x1F, 0x17, 0x4D, 0x02, 0x27, 0x26, 0x16, 0x1E, 0x1C, 0x17, 0x04,
317 0x43, 0x0C, 0x0B, 0x21, 0x18, 0x3E, 0x0F, 0x46, 0x47, 0x66, 0x25, 0x29, 0x3E, 0x1B, 0x03, 0x08,
318 0x22, 0x0C, 0xFE, 0x4D, 0x22, 0x59, 0x34, 0x1E, 0x2B, 0x03, 0x33, 0x16, 0x5C, 0x16, 0x0C, 0x18,
319 0x3C, 0x16, 0x0B, 0x05, 0x22, 0x21, 0x01, 0x03, 0x10, 0x1F, 0x49, 0x36, 0x43, 0x02, 0x01, 0x1C,
320 0x2D, 0x56, 0x1B, 0x04, 0x07, 0x20, 0x13, 0x4B, 0x0D, 0x01, 0x04, 0x1D, 0x1E, 0x02, 0x02, 0x04,
321 0x02, 0xAB, 0xD2, 0xAA, 0xD2, 0x02, 0x4E, 0xFE, 0x39, 0x89, 0x01, 0x01, 0x11, 0x75, 0x01, 0x25,
322 0x2F, 0x27, 0x0F, 0x08, 0x0C, 0x38, 0x33, 0x21, 0x19, 0x02, 0x01, 0x8A, 0x53, 0x0D, 0x0F, 0x2A,
323 0x09, 0x04, 0x8A, 0x3A, 0x03, 0x01, 0x12, 0x1B, 0x71, 0x1B, 0x0C, 0x17, 0x0D, 0x18, 0x17, 0x09,
324 0x11, 0x09, 0x1A, 0x01, 0x01, 0x07, 0x1E, 0x15, 0x29, 0x01, 0x2D, 0x2D, 0x1A, 0x2C, 0x16, 0x16,
325 0x0D, 0x0F, 0x1A, 0x14, 0x0C, 0x0D, 0x27, 0x04, 0x0C, 0x03, 0x03, 0x04, 0x1E, 0x00, 0x00, 0x00,
326 0x00, 0x02, 0x00, 0x14, 0xFF, 0x98, 0x03, 0xEC, 0x03, 0x70, 0x00, 0x0B, 0x00, 0x17, 0x00, 0x00,
327 0x00, 0x20, 0x1E, 0x01, 0x10, 0x0E, 0x01, 0x20, 0x2E, 0x01, 0x10, 0x36, 0x13, 0x15, 0x33, 0x15,
328 0x33, 0x35, 0x33, 0x35, 0x23, 0x35, 0x23, 0x15, 0x01, 0x7A, 0x01, 0x0C, 0xE2, 0x84, 0x84, 0xE2,
329 0xFE, 0xF4, 0xE2, 0x84, 0x84, 0x7C, 0xC4, 0x50, 0xC4, 0xC5, 0x4E, 0x03, 0x70, 0x84, 0xE2, 0xFE,
330 0xF4, 0xE2, 0x84, 0x84, 0xE2, 0x01, 0x0C, 0xE2, 0xFE, 0xC0, 0x4F, 0xC5, 0xC5, 0x4E, 0xC5, 0xC4,
331 0x00, 0x02, 0x00, 0x14, 0xFF, 0x98, 0x03, 0xEC, 0x03, 0x70, 0x00, 0x0B, 0x00, 0x0F, 0x00, 0x00,
332 0x00, 0x20, 0x1E, 0x01, 0x10, 0x0E, 0x01, 0x20, 0x2E, 0x01, 0x10, 0x36, 0x13, 0x21, 0x35, 0x21,
333 0x01, 0x7A, 0x01, 0x0C, 0xE2, 0x84, 0x84, 0xE2, 0xFE, 0xF4, 0xE2, 0x84, 0x84, 0x7C, 0x01, 0xD8,
334 0xFE, 0x28, 0x03, 0x70, 0x84, 0xE2, 0xFE, 0xF4, 0xE2, 0x84, 0x84, 0xE2, 0x01, 0x0C, 0xE2, 0xFE,
335 0x71, 0x4E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0xAE, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
336 0x00, 0x00, 0x00, 0x15, 0x00, 0x2C, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x10,
337 0x00, 0x64, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x07, 0x00, 0x85, 0x00, 0x01,
338 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x10, 0x00, 0xAF, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
339 0x00, 0x04, 0x00, 0x10, 0x00, 0xE2, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x0D,
340 0x01, 0x0F, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x10, 0x01, 0x3F, 0x00, 0x03,
341 0x00, 0x01, 0x04, 0x09, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09,
342 0x00, 0x01, 0x00, 0x20, 0x00, 0x42, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, 0x00, 0x02, 0x00, 0x0E,
343 0x00, 0x75, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, 0x00, 0x03, 0x00, 0x20, 0x00, 0x8D, 0x00, 0x03,
344 0x00, 0x01, 0x04, 0x09, 0x00, 0x04, 0x00, 0x20, 0x00, 0xC0, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09,
345 0x00, 0x05, 0x00, 0x1A, 0x00, 0xF3, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, 0x00, 0x06, 0x00, 0x20,
346 0x01, 0x1D, 0x00, 0x59, 0x00, 0x75, 0x00, 0x7A, 0x00, 0x75, 0x00, 0x20, 0x00, 0x45, 0x00, 0x6D,
347 0x00, 0x75, 0x00, 0x6C, 0x00, 0x61, 0x00, 0x74, 0x00, 0x6F, 0x00, 0x72, 0x00, 0x20, 0x00, 0x50,
348 0x00, 0x72, 0x00, 0x6F, 0x00, 0x6A, 0x00, 0x65, 0x00, 0x63, 0x00, 0x74, 0x00, 0x00, 0x59, 0x75,
349 0x7A, 0x75, 0x20, 0x45, 0x6D, 0x75, 0x6C, 0x61, 0x74, 0x6F, 0x72, 0x20, 0x50, 0x72, 0x6F, 0x6A,
350 0x65, 0x63, 0x74, 0x00, 0x00, 0x59, 0x00, 0x75, 0x00, 0x7A, 0x00, 0x75, 0x00, 0x4F, 0x00, 0x53,
351 0x00, 0x53, 0x00, 0x45, 0x00, 0x78, 0x00, 0x74, 0x00, 0x65, 0x00, 0x6E, 0x00, 0x73, 0x00, 0x69,
352 0x00, 0x6F, 0x00, 0x6E, 0x00, 0x00, 0x59, 0x75, 0x7A, 0x75, 0x4F, 0x53, 0x53, 0x45, 0x78, 0x74,
353 0x65, 0x6E, 0x73, 0x69, 0x6F, 0x6E, 0x00, 0x00, 0x52, 0x00, 0x65, 0x00, 0x67, 0x00, 0x75, 0x00,
354 0x6C, 0x00, 0x61, 0x00, 0x72, 0x00, 0x00, 0x52, 0x65, 0x67, 0x75, 0x6C, 0x61, 0x72, 0x00, 0x00,
355 0x59, 0x00, 0x75, 0x00, 0x7A, 0x00, 0x75, 0x00, 0x4F, 0x00, 0x53, 0x00, 0x53, 0x00, 0x45, 0x00,
356 0x78, 0x00, 0x74, 0x00, 0x65, 0x00, 0x6E, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6F, 0x00, 0x6E, 0x00,
357 0x00, 0x59, 0x75, 0x7A, 0x75, 0x4F, 0x53, 0x53, 0x45, 0x78, 0x74, 0x65, 0x6E, 0x73, 0x69, 0x6F,
358 0x6E, 0x00, 0x00, 0x59, 0x00, 0x75, 0x00, 0x7A, 0x00, 0x75, 0x00, 0x4F, 0x00, 0x53, 0x00, 0x53,
359 0x00, 0x45, 0x00, 0x78, 0x00, 0x74, 0x00, 0x65, 0x00, 0x6E, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6F,
360 0x00, 0x6E, 0x00, 0x00, 0x59, 0x75, 0x7A, 0x75, 0x4F, 0x53, 0x53, 0x45, 0x78, 0x74, 0x65, 0x6E,
361 0x73, 0x69, 0x6F, 0x6E, 0x00, 0x00, 0x56, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x69, 0x00,
362 0x6F, 0x00, 0x6E, 0x00, 0x20, 0x00, 0x31, 0x00, 0x2E, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00,
363 0x00, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x20, 0x31, 0x2E, 0x30, 0x30, 0x30, 0x00, 0x00,
364 0x59, 0x00, 0x75, 0x00, 0x7A, 0x00, 0x75, 0x00, 0x4F, 0x00, 0x53, 0x00, 0x53, 0x00, 0x45, 0x00,
365 0x78, 0x00, 0x74, 0x00, 0x65, 0x00, 0x6E, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6F, 0x00, 0x6E, 0x00,
366 0x00, 0x59, 0x75, 0x7A, 0x75, 0x4F, 0x53, 0x53, 0x45, 0x78, 0x74, 0x65, 0x6E, 0x73, 0x69, 0x6F,
367 0x6E, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xB5, 0x00, 0x32,
368 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
369 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x01, 0x02, 0x01, 0x03, 0x00, 0x03, 0x01, 0x04,
370 0x01, 0x05, 0x01, 0x06, 0x01, 0x07, 0x01, 0x08, 0x01, 0x09, 0x01, 0x0A, 0x01, 0x0B, 0x01, 0x0C,
371 0x01, 0x0D, 0x01, 0x0E, 0x01, 0x0F, 0x01, 0x10, 0x01, 0x11, 0x01, 0x12, 0x01, 0x13, 0x01, 0x14,
372 0x01, 0x15, 0x01, 0x16, 0x01, 0x17, 0x01, 0x18, 0x01, 0x19, 0x01, 0x1A, 0x01, 0x1B, 0x07, 0x75,
373 0x6E, 0x69, 0x30, 0x30, 0x30, 0x30, 0x07, 0x75, 0x6E, 0x69, 0x30, 0x30, 0x30, 0x44, 0x07, 0x75,
374 0x6E, 0x69, 0x45, 0x30, 0x41, 0x30, 0x07, 0x75, 0x6E, 0x69, 0x45, 0x30, 0x41, 0x31, 0x07, 0x75,
375 0x6E, 0x69, 0x45, 0x30, 0x41, 0x32, 0x07, 0x75, 0x6E, 0x69, 0x45, 0x30, 0x41, 0x33, 0x07, 0x75,
376 0x6E, 0x69, 0x45, 0x30, 0x41, 0x34, 0x07, 0x75, 0x6E, 0x69, 0x45, 0x30, 0x41, 0x35, 0x07, 0x75,
377 0x6E, 0x69, 0x45, 0x30, 0x41, 0x36, 0x07, 0x75, 0x6E, 0x69, 0x45, 0x30, 0x41, 0x37, 0x07, 0x75,
378 0x6E, 0x69, 0x45, 0x30, 0x41, 0x38, 0x07, 0x75, 0x6E, 0x69, 0x45, 0x30, 0x41, 0x39, 0x07, 0x75,
379 0x6E, 0x69, 0x45, 0x30, 0x42, 0x33, 0x07, 0x75, 0x6E, 0x69, 0x45, 0x30, 0x42, 0x34, 0x07, 0x75,
380 0x6E, 0x69, 0x45, 0x30, 0x45, 0x30, 0x07, 0x75, 0x6E, 0x69, 0x45, 0x30, 0x45, 0x31, 0x07, 0x75,
381 0x6E, 0x69, 0x45, 0x30, 0x45, 0x32, 0x07, 0x75, 0x6E, 0x69, 0x45, 0x30, 0x45, 0x33, 0x07, 0x75,
382 0x6E, 0x69, 0x45, 0x30, 0x45, 0x34, 0x07, 0x75, 0x6E, 0x69, 0x45, 0x30, 0x45, 0x35, 0x07, 0x75,
383 0x6E, 0x69, 0x45, 0x30, 0x45, 0x36, 0x07, 0x75, 0x6E, 0x69, 0x45, 0x30, 0x45, 0x37, 0x07, 0x75,
384 0x6E, 0x69, 0x45, 0x30, 0x45, 0x38, 0x07, 0x75, 0x6E, 0x69, 0x45, 0x30, 0x45, 0x39, 0x07, 0x75,
385 0x6E, 0x69, 0x45, 0x30, 0x45, 0x46, 0x07, 0x75, 0x6E, 0x69, 0x45, 0x30, 0x46, 0x30, 0x00, 0x00,
386 0x00, 0x01, 0x00, 0x01, 0xFF, 0xFF, 0x00, 0x0F,
194}}; 387}};
195 388
196} // namespace FileSys::SystemArchive::SharedFontData 389} // namespace FileSys::SystemArchive::SharedFontData
diff --git a/src/core/file_sys/system_archive/data/font_nintendo_extended.h b/src/core/file_sys/system_archive/data/font_nintendo_extended.h
index 2089f3db9..edb9df914 100644
--- a/src/core/file_sys/system_archive/data/font_nintendo_extended.h
+++ b/src/core/file_sys/system_archive/data/font_nintendo_extended.h
@@ -8,6 +8,6 @@
8 8
9namespace FileSys::SystemArchive::SharedFontData { 9namespace FileSys::SystemArchive::SharedFontData {
10 10
11extern const std::array<unsigned char, 2932> FONT_NINTENDO_EXTENDED; 11extern const std::array<unsigned char, 6024> FONT_NINTENDO_EXTENDED;
12 12
13} // namespace FileSys::SystemArchive::SharedFontData 13} // namespace FileSys::SystemArchive::SharedFontData
diff --git a/src/core/file_sys/system_archive/system_version.cpp b/src/core/file_sys/system_archive/system_version.cpp
index aa313de66..7bfbc9a67 100644
--- a/src/core/file_sys/system_archive/system_version.cpp
+++ b/src/core/file_sys/system_archive/system_version.cpp
@@ -12,17 +12,17 @@ namespace SystemVersionData {
12// This section should reflect the best system version to describe yuzu's HLE api. 12// This section should reflect the best system version to describe yuzu's HLE api.
13// TODO(DarkLordZach): Update when HLE gets better. 13// TODO(DarkLordZach): Update when HLE gets better.
14 14
15constexpr u8 VERSION_MAJOR = 10; 15constexpr u8 VERSION_MAJOR = 11;
16constexpr u8 VERSION_MINOR = 0; 16constexpr u8 VERSION_MINOR = 0;
17constexpr u8 VERSION_MICRO = 2; 17constexpr u8 VERSION_MICRO = 0;
18 18
19constexpr u8 REVISION_MAJOR = 1; 19constexpr u8 REVISION_MAJOR = 5;
20constexpr u8 REVISION_MINOR = 0; 20constexpr u8 REVISION_MINOR = 0;
21 21
22constexpr char PLATFORM_STRING[] = "NX"; 22constexpr char PLATFORM_STRING[] = "NX";
23constexpr char VERSION_HASH[] = "f90143fa8bbc061d4f68c35f95f04f8080c0ecdc"; 23constexpr char VERSION_HASH[] = "34197eba8810e2edd5e9dfcfbde7b340882e856d";
24constexpr char DISPLAY_VERSION[] = "10.0.2"; 24constexpr char DISPLAY_VERSION[] = "11.0.0";
25constexpr char DISPLAY_TITLE[] = "NintendoSDK Firmware for NX 10.0.2-1.0"; 25constexpr char DISPLAY_TITLE[] = "NintendoSDK Firmware for NX 11.0.0-5.0";
26 26
27} // namespace SystemVersionData 27} // namespace SystemVersionData
28 28
diff --git a/src/core/file_sys/vfs.cpp b/src/core/file_sys/vfs.cpp
index b2f026b6d..f497e9396 100644
--- a/src/core/file_sys/vfs.cpp
+++ b/src/core/file_sys/vfs.cpp
@@ -203,7 +203,7 @@ std::string VfsFile::GetFullPath() const {
203 return GetContainingDirectory()->GetFullPath() + "/" + GetName(); 203 return GetContainingDirectory()->GetFullPath() + "/" + GetName();
204} 204}
205 205
206std::shared_ptr<VfsFile> VfsDirectory::GetFileRelative(std::string_view path) const { 206VirtualFile VfsDirectory::GetFileRelative(std::string_view path) const {
207 auto vec = Common::FS::SplitPathComponents(path); 207 auto vec = Common::FS::SplitPathComponents(path);
208 vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }), 208 vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }),
209 vec.end()); 209 vec.end());
@@ -231,7 +231,7 @@ std::shared_ptr<VfsFile> VfsDirectory::GetFileRelative(std::string_view path) co
231 return dir->GetFile(vec.back()); 231 return dir->GetFile(vec.back());
232} 232}
233 233
234std::shared_ptr<VfsFile> VfsDirectory::GetFileAbsolute(std::string_view path) const { 234VirtualFile VfsDirectory::GetFileAbsolute(std::string_view path) const {
235 if (IsRoot()) { 235 if (IsRoot()) {
236 return GetFileRelative(path); 236 return GetFileRelative(path);
237 } 237 }
@@ -239,7 +239,7 @@ std::shared_ptr<VfsFile> VfsDirectory::GetFileAbsolute(std::string_view path) co
239 return GetParentDirectory()->GetFileAbsolute(path); 239 return GetParentDirectory()->GetFileAbsolute(path);
240} 240}
241 241
242std::shared_ptr<VfsDirectory> VfsDirectory::GetDirectoryRelative(std::string_view path) const { 242VirtualDir VfsDirectory::GetDirectoryRelative(std::string_view path) const {
243 auto vec = Common::FS::SplitPathComponents(path); 243 auto vec = Common::FS::SplitPathComponents(path);
244 vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }), 244 vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }),
245 vec.end()); 245 vec.end());
@@ -261,7 +261,7 @@ std::shared_ptr<VfsDirectory> VfsDirectory::GetDirectoryRelative(std::string_vie
261 return dir; 261 return dir;
262} 262}
263 263
264std::shared_ptr<VfsDirectory> VfsDirectory::GetDirectoryAbsolute(std::string_view path) const { 264VirtualDir VfsDirectory::GetDirectoryAbsolute(std::string_view path) const {
265 if (IsRoot()) { 265 if (IsRoot()) {
266 return GetDirectoryRelative(path); 266 return GetDirectoryRelative(path);
267 } 267 }
@@ -269,14 +269,14 @@ std::shared_ptr<VfsDirectory> VfsDirectory::GetDirectoryAbsolute(std::string_vie
269 return GetParentDirectory()->GetDirectoryAbsolute(path); 269 return GetParentDirectory()->GetDirectoryAbsolute(path);
270} 270}
271 271
272std::shared_ptr<VfsFile> VfsDirectory::GetFile(std::string_view name) const { 272VirtualFile VfsDirectory::GetFile(std::string_view name) const {
273 const auto& files = GetFiles(); 273 const auto& files = GetFiles();
274 const auto iter = std::find_if(files.begin(), files.end(), 274 const auto iter = std::find_if(files.begin(), files.end(),
275 [&name](const auto& file1) { return name == file1->GetName(); }); 275 [&name](const auto& file1) { return name == file1->GetName(); });
276 return iter == files.end() ? nullptr : *iter; 276 return iter == files.end() ? nullptr : *iter;
277} 277}
278 278
279std::shared_ptr<VfsDirectory> VfsDirectory::GetSubdirectory(std::string_view name) const { 279VirtualDir VfsDirectory::GetSubdirectory(std::string_view name) const {
280 const auto& subs = GetSubdirectories(); 280 const auto& subs = GetSubdirectories();
281 const auto iter = std::find_if(subs.begin(), subs.end(), 281 const auto iter = std::find_if(subs.begin(), subs.end(),
282 [&name](const auto& file1) { return name == file1->GetName(); }); 282 [&name](const auto& file1) { return name == file1->GetName(); });
@@ -301,7 +301,7 @@ std::size_t VfsDirectory::GetSize() const {
301 return file_total + subdir_total; 301 return file_total + subdir_total;
302} 302}
303 303
304std::shared_ptr<VfsFile> VfsDirectory::CreateFileRelative(std::string_view path) { 304VirtualFile VfsDirectory::CreateFileRelative(std::string_view path) {
305 auto vec = Common::FS::SplitPathComponents(path); 305 auto vec = Common::FS::SplitPathComponents(path);
306 vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }), 306 vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }),
307 vec.end()); 307 vec.end());
@@ -324,7 +324,7 @@ std::shared_ptr<VfsFile> VfsDirectory::CreateFileRelative(std::string_view path)
324 return dir->CreateFileRelative(Common::FS::GetPathWithoutTop(path)); 324 return dir->CreateFileRelative(Common::FS::GetPathWithoutTop(path));
325} 325}
326 326
327std::shared_ptr<VfsFile> VfsDirectory::CreateFileAbsolute(std::string_view path) { 327VirtualFile VfsDirectory::CreateFileAbsolute(std::string_view path) {
328 if (IsRoot()) { 328 if (IsRoot()) {
329 return CreateFileRelative(path); 329 return CreateFileRelative(path);
330 } 330 }
@@ -332,7 +332,7 @@ std::shared_ptr<VfsFile> VfsDirectory::CreateFileAbsolute(std::string_view path)
332 return GetParentDirectory()->CreateFileAbsolute(path); 332 return GetParentDirectory()->CreateFileAbsolute(path);
333} 333}
334 334
335std::shared_ptr<VfsDirectory> VfsDirectory::CreateDirectoryRelative(std::string_view path) { 335VirtualDir VfsDirectory::CreateDirectoryRelative(std::string_view path) {
336 auto vec = Common::FS::SplitPathComponents(path); 336 auto vec = Common::FS::SplitPathComponents(path);
337 vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }), 337 vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }),
338 vec.end()); 338 vec.end());
@@ -355,7 +355,7 @@ std::shared_ptr<VfsDirectory> VfsDirectory::CreateDirectoryRelative(std::string_
355 return dir->CreateDirectoryRelative(Common::FS::GetPathWithoutTop(path)); 355 return dir->CreateDirectoryRelative(Common::FS::GetPathWithoutTop(path));
356} 356}
357 357
358std::shared_ptr<VfsDirectory> VfsDirectory::CreateDirectoryAbsolute(std::string_view path) { 358VirtualDir VfsDirectory::CreateDirectoryAbsolute(std::string_view path) {
359 if (IsRoot()) { 359 if (IsRoot()) {
360 return CreateDirectoryRelative(path); 360 return CreateDirectoryRelative(path);
361 } 361 }
@@ -446,27 +446,27 @@ bool ReadOnlyVfsDirectory::IsReadable() const {
446 return true; 446 return true;
447} 447}
448 448
449std::shared_ptr<VfsDirectory> ReadOnlyVfsDirectory::CreateSubdirectory(std::string_view name) { 449VirtualDir ReadOnlyVfsDirectory::CreateSubdirectory(std::string_view name) {
450 return nullptr; 450 return nullptr;
451} 451}
452 452
453std::shared_ptr<VfsFile> ReadOnlyVfsDirectory::CreateFile(std::string_view name) { 453VirtualFile ReadOnlyVfsDirectory::CreateFile(std::string_view name) {
454 return nullptr; 454 return nullptr;
455} 455}
456 456
457std::shared_ptr<VfsFile> ReadOnlyVfsDirectory::CreateFileAbsolute(std::string_view path) { 457VirtualFile ReadOnlyVfsDirectory::CreateFileAbsolute(std::string_view path) {
458 return nullptr; 458 return nullptr;
459} 459}
460 460
461std::shared_ptr<VfsFile> ReadOnlyVfsDirectory::CreateFileRelative(std::string_view path) { 461VirtualFile ReadOnlyVfsDirectory::CreateFileRelative(std::string_view path) {
462 return nullptr; 462 return nullptr;
463} 463}
464 464
465std::shared_ptr<VfsDirectory> ReadOnlyVfsDirectory::CreateDirectoryAbsolute(std::string_view path) { 465VirtualDir ReadOnlyVfsDirectory::CreateDirectoryAbsolute(std::string_view path) {
466 return nullptr; 466 return nullptr;
467} 467}
468 468
469std::shared_ptr<VfsDirectory> ReadOnlyVfsDirectory::CreateDirectoryRelative(std::string_view path) { 469VirtualDir ReadOnlyVfsDirectory::CreateDirectoryRelative(std::string_view path) {
470 return nullptr; 470 return nullptr;
471} 471}
472 472
diff --git a/src/core/file_sys/vfs.h b/src/core/file_sys/vfs.h
index 954094772..afd64e95c 100644
--- a/src/core/file_sys/vfs.h
+++ b/src/core/file_sys/vfs.h
@@ -91,7 +91,7 @@ public:
91 // Resizes the file to new_size. Returns whether or not the operation was successful. 91 // Resizes the file to new_size. Returns whether or not the operation was successful.
92 virtual bool Resize(std::size_t new_size) = 0; 92 virtual bool Resize(std::size_t new_size) = 0;
93 // Gets a pointer to the directory containing this file, returning nullptr if there is none. 93 // Gets a pointer to the directory containing this file, returning nullptr if there is none.
94 virtual std::shared_ptr<VfsDirectory> GetContainingDirectory() const = 0; 94 virtual VirtualDir GetContainingDirectory() const = 0;
95 95
96 // Returns whether or not the file can be written to. 96 // Returns whether or not the file can be written to.
97 virtual bool IsWritable() const = 0; 97 virtual bool IsWritable() const = 0;
@@ -183,27 +183,27 @@ public:
183 183
184 // Retrives the file located at path as if the current directory was root. Returns nullptr if 184 // Retrives the file located at path as if the current directory was root. Returns nullptr if
185 // not found. 185 // not found.
186 virtual std::shared_ptr<VfsFile> GetFileRelative(std::string_view path) const; 186 virtual VirtualFile GetFileRelative(std::string_view path) const;
187 // Calls GetFileRelative(path) on the root of the current directory. 187 // Calls GetFileRelative(path) on the root of the current directory.
188 virtual std::shared_ptr<VfsFile> GetFileAbsolute(std::string_view path) const; 188 virtual VirtualFile GetFileAbsolute(std::string_view path) const;
189 189
190 // Retrives the directory located at path as if the current directory was root. Returns nullptr 190 // Retrives the directory located at path as if the current directory was root. Returns nullptr
191 // if not found. 191 // if not found.
192 virtual std::shared_ptr<VfsDirectory> GetDirectoryRelative(std::string_view path) const; 192 virtual VirtualDir GetDirectoryRelative(std::string_view path) const;
193 // Calls GetDirectoryRelative(path) on the root of the current directory. 193 // Calls GetDirectoryRelative(path) on the root of the current directory.
194 virtual std::shared_ptr<VfsDirectory> GetDirectoryAbsolute(std::string_view path) const; 194 virtual VirtualDir GetDirectoryAbsolute(std::string_view path) const;
195 195
196 // Returns a vector containing all of the files in this directory. 196 // Returns a vector containing all of the files in this directory.
197 virtual std::vector<std::shared_ptr<VfsFile>> GetFiles() const = 0; 197 virtual std::vector<VirtualFile> GetFiles() const = 0;
198 // Returns the file with filename matching name. Returns nullptr if directory dosen't have a 198 // Returns the file with filename matching name. Returns nullptr if directory dosen't have a
199 // file with name. 199 // file with name.
200 virtual std::shared_ptr<VfsFile> GetFile(std::string_view name) const; 200 virtual VirtualFile GetFile(std::string_view name) const;
201 201
202 // Returns a vector containing all of the subdirectories in this directory. 202 // Returns a vector containing all of the subdirectories in this directory.
203 virtual std::vector<std::shared_ptr<VfsDirectory>> GetSubdirectories() const = 0; 203 virtual std::vector<VirtualDir> GetSubdirectories() const = 0;
204 // Returns the directory with name matching name. Returns nullptr if directory dosen't have a 204 // Returns the directory with name matching name. Returns nullptr if directory dosen't have a
205 // directory with name. 205 // directory with name.
206 virtual std::shared_ptr<VfsDirectory> GetSubdirectory(std::string_view name) const; 206 virtual VirtualDir GetSubdirectory(std::string_view name) const;
207 207
208 // Returns whether or not the directory can be written to. 208 // Returns whether or not the directory can be written to.
209 virtual bool IsWritable() const = 0; 209 virtual bool IsWritable() const = 0;
@@ -219,31 +219,31 @@ public:
219 virtual std::size_t GetSize() const; 219 virtual std::size_t GetSize() const;
220 // Returns the parent directory of this directory. Returns nullptr if this directory is root or 220 // Returns the parent directory of this directory. Returns nullptr if this directory is root or
221 // has no parent. 221 // has no parent.
222 virtual std::shared_ptr<VfsDirectory> GetParentDirectory() const = 0; 222 virtual VirtualDir GetParentDirectory() const = 0;
223 223
224 // Creates a new subdirectory with name name. Returns a pointer to the new directory or nullptr 224 // Creates a new subdirectory with name name. Returns a pointer to the new directory or nullptr
225 // if the operation failed. 225 // if the operation failed.
226 virtual std::shared_ptr<VfsDirectory> CreateSubdirectory(std::string_view name) = 0; 226 virtual VirtualDir CreateSubdirectory(std::string_view name) = 0;
227 // Creates a new file with name name. Returns a pointer to the new file or nullptr if the 227 // Creates a new file with name name. Returns a pointer to the new file or nullptr if the
228 // operation failed. 228 // operation failed.
229 virtual std::shared_ptr<VfsFile> CreateFile(std::string_view name) = 0; 229 virtual VirtualFile CreateFile(std::string_view name) = 0;
230 230
231 // Creates a new file at the path relative to this directory. Also creates directories if 231 // Creates a new file at the path relative to this directory. Also creates directories if
232 // they do not exist and is supported by this implementation. Returns nullptr on any failure. 232 // they do not exist and is supported by this implementation. Returns nullptr on any failure.
233 virtual std::shared_ptr<VfsFile> CreateFileRelative(std::string_view path); 233 virtual VirtualFile CreateFileRelative(std::string_view path);
234 234
235 // Creates a new file at the path relative to root of this directory. Also creates directories 235 // Creates a new file at the path relative to root of this directory. Also creates directories
236 // if they do not exist and is supported by this implementation. Returns nullptr on any failure. 236 // if they do not exist and is supported by this implementation. Returns nullptr on any failure.
237 virtual std::shared_ptr<VfsFile> CreateFileAbsolute(std::string_view path); 237 virtual VirtualFile CreateFileAbsolute(std::string_view path);
238 238
239 // Creates a new directory at the path relative to this directory. Also creates directories if 239 // Creates a new directory at the path relative to this directory. Also creates directories if
240 // they do not exist and is supported by this implementation. Returns nullptr on any failure. 240 // they do not exist and is supported by this implementation. Returns nullptr on any failure.
241 virtual std::shared_ptr<VfsDirectory> CreateDirectoryRelative(std::string_view path); 241 virtual VirtualDir CreateDirectoryRelative(std::string_view path);
242 242
243 // Creates a new directory at the path relative to root of this directory. Also creates 243 // Creates a new directory at the path relative to root of this directory. Also creates
244 // directories if they do not exist and is supported by this implementation. Returns nullptr on 244 // directories if they do not exist and is supported by this implementation. Returns nullptr on
245 // any failure. 245 // any failure.
246 virtual std::shared_ptr<VfsDirectory> CreateDirectoryAbsolute(std::string_view path); 246 virtual VirtualDir CreateDirectoryAbsolute(std::string_view path);
247 247
248 // Deletes the subdirectory with the given name and returns true on success. 248 // Deletes the subdirectory with the given name and returns true on success.
249 virtual bool DeleteSubdirectory(std::string_view name) = 0; 249 virtual bool DeleteSubdirectory(std::string_view name) = 0;
@@ -280,12 +280,12 @@ class ReadOnlyVfsDirectory : public VfsDirectory {
280public: 280public:
281 bool IsWritable() const override; 281 bool IsWritable() const override;
282 bool IsReadable() const override; 282 bool IsReadable() const override;
283 std::shared_ptr<VfsDirectory> CreateSubdirectory(std::string_view name) override; 283 VirtualDir CreateSubdirectory(std::string_view name) override;
284 std::shared_ptr<VfsFile> CreateFile(std::string_view name) override; 284 VirtualFile CreateFile(std::string_view name) override;
285 std::shared_ptr<VfsFile> CreateFileAbsolute(std::string_view path) override; 285 VirtualFile CreateFileAbsolute(std::string_view path) override;
286 std::shared_ptr<VfsFile> CreateFileRelative(std::string_view path) override; 286 VirtualFile CreateFileRelative(std::string_view path) override;
287 std::shared_ptr<VfsDirectory> CreateDirectoryAbsolute(std::string_view path) override; 287 VirtualDir CreateDirectoryAbsolute(std::string_view path) override;
288 std::shared_ptr<VfsDirectory> CreateDirectoryRelative(std::string_view path) override; 288 VirtualDir CreateDirectoryRelative(std::string_view path) override;
289 bool DeleteSubdirectory(std::string_view name) override; 289 bool DeleteSubdirectory(std::string_view name) override;
290 bool DeleteSubdirectoryRecursive(std::string_view name) override; 290 bool DeleteSubdirectoryRecursive(std::string_view name) override;
291 bool CleanSubdirectoryRecursive(std::string_view name) override; 291 bool CleanSubdirectoryRecursive(std::string_view name) override;
diff --git a/src/core/file_sys/vfs_concat.cpp b/src/core/file_sys/vfs_concat.cpp
index e0ff70174..3c5a7d87a 100644
--- a/src/core/file_sys/vfs_concat.cpp
+++ b/src/core/file_sys/vfs_concat.cpp
@@ -46,7 +46,7 @@ VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(std::vector<VirtualFile> f
46 if (files.size() == 1) 46 if (files.size() == 1)
47 return files[0]; 47 return files[0];
48 48
49 return std::shared_ptr<VfsFile>(new ConcatenatedVfsFile(std::move(files), std::move(name))); 49 return VirtualFile(new ConcatenatedVfsFile(std::move(files), std::move(name)));
50} 50}
51 51
52VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(u8 filler_byte, 52VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(u8 filler_byte,
@@ -71,20 +71,23 @@ VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(u8 filler_byte,
71 if (files.begin()->first != 0) 71 if (files.begin()->first != 0)
72 files.emplace(0, std::make_shared<StaticVfsFile>(filler_byte, files.begin()->first)); 72 files.emplace(0, std::make_shared<StaticVfsFile>(filler_byte, files.begin()->first));
73 73
74 return std::shared_ptr<VfsFile>(new ConcatenatedVfsFile(std::move(files), std::move(name))); 74 return VirtualFile(new ConcatenatedVfsFile(std::move(files), std::move(name)));
75} 75}
76 76
77std::string ConcatenatedVfsFile::GetName() const { 77std::string ConcatenatedVfsFile::GetName() const {
78 if (files.empty()) 78 if (files.empty()) {
79 return ""; 79 return "";
80 if (!name.empty()) 80 }
81 if (!name.empty()) {
81 return name; 82 return name;
83 }
82 return files.begin()->second->GetName(); 84 return files.begin()->second->GetName();
83} 85}
84 86
85std::size_t ConcatenatedVfsFile::GetSize() const { 87std::size_t ConcatenatedVfsFile::GetSize() const {
86 if (files.empty()) 88 if (files.empty()) {
87 return 0; 89 return 0;
90 }
88 return files.rbegin()->first + files.rbegin()->second->GetSize(); 91 return files.rbegin()->first + files.rbegin()->second->GetSize();
89} 92}
90 93
@@ -92,9 +95,10 @@ bool ConcatenatedVfsFile::Resize(std::size_t new_size) {
92 return false; 95 return false;
93} 96}
94 97
95std::shared_ptr<VfsDirectory> ConcatenatedVfsFile::GetContainingDirectory() const { 98VirtualDir ConcatenatedVfsFile::GetContainingDirectory() const {
96 if (files.empty()) 99 if (files.empty()) {
97 return nullptr; 100 return nullptr;
101 }
98 return files.begin()->second->GetContainingDirectory(); 102 return files.begin()->second->GetContainingDirectory();
99} 103}
100 104
diff --git a/src/core/file_sys/vfs_concat.h b/src/core/file_sys/vfs_concat.h
index 7a26343c0..287c72555 100644
--- a/src/core/file_sys/vfs_concat.h
+++ b/src/core/file_sys/vfs_concat.h
@@ -31,7 +31,7 @@ public:
31 std::string GetName() const override; 31 std::string GetName() const override;
32 std::size_t GetSize() const override; 32 std::size_t GetSize() const override;
33 bool Resize(std::size_t new_size) override; 33 bool Resize(std::size_t new_size) override;
34 std::shared_ptr<VfsDirectory> GetContainingDirectory() const override; 34 VirtualDir GetContainingDirectory() const override;
35 bool IsWritable() const override; 35 bool IsWritable() const override;
36 bool IsReadable() const override; 36 bool IsReadable() const override;
37 std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override; 37 std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override;
diff --git a/src/core/file_sys/vfs_layered.cpp b/src/core/file_sys/vfs_layered.cpp
index 338e398da..434b03cec 100644
--- a/src/core/file_sys/vfs_layered.cpp
+++ b/src/core/file_sys/vfs_layered.cpp
@@ -20,10 +20,10 @@ VirtualDir LayeredVfsDirectory::MakeLayeredDirectory(std::vector<VirtualDir> dir
20 if (dirs.size() == 1) 20 if (dirs.size() == 1)
21 return dirs[0]; 21 return dirs[0];
22 22
23 return std::shared_ptr<VfsDirectory>(new LayeredVfsDirectory(std::move(dirs), std::move(name))); 23 return VirtualDir(new LayeredVfsDirectory(std::move(dirs), std::move(name)));
24} 24}
25 25
26std::shared_ptr<VfsFile> LayeredVfsDirectory::GetFileRelative(std::string_view path) const { 26VirtualFile LayeredVfsDirectory::GetFileRelative(std::string_view path) const {
27 for (const auto& layer : dirs) { 27 for (const auto& layer : dirs) {
28 const auto file = layer->GetFileRelative(path); 28 const auto file = layer->GetFileRelative(path);
29 if (file != nullptr) 29 if (file != nullptr)
@@ -33,23 +33,23 @@ std::shared_ptr<VfsFile> LayeredVfsDirectory::GetFileRelative(std::string_view p
33 return nullptr; 33 return nullptr;
34} 34}
35 35
36std::shared_ptr<VfsDirectory> LayeredVfsDirectory::GetDirectoryRelative( 36VirtualDir LayeredVfsDirectory::GetDirectoryRelative(std::string_view path) const {
37 std::string_view path) const {
38 std::vector<VirtualDir> out; 37 std::vector<VirtualDir> out;
39 for (const auto& layer : dirs) { 38 for (const auto& layer : dirs) {
40 auto dir = layer->GetDirectoryRelative(path); 39 auto dir = layer->GetDirectoryRelative(path);
41 if (dir != nullptr) 40 if (dir != nullptr) {
42 out.push_back(std::move(dir)); 41 out.push_back(std::move(dir));
42 }
43 } 43 }
44 44
45 return MakeLayeredDirectory(std::move(out)); 45 return MakeLayeredDirectory(std::move(out));
46} 46}
47 47
48std::shared_ptr<VfsFile> LayeredVfsDirectory::GetFile(std::string_view name) const { 48VirtualFile LayeredVfsDirectory::GetFile(std::string_view name) const {
49 return GetFileRelative(name); 49 return GetFileRelative(name);
50} 50}
51 51
52std::shared_ptr<VfsDirectory> LayeredVfsDirectory::GetSubdirectory(std::string_view name) const { 52VirtualDir LayeredVfsDirectory::GetSubdirectory(std::string_view name) const {
53 return GetDirectoryRelative(name); 53 return GetDirectoryRelative(name);
54} 54}
55 55
@@ -57,7 +57,7 @@ std::string LayeredVfsDirectory::GetFullPath() const {
57 return dirs[0]->GetFullPath(); 57 return dirs[0]->GetFullPath();
58} 58}
59 59
60std::vector<std::shared_ptr<VfsFile>> LayeredVfsDirectory::GetFiles() const { 60std::vector<VirtualFile> LayeredVfsDirectory::GetFiles() const {
61 std::vector<VirtualFile> out; 61 std::vector<VirtualFile> out;
62 for (const auto& layer : dirs) { 62 for (const auto& layer : dirs) {
63 for (const auto& file : layer->GetFiles()) { 63 for (const auto& file : layer->GetFiles()) {
@@ -72,7 +72,7 @@ std::vector<std::shared_ptr<VfsFile>> LayeredVfsDirectory::GetFiles() const {
72 return out; 72 return out;
73} 73}
74 74
75std::vector<std::shared_ptr<VfsDirectory>> LayeredVfsDirectory::GetSubdirectories() const { 75std::vector<VirtualDir> LayeredVfsDirectory::GetSubdirectories() const {
76 std::vector<std::string> names; 76 std::vector<std::string> names;
77 for (const auto& layer : dirs) { 77 for (const auto& layer : dirs) {
78 for (const auto& sd : layer->GetSubdirectories()) { 78 for (const auto& sd : layer->GetSubdirectories()) {
@@ -101,15 +101,15 @@ std::string LayeredVfsDirectory::GetName() const {
101 return name.empty() ? dirs[0]->GetName() : name; 101 return name.empty() ? dirs[0]->GetName() : name;
102} 102}
103 103
104std::shared_ptr<VfsDirectory> LayeredVfsDirectory::GetParentDirectory() const { 104VirtualDir LayeredVfsDirectory::GetParentDirectory() const {
105 return dirs[0]->GetParentDirectory(); 105 return dirs[0]->GetParentDirectory();
106} 106}
107 107
108std::shared_ptr<VfsDirectory> LayeredVfsDirectory::CreateSubdirectory(std::string_view name) { 108VirtualDir LayeredVfsDirectory::CreateSubdirectory(std::string_view name) {
109 return nullptr; 109 return nullptr;
110} 110}
111 111
112std::shared_ptr<VfsFile> LayeredVfsDirectory::CreateFile(std::string_view name) { 112VirtualFile LayeredVfsDirectory::CreateFile(std::string_view name) {
113 return nullptr; 113 return nullptr;
114} 114}
115 115
diff --git a/src/core/file_sys/vfs_layered.h b/src/core/file_sys/vfs_layered.h
index 8a25c3428..6d7513ac6 100644
--- a/src/core/file_sys/vfs_layered.h
+++ b/src/core/file_sys/vfs_layered.h
@@ -21,20 +21,20 @@ public:
21 /// Wrapper function to allow for more efficient handling of dirs.size() == 0, 1 cases. 21 /// Wrapper function to allow for more efficient handling of dirs.size() == 0, 1 cases.
22 static VirtualDir MakeLayeredDirectory(std::vector<VirtualDir> dirs, std::string name = ""); 22 static VirtualDir MakeLayeredDirectory(std::vector<VirtualDir> dirs, std::string name = "");
23 23
24 std::shared_ptr<VfsFile> GetFileRelative(std::string_view path) const override; 24 VirtualFile GetFileRelative(std::string_view path) const override;
25 std::shared_ptr<VfsDirectory> GetDirectoryRelative(std::string_view path) const override; 25 VirtualDir GetDirectoryRelative(std::string_view path) const override;
26 std::shared_ptr<VfsFile> GetFile(std::string_view name) const override; 26 VirtualFile GetFile(std::string_view name) const override;
27 std::shared_ptr<VfsDirectory> GetSubdirectory(std::string_view name) const override; 27 VirtualDir GetSubdirectory(std::string_view name) const override;
28 std::string GetFullPath() const override; 28 std::string GetFullPath() const override;
29 29
30 std::vector<std::shared_ptr<VfsFile>> GetFiles() const override; 30 std::vector<VirtualFile> GetFiles() const override;
31 std::vector<std::shared_ptr<VfsDirectory>> GetSubdirectories() const override; 31 std::vector<VirtualDir> GetSubdirectories() const override;
32 bool IsWritable() const override; 32 bool IsWritable() const override;
33 bool IsReadable() const override; 33 bool IsReadable() const override;
34 std::string GetName() const override; 34 std::string GetName() const override;
35 std::shared_ptr<VfsDirectory> GetParentDirectory() const override; 35 VirtualDir GetParentDirectory() const override;
36 std::shared_ptr<VfsDirectory> CreateSubdirectory(std::string_view name) override; 36 VirtualDir CreateSubdirectory(std::string_view name) override;
37 std::shared_ptr<VfsFile> CreateFile(std::string_view name) override; 37 VirtualFile CreateFile(std::string_view name) override;
38 bool DeleteSubdirectory(std::string_view name) override; 38 bool DeleteSubdirectory(std::string_view name) override;
39 bool DeleteFile(std::string_view name) override; 39 bool DeleteFile(std::string_view name) override;
40 bool Rename(std::string_view name) override; 40 bool Rename(std::string_view name) override;
diff --git a/src/core/file_sys/vfs_offset.cpp b/src/core/file_sys/vfs_offset.cpp
index 7714d3de5..056737b54 100644
--- a/src/core/file_sys/vfs_offset.cpp
+++ b/src/core/file_sys/vfs_offset.cpp
@@ -9,7 +9,7 @@
9 9
10namespace FileSys { 10namespace FileSys {
11 11
12OffsetVfsFile::OffsetVfsFile(std::shared_ptr<VfsFile> file_, std::size_t size_, std::size_t offset_, 12OffsetVfsFile::OffsetVfsFile(VirtualFile file_, std::size_t size_, std::size_t offset_,
13 std::string name_, VirtualDir parent_) 13 std::string name_, VirtualDir parent_)
14 : file(file_), offset(offset_), size(size_), name(std::move(name_)), 14 : file(file_), offset(offset_), size(size_), name(std::move(name_)),
15 parent(parent_ == nullptr ? file->GetContainingDirectory() : std::move(parent_)) {} 15 parent(parent_ == nullptr ? file->GetContainingDirectory() : std::move(parent_)) {}
@@ -37,7 +37,7 @@ bool OffsetVfsFile::Resize(std::size_t new_size) {
37 return true; 37 return true;
38} 38}
39 39
40std::shared_ptr<VfsDirectory> OffsetVfsFile::GetContainingDirectory() const { 40VirtualDir OffsetVfsFile::GetContainingDirectory() const {
41 return parent; 41 return parent;
42} 42}
43 43
diff --git a/src/core/file_sys/vfs_offset.h b/src/core/file_sys/vfs_offset.h
index f7b7a3256..b2ccc5c7b 100644
--- a/src/core/file_sys/vfs_offset.h
+++ b/src/core/file_sys/vfs_offset.h
@@ -17,14 +17,14 @@ namespace FileSys {
17// the size of this wrapper. 17// the size of this wrapper.
18class OffsetVfsFile : public VfsFile { 18class OffsetVfsFile : public VfsFile {
19public: 19public:
20 OffsetVfsFile(std::shared_ptr<VfsFile> file, std::size_t size, std::size_t offset = 0, 20 OffsetVfsFile(VirtualFile file, std::size_t size, std::size_t offset = 0,
21 std::string new_name = "", VirtualDir new_parent = nullptr); 21 std::string new_name = "", VirtualDir new_parent = nullptr);
22 ~OffsetVfsFile() override; 22 ~OffsetVfsFile() override;
23 23
24 std::string GetName() const override; 24 std::string GetName() const override;
25 std::size_t GetSize() const override; 25 std::size_t GetSize() const override;
26 bool Resize(std::size_t new_size) override; 26 bool Resize(std::size_t new_size) override;
27 std::shared_ptr<VfsDirectory> GetContainingDirectory() const override; 27 VirtualDir GetContainingDirectory() const override;
28 bool IsWritable() const override; 28 bool IsWritable() const override;
29 bool IsReadable() const override; 29 bool IsReadable() const override;
30 std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override; 30 std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override;
@@ -42,7 +42,7 @@ public:
42private: 42private:
43 std::size_t TrimToFit(std::size_t r_size, std::size_t r_offset) const; 43 std::size_t TrimToFit(std::size_t r_size, std::size_t r_offset) const;
44 44
45 std::shared_ptr<VfsFile> file; 45 VirtualFile file;
46 std::size_t offset; 46 std::size_t offset;
47 std::size_t size; 47 std::size_t size;
48 std::string name; 48 std::string name;
diff --git a/src/core/file_sys/vfs_real.cpp b/src/core/file_sys/vfs_real.cpp
index 488687ba9..a287eebe3 100644
--- a/src/core/file_sys/vfs_real.cpp
+++ b/src/core/file_sys/vfs_real.cpp
@@ -263,7 +263,7 @@ bool RealVfsFile::Resize(std::size_t new_size) {
263 return backing->Resize(new_size); 263 return backing->Resize(new_size);
264} 264}
265 265
266std::shared_ptr<VfsDirectory> RealVfsFile::GetContainingDirectory() const { 266VirtualDir RealVfsFile::GetContainingDirectory() const {
267 return base.OpenDirectory(parent_path, perms); 267 return base.OpenDirectory(parent_path, perms);
268} 268}
269 269
@@ -352,7 +352,7 @@ RealVfsDirectory::RealVfsDirectory(RealVfsFilesystem& base_, const std::string&
352 352
353RealVfsDirectory::~RealVfsDirectory() = default; 353RealVfsDirectory::~RealVfsDirectory() = default;
354 354
355std::shared_ptr<VfsFile> RealVfsDirectory::GetFileRelative(std::string_view path) const { 355VirtualFile RealVfsDirectory::GetFileRelative(std::string_view path) const {
356 const auto full_path = FS::SanitizePath(this->path + DIR_SEP + std::string(path)); 356 const auto full_path = FS::SanitizePath(this->path + DIR_SEP + std::string(path));
357 if (!FS::Exists(full_path) || FS::IsDirectory(full_path)) { 357 if (!FS::Exists(full_path) || FS::IsDirectory(full_path)) {
358 return nullptr; 358 return nullptr;
@@ -360,7 +360,7 @@ std::shared_ptr<VfsFile> RealVfsDirectory::GetFileRelative(std::string_view path
360 return base.OpenFile(full_path, perms); 360 return base.OpenFile(full_path, perms);
361} 361}
362 362
363std::shared_ptr<VfsDirectory> RealVfsDirectory::GetDirectoryRelative(std::string_view path) const { 363VirtualDir RealVfsDirectory::GetDirectoryRelative(std::string_view path) const {
364 const auto full_path = FS::SanitizePath(this->path + DIR_SEP + std::string(path)); 364 const auto full_path = FS::SanitizePath(this->path + DIR_SEP + std::string(path));
365 if (!FS::Exists(full_path) || !FS::IsDirectory(full_path)) { 365 if (!FS::Exists(full_path) || !FS::IsDirectory(full_path)) {
366 return nullptr; 366 return nullptr;
@@ -368,20 +368,20 @@ std::shared_ptr<VfsDirectory> RealVfsDirectory::GetDirectoryRelative(std::string
368 return base.OpenDirectory(full_path, perms); 368 return base.OpenDirectory(full_path, perms);
369} 369}
370 370
371std::shared_ptr<VfsFile> RealVfsDirectory::GetFile(std::string_view name) const { 371VirtualFile RealVfsDirectory::GetFile(std::string_view name) const {
372 return GetFileRelative(name); 372 return GetFileRelative(name);
373} 373}
374 374
375std::shared_ptr<VfsDirectory> RealVfsDirectory::GetSubdirectory(std::string_view name) const { 375VirtualDir RealVfsDirectory::GetSubdirectory(std::string_view name) const {
376 return GetDirectoryRelative(name); 376 return GetDirectoryRelative(name);
377} 377}
378 378
379std::shared_ptr<VfsFile> RealVfsDirectory::CreateFileRelative(std::string_view path) { 379VirtualFile RealVfsDirectory::CreateFileRelative(std::string_view path) {
380 const auto full_path = FS::SanitizePath(this->path + DIR_SEP + std::string(path)); 380 const auto full_path = FS::SanitizePath(this->path + DIR_SEP + std::string(path));
381 return base.CreateFile(full_path, perms); 381 return base.CreateFile(full_path, perms);
382} 382}
383 383
384std::shared_ptr<VfsDirectory> RealVfsDirectory::CreateDirectoryRelative(std::string_view path) { 384VirtualDir RealVfsDirectory::CreateDirectoryRelative(std::string_view path) {
385 const auto full_path = FS::SanitizePath(this->path + DIR_SEP + std::string(path)); 385 const auto full_path = FS::SanitizePath(this->path + DIR_SEP + std::string(path));
386 return base.CreateDirectory(full_path, perms); 386 return base.CreateDirectory(full_path, perms);
387} 387}
@@ -391,11 +391,11 @@ bool RealVfsDirectory::DeleteSubdirectoryRecursive(std::string_view name) {
391 return base.DeleteDirectory(full_path); 391 return base.DeleteDirectory(full_path);
392} 392}
393 393
394std::vector<std::shared_ptr<VfsFile>> RealVfsDirectory::GetFiles() const { 394std::vector<VirtualFile> RealVfsDirectory::GetFiles() const {
395 return IterateEntries<RealVfsFile, VfsFile>(); 395 return IterateEntries<RealVfsFile, VfsFile>();
396} 396}
397 397
398std::vector<std::shared_ptr<VfsDirectory>> RealVfsDirectory::GetSubdirectories() const { 398std::vector<VirtualDir> RealVfsDirectory::GetSubdirectories() const {
399 return IterateEntries<RealVfsDirectory, VfsDirectory>(); 399 return IterateEntries<RealVfsDirectory, VfsDirectory>();
400} 400}
401 401
@@ -411,7 +411,7 @@ std::string RealVfsDirectory::GetName() const {
411 return path_components.back(); 411 return path_components.back();
412} 412}
413 413
414std::shared_ptr<VfsDirectory> RealVfsDirectory::GetParentDirectory() const { 414VirtualDir RealVfsDirectory::GetParentDirectory() const {
415 if (path_components.size() <= 1) { 415 if (path_components.size() <= 1) {
416 return nullptr; 416 return nullptr;
417 } 417 }
@@ -419,12 +419,12 @@ std::shared_ptr<VfsDirectory> RealVfsDirectory::GetParentDirectory() const {
419 return base.OpenDirectory(parent_path, perms); 419 return base.OpenDirectory(parent_path, perms);
420} 420}
421 421
422std::shared_ptr<VfsDirectory> RealVfsDirectory::CreateSubdirectory(std::string_view name) { 422VirtualDir RealVfsDirectory::CreateSubdirectory(std::string_view name) {
423 const std::string subdir_path = (path + DIR_SEP).append(name); 423 const std::string subdir_path = (path + DIR_SEP).append(name);
424 return base.CreateDirectory(subdir_path, perms); 424 return base.CreateDirectory(subdir_path, perms);
425} 425}
426 426
427std::shared_ptr<VfsFile> RealVfsDirectory::CreateFile(std::string_view name) { 427VirtualFile RealVfsDirectory::CreateFile(std::string_view name) {
428 const std::string file_path = (path + DIR_SEP).append(name); 428 const std::string file_path = (path + DIR_SEP).append(name);
429 return base.CreateFile(file_path, perms); 429 return base.CreateFile(file_path, perms);
430} 430}
diff --git a/src/core/file_sys/vfs_real.h b/src/core/file_sys/vfs_real.h
index 0b537b22c..23e99865e 100644
--- a/src/core/file_sys/vfs_real.h
+++ b/src/core/file_sys/vfs_real.h
@@ -50,7 +50,7 @@ public:
50 std::string GetName() const override; 50 std::string GetName() const override;
51 std::size_t GetSize() const override; 51 std::size_t GetSize() const override;
52 bool Resize(std::size_t new_size) override; 52 bool Resize(std::size_t new_size) override;
53 std::shared_ptr<VfsDirectory> GetContainingDirectory() const override; 53 VirtualDir GetContainingDirectory() const override;
54 bool IsWritable() const override; 54 bool IsWritable() const override;
55 bool IsReadable() const override; 55 bool IsReadable() const override;
56 std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override; 56 std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override;
@@ -79,21 +79,21 @@ class RealVfsDirectory : public VfsDirectory {
79public: 79public:
80 ~RealVfsDirectory() override; 80 ~RealVfsDirectory() override;
81 81
82 std::shared_ptr<VfsFile> GetFileRelative(std::string_view path) const override; 82 VirtualFile GetFileRelative(std::string_view path) const override;
83 std::shared_ptr<VfsDirectory> GetDirectoryRelative(std::string_view path) const override; 83 VirtualDir GetDirectoryRelative(std::string_view path) const override;
84 std::shared_ptr<VfsFile> GetFile(std::string_view name) const override; 84 VirtualFile GetFile(std::string_view name) const override;
85 std::shared_ptr<VfsDirectory> GetSubdirectory(std::string_view name) const override; 85 VirtualDir GetSubdirectory(std::string_view name) const override;
86 std::shared_ptr<VfsFile> CreateFileRelative(std::string_view path) override; 86 VirtualFile CreateFileRelative(std::string_view path) override;
87 std::shared_ptr<VfsDirectory> CreateDirectoryRelative(std::string_view path) override; 87 VirtualDir CreateDirectoryRelative(std::string_view path) override;
88 bool DeleteSubdirectoryRecursive(std::string_view name) override; 88 bool DeleteSubdirectoryRecursive(std::string_view name) override;
89 std::vector<std::shared_ptr<VfsFile>> GetFiles() const override; 89 std::vector<VirtualFile> GetFiles() const override;
90 std::vector<std::shared_ptr<VfsDirectory>> GetSubdirectories() const override; 90 std::vector<VirtualDir> GetSubdirectories() const override;
91 bool IsWritable() const override; 91 bool IsWritable() const override;
92 bool IsReadable() const override; 92 bool IsReadable() const override;
93 std::string GetName() const override; 93 std::string GetName() const override;
94 std::shared_ptr<VfsDirectory> GetParentDirectory() const override; 94 VirtualDir GetParentDirectory() const override;
95 std::shared_ptr<VfsDirectory> CreateSubdirectory(std::string_view name) override; 95 VirtualDir CreateSubdirectory(std::string_view name) override;
96 std::shared_ptr<VfsFile> CreateFile(std::string_view name) override; 96 VirtualFile CreateFile(std::string_view name) override;
97 bool DeleteSubdirectory(std::string_view name) override; 97 bool DeleteSubdirectory(std::string_view name) override;
98 bool DeleteFile(std::string_view name) override; 98 bool DeleteFile(std::string_view name) override;
99 bool Rename(std::string_view name) override; 99 bool Rename(std::string_view name) override;
diff --git a/src/core/file_sys/vfs_static.h b/src/core/file_sys/vfs_static.h
index 8b27c30fa..c840b24b9 100644
--- a/src/core/file_sys/vfs_static.h
+++ b/src/core/file_sys/vfs_static.h
@@ -31,7 +31,7 @@ public:
31 return true; 31 return true;
32 } 32 }
33 33
34 std::shared_ptr<VfsDirectory> GetContainingDirectory() const override { 34 VirtualDir GetContainingDirectory() const override {
35 return parent; 35 return parent;
36 } 36 }
37 37
diff --git a/src/core/file_sys/vfs_vector.cpp b/src/core/file_sys/vfs_vector.cpp
index 75fc04302..c1ec1e645 100644
--- a/src/core/file_sys/vfs_vector.cpp
+++ b/src/core/file_sys/vfs_vector.cpp
@@ -25,7 +25,7 @@ bool VectorVfsFile::Resize(size_t new_size) {
25 return true; 25 return true;
26} 26}
27 27
28std::shared_ptr<VfsDirectory> VectorVfsFile::GetContainingDirectory() const { 28VirtualDir VectorVfsFile::GetContainingDirectory() const {
29 return parent; 29 return parent;
30} 30}
31 31
@@ -68,11 +68,11 @@ VectorVfsDirectory::VectorVfsDirectory(std::vector<VirtualFile> files_,
68 68
69VectorVfsDirectory::~VectorVfsDirectory() = default; 69VectorVfsDirectory::~VectorVfsDirectory() = default;
70 70
71std::vector<std::shared_ptr<VfsFile>> VectorVfsDirectory::GetFiles() const { 71std::vector<VirtualFile> VectorVfsDirectory::GetFiles() const {
72 return files; 72 return files;
73} 73}
74 74
75std::vector<std::shared_ptr<VfsDirectory>> VectorVfsDirectory::GetSubdirectories() const { 75std::vector<VirtualDir> VectorVfsDirectory::GetSubdirectories() const {
76 return dirs; 76 return dirs;
77} 77}
78 78
@@ -88,7 +88,7 @@ std::string VectorVfsDirectory::GetName() const {
88 return name; 88 return name;
89} 89}
90 90
91std::shared_ptr<VfsDirectory> VectorVfsDirectory::GetParentDirectory() const { 91VirtualDir VectorVfsDirectory::GetParentDirectory() const {
92 return parent; 92 return parent;
93} 93}
94 94
@@ -116,11 +116,11 @@ bool VectorVfsDirectory::Rename(std::string_view name_) {
116 return true; 116 return true;
117} 117}
118 118
119std::shared_ptr<VfsDirectory> VectorVfsDirectory::CreateSubdirectory(std::string_view name) { 119VirtualDir VectorVfsDirectory::CreateSubdirectory(std::string_view name) {
120 return nullptr; 120 return nullptr;
121} 121}
122 122
123std::shared_ptr<VfsFile> VectorVfsDirectory::CreateFile(std::string_view name) { 123VirtualFile VectorVfsDirectory::CreateFile(std::string_view name) {
124 return nullptr; 124 return nullptr;
125} 125}
126 126
diff --git a/src/core/file_sys/vfs_vector.h b/src/core/file_sys/vfs_vector.h
index 95d3da2f2..2aff9ca34 100644
--- a/src/core/file_sys/vfs_vector.h
+++ b/src/core/file_sys/vfs_vector.h
@@ -17,9 +17,9 @@ namespace FileSys {
17template <std::size_t size> 17template <std::size_t size>
18class ArrayVfsFile : public VfsFile { 18class ArrayVfsFile : public VfsFile {
19public: 19public:
20 explicit ArrayVfsFile(const std::array<u8, size>& data, std::string name = "", 20 explicit ArrayVfsFile(const std::array<u8, size>& data_, std::string name_ = "",
21 VirtualDir parent = nullptr) 21 VirtualDir parent_ = nullptr)
22 : data(data), name(std::move(name)), parent(std::move(parent)) {} 22 : data(data_), name(std::move(name_)), parent(std::move(parent_)) {}
23 23
24 std::string GetName() const override { 24 std::string GetName() const override {
25 return name; 25 return name;
@@ -33,7 +33,7 @@ public:
33 return false; 33 return false;
34 } 34 }
35 35
36 std::shared_ptr<VfsDirectory> GetContainingDirectory() const override { 36 VirtualDir GetContainingDirectory() const override {
37 return parent; 37 return parent;
38 } 38 }
39 39
@@ -51,12 +51,12 @@ public:
51 return read; 51 return read;
52 } 52 }
53 53
54 std::size_t Write(const u8* data, std::size_t length, std::size_t offset) override { 54 std::size_t Write(const u8* data_, std::size_t length, std::size_t offset) override {
55 return 0; 55 return 0;
56 } 56 }
57 57
58 bool Rename(std::string_view name) override { 58 bool Rename(std::string_view new_name) override {
59 this->name = name; 59 name = new_name;
60 return true; 60 return true;
61 } 61 }
62 62
@@ -82,7 +82,7 @@ public:
82 std::string GetName() const override; 82 std::string GetName() const override;
83 std::size_t GetSize() const override; 83 std::size_t GetSize() const override;
84 bool Resize(std::size_t new_size) override; 84 bool Resize(std::size_t new_size) override;
85 std::shared_ptr<VfsDirectory> GetContainingDirectory() const override; 85 VirtualDir GetContainingDirectory() const override;
86 bool IsWritable() const override; 86 bool IsWritable() const override;
87 bool IsReadable() const override; 87 bool IsReadable() const override;
88 std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override; 88 std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override;
@@ -106,17 +106,17 @@ public:
106 VirtualDir parent = nullptr); 106 VirtualDir parent = nullptr);
107 ~VectorVfsDirectory() override; 107 ~VectorVfsDirectory() override;
108 108
109 std::vector<std::shared_ptr<VfsFile>> GetFiles() const override; 109 std::vector<VirtualFile> GetFiles() const override;
110 std::vector<std::shared_ptr<VfsDirectory>> GetSubdirectories() const override; 110 std::vector<VirtualDir> GetSubdirectories() const override;
111 bool IsWritable() const override; 111 bool IsWritable() const override;
112 bool IsReadable() const override; 112 bool IsReadable() const override;
113 std::string GetName() const override; 113 std::string GetName() const override;
114 std::shared_ptr<VfsDirectory> GetParentDirectory() const override; 114 VirtualDir GetParentDirectory() const override;
115 bool DeleteSubdirectory(std::string_view name) override; 115 bool DeleteSubdirectory(std::string_view name) override;
116 bool DeleteFile(std::string_view name) override; 116 bool DeleteFile(std::string_view name) override;
117 bool Rename(std::string_view name) override; 117 bool Rename(std::string_view name) override;
118 std::shared_ptr<VfsDirectory> CreateSubdirectory(std::string_view name) override; 118 VirtualDir CreateSubdirectory(std::string_view name) override;
119 std::shared_ptr<VfsFile> CreateFile(std::string_view name) override; 119 VirtualFile CreateFile(std::string_view name) override;
120 120
121 virtual void AddFile(VirtualFile file); 121 virtual void AddFile(VirtualFile file);
122 virtual void AddDirectory(VirtualDir dir); 122 virtual void AddDirectory(VirtualDir dir);
diff --git a/src/core/file_sys/xts_archive.cpp b/src/core/file_sys/xts_archive.cpp
index 24c58e7ae..814fd5680 100644
--- a/src/core/file_sys/xts_archive.cpp
+++ b/src/core/file_sys/xts_archive.cpp
@@ -152,11 +152,11 @@ NAXContentType NAX::GetContentType() const {
152 return type; 152 return type;
153} 153}
154 154
155std::vector<std::shared_ptr<VfsFile>> NAX::GetFiles() const { 155std::vector<VirtualFile> NAX::GetFiles() const {
156 return {dec_file}; 156 return {dec_file};
157} 157}
158 158
159std::vector<std::shared_ptr<VfsDirectory>> NAX::GetSubdirectories() const { 159std::vector<VirtualDir> NAX::GetSubdirectories() const {
160 return {}; 160 return {};
161} 161}
162 162
@@ -164,7 +164,7 @@ std::string NAX::GetName() const {
164 return file->GetName(); 164 return file->GetName();
165} 165}
166 166
167std::shared_ptr<VfsDirectory> NAX::GetParentDirectory() const { 167VirtualDir NAX::GetParentDirectory() const {
168 return file->GetContainingDirectory(); 168 return file->GetContainingDirectory();
169} 169}
170 170
diff --git a/src/core/file_sys/xts_archive.h b/src/core/file_sys/xts_archive.h
index c472e226e..63a032b68 100644
--- a/src/core/file_sys/xts_archive.h
+++ b/src/core/file_sys/xts_archive.h
@@ -47,13 +47,13 @@ public:
47 47
48 NAXContentType GetContentType() const; 48 NAXContentType GetContentType() const;
49 49
50 std::vector<std::shared_ptr<VfsFile>> GetFiles() const override; 50 std::vector<VirtualFile> GetFiles() const override;
51 51
52 std::vector<std::shared_ptr<VfsDirectory>> GetSubdirectories() const override; 52 std::vector<VirtualDir> GetSubdirectories() const override;
53 53
54 std::string GetName() const override; 54 std::string GetName() const override;
55 55
56 std::shared_ptr<VfsDirectory> GetParentDirectory() const override; 56 VirtualDir GetParentDirectory() const override;
57 57
58private: 58private:
59 Loader::ResultStatus Parse(std::string_view path); 59 Loader::ResultStatus Parse(std::string_view path);
diff --git a/src/core/frontend/applets/controller.cpp b/src/core/frontend/applets/controller.cpp
index 4505da758..03bbedf8b 100644
--- a/src/core/frontend/applets/controller.cpp
+++ b/src/core/frontend/applets/controller.cpp
@@ -4,7 +4,6 @@
4 4
5#include "common/assert.h" 5#include "common/assert.h"
6#include "common/logging/log.h" 6#include "common/logging/log.h"
7#include "core/core.h"
8#include "core/frontend/applets/controller.h" 7#include "core/frontend/applets/controller.h"
9#include "core/hle/service/hid/controllers/npad.h" 8#include "core/hle/service/hid/controllers/npad.h"
10#include "core/hle/service/hid/hid.h" 9#include "core/hle/service/hid/hid.h"
@@ -14,32 +13,33 @@ namespace Core::Frontend {
14 13
15ControllerApplet::~ControllerApplet() = default; 14ControllerApplet::~ControllerApplet() = default;
16 15
16DefaultControllerApplet::DefaultControllerApplet(Service::SM::ServiceManager& service_manager_)
17 : service_manager{service_manager_} {}
18
17DefaultControllerApplet::~DefaultControllerApplet() = default; 19DefaultControllerApplet::~DefaultControllerApplet() = default;
18 20
19void DefaultControllerApplet::ReconfigureControllers(std::function<void()> callback, 21void DefaultControllerApplet::ReconfigureControllers(std::function<void()> callback,
20 ControllerParameters parameters) const { 22 const ControllerParameters& parameters) const {
21 LOG_INFO(Service_HID, "called, deducing the best configuration based on the given parameters!"); 23 LOG_INFO(Service_HID, "called, deducing the best configuration based on the given parameters!");
22 24
23 auto& npad = 25 auto& npad =
24 Core::System::GetInstance() 26 service_manager.GetService<Service::HID::Hid>("hid")
25 .ServiceManager()
26 .GetService<Service::HID::Hid>("hid")
27 ->GetAppletResource() 27 ->GetAppletResource()
28 ->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad); 28 ->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad);
29 29
30 auto& players = Settings::values.players; 30 auto& players = Settings::values.players.GetValue();
31 31
32 const std::size_t min_supported_players = 32 const std::size_t min_supported_players =
33 parameters.enable_single_mode ? 1 : parameters.min_players; 33 parameters.enable_single_mode ? 1 : parameters.min_players;
34 34
35 // Disconnect Handheld first. 35 // Disconnect Handheld first.
36 npad.DisconnectNPadAtIndex(8); 36 npad.DisconnectNpadAtIndex(8);
37 37
38 // Deduce the best configuration based on the input parameters. 38 // Deduce the best configuration based on the input parameters.
39 for (std::size_t index = 0; index < players.size() - 2; ++index) { 39 for (std::size_t index = 0; index < players.size() - 2; ++index) {
40 // First, disconnect all controllers regardless of the value of keep_controllers_connected. 40 // First, disconnect all controllers regardless of the value of keep_controllers_connected.
41 // This makes it easy to connect the desired controllers. 41 // This makes it easy to connect the desired controllers.
42 npad.DisconnectNPadAtIndex(index); 42 npad.DisconnectNpadAtIndex(index);
43 43
44 // Only connect the minimum number of required players. 44 // Only connect the minimum number of required players.
45 if (index >= min_supported_players) { 45 if (index >= min_supported_players) {
@@ -66,7 +66,7 @@ void DefaultControllerApplet::ReconfigureControllers(std::function<void()> callb
66 npad.MapSettingsTypeToNPad(Settings::ControllerType::RightJoycon), index); 66 npad.MapSettingsTypeToNPad(Settings::ControllerType::RightJoycon), index);
67 } 67 }
68 } else if (index == 0 && parameters.enable_single_mode && parameters.allow_handheld && 68 } else if (index == 0 && parameters.enable_single_mode && parameters.allow_handheld &&
69 !Settings::values.use_docked_mode) { 69 !Settings::values.use_docked_mode.GetValue()) {
70 // We should *never* reach here under any normal circumstances. 70 // We should *never* reach here under any normal circumstances.
71 npad.AddNewControllerAt(npad.MapSettingsTypeToNPad(Settings::ControllerType::Handheld), 71 npad.AddNewControllerAt(npad.MapSettingsTypeToNPad(Settings::ControllerType::Handheld),
72 index); 72 index);
diff --git a/src/core/frontend/applets/controller.h b/src/core/frontend/applets/controller.h
index a227f15cd..dff71d8d9 100644
--- a/src/core/frontend/applets/controller.h
+++ b/src/core/frontend/applets/controller.h
@@ -8,6 +8,10 @@
8 8
9#include "common/common_types.h" 9#include "common/common_types.h"
10 10
11namespace Service::SM {
12class ServiceManager;
13}
14
11namespace Core::Frontend { 15namespace Core::Frontend {
12 16
13using BorderColor = std::array<u8, 4>; 17using BorderColor = std::array<u8, 4>;
@@ -34,15 +38,19 @@ public:
34 virtual ~ControllerApplet(); 38 virtual ~ControllerApplet();
35 39
36 virtual void ReconfigureControllers(std::function<void()> callback, 40 virtual void ReconfigureControllers(std::function<void()> callback,
37 ControllerParameters parameters) const = 0; 41 const ControllerParameters& parameters) const = 0;
38}; 42};
39 43
40class DefaultControllerApplet final : public ControllerApplet { 44class DefaultControllerApplet final : public ControllerApplet {
41public: 45public:
46 explicit DefaultControllerApplet(Service::SM::ServiceManager& service_manager_);
42 ~DefaultControllerApplet() override; 47 ~DefaultControllerApplet() override;
43 48
44 void ReconfigureControllers(std::function<void()> callback, 49 void ReconfigureControllers(std::function<void()> callback,
45 ControllerParameters parameters) const override; 50 const ControllerParameters& parameters) const override;
51
52private:
53 Service::SM::ServiceManager& service_manager;
46}; 54};
47 55
48} // namespace Core::Frontend 56} // namespace Core::Frontend
diff --git a/src/core/frontend/applets/error.cpp b/src/core/frontend/applets/error.cpp
index 4002a9211..dceb20ff8 100644
--- a/src/core/frontend/applets/error.cpp
+++ b/src/core/frontend/applets/error.cpp
@@ -2,6 +2,7 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/logging/log.h"
5#include "core/frontend/applets/error.h" 6#include "core/frontend/applets/error.h"
6 7
7namespace Core::Frontend { 8namespace Core::Frontend {
@@ -10,7 +11,7 @@ ErrorApplet::~ErrorApplet() = default;
10 11
11void DefaultErrorApplet::ShowError(ResultCode error, std::function<void()> finished) const { 12void DefaultErrorApplet::ShowError(ResultCode error, std::function<void()> finished) const {
12 LOG_CRITICAL(Service_Fatal, "Application requested error display: {:04}-{:04} (raw={:08X})", 13 LOG_CRITICAL(Service_Fatal, "Application requested error display: {:04}-{:04} (raw={:08X})",
13 static_cast<u32>(error.module.Value()), error.description.Value(), error.raw); 14 error.module.Value(), error.description.Value(), error.raw);
14} 15}
15 16
16void DefaultErrorApplet::ShowErrorWithTimestamp(ResultCode error, std::chrono::seconds time, 17void DefaultErrorApplet::ShowErrorWithTimestamp(ResultCode error, std::chrono::seconds time,
@@ -18,7 +19,7 @@ void DefaultErrorApplet::ShowErrorWithTimestamp(ResultCode error, std::chrono::s
18 LOG_CRITICAL( 19 LOG_CRITICAL(
19 Service_Fatal, 20 Service_Fatal,
20 "Application requested error display: {:04X}-{:04X} (raw={:08X}) with timestamp={:016X}", 21 "Application requested error display: {:04X}-{:04X} (raw={:08X}) with timestamp={:016X}",
21 static_cast<u32>(error.module.Value()), error.description.Value(), error.raw, time.count()); 22 error.module.Value(), error.description.Value(), error.raw, time.count());
22} 23}
23 24
24void DefaultErrorApplet::ShowCustomErrorText(ResultCode error, std::string main_text, 25void DefaultErrorApplet::ShowCustomErrorText(ResultCode error, std::string main_text,
@@ -26,7 +27,7 @@ void DefaultErrorApplet::ShowCustomErrorText(ResultCode error, std::string main_
26 std::function<void()> finished) const { 27 std::function<void()> finished) const {
27 LOG_CRITICAL(Service_Fatal, 28 LOG_CRITICAL(Service_Fatal,
28 "Application requested custom error with error_code={:04X}-{:04X} (raw={:08X})", 29 "Application requested custom error with error_code={:04X}-{:04X} (raw={:08X})",
29 static_cast<u32>(error.module.Value()), error.description.Value(), error.raw); 30 error.module.Value(), error.description.Value(), error.raw);
30 LOG_CRITICAL(Service_Fatal, " Main Text: {}", main_text); 31 LOG_CRITICAL(Service_Fatal, " Main Text: {}", main_text);
31 LOG_CRITICAL(Service_Fatal, " Detail Text: {}", detail_text); 32 LOG_CRITICAL(Service_Fatal, " Detail Text: {}", detail_text);
32} 33}
diff --git a/src/core/frontend/applets/general_frontend.cpp b/src/core/frontend/applets/general_frontend.cpp
index c30b36de7..7483ffb76 100644
--- a/src/core/frontend/applets/general_frontend.cpp
+++ b/src/core/frontend/applets/general_frontend.cpp
@@ -53,72 +53,4 @@ void DefaultPhotoViewerApplet::ShowAllPhotos(std::function<void()> finished) con
53 finished(); 53 finished();
54} 54}
55 55
56ECommerceApplet::~ECommerceApplet() = default;
57
58DefaultECommerceApplet::~DefaultECommerceApplet() = default;
59
60void DefaultECommerceApplet::ShowApplicationInformation(
61 std::function<void()> finished, u64 title_id, std::optional<u128> user_id,
62 std::optional<bool> full_display, std::optional<std::string> extra_parameter) {
63 const auto value = user_id.value_or(u128{});
64 LOG_INFO(Service_AM,
65 "Application requested frontend show application information for EShop, "
66 "title_id={:016X}, user_id={:016X}{:016X}, full_display={}, extra_parameter={}",
67 title_id, value[1], value[0],
68 full_display.has_value() ? fmt::format("{}", *full_display) : "null",
69 extra_parameter.value_or("null"));
70 finished();
71}
72
73void DefaultECommerceApplet::ShowAddOnContentList(std::function<void()> finished, u64 title_id,
74 std::optional<u128> user_id,
75 std::optional<bool> full_display) {
76 const auto value = user_id.value_or(u128{});
77 LOG_INFO(Service_AM,
78 "Application requested frontend show add on content list for EShop, "
79 "title_id={:016X}, user_id={:016X}{:016X}, full_display={}",
80 title_id, value[1], value[0],
81 full_display.has_value() ? fmt::format("{}", *full_display) : "null");
82 finished();
83}
84
85void DefaultECommerceApplet::ShowSubscriptionList(std::function<void()> finished, u64 title_id,
86 std::optional<u128> user_id) {
87 const auto value = user_id.value_or(u128{});
88 LOG_INFO(Service_AM,
89 "Application requested frontend show subscription list for EShop, title_id={:016X}, "
90 "user_id={:016X}{:016X}",
91 title_id, value[1], value[0]);
92 finished();
93}
94
95void DefaultECommerceApplet::ShowConsumableItemList(std::function<void()> finished, u64 title_id,
96 std::optional<u128> user_id) {
97 const auto value = user_id.value_or(u128{});
98 LOG_INFO(
99 Service_AM,
100 "Application requested frontend show consumable item list for EShop, title_id={:016X}, "
101 "user_id={:016X}{:016X}",
102 title_id, value[1], value[0]);
103 finished();
104}
105
106void DefaultECommerceApplet::ShowShopHome(std::function<void()> finished, u128 user_id,
107 bool full_display) {
108 LOG_INFO(Service_AM,
109 "Application requested frontend show home menu for EShop, user_id={:016X}{:016X}, "
110 "full_display={}",
111 user_id[1], user_id[0], full_display);
112 finished();
113}
114
115void DefaultECommerceApplet::ShowSettings(std::function<void()> finished, u128 user_id,
116 bool full_display) {
117 LOG_INFO(Service_AM,
118 "Application requested frontend show settings menu for EShop, user_id={:016X}{:016X}, "
119 "full_display={}",
120 user_id[1], user_id[0], full_display);
121 finished();
122}
123
124} // namespace Core::Frontend 56} // namespace Core::Frontend
diff --git a/src/core/frontend/applets/general_frontend.h b/src/core/frontend/applets/general_frontend.h
index 4b63f828e..b713b14ee 100644
--- a/src/core/frontend/applets/general_frontend.h
+++ b/src/core/frontend/applets/general_frontend.h
@@ -58,55 +58,4 @@ public:
58 void ShowAllPhotos(std::function<void()> finished) const override; 58 void ShowAllPhotos(std::function<void()> finished) const override;
59}; 59};
60 60
61class ECommerceApplet {
62public:
63 virtual ~ECommerceApplet();
64
65 // Shows a page with application icons, description, name, and price.
66 virtual void ShowApplicationInformation(std::function<void()> finished, u64 title_id,
67 std::optional<u128> user_id = {},
68 std::optional<bool> full_display = {},
69 std::optional<std::string> extra_parameter = {}) = 0;
70
71 // Shows a page with all of the add on content available for a game, with name, description, and
72 // price.
73 virtual void ShowAddOnContentList(std::function<void()> finished, u64 title_id,
74 std::optional<u128> user_id = {},
75 std::optional<bool> full_display = {}) = 0;
76
77 // Shows a page with all of the subscriptions (recurring payments) for a game, with name,
78 // description, price, and renewal period.
79 virtual void ShowSubscriptionList(std::function<void()> finished, u64 title_id,
80 std::optional<u128> user_id = {}) = 0;
81
82 // Shows a page with a list of any additional game related purchasable items (DLC,
83 // subscriptions, etc) for a particular game, with name, description, type, and price.
84 virtual void ShowConsumableItemList(std::function<void()> finished, u64 title_id,
85 std::optional<u128> user_id = {}) = 0;
86
87 // Shows the home page of the shop.
88 virtual void ShowShopHome(std::function<void()> finished, u128 user_id, bool full_display) = 0;
89
90 // Shows the user settings page of the shop.
91 virtual void ShowSettings(std::function<void()> finished, u128 user_id, bool full_display) = 0;
92};
93
94class DefaultECommerceApplet : public ECommerceApplet {
95public:
96 ~DefaultECommerceApplet() override;
97
98 void ShowApplicationInformation(std::function<void()> finished, u64 title_id,
99 std::optional<u128> user_id, std::optional<bool> full_display,
100 std::optional<std::string> extra_parameter) override;
101 void ShowAddOnContentList(std::function<void()> finished, u64 title_id,
102 std::optional<u128> user_id,
103 std::optional<bool> full_display) override;
104 void ShowSubscriptionList(std::function<void()> finished, u64 title_id,
105 std::optional<u128> user_id) override;
106 void ShowConsumableItemList(std::function<void()> finished, u64 title_id,
107 std::optional<u128> user_id) override;
108 void ShowShopHome(std::function<void()> finished, u128 user_id, bool full_display) override;
109 void ShowSettings(std::function<void()> finished, u128 user_id, bool full_display) override;
110};
111
112} // namespace Core::Frontend 61} // namespace Core::Frontend
diff --git a/src/core/frontend/applets/web_browser.cpp b/src/core/frontend/applets/web_browser.cpp
index 528295ffc..50db6a654 100644
--- a/src/core/frontend/applets/web_browser.cpp
+++ b/src/core/frontend/applets/web_browser.cpp
@@ -11,14 +11,22 @@ WebBrowserApplet::~WebBrowserApplet() = default;
11 11
12DefaultWebBrowserApplet::~DefaultWebBrowserApplet() = default; 12DefaultWebBrowserApplet::~DefaultWebBrowserApplet() = default;
13 13
14void DefaultWebBrowserApplet::OpenPageLocal(std::string_view filename, 14void DefaultWebBrowserApplet::OpenLocalWebPage(
15 std::function<void()> unpack_romfs_callback, 15 std::string_view local_url, std::function<void()> extract_romfs_callback,
16 std::function<void()> finished_callback) { 16 std::function<void(Service::AM::Applets::WebExitReason, std::string)> callback) const {
17 LOG_INFO(Service_AM, 17 LOG_WARNING(Service_AM, "(STUBBED) called, backend requested to open local web page at {}",
18 "(STUBBED) called - No suitable web browser implementation found to open website page " 18 local_url);
19 "at '{}'!", 19
20 filename); 20 callback(Service::AM::Applets::WebExitReason::WindowClosed, "http://localhost/");
21 finished_callback(); 21}
22
23void DefaultWebBrowserApplet::OpenExternalWebPage(
24 std::string_view external_url,
25 std::function<void(Service::AM::Applets::WebExitReason, std::string)> callback) const {
26 LOG_WARNING(Service_AM, "(STUBBED) called, backend requested to open external web page at {}",
27 external_url);
28
29 callback(Service::AM::Applets::WebExitReason::WindowClosed, "http://localhost/");
22} 30}
23 31
24} // namespace Core::Frontend 32} // namespace Core::Frontend
diff --git a/src/core/frontend/applets/web_browser.h b/src/core/frontend/applets/web_browser.h
index 110e33bc4..1c5ef19a9 100644
--- a/src/core/frontend/applets/web_browser.h
+++ b/src/core/frontend/applets/web_browser.h
@@ -7,22 +7,34 @@
7#include <functional> 7#include <functional>
8#include <string_view> 8#include <string_view>
9 9
10#include "core/hle/service/am/applets/web_types.h"
11
10namespace Core::Frontend { 12namespace Core::Frontend {
11 13
12class WebBrowserApplet { 14class WebBrowserApplet {
13public: 15public:
14 virtual ~WebBrowserApplet(); 16 virtual ~WebBrowserApplet();
15 17
16 virtual void OpenPageLocal(std::string_view url, std::function<void()> unpack_romfs_callback, 18 virtual void OpenLocalWebPage(
17 std::function<void()> finished_callback) = 0; 19 std::string_view local_url, std::function<void()> extract_romfs_callback,
20 std::function<void(Service::AM::Applets::WebExitReason, std::string)> callback) const = 0;
21
22 virtual void OpenExternalWebPage(
23 std::string_view external_url,
24 std::function<void(Service::AM::Applets::WebExitReason, std::string)> callback) const = 0;
18}; 25};
19 26
20class DefaultWebBrowserApplet final : public WebBrowserApplet { 27class DefaultWebBrowserApplet final : public WebBrowserApplet {
21public: 28public:
22 ~DefaultWebBrowserApplet() override; 29 ~DefaultWebBrowserApplet() override;
23 30
24 void OpenPageLocal(std::string_view url, std::function<void()> unpack_romfs_callback, 31 void OpenLocalWebPage(std::string_view local_url, std::function<void()> extract_romfs_callback,
25 std::function<void()> finished_callback) override; 32 std::function<void(Service::AM::Applets::WebExitReason, std::string)>
33 callback) const override;
34
35 void OpenExternalWebPage(std::string_view external_url,
36 std::function<void(Service::AM::Applets::WebExitReason, std::string)>
37 callback) const override;
26}; 38};
27 39
28} // namespace Core::Frontend 40} // namespace Core::Frontend
diff --git a/src/core/frontend/emu_window.cpp b/src/core/frontend/emu_window.cpp
index 9a081fbd4..8c1193894 100644
--- a/src/core/frontend/emu_window.cpp
+++ b/src/core/frontend/emu_window.cpp
@@ -84,10 +84,12 @@ void EmuWindow::TouchPressed(unsigned framebuffer_x, unsigned framebuffer_y) {
84 return; 84 return;
85 85
86 std::lock_guard guard{touch_state->mutex}; 86 std::lock_guard guard{touch_state->mutex};
87 touch_state->touch_x = static_cast<float>(framebuffer_x - framebuffer_layout.screen.left) / 87 touch_state->touch_x =
88 (framebuffer_layout.screen.right - framebuffer_layout.screen.left); 88 static_cast<float>(framebuffer_x - framebuffer_layout.screen.left) /
89 touch_state->touch_y = static_cast<float>(framebuffer_y - framebuffer_layout.screen.top) / 89 static_cast<float>(framebuffer_layout.screen.right - framebuffer_layout.screen.left);
90 (framebuffer_layout.screen.bottom - framebuffer_layout.screen.top); 90 touch_state->touch_y =
91 static_cast<float>(framebuffer_y - framebuffer_layout.screen.top) /
92 static_cast<float>(framebuffer_layout.screen.bottom - framebuffer_layout.screen.top);
91 93
92 touch_state->touch_pressed = true; 94 touch_state->touch_pressed = true;
93} 95}
diff --git a/src/core/frontend/emu_window.h b/src/core/frontend/emu_window.h
index 3e8780243..276d2b906 100644
--- a/src/core/frontend/emu_window.h
+++ b/src/core/frontend/emu_window.h
@@ -102,8 +102,8 @@ public:
102 float render_surface_scale = 1.0f; 102 float render_surface_scale = 1.0f;
103 }; 103 };
104 104
105 /// Polls window events 105 /// Called from GPU thread when a frame is displayed.
106 virtual void PollEvents() = 0; 106 virtual void OnFrameDisplayed() {}
107 107
108 /** 108 /**
109 * Returns a GraphicsContext that the frontend provides to be used for rendering. 109 * Returns a GraphicsContext that the frontend provides to be used for rendering.
diff --git a/src/core/frontend/framebuffer_layout.cpp b/src/core/frontend/framebuffer_layout.cpp
index c1fbc235b..b9a270a55 100644
--- a/src/core/frontend/framebuffer_layout.cpp
+++ b/src/core/frontend/framebuffer_layout.cpp
@@ -14,8 +14,8 @@ namespace Layout {
14template <class T> 14template <class T>
15static Common::Rectangle<T> MaxRectangle(Common::Rectangle<T> window_area, 15static Common::Rectangle<T> MaxRectangle(Common::Rectangle<T> window_area,
16 float screen_aspect_ratio) { 16 float screen_aspect_ratio) {
17 float scale = std::min(static_cast<float>(window_area.GetWidth()), 17 const float scale = std::min(static_cast<float>(window_area.GetWidth()),
18 window_area.GetHeight() / screen_aspect_ratio); 18 static_cast<float>(window_area.GetHeight()) / screen_aspect_ratio);
19 return Common::Rectangle<T>{0, 0, static_cast<T>(std::round(scale)), 19 return Common::Rectangle<T>{0, 0, static_cast<T>(std::round(scale)),
20 static_cast<T>(std::round(scale * screen_aspect_ratio))}; 20 static_cast<T>(std::round(scale * screen_aspect_ratio))};
21} 21}
@@ -27,7 +27,7 @@ FramebufferLayout DefaultFrameLayout(u32 width, u32 height) {
27 // so just calculate them both even if the other isn't showing. 27 // so just calculate them both even if the other isn't showing.
28 FramebufferLayout res{width, height, false, {}}; 28 FramebufferLayout res{width, height, false, {}};
29 29
30 const float window_aspect_ratio = static_cast<float>(height) / width; 30 const float window_aspect_ratio = static_cast<float>(height) / static_cast<float>(width);
31 const float emulation_aspect_ratio = EmulationAspectRatio( 31 const float emulation_aspect_ratio = EmulationAspectRatio(
32 static_cast<AspectRatio>(Settings::values.aspect_ratio.GetValue()), window_aspect_ratio); 32 static_cast<AspectRatio>(Settings::values.aspect_ratio.GetValue()), window_aspect_ratio);
33 33
@@ -47,7 +47,7 @@ FramebufferLayout DefaultFrameLayout(u32 width, u32 height) {
47FramebufferLayout FrameLayoutFromResolutionScale(u32 res_scale) { 47FramebufferLayout FrameLayoutFromResolutionScale(u32 res_scale) {
48 u32 width, height; 48 u32 width, height;
49 49
50 if (Settings::values.use_docked_mode) { 50 if (Settings::values.use_docked_mode.GetValue()) {
51 width = ScreenDocked::Width * res_scale; 51 width = ScreenDocked::Width * res_scale;
52 height = ScreenDocked::Height * res_scale; 52 height = ScreenDocked::Height * res_scale;
53 } else { 53 } else {
diff --git a/src/core/frontend/input.h b/src/core/frontend/input.h
index 9da0d2829..de51a754e 100644
--- a/src/core/frontend/input.h
+++ b/src/core/frontend/input.h
@@ -30,7 +30,12 @@ public:
30 virtual StatusType GetStatus() const { 30 virtual StatusType GetStatus() const {
31 return {}; 31 return {};
32 } 32 }
33 virtual bool GetAnalogDirectionStatus(AnalogDirection direction) const { 33 virtual bool GetAnalogDirectionStatus([[maybe_unused]] AnalogDirection direction) const {
34 return {};
35 }
36 virtual bool SetRumblePlay([[maybe_unused]] f32 amp_low, [[maybe_unused]] f32 freq_low,
37 [[maybe_unused]] f32 amp_high,
38 [[maybe_unused]] f32 freq_high) const {
34 return {}; 39 return {};
35 } 40 }
36}; 41};
@@ -119,6 +124,13 @@ using ButtonDevice = InputDevice<bool>;
119using AnalogDevice = InputDevice<std::tuple<float, float>>; 124using AnalogDevice = InputDevice<std::tuple<float, float>>;
120 125
121/** 126/**
127 * A vibration device is an input device that returns an unsigned byte as status.
128 * It represents whether the vibration device supports vibration or not.
129 * If the status returns 1, it supports vibration. Otherwise, it does not support vibration.
130 */
131using VibrationDevice = InputDevice<u8>;
132
133/**
122 * A motion status is an object that returns a tuple of accelerometer state vector, 134 * A motion status is an object that returns a tuple of accelerometer state vector,
123 * gyroscope state vector, rotation state vector and orientation state matrix. 135 * gyroscope state vector, rotation state vector and orientation state matrix.
124 * 136 *
@@ -151,10 +163,15 @@ using MotionStatus = std::tuple<Common::Vec3<float>, Common::Vec3<float>, Common
151using MotionDevice = InputDevice<MotionStatus>; 163using MotionDevice = InputDevice<MotionStatus>;
152 164
153/** 165/**
154 * A touch device is an input device that returns a tuple of two floats and a bool. The floats are 166 * A touch status is an object that returns a tuple of two floats and a bool. The floats are
155 * x and y coordinates in the range 0.0 - 1.0, and the bool indicates whether it is pressed. 167 * x and y coordinates in the range 0.0 - 1.0, and the bool indicates whether it is pressed.
156 */ 168 */
157using TouchDevice = InputDevice<std::tuple<float, float, bool>>; 169using TouchStatus = std::tuple<float, float, bool>;
170
171/**
172 * A touch device is an input device that returns a touch status object
173 */
174using TouchDevice = InputDevice<TouchStatus>;
158 175
159/** 176/**
160 * A mouse device is an input device that returns a tuple of two floats and four ints. 177 * A mouse device is an input device that returns a tuple of two floats and four ints.
diff --git a/src/core/frontend/input_interpreter.cpp b/src/core/frontend/input_interpreter.cpp
new file mode 100644
index 000000000..66ae506cd
--- /dev/null
+++ b/src/core/frontend/input_interpreter.cpp
@@ -0,0 +1,45 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "core/core.h"
6#include "core/frontend/input_interpreter.h"
7#include "core/hle/service/hid/controllers/npad.h"
8#include "core/hle/service/hid/hid.h"
9#include "core/hle/service/sm/sm.h"
10
11InputInterpreter::InputInterpreter(Core::System& system)
12 : npad{system.ServiceManager()
13 .GetService<Service::HID::Hid>("hid")
14 ->GetAppletResource()
15 ->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad)} {}
16
17InputInterpreter::~InputInterpreter() = default;
18
19void InputInterpreter::PollInput() {
20 const u32 button_state = npad.GetAndResetPressState();
21
22 previous_index = current_index;
23 current_index = (current_index + 1) % button_states.size();
24
25 button_states[current_index] = button_state;
26}
27
28bool InputInterpreter::IsButtonPressedOnce(HIDButton button) const {
29 const bool current_press =
30 (button_states[current_index] & (1U << static_cast<u8>(button))) != 0;
31 const bool previous_press =
32 (button_states[previous_index] & (1U << static_cast<u8>(button))) != 0;
33
34 return current_press && !previous_press;
35}
36
37bool InputInterpreter::IsButtonHeld(HIDButton button) const {
38 u32 held_buttons{button_states[0]};
39
40 for (std::size_t i = 1; i < button_states.size(); ++i) {
41 held_buttons &= button_states[i];
42 }
43
44 return (held_buttons & (1U << static_cast<u8>(button))) != 0;
45}
diff --git a/src/core/frontend/input_interpreter.h b/src/core/frontend/input_interpreter.h
new file mode 100644
index 000000000..fea9aebe6
--- /dev/null
+++ b/src/core/frontend/input_interpreter.h
@@ -0,0 +1,120 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <array>
8
9#include "common/common_types.h"
10
11namespace Core {
12class System;
13}
14
15namespace Service::HID {
16class Controller_NPad;
17}
18
19enum class HIDButton : u8 {
20 A,
21 B,
22 X,
23 Y,
24 LStick,
25 RStick,
26 L,
27 R,
28 ZL,
29 ZR,
30 Plus,
31 Minus,
32
33 DLeft,
34 DUp,
35 DRight,
36 DDown,
37
38 LStickLeft,
39 LStickUp,
40 LStickRight,
41 LStickDown,
42
43 RStickLeft,
44 RStickUp,
45 RStickRight,
46 RStickDown,
47
48 LeftSL,
49 LeftSR,
50
51 RightSL,
52 RightSR,
53};
54
55/**
56 * The InputInterpreter class interfaces with HID to retrieve button press states.
57 * Input is intended to be polled every 50ms so that a button is considered to be
58 * held down after 400ms has elapsed since the initial button press and subsequent
59 * repeated presses occur every 50ms.
60 */
61class InputInterpreter {
62public:
63 explicit InputInterpreter(Core::System& system);
64 virtual ~InputInterpreter();
65
66 /// Gets a button state from HID and inserts it into the array of button states.
67 void PollInput();
68
69 /**
70 * The specified button is considered to be pressed once
71 * if it is currently pressed and not pressed previously.
72 *
73 * @param button The button to check.
74 *
75 * @returns True when the button is pressed once.
76 */
77 [[nodiscard]] bool IsButtonPressedOnce(HIDButton button) const;
78
79 /**
80 * Checks whether any of the buttons in the parameter list is pressed once.
81 *
82 * @tparam HIDButton The buttons to check.
83 *
84 * @returns True when at least one of the buttons is pressed once.
85 */
86 template <HIDButton... T>
87 [[nodiscard]] bool IsAnyButtonPressedOnce() {
88 return (IsButtonPressedOnce(T) || ...);
89 }
90
91 /**
92 * The specified button is considered to be held down if it is pressed in all 9 button states.
93 *
94 * @param button The button to check.
95 *
96 * @returns True when the button is held down.
97 */
98 [[nodiscard]] bool IsButtonHeld(HIDButton button) const;
99
100 /**
101 * Checks whether any of the buttons in the parameter list is held down.
102 *
103 * @tparam HIDButton The buttons to check.
104 *
105 * @returns True when at least one of the buttons is held down.
106 */
107 template <HIDButton... T>
108 [[nodiscard]] bool IsAnyButtonHeld() {
109 return (IsButtonHeld(T) || ...);
110 }
111
112private:
113 Service::HID::Controller_NPad& npad;
114
115 /// Stores 9 consecutive button states polled from HID.
116 std::array<u32, 9> button_states{};
117
118 std::size_t previous_index{};
119 std::size_t current_index{};
120};
diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp
deleted file mode 100644
index 79f22a403..000000000
--- a/src/core/gdbstub/gdbstub.cpp
+++ /dev/null
@@ -1,1397 +0,0 @@
1// Copyright 2013 Dolphin Emulator Project
2// Licensed under GPLv2+
3// Refer to the license.txt file included.
4
5// Originally written by Sven Peter <sven@fail0verflow.com> for anergistic.
6
7#include <algorithm>
8#include <atomic>
9#include <climits>
10#include <csignal>
11#include <cstdarg>
12#include <cstdio>
13#include <cstring>
14#include <map>
15#include <numeric>
16#include <fcntl.h>
17
18#ifdef _WIN32
19#include <winsock2.h>
20// winsock2.h needs to be included first to prevent winsock.h being included by other includes
21#include <io.h>
22#include <iphlpapi.h>
23#include <ws2tcpip.h>
24#define SHUT_RDWR 2
25#else
26#include <netinet/in.h>
27#include <sys/select.h>
28#include <sys/socket.h>
29#include <sys/un.h>
30#include <unistd.h>
31#endif
32
33#include "common/logging/log.h"
34#include "common/string_util.h"
35#include "common/swap.h"
36#include "core/arm/arm_interface.h"
37#include "core/core.h"
38#include "core/gdbstub/gdbstub.h"
39#include "core/hle/kernel/memory/page_table.h"
40#include "core/hle/kernel/process.h"
41#include "core/hle/kernel/scheduler.h"
42#include "core/loader/loader.h"
43#include "core/memory.h"
44
45namespace GDBStub {
46namespace {
47constexpr int GDB_BUFFER_SIZE = 10000;
48
49constexpr char GDB_STUB_START = '$';
50constexpr char GDB_STUB_END = '#';
51constexpr char GDB_STUB_ACK = '+';
52constexpr char GDB_STUB_NACK = '-';
53
54#ifndef SIGTRAP
55constexpr u32 SIGTRAP = 5;
56#endif
57
58#ifndef SIGTERM
59constexpr u32 SIGTERM = 15;
60#endif
61
62#ifndef MSG_WAITALL
63constexpr u32 MSG_WAITALL = 8;
64#endif
65
66constexpr u32 LR_REGISTER = 30;
67constexpr u32 SP_REGISTER = 31;
68constexpr u32 PC_REGISTER = 32;
69constexpr u32 PSTATE_REGISTER = 33;
70constexpr u32 UC_ARM64_REG_Q0 = 34;
71constexpr u32 FPCR_REGISTER = 66;
72
73// For sample XML files see the GDB source /gdb/features
74// GDB also wants the l character at the start
75// This XML defines what the registers are for this specific ARM device
76constexpr char target_xml[] =
77 R"(l<?xml version="1.0"?>
78<!DOCTYPE target SYSTEM "gdb-target.dtd">
79<target version="1.0">
80 <feature name="org.gnu.gdb.aarch64.core">
81 <reg name="x0" bitsize="64"/>
82 <reg name="x1" bitsize="64"/>
83 <reg name="x2" bitsize="64"/>
84 <reg name="x3" bitsize="64"/>
85 <reg name="x4" bitsize="64"/>
86 <reg name="x5" bitsize="64"/>
87 <reg name="x6" bitsize="64"/>
88 <reg name="x7" bitsize="64"/>
89 <reg name="x8" bitsize="64"/>
90 <reg name="x9" bitsize="64"/>
91 <reg name="x10" bitsize="64"/>
92 <reg name="x11" bitsize="64"/>
93 <reg name="x12" bitsize="64"/>
94 <reg name="x13" bitsize="64"/>
95 <reg name="x14" bitsize="64"/>
96 <reg name="x15" bitsize="64"/>
97 <reg name="x16" bitsize="64"/>
98 <reg name="x17" bitsize="64"/>
99 <reg name="x18" bitsize="64"/>
100 <reg name="x19" bitsize="64"/>
101 <reg name="x20" bitsize="64"/>
102 <reg name="x21" bitsize="64"/>
103 <reg name="x22" bitsize="64"/>
104 <reg name="x23" bitsize="64"/>
105 <reg name="x24" bitsize="64"/>
106 <reg name="x25" bitsize="64"/>
107 <reg name="x26" bitsize="64"/>
108 <reg name="x27" bitsize="64"/>
109 <reg name="x28" bitsize="64"/>
110 <reg name="x29" bitsize="64"/>
111 <reg name="x30" bitsize="64"/>
112 <reg name="sp" bitsize="64" type="data_ptr"/>
113
114 <reg name="pc" bitsize="64" type="code_ptr"/>
115
116 <flags id="pstate_flags" size="4">
117 <field name="SP" start="0" end="0"/>
118 <field name="" start="1" end="1"/>
119 <field name="EL" start="2" end="3"/>
120 <field name="nRW" start="4" end="4"/>
121 <field name="" start="5" end="5"/>
122 <field name="F" start="6" end="6"/>
123 <field name="I" start="7" end="7"/>
124 <field name="A" start="8" end="8"/>
125 <field name="D" start="9" end="9"/>
126
127 <field name="IL" start="20" end="20"/>
128 <field name="SS" start="21" end="21"/>
129
130 <field name="V" start="28" end="28"/>
131 <field name="C" start="29" end="29"/>
132 <field name="Z" start="30" end="30"/>
133 <field name="N" start="31" end="31"/>
134 </flags>
135 <reg name="pstate" bitsize="32" type="pstate_flags"/>
136 </feature>
137 <feature name="org.gnu.gdb.aarch64.fpu">
138 </feature>
139</target>
140)";
141
142int gdbserver_socket = -1;
143bool defer_start = false;
144
145u8 command_buffer[GDB_BUFFER_SIZE];
146u32 command_length;
147
148u32 latest_signal = 0;
149bool memory_break = false;
150
151Kernel::Thread* current_thread = nullptr;
152u32 current_core = 0;
153
154// Binding to a port within the reserved ports range (0-1023) requires root permissions,
155// so default to a port outside of that range.
156u16 gdbstub_port = 24689;
157
158bool halt_loop = true;
159bool step_loop = false;
160bool send_trap = false;
161
162// If set to false, the server will never be started and no
163// gdbstub-related functions will be executed.
164std::atomic<bool> server_enabled(false);
165
166#ifdef _WIN32
167WSADATA InitData;
168#endif
169
170struct Breakpoint {
171 bool active;
172 VAddr addr;
173 u64 len;
174 std::array<u8, 4> inst;
175};
176
177using BreakpointMap = std::map<VAddr, Breakpoint>;
178BreakpointMap breakpoints_execute;
179BreakpointMap breakpoints_read;
180BreakpointMap breakpoints_write;
181
182struct Module {
183 std::string name;
184 VAddr beg;
185 VAddr end;
186};
187
188std::vector<Module> modules;
189} // Anonymous namespace
190
191void RegisterModule(std::string name, VAddr beg, VAddr end, bool add_elf_ext) {
192 Module module;
193 if (add_elf_ext) {
194 Common::SplitPath(name, nullptr, &module.name, nullptr);
195 module.name += ".elf";
196 } else {
197 module.name = std::move(name);
198 }
199 module.beg = beg;
200 module.end = end;
201 modules.push_back(std::move(module));
202}
203
204static Kernel::Thread* FindThreadById(s64 id) {
205 const auto& threads = Core::System::GetInstance().GlobalScheduler().GetThreadList();
206 for (auto& thread : threads) {
207 if (thread->GetThreadID() == static_cast<u64>(id)) {
208 current_core = thread->GetProcessorID();
209 return thread.get();
210 }
211 }
212 return nullptr;
213}
214
215static u64 RegRead(std::size_t id, Kernel::Thread* thread = nullptr) {
216 if (!thread) {
217 return 0;
218 }
219
220 const auto& thread_context = thread->GetContext64();
221
222 if (id < SP_REGISTER) {
223 return thread_context.cpu_registers[id];
224 } else if (id == SP_REGISTER) {
225 return thread_context.sp;
226 } else if (id == PC_REGISTER) {
227 return thread_context.pc;
228 } else if (id == PSTATE_REGISTER) {
229 return thread_context.pstate;
230 } else if (id > PSTATE_REGISTER && id < FPCR_REGISTER) {
231 return thread_context.vector_registers[id - UC_ARM64_REG_Q0][0];
232 } else {
233 return 0;
234 }
235}
236
237static void RegWrite(std::size_t id, u64 val, Kernel::Thread* thread = nullptr) {
238 if (!thread) {
239 return;
240 }
241
242 auto& thread_context = thread->GetContext64();
243
244 if (id < SP_REGISTER) {
245 thread_context.cpu_registers[id] = val;
246 } else if (id == SP_REGISTER) {
247 thread_context.sp = val;
248 } else if (id == PC_REGISTER) {
249 thread_context.pc = val;
250 } else if (id == PSTATE_REGISTER) {
251 thread_context.pstate = static_cast<u32>(val);
252 } else if (id > PSTATE_REGISTER && id < FPCR_REGISTER) {
253 thread_context.vector_registers[id - (PSTATE_REGISTER + 1)][0] = val;
254 }
255}
256
257static u128 FpuRead(std::size_t id, Kernel::Thread* thread = nullptr) {
258 if (!thread) {
259 return u128{0};
260 }
261
262 auto& thread_context = thread->GetContext64();
263
264 if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) {
265 return thread_context.vector_registers[id - UC_ARM64_REG_Q0];
266 } else if (id == FPCR_REGISTER) {
267 return u128{thread_context.fpcr, 0};
268 } else {
269 return u128{0};
270 }
271}
272
273static void FpuWrite(std::size_t id, u128 val, Kernel::Thread* thread = nullptr) {
274 if (!thread) {
275 return;
276 }
277
278 auto& thread_context = thread->GetContext64();
279
280 if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) {
281 thread_context.vector_registers[id - UC_ARM64_REG_Q0] = val;
282 } else if (id == FPCR_REGISTER) {
283 thread_context.fpcr = static_cast<u32>(val[0]);
284 }
285}
286
287/**
288 * Turns hex string character into the equivalent byte.
289 *
290 * @param hex Input hex character to be turned into byte.
291 */
292static u8 HexCharToValue(u8 hex) {
293 if (hex >= '0' && hex <= '9') {
294 return hex - '0';
295 } else if (hex >= 'a' && hex <= 'f') {
296 return hex - 'a' + 0xA;
297 } else if (hex >= 'A' && hex <= 'F') {
298 return hex - 'A' + 0xA;
299 }
300
301 LOG_ERROR(Debug_GDBStub, "Invalid nibble: {} ({:02X})", hex, hex);
302 return 0;
303}
304
305/**
306 * Turn nibble of byte into hex string character.
307 *
308 * @param n Nibble to be turned into hex character.
309 */
310static u8 NibbleToHex(u8 n) {
311 n &= 0xF;
312 if (n < 0xA) {
313 return '0' + n;
314 } else {
315 return 'a' + n - 0xA;
316 }
317}
318
319/**
320 * Converts input hex string characters into an array of equivalent of u8 bytes.
321 *
322 * @param src Pointer to array of output hex string characters.
323 * @param len Length of src array.
324 */
325static u32 HexToInt(const u8* src, std::size_t len) {
326 u32 output = 0;
327 while (len-- > 0) {
328 output = (output << 4) | HexCharToValue(src[0]);
329 src++;
330 }
331 return output;
332}
333
334/**
335 * Converts input hex string characters into an array of equivalent of u8 bytes.
336 *
337 * @param src Pointer to array of output hex string characters.
338 * @param len Length of src array.
339 */
340static u64 HexToLong(const u8* src, std::size_t len) {
341 u64 output = 0;
342 while (len-- > 0) {
343 output = (output << 4) | HexCharToValue(src[0]);
344 src++;
345 }
346 return output;
347}
348
349/**
350 * Converts input array of u8 bytes into their equivalent hex string characters.
351 *
352 * @param dest Pointer to buffer to store output hex string characters.
353 * @param src Pointer to array of u8 bytes.
354 * @param len Length of src array.
355 */
356static void MemToGdbHex(u8* dest, const u8* src, std::size_t len) {
357 while (len-- > 0) {
358 u8 tmp = *src++;
359 *dest++ = NibbleToHex(tmp >> 4);
360 *dest++ = NibbleToHex(tmp);
361 }
362}
363
364/**
365 * Converts input gdb-formatted hex string characters into an array of equivalent of u8 bytes.
366 *
367 * @param dest Pointer to buffer to store u8 bytes.
368 * @param src Pointer to array of output hex string characters.
369 * @param len Length of src array.
370 */
371static void GdbHexToMem(u8* dest, const u8* src, std::size_t len) {
372 while (len-- > 0) {
373 *dest++ = (HexCharToValue(src[0]) << 4) | HexCharToValue(src[1]);
374 src += 2;
375 }
376}
377
378/**
379 * Convert a u32 into a gdb-formatted hex string.
380 *
381 * @param dest Pointer to buffer to store output hex string characters.
382 * @param v Value to convert.
383 */
384static void IntToGdbHex(u8* dest, u32 v) {
385 for (int i = 0; i < 8; i += 2) {
386 dest[i + 1] = NibbleToHex(static_cast<u8>(v >> (4 * i)));
387 dest[i] = NibbleToHex(static_cast<u8>(v >> (4 * (i + 1))));
388 }
389}
390
391/**
392 * Convert a u64 into a gdb-formatted hex string.
393 *
394 * @param dest Pointer to buffer to store output hex string characters.
395 * @param v Value to convert.
396 */
397static void LongToGdbHex(u8* dest, u64 v) {
398 for (int i = 0; i < 16; i += 2) {
399 dest[i + 1] = NibbleToHex(static_cast<u8>(v >> (4 * i)));
400 dest[i] = NibbleToHex(static_cast<u8>(v >> (4 * (i + 1))));
401 }
402}
403
404/**
405 * Convert a gdb-formatted hex string into a u32.
406 *
407 * @param src Pointer to hex string.
408 */
409static u32 GdbHexToInt(const u8* src) {
410 u32 output = 0;
411
412 for (int i = 0; i < 8; i += 2) {
413 output = (output << 4) | HexCharToValue(src[7 - i - 1]);
414 output = (output << 4) | HexCharToValue(src[7 - i]);
415 }
416
417 return output;
418}
419
420/**
421 * Convert a gdb-formatted hex string into a u64.
422 *
423 * @param src Pointer to hex string.
424 */
425static u64 GdbHexToLong(const u8* src) {
426 u64 output = 0;
427
428 for (int i = 0; i < 16; i += 2) {
429 output = (output << 4) | HexCharToValue(src[15 - i - 1]);
430 output = (output << 4) | HexCharToValue(src[15 - i]);
431 }
432
433 return output;
434}
435
436/**
437 * Convert a gdb-formatted hex string into a u128.
438 *
439 * @param src Pointer to hex string.
440 */
441static u128 GdbHexToU128(const u8* src) {
442 u128 output;
443
444 for (int i = 0; i < 16; i += 2) {
445 output[0] = (output[0] << 4) | HexCharToValue(src[15 - i - 1]);
446 output[0] = (output[0] << 4) | HexCharToValue(src[15 - i]);
447 }
448
449 for (int i = 0; i < 16; i += 2) {
450 output[1] = (output[1] << 4) | HexCharToValue(src[16 + 15 - i - 1]);
451 output[1] = (output[1] << 4) | HexCharToValue(src[16 + 15 - i]);
452 }
453
454 return output;
455}
456
457/// Read a byte from the gdb client.
458static u8 ReadByte() {
459 u8 c;
460 std::size_t received_size = recv(gdbserver_socket, reinterpret_cast<char*>(&c), 1, MSG_WAITALL);
461 if (received_size != 1) {
462 LOG_ERROR(Debug_GDBStub, "recv failed: {}", received_size);
463 Shutdown();
464 }
465
466 return c;
467}
468
469/// Calculate the checksum of the current command buffer.
470static u8 CalculateChecksum(const u8* buffer, std::size_t length) {
471 return static_cast<u8>(std::accumulate(buffer, buffer + length, u8{0},
472 [](u8 lhs, u8 rhs) { return u8(lhs + rhs); }));
473}
474
475/**
476 * Get the map of breakpoints for a given breakpoint type.
477 *
478 * @param type Type of breakpoint map.
479 */
480static BreakpointMap& GetBreakpointMap(BreakpointType type) {
481 switch (type) {
482 case BreakpointType::Execute:
483 return breakpoints_execute;
484 case BreakpointType::Read:
485 return breakpoints_read;
486 case BreakpointType::Write:
487 return breakpoints_write;
488 default:
489 return breakpoints_read;
490 }
491}
492
493/**
494 * Remove the breakpoint from the given address of the specified type.
495 *
496 * @param type Type of breakpoint.
497 * @param addr Address of breakpoint.
498 */
499static void RemoveBreakpoint(BreakpointType type, VAddr addr) {
500 BreakpointMap& p = GetBreakpointMap(type);
501
502 const auto bp = p.find(addr);
503 if (bp == p.end()) {
504 return;
505 }
506
507 LOG_DEBUG(Debug_GDBStub, "gdb: removed a breakpoint: {:016X} bytes at {:016X} of type {}",
508 bp->second.len, bp->second.addr, static_cast<int>(type));
509
510 if (type == BreakpointType::Execute) {
511 auto& system = Core::System::GetInstance();
512 system.Memory().WriteBlock(bp->second.addr, bp->second.inst.data(), bp->second.inst.size());
513 system.InvalidateCpuInstructionCaches();
514 }
515 p.erase(addr);
516}
517
518BreakpointAddress GetNextBreakpointFromAddress(VAddr addr, BreakpointType type) {
519 const BreakpointMap& p = GetBreakpointMap(type);
520 const auto next_breakpoint = p.lower_bound(addr);
521 BreakpointAddress breakpoint;
522
523 if (next_breakpoint != p.end()) {
524 breakpoint.address = next_breakpoint->first;
525 breakpoint.type = type;
526 } else {
527 breakpoint.address = 0;
528 breakpoint.type = BreakpointType::None;
529 }
530
531 return breakpoint;
532}
533
534bool CheckBreakpoint(VAddr addr, BreakpointType type) {
535 if (!IsConnected()) {
536 return false;
537 }
538
539 const BreakpointMap& p = GetBreakpointMap(type);
540 const auto bp = p.find(addr);
541
542 if (bp == p.end()) {
543 return false;
544 }
545
546 u64 len = bp->second.len;
547
548 // IDA Pro defaults to 4-byte breakpoints for all non-hardware breakpoints
549 // no matter if it's a 4-byte or 2-byte instruction. When you execute a
550 // Thumb instruction with a 4-byte breakpoint set, it will set a breakpoint on
551 // two instructions instead of the single instruction you placed the breakpoint
552 // on. So, as a way to make sure that execution breakpoints are only breaking
553 // on the instruction that was specified, set the length of an execution
554 // breakpoint to 1. This should be fine since the CPU should never begin executing
555 // an instruction anywhere except the beginning of the instruction.
556 if (type == BreakpointType::Execute) {
557 len = 1;
558 }
559
560 if (bp->second.active && (addr >= bp->second.addr && addr < bp->second.addr + len)) {
561 LOG_DEBUG(Debug_GDBStub,
562 "Found breakpoint type {} @ {:016X}, range: {:016X}"
563 " - {:016X} ({:X} bytes)",
564 static_cast<int>(type), addr, bp->second.addr, bp->second.addr + len, len);
565 return true;
566 }
567
568 return false;
569}
570
571/**
572 * Send packet to gdb client.
573 *
574 * @param packet Packet to be sent to client.
575 */
576static void SendPacket(const char packet) {
577 std::size_t sent_size = send(gdbserver_socket, &packet, 1, 0);
578 if (sent_size != 1) {
579 LOG_ERROR(Debug_GDBStub, "send failed");
580 }
581}
582
583/**
584 * Send reply to gdb client.
585 *
586 * @param reply Reply to be sent to client.
587 */
588static void SendReply(const char* reply) {
589 if (!IsConnected()) {
590 return;
591 }
592
593 LOG_DEBUG(Debug_GDBStub, "Reply: {}", reply);
594
595 memset(command_buffer, 0, sizeof(command_buffer));
596
597 command_length = static_cast<u32>(strlen(reply));
598 if (command_length + 4 > sizeof(command_buffer)) {
599 LOG_ERROR(Debug_GDBStub, "command_buffer overflow in SendReply");
600 return;
601 }
602
603 memcpy(command_buffer + 1, reply, command_length);
604
605 u8 checksum = CalculateChecksum(command_buffer, command_length + 1);
606 command_buffer[0] = GDB_STUB_START;
607 command_buffer[command_length + 1] = GDB_STUB_END;
608 command_buffer[command_length + 2] = NibbleToHex(checksum >> 4);
609 command_buffer[command_length + 3] = NibbleToHex(checksum);
610
611 u8* ptr = command_buffer;
612 u32 left = command_length + 4;
613 while (left > 0) {
614 int sent_size = send(gdbserver_socket, reinterpret_cast<char*>(ptr), left, 0);
615 if (sent_size < 0) {
616 LOG_ERROR(Debug_GDBStub, "gdb: send failed");
617 return Shutdown();
618 }
619
620 left -= sent_size;
621 ptr += sent_size;
622 }
623}
624
625/// Handle query command from gdb client.
626static void HandleQuery() {
627 LOG_DEBUG(Debug_GDBStub, "gdb: query '{}'", command_buffer + 1);
628
629 const char* query = reinterpret_cast<const char*>(command_buffer + 1);
630
631 if (strcmp(query, "TStatus") == 0) {
632 SendReply("T0");
633 } else if (strncmp(query, "Supported", strlen("Supported")) == 0) {
634 // PacketSize needs to be large enough for target xml
635 std::string buffer = "PacketSize=2000;qXfer:features:read+;qXfer:threads:read+";
636 if (!modules.empty()) {
637 buffer += ";qXfer:libraries:read+";
638 }
639 SendReply(buffer.c_str());
640 } else if (strncmp(query, "Xfer:features:read:target.xml:",
641 strlen("Xfer:features:read:target.xml:")) == 0) {
642 SendReply(target_xml);
643 } else if (strncmp(query, "Offsets", strlen("Offsets")) == 0) {
644 const VAddr base_address =
645 Core::System::GetInstance().CurrentProcess()->PageTable().GetCodeRegionStart();
646 std::string buffer = fmt::format("TextSeg={:0x}", base_address);
647 SendReply(buffer.c_str());
648 } else if (strncmp(query, "fThreadInfo", strlen("fThreadInfo")) == 0) {
649 std::string val = "m";
650 const auto& threads = Core::System::GetInstance().GlobalScheduler().GetThreadList();
651 for (const auto& thread : threads) {
652 val += fmt::format("{:x},", thread->GetThreadID());
653 }
654 val.pop_back();
655 SendReply(val.c_str());
656 } else if (strncmp(query, "sThreadInfo", strlen("sThreadInfo")) == 0) {
657 SendReply("l");
658 } else if (strncmp(query, "Xfer:threads:read", strlen("Xfer:threads:read")) == 0) {
659 std::string buffer;
660 buffer += "l<?xml version=\"1.0\"?>";
661 buffer += "<threads>";
662 const auto& threads = Core::System::GetInstance().GlobalScheduler().GetThreadList();
663 for (const auto& thread : threads) {
664 buffer +=
665 fmt::format(R"*(<thread id="{:x}" core="{:d}" name="Thread {:x}"></thread>)*",
666 thread->GetThreadID(), thread->GetProcessorID(), thread->GetThreadID());
667 }
668 buffer += "</threads>";
669 SendReply(buffer.c_str());
670 } else if (strncmp(query, "Xfer:libraries:read", strlen("Xfer:libraries:read")) == 0) {
671 std::string buffer;
672 buffer += "l<?xml version=\"1.0\"?>";
673 buffer += "<library-list>";
674 for (const auto& module : modules) {
675 buffer +=
676 fmt::format(R"*("<library name = "{}"><segment address = "0x{:x}"/></library>)*",
677 module.name, module.beg);
678 }
679 buffer += "</library-list>";
680 SendReply(buffer.c_str());
681 } else {
682 SendReply("");
683 }
684}
685
686/// Handle set thread command from gdb client.
687static void HandleSetThread() {
688 int thread_id = -1;
689 if (command_buffer[2] != '-') {
690 thread_id = static_cast<int>(HexToInt(command_buffer + 2, command_length - 2));
691 }
692 if (thread_id >= 1) {
693 current_thread = FindThreadById(thread_id);
694 }
695 if (!current_thread) {
696 thread_id = 1;
697 current_thread = FindThreadById(thread_id);
698 }
699 if (current_thread) {
700 SendReply("OK");
701 return;
702 }
703 SendReply("E01");
704}
705
706/// Handle thread alive command from gdb client.
707static void HandleThreadAlive() {
708 int thread_id = static_cast<int>(HexToInt(command_buffer + 1, command_length - 1));
709 if (thread_id == 0) {
710 thread_id = 1;
711 }
712 if (FindThreadById(thread_id)) {
713 SendReply("OK");
714 return;
715 }
716 SendReply("E01");
717}
718
719/**
720 * Send signal packet to client.
721 *
722 * @param signal Signal to be sent to client.
723 */
724static void SendSignal(Kernel::Thread* thread, u32 signal, bool full = true) {
725 if (gdbserver_socket == -1) {
726 return;
727 }
728
729 latest_signal = signal;
730
731 if (!thread) {
732 full = false;
733 }
734
735 std::string buffer;
736 if (full) {
737 buffer = fmt::format("T{:02x}{:02x}:{:016x};{:02x}:{:016x};{:02x}:{:016x}", latest_signal,
738 PC_REGISTER, Common::swap64(RegRead(PC_REGISTER, thread)), SP_REGISTER,
739 Common::swap64(RegRead(SP_REGISTER, thread)), LR_REGISTER,
740 Common::swap64(RegRead(LR_REGISTER, thread)));
741 } else {
742 buffer = fmt::format("T{:02x}", latest_signal);
743 }
744
745 if (thread) {
746 buffer += fmt::format(";thread:{:x};", thread->GetThreadID());
747 }
748
749 SendReply(buffer.c_str());
750}
751
752/// Read command from gdb client.
753static void ReadCommand() {
754 command_length = 0;
755 memset(command_buffer, 0, sizeof(command_buffer));
756
757 u8 c = ReadByte();
758 if (c == '+') {
759 // ignore ack
760 return;
761 } else if (c == 0x03) {
762 LOG_INFO(Debug_GDBStub, "gdb: found break command");
763 halt_loop = true;
764 SendSignal(current_thread, SIGTRAP);
765 return;
766 } else if (c != GDB_STUB_START) {
767 LOG_DEBUG(Debug_GDBStub, "gdb: read invalid byte {:02X}", c);
768 return;
769 }
770
771 while ((c = ReadByte()) != GDB_STUB_END) {
772 if (command_length >= sizeof(command_buffer)) {
773 LOG_ERROR(Debug_GDBStub, "gdb: command_buffer overflow");
774 SendPacket(GDB_STUB_NACK);
775 return;
776 }
777 command_buffer[command_length++] = c;
778 }
779
780 u8 checksum_received = HexCharToValue(ReadByte()) << 4;
781 checksum_received |= HexCharToValue(ReadByte());
782
783 u8 checksum_calculated = CalculateChecksum(command_buffer, command_length);
784
785 if (checksum_received != checksum_calculated) {
786 LOG_ERROR(Debug_GDBStub,
787 "gdb: invalid checksum: calculated {:02X} and read {:02X} for ${}# (length: {})",
788 checksum_calculated, checksum_received, command_buffer, command_length);
789
790 command_length = 0;
791
792 SendPacket(GDB_STUB_NACK);
793 return;
794 }
795
796 SendPacket(GDB_STUB_ACK);
797}
798
799/// Check if there is data to be read from the gdb client.
800static bool IsDataAvailable() {
801 if (!IsConnected()) {
802 return false;
803 }
804
805 fd_set fd_socket;
806
807 FD_ZERO(&fd_socket);
808 FD_SET(static_cast<u32>(gdbserver_socket), &fd_socket);
809
810 struct timeval t;
811 t.tv_sec = 0;
812 t.tv_usec = 0;
813
814 if (select(gdbserver_socket + 1, &fd_socket, nullptr, nullptr, &t) < 0) {
815 LOG_ERROR(Debug_GDBStub, "select failed");
816 return false;
817 }
818
819 return FD_ISSET(gdbserver_socket, &fd_socket) != 0;
820}
821
822/// Send requested register to gdb client.
823static void ReadRegister() {
824 static u8 reply[64];
825 memset(reply, 0, sizeof(reply));
826
827 u32 id = HexCharToValue(command_buffer[1]);
828 if (command_buffer[2] != '\0') {
829 id <<= 4;
830 id |= HexCharToValue(command_buffer[2]);
831 }
832
833 if (id <= SP_REGISTER) {
834 LongToGdbHex(reply, RegRead(id, current_thread));
835 } else if (id == PC_REGISTER) {
836 LongToGdbHex(reply, RegRead(id, current_thread));
837 } else if (id == PSTATE_REGISTER) {
838 IntToGdbHex(reply, static_cast<u32>(RegRead(id, current_thread)));
839 } else if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) {
840 u128 r = FpuRead(id, current_thread);
841 LongToGdbHex(reply, r[0]);
842 LongToGdbHex(reply + 16, r[1]);
843 } else if (id == FPCR_REGISTER) {
844 u128 r = FpuRead(id, current_thread);
845 IntToGdbHex(reply, static_cast<u32>(r[0]));
846 } else if (id == FPCR_REGISTER + 1) {
847 u128 r = FpuRead(id, current_thread);
848 IntToGdbHex(reply, static_cast<u32>(r[0] >> 32));
849 }
850
851 SendReply(reinterpret_cast<char*>(reply));
852}
853
854/// Send all registers to the gdb client.
855static void ReadRegisters() {
856 static u8 buffer[GDB_BUFFER_SIZE - 4];
857 memset(buffer, 0, sizeof(buffer));
858
859 u8* bufptr = buffer;
860
861 for (u32 reg = 0; reg <= SP_REGISTER; reg++) {
862 LongToGdbHex(bufptr + reg * 16, RegRead(reg, current_thread));
863 }
864
865 bufptr += 32 * 16;
866
867 LongToGdbHex(bufptr, RegRead(PC_REGISTER, current_thread));
868
869 bufptr += 16;
870
871 IntToGdbHex(bufptr, static_cast<u32>(RegRead(PSTATE_REGISTER, current_thread)));
872
873 bufptr += 8;
874
875 u128 r;
876
877 for (u32 reg = UC_ARM64_REG_Q0; reg < FPCR_REGISTER; reg++) {
878 r = FpuRead(reg, current_thread);
879 LongToGdbHex(bufptr + reg * 32, r[0]);
880 LongToGdbHex(bufptr + reg * 32 + 16, r[1]);
881 }
882
883 bufptr += 32 * 32;
884
885 r = FpuRead(FPCR_REGISTER, current_thread);
886 IntToGdbHex(bufptr, static_cast<u32>(r[0]));
887
888 bufptr += 8;
889
890 SendReply(reinterpret_cast<char*>(buffer));
891}
892
893/// Modify data of register specified by gdb client.
894static void WriteRegister() {
895 const u8* buffer_ptr = command_buffer + 3;
896
897 u32 id = HexCharToValue(command_buffer[1]);
898 if (command_buffer[2] != '=') {
899 ++buffer_ptr;
900 id <<= 4;
901 id |= HexCharToValue(command_buffer[2]);
902 }
903
904 if (id <= SP_REGISTER) {
905 RegWrite(id, GdbHexToLong(buffer_ptr), current_thread);
906 } else if (id == PC_REGISTER) {
907 RegWrite(id, GdbHexToLong(buffer_ptr), current_thread);
908 } else if (id == PSTATE_REGISTER) {
909 RegWrite(id, GdbHexToInt(buffer_ptr), current_thread);
910 } else if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) {
911 FpuWrite(id, GdbHexToU128(buffer_ptr), current_thread);
912 } else if (id == FPCR_REGISTER) {
913 } else if (id == FPCR_REGISTER + 1) {
914 }
915
916 // Update ARM context, skipping scheduler - no running threads at this point
917 Core::System::GetInstance()
918 .ArmInterface(current_core)
919 .LoadContext(current_thread->GetContext64());
920
921 SendReply("OK");
922}
923
924/// Modify all registers with data received from the client.
925static void WriteRegisters() {
926 const u8* buffer_ptr = command_buffer + 1;
927
928 if (command_buffer[0] != 'G')
929 return SendReply("E01");
930
931 for (u32 i = 0, reg = 0; reg <= FPCR_REGISTER; i++, reg++) {
932 if (reg <= SP_REGISTER) {
933 RegWrite(reg, GdbHexToLong(buffer_ptr + i * 16), current_thread);
934 } else if (reg == PC_REGISTER) {
935 RegWrite(PC_REGISTER, GdbHexToLong(buffer_ptr + i * 16), current_thread);
936 } else if (reg == PSTATE_REGISTER) {
937 RegWrite(PSTATE_REGISTER, GdbHexToInt(buffer_ptr + i * 16), current_thread);
938 } else if (reg >= UC_ARM64_REG_Q0 && reg < FPCR_REGISTER) {
939 RegWrite(reg, GdbHexToLong(buffer_ptr + i * 16), current_thread);
940 } else if (reg == FPCR_REGISTER) {
941 RegWrite(FPCR_REGISTER, GdbHexToLong(buffer_ptr + i * 16), current_thread);
942 } else if (reg == FPCR_REGISTER + 1) {
943 RegWrite(FPCR_REGISTER, GdbHexToLong(buffer_ptr + i * 16), current_thread);
944 }
945 }
946
947 // Update ARM context, skipping scheduler - no running threads at this point
948 Core::System::GetInstance()
949 .ArmInterface(current_core)
950 .LoadContext(current_thread->GetContext64());
951
952 SendReply("OK");
953}
954
955/// Read location in memory specified by gdb client.
956static void ReadMemory() {
957 static u8 reply[GDB_BUFFER_SIZE - 4];
958
959 auto start_offset = command_buffer + 1;
960 const auto addr_pos = std::find(start_offset, command_buffer + command_length, ',');
961 const VAddr addr = HexToLong(start_offset, static_cast<u64>(addr_pos - start_offset));
962
963 start_offset = addr_pos + 1;
964 const u64 len =
965 HexToLong(start_offset, static_cast<u64>((command_buffer + command_length) - start_offset));
966
967 LOG_DEBUG(Debug_GDBStub, "gdb: addr: {:016X} len: {:016X}", addr, len);
968
969 if (len * 2 > sizeof(reply)) {
970 SendReply("E01");
971 }
972
973 auto& memory = Core::System::GetInstance().Memory();
974 if (!memory.IsValidVirtualAddress(addr)) {
975 return SendReply("E00");
976 }
977
978 std::vector<u8> data(len);
979 memory.ReadBlock(addr, data.data(), len);
980
981 MemToGdbHex(reply, data.data(), len);
982 reply[len * 2] = '\0';
983 SendReply(reinterpret_cast<char*>(reply));
984}
985
986/// Modify location in memory with data received from the gdb client.
987static void WriteMemory() {
988 auto start_offset = command_buffer + 1;
989 const auto addr_pos = std::find(start_offset, command_buffer + command_length, ',');
990 const VAddr addr = HexToLong(start_offset, static_cast<u64>(addr_pos - start_offset));
991
992 start_offset = addr_pos + 1;
993 const auto len_pos = std::find(start_offset, command_buffer + command_length, ':');
994 const u64 len = HexToLong(start_offset, static_cast<u64>(len_pos - start_offset));
995
996 auto& system = Core::System::GetInstance();
997 auto& memory = system.Memory();
998 if (!memory.IsValidVirtualAddress(addr)) {
999 return SendReply("E00");
1000 }
1001
1002 std::vector<u8> data(len);
1003 GdbHexToMem(data.data(), len_pos + 1, len);
1004 memory.WriteBlock(addr, data.data(), len);
1005 system.InvalidateCpuInstructionCaches();
1006 SendReply("OK");
1007}
1008
1009void Break(bool is_memory_break) {
1010 send_trap = true;
1011
1012 memory_break = is_memory_break;
1013}
1014
1015/// Tell the CPU that it should perform a single step.
1016static void Step() {
1017 if (command_length > 1) {
1018 RegWrite(PC_REGISTER, GdbHexToLong(command_buffer + 1), current_thread);
1019 // Update ARM context, skipping scheduler - no running threads at this point
1020 Core::System::GetInstance()
1021 .ArmInterface(current_core)
1022 .LoadContext(current_thread->GetContext64());
1023 }
1024 step_loop = true;
1025 halt_loop = true;
1026 send_trap = true;
1027 Core::System::GetInstance().InvalidateCpuInstructionCaches();
1028}
1029
1030/// Tell the CPU if we hit a memory breakpoint.
1031bool IsMemoryBreak() {
1032 if (!IsConnected()) {
1033 return false;
1034 }
1035
1036 return memory_break;
1037}
1038
1039/// Tell the CPU to continue executing.
1040static void Continue() {
1041 memory_break = false;
1042 step_loop = false;
1043 halt_loop = false;
1044 Core::System::GetInstance().InvalidateCpuInstructionCaches();
1045}
1046
1047/**
1048 * Commit breakpoint to list of breakpoints.
1049 *
1050 * @param type Type of breakpoint.
1051 * @param addr Address of breakpoint.
1052 * @param len Length of breakpoint.
1053 */
1054static bool CommitBreakpoint(BreakpointType type, VAddr addr, u64 len) {
1055 BreakpointMap& p = GetBreakpointMap(type);
1056
1057 Breakpoint breakpoint;
1058 breakpoint.active = true;
1059 breakpoint.addr = addr;
1060 breakpoint.len = len;
1061
1062 auto& system = Core::System::GetInstance();
1063 auto& memory = system.Memory();
1064 memory.ReadBlock(addr, breakpoint.inst.data(), breakpoint.inst.size());
1065
1066 static constexpr std::array<u8, 4> btrap{0x00, 0x7d, 0x20, 0xd4};
1067 if (type == BreakpointType::Execute) {
1068 memory.WriteBlock(addr, btrap.data(), btrap.size());
1069 system.InvalidateCpuInstructionCaches();
1070 }
1071 p.insert({addr, breakpoint});
1072
1073 LOG_DEBUG(Debug_GDBStub, "gdb: added {} breakpoint: {:016X} bytes at {:016X}",
1074 static_cast<int>(type), breakpoint.len, breakpoint.addr);
1075
1076 return true;
1077}
1078
1079/// Handle add breakpoint command from gdb client.
1080static void AddBreakpoint() {
1081 BreakpointType type;
1082
1083 u8 type_id = HexCharToValue(command_buffer[1]);
1084 switch (type_id) {
1085 case 0:
1086 case 1:
1087 type = BreakpointType::Execute;
1088 break;
1089 case 2:
1090 type = BreakpointType::Write;
1091 break;
1092 case 3:
1093 type = BreakpointType::Read;
1094 break;
1095 case 4:
1096 type = BreakpointType::Access;
1097 break;
1098 default:
1099 return SendReply("E01");
1100 }
1101
1102 auto start_offset = command_buffer + 3;
1103 auto addr_pos = std::find(start_offset, command_buffer + command_length, ',');
1104 VAddr addr = HexToLong(start_offset, static_cast<u64>(addr_pos - start_offset));
1105
1106 start_offset = addr_pos + 1;
1107 u64 len =
1108 HexToLong(start_offset, static_cast<u64>((command_buffer + command_length) - start_offset));
1109
1110 if (type == BreakpointType::Access) {
1111 // Access is made up of Read and Write types, so add both breakpoints
1112 type = BreakpointType::Read;
1113
1114 if (!CommitBreakpoint(type, addr, len)) {
1115 return SendReply("E02");
1116 }
1117
1118 type = BreakpointType::Write;
1119 }
1120
1121 if (!CommitBreakpoint(type, addr, len)) {
1122 return SendReply("E02");
1123 }
1124
1125 SendReply("OK");
1126}
1127
1128/// Handle remove breakpoint command from gdb client.
1129static void RemoveBreakpoint() {
1130 BreakpointType type;
1131
1132 u8 type_id = HexCharToValue(command_buffer[1]);
1133 switch (type_id) {
1134 case 0:
1135 case 1:
1136 type = BreakpointType::Execute;
1137 break;
1138 case 2:
1139 type = BreakpointType::Write;
1140 break;
1141 case 3:
1142 type = BreakpointType::Read;
1143 break;
1144 case 4:
1145 type = BreakpointType::Access;
1146 break;
1147 default:
1148 return SendReply("E01");
1149 }
1150
1151 auto start_offset = command_buffer + 3;
1152 auto addr_pos = std::find(start_offset, command_buffer + command_length, ',');
1153 VAddr addr = HexToLong(start_offset, static_cast<u64>(addr_pos - start_offset));
1154
1155 if (type == BreakpointType::Access) {
1156 // Access is made up of Read and Write types, so add both breakpoints
1157 type = BreakpointType::Read;
1158 RemoveBreakpoint(type, addr);
1159
1160 type = BreakpointType::Write;
1161 }
1162
1163 RemoveBreakpoint(type, addr);
1164 SendReply("OK");
1165}
1166
1167void HandlePacket() {
1168 if (!IsConnected()) {
1169 if (defer_start) {
1170 ToggleServer(true);
1171 }
1172 return;
1173 }
1174
1175 if (!IsDataAvailable()) {
1176 return;
1177 }
1178
1179 ReadCommand();
1180 if (command_length == 0) {
1181 return;
1182 }
1183
1184 LOG_DEBUG(Debug_GDBStub, "Packet: {}", command_buffer);
1185
1186 switch (command_buffer[0]) {
1187 case 'q':
1188 HandleQuery();
1189 break;
1190 case 'H':
1191 HandleSetThread();
1192 break;
1193 case '?':
1194 SendSignal(current_thread, latest_signal);
1195 break;
1196 case 'k':
1197 Shutdown();
1198 LOG_INFO(Debug_GDBStub, "killed by gdb");
1199 return;
1200 case 'g':
1201 ReadRegisters();
1202 break;
1203 case 'G':
1204 WriteRegisters();
1205 break;
1206 case 'p':
1207 ReadRegister();
1208 break;
1209 case 'P':
1210 WriteRegister();
1211 break;
1212 case 'm':
1213 ReadMemory();
1214 break;
1215 case 'M':
1216 WriteMemory();
1217 break;
1218 case 's':
1219 Step();
1220 return;
1221 case 'C':
1222 case 'c':
1223 Continue();
1224 return;
1225 case 'z':
1226 RemoveBreakpoint();
1227 break;
1228 case 'Z':
1229 AddBreakpoint();
1230 break;
1231 case 'T':
1232 HandleThreadAlive();
1233 break;
1234 default:
1235 SendReply("");
1236 break;
1237 }
1238}
1239
1240void SetServerPort(u16 port) {
1241 gdbstub_port = port;
1242}
1243
1244void ToggleServer(bool status) {
1245 if (status) {
1246 server_enabled = status;
1247
1248 // Start server
1249 if (!IsConnected() && Core::System::GetInstance().IsPoweredOn()) {
1250 Init();
1251 }
1252 } else {
1253 // Stop server
1254 if (IsConnected()) {
1255 Shutdown();
1256 }
1257
1258 server_enabled = status;
1259 }
1260}
1261
1262void DeferStart() {
1263 defer_start = true;
1264}
1265
1266static void Init(u16 port) {
1267 if (!server_enabled) {
1268 // Set the halt loop to false in case the user enabled the gdbstub mid-execution.
1269 // This way the CPU can still execute normally.
1270 halt_loop = false;
1271 step_loop = false;
1272 return;
1273 }
1274
1275 // Setup initial gdbstub status
1276 halt_loop = true;
1277 step_loop = false;
1278
1279 breakpoints_execute.clear();
1280 breakpoints_read.clear();
1281 breakpoints_write.clear();
1282
1283 modules.clear();
1284
1285 // Start gdb server
1286 LOG_INFO(Debug_GDBStub, "Starting GDB server on port {}...", port);
1287
1288 sockaddr_in saddr_server = {};
1289 saddr_server.sin_family = AF_INET;
1290 saddr_server.sin_port = htons(port);
1291 saddr_server.sin_addr.s_addr = INADDR_ANY;
1292
1293#ifdef _WIN32
1294 WSAStartup(MAKEWORD(2, 2), &InitData);
1295#endif
1296
1297 int tmpsock = static_cast<int>(socket(PF_INET, SOCK_STREAM, 0));
1298 if (tmpsock == -1) {
1299 LOG_ERROR(Debug_GDBStub, "Failed to create gdb socket");
1300 }
1301
1302 // Set socket to SO_REUSEADDR so it can always bind on the same port
1303 int reuse_enabled = 1;
1304 if (setsockopt(tmpsock, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse_enabled,
1305 sizeof(reuse_enabled)) < 0) {
1306 LOG_ERROR(Debug_GDBStub, "Failed to set gdb socket option");
1307 }
1308
1309 const sockaddr* server_addr = reinterpret_cast<const sockaddr*>(&saddr_server);
1310 socklen_t server_addrlen = sizeof(saddr_server);
1311 if (bind(tmpsock, server_addr, server_addrlen) < 0) {
1312 LOG_ERROR(Debug_GDBStub, "Failed to bind gdb socket");
1313 }
1314
1315 if (listen(tmpsock, 1) < 0) {
1316 LOG_ERROR(Debug_GDBStub, "Failed to listen to gdb socket");
1317 }
1318
1319 // Wait for gdb to connect
1320 LOG_INFO(Debug_GDBStub, "Waiting for gdb to connect...");
1321 sockaddr_in saddr_client;
1322 sockaddr* client_addr = reinterpret_cast<sockaddr*>(&saddr_client);
1323 socklen_t client_addrlen = sizeof(saddr_client);
1324 gdbserver_socket = static_cast<int>(accept(tmpsock, client_addr, &client_addrlen));
1325 if (gdbserver_socket < 0) {
1326 // In the case that we couldn't start the server for whatever reason, just start CPU
1327 // execution like normal.
1328 halt_loop = false;
1329 step_loop = false;
1330
1331 LOG_ERROR(Debug_GDBStub, "Failed to accept gdb client");
1332 } else {
1333 LOG_INFO(Debug_GDBStub, "Client connected.");
1334 saddr_client.sin_addr.s_addr = ntohl(saddr_client.sin_addr.s_addr);
1335 }
1336
1337 // Clean up temporary socket if it's still alive at this point.
1338 if (tmpsock != -1) {
1339 shutdown(tmpsock, SHUT_RDWR);
1340 }
1341}
1342
1343void Init() {
1344 Init(gdbstub_port);
1345}
1346
1347void Shutdown() {
1348 if (!server_enabled) {
1349 return;
1350 }
1351 defer_start = false;
1352
1353 LOG_INFO(Debug_GDBStub, "Stopping GDB ...");
1354 if (gdbserver_socket != -1) {
1355 shutdown(gdbserver_socket, SHUT_RDWR);
1356 gdbserver_socket = -1;
1357 }
1358
1359#ifdef _WIN32
1360 WSACleanup();
1361#endif
1362
1363 LOG_INFO(Debug_GDBStub, "GDB stopped.");
1364}
1365
1366bool IsServerEnabled() {
1367 return server_enabled;
1368}
1369
1370bool IsConnected() {
1371 return IsServerEnabled() && gdbserver_socket != -1;
1372}
1373
1374bool GetCpuHaltFlag() {
1375 return halt_loop;
1376}
1377
1378bool GetCpuStepFlag() {
1379 return step_loop;
1380}
1381
1382void SetCpuStepFlag(bool is_step) {
1383 step_loop = is_step;
1384}
1385
1386void SendTrap(Kernel::Thread* thread, int trap) {
1387 if (!send_trap) {
1388 return;
1389 }
1390
1391 current_thread = thread;
1392 SendSignal(thread, trap);
1393
1394 halt_loop = true;
1395 send_trap = false;
1396}
1397}; // namespace GDBStub
diff --git a/src/core/gdbstub/gdbstub.h b/src/core/gdbstub/gdbstub.h
deleted file mode 100644
index 8fe3c320b..000000000
--- a/src/core/gdbstub/gdbstub.h
+++ /dev/null
@@ -1,114 +0,0 @@
1// Copyright 2013 Dolphin Emulator Project
2// Licensed under GPLv2+
3// Refer to the license.txt file included.
4
5// Originally written by Sven Peter <sven@fail0verflow.com> for anergistic.
6
7#pragma once
8
9#include <string>
10#include "common/common_types.h"
11#include "core/hle/kernel/thread.h"
12
13namespace GDBStub {
14
15/// Breakpoint Method
16enum class BreakpointType {
17 None, ///< None
18 Execute, ///< Execution Breakpoint
19 Read, ///< Read Breakpoint
20 Write, ///< Write Breakpoint
21 Access ///< Access (R/W) Breakpoint
22};
23
24struct BreakpointAddress {
25 VAddr address;
26 BreakpointType type;
27};
28
29/**
30 * Set the port the gdbstub should use to listen for connections.
31 *
32 * @param port Port to listen for connection
33 */
34void SetServerPort(u16 port);
35
36/**
37 * Starts or stops the server if possible.
38 *
39 * @param status Set the server to enabled or disabled.
40 */
41void ToggleServer(bool status);
42
43/// Start the gdbstub server.
44void Init();
45
46/**
47 * Defer initialization of the gdbstub to the first packet processing functions.
48 * This avoids a case where the gdbstub thread is frozen after initialization
49 * and fails to respond in time to packets.
50 */
51void DeferStart();
52
53/// Stop gdbstub server.
54void Shutdown();
55
56/// Checks if the gdbstub server is enabled.
57bool IsServerEnabled();
58
59/// Returns true if there is an active socket connection.
60bool IsConnected();
61
62/// Register module.
63void RegisterModule(std::string name, VAddr beg, VAddr end, bool add_elf_ext = true);
64
65/**
66 * Signal to the gdbstub server that it should halt CPU execution.
67 *
68 * @param is_memory_break If true, the break resulted from a memory breakpoint.
69 */
70void Break(bool is_memory_break = false);
71
72/// Determine if there was a memory breakpoint.
73bool IsMemoryBreak();
74
75/// Read and handle packet from gdb client.
76void HandlePacket();
77
78/**
79 * Get the nearest breakpoint of the specified type at the given address.
80 *
81 * @param addr Address to search from.
82 * @param type Type of breakpoint.
83 */
84BreakpointAddress GetNextBreakpointFromAddress(VAddr addr, GDBStub::BreakpointType type);
85
86/**
87 * Check if a breakpoint of the specified type exists at the given address.
88 *
89 * @param addr Address of breakpoint.
90 * @param type Type of breakpoint.
91 */
92bool CheckBreakpoint(VAddr addr, GDBStub::BreakpointType type);
93
94/// If set to true, the CPU will halt at the beginning of the next CPU loop.
95bool GetCpuHaltFlag();
96
97/// If set to true and the CPU is halted, the CPU will step one instruction.
98bool GetCpuStepFlag();
99
100/**
101 * When set to true, the CPU will step one instruction when the CPU is halted next.
102 *
103 * @param is_step
104 */
105void SetCpuStepFlag(bool is_step);
106
107/**
108 * Send trap signal from thread back to the gdbstub server.
109 *
110 * @param thread Sending thread.
111 * @param trap Trap no.
112 */
113void SendTrap(Kernel::Thread* thread, int trap);
114} // namespace GDBStub
diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/ipc_helpers.h
index 1b503331f..56cc911d1 100644
--- a/src/core/hle/ipc_helpers.h
+++ b/src/core/hle/ipc_helpers.h
@@ -12,7 +12,6 @@
12#include <utility> 12#include <utility>
13#include "common/assert.h" 13#include "common/assert.h"
14#include "common/common_types.h" 14#include "common/common_types.h"
15#include "core/core.h"
16#include "core/hle/ipc.h" 15#include "core/hle/ipc.h"
17#include "core/hle/kernel/client_port.h" 16#include "core/hle/kernel/client_port.h"
18#include "core/hle/kernel/client_session.h" 17#include "core/hle/kernel/client_session.h"
@@ -38,10 +37,11 @@ public:
38 explicit RequestHelperBase(Kernel::HLERequestContext& context) 37 explicit RequestHelperBase(Kernel::HLERequestContext& context)
39 : context(&context), cmdbuf(context.CommandBuffer()) {} 38 : context(&context), cmdbuf(context.CommandBuffer()) {}
40 39
41 void Skip(unsigned size_in_words, bool set_to_null) { 40 void Skip(u32 size_in_words, bool set_to_null) {
42 if (set_to_null) 41 if (set_to_null) {
43 memset(cmdbuf + index, 0, size_in_words * sizeof(u32)); 42 memset(cmdbuf + index, 0, size_in_words * sizeof(u32));
44 index += size_in_words; 43 }
44 index += static_cast<ptrdiff_t>(size_in_words);
45 } 45 }
46 46
47 /** 47 /**
@@ -49,15 +49,15 @@ public:
49 */ 49 */
50 void AlignWithPadding() { 50 void AlignWithPadding() {
51 if (index & 3) { 51 if (index & 3) {
52 Skip(4 - (index & 3), true); 52 Skip(static_cast<u32>(4 - (index & 3)), true);
53 } 53 }
54 } 54 }
55 55
56 unsigned GetCurrentOffset() const { 56 u32 GetCurrentOffset() const {
57 return static_cast<unsigned>(index); 57 return static_cast<u32>(index);
58 } 58 }
59 59
60 void SetCurrentOffset(unsigned offset) { 60 void SetCurrentOffset(u32 offset) {
61 index = static_cast<ptrdiff_t>(offset); 61 index = static_cast<ptrdiff_t>(offset);
62 } 62 }
63}; 63};
@@ -72,14 +72,12 @@ public:
72 AlwaysMoveHandles = 1, 72 AlwaysMoveHandles = 1,
73 }; 73 };
74 74
75 explicit ResponseBuilder(u32* command_buffer) : RequestHelperBase(command_buffer) {}
76
77 explicit ResponseBuilder(Kernel::HLERequestContext& context, u32 normal_params_size, 75 explicit ResponseBuilder(Kernel::HLERequestContext& context, u32 normal_params_size,
78 u32 num_handles_to_copy = 0, u32 num_objects_to_move = 0, 76 u32 num_handles_to_copy = 0, u32 num_objects_to_move = 0,
79 Flags flags = Flags::None) 77 Flags flags = Flags::None)
80
81 : RequestHelperBase(context), normal_params_size(normal_params_size), 78 : RequestHelperBase(context), normal_params_size(normal_params_size),
82 num_handles_to_copy(num_handles_to_copy), num_objects_to_move(num_objects_to_move) { 79 num_handles_to_copy(num_handles_to_copy),
80 num_objects_to_move(num_objects_to_move), kernel{context.kernel} {
83 81
84 memset(cmdbuf, 0, sizeof(u32) * IPC::COMMAND_BUFFER_LENGTH); 82 memset(cmdbuf, 0, sizeof(u32) * IPC::COMMAND_BUFFER_LENGTH);
85 83
@@ -89,7 +87,7 @@ public:
89 87
90 // The entire size of the raw data section in u32 units, including the 16 bytes of mandatory 88 // The entire size of the raw data section in u32 units, including the 16 bytes of mandatory
91 // padding. 89 // padding.
92 u32 raw_data_size = sizeof(IPC::DataPayloadHeader) / 4 + 4 + normal_params_size; 90 u64 raw_data_size = sizeof(IPC::DataPayloadHeader) / 4 + 4 + normal_params_size;
93 91
94 u32 num_handles_to_move{}; 92 u32 num_handles_to_move{};
95 u32 num_domain_objects{}; 93 u32 num_domain_objects{};
@@ -105,7 +103,7 @@ public:
105 raw_data_size += sizeof(DomainMessageHeader) / 4 + num_domain_objects; 103 raw_data_size += sizeof(DomainMessageHeader) / 4 + num_domain_objects;
106 } 104 }
107 105
108 header.data_size.Assign(raw_data_size); 106 header.data_size.Assign(static_cast<u32>(raw_data_size));
109 if (num_handles_to_copy || num_handles_to_move) { 107 if (num_handles_to_copy || num_handles_to_move) {
110 header.enable_handle_descriptor.Assign(1); 108 header.enable_handle_descriptor.Assign(1);
111 } 109 }
@@ -139,7 +137,6 @@ public:
139 if (context->Session()->IsDomain()) { 137 if (context->Session()->IsDomain()) {
140 context->AddDomainObject(std::move(iface)); 138 context->AddDomainObject(std::move(iface));
141 } else { 139 } else {
142 auto& kernel = Core::System::GetInstance().Kernel();
143 auto [client, server] = Kernel::Session::Create(kernel, iface->GetServiceName()); 140 auto [client, server] = Kernel::Session::Create(kernel, iface->GetServiceName());
144 context->AddMoveObject(std::move(client)); 141 context->AddMoveObject(std::move(client));
145 iface->ClientConnected(std::move(server)); 142 iface->ClientConnected(std::move(server));
@@ -169,8 +166,23 @@ public:
169 ValidateHeader(); 166 ValidateHeader();
170 } 167 }
171 168
169 void PushImpl(s8 value);
170 void PushImpl(s16 value);
171 void PushImpl(s32 value);
172 void PushImpl(s64 value);
173 void PushImpl(u8 value);
174 void PushImpl(u16 value);
175 void PushImpl(u32 value);
176 void PushImpl(u64 value);
177 void PushImpl(float value);
178 void PushImpl(double value);
179 void PushImpl(bool value);
180 void PushImpl(ResultCode value);
181
172 template <typename T> 182 template <typename T>
173 void Push(T value); 183 void Push(T value) {
184 return PushImpl(value);
185 }
174 186
175 template <typename First, typename... Other> 187 template <typename First, typename... Other>
176 void Push(const First& first_value, const Other&... other_values); 188 void Push(const First& first_value, const Other&... other_values);
@@ -213,17 +225,16 @@ private:
213 u32 num_handles_to_copy{}; 225 u32 num_handles_to_copy{};
214 u32 num_objects_to_move{}; ///< Domain objects or move handles, context dependent 226 u32 num_objects_to_move{}; ///< Domain objects or move handles, context dependent
215 std::ptrdiff_t datapayload_index{}; 227 std::ptrdiff_t datapayload_index{};
228 Kernel::KernelCore& kernel;
216}; 229};
217 230
218/// Push /// 231/// Push ///
219 232
220template <> 233inline void ResponseBuilder::PushImpl(s32 value) {
221inline void ResponseBuilder::Push(s32 value) {
222 cmdbuf[index++] = static_cast<u32>(value); 234 cmdbuf[index++] = static_cast<u32>(value);
223} 235}
224 236
225template <> 237inline void ResponseBuilder::PushImpl(u32 value) {
226inline void ResponseBuilder::Push(u32 value) {
227 cmdbuf[index++] = value; 238 cmdbuf[index++] = value;
228} 239}
229 240
@@ -235,62 +246,52 @@ void ResponseBuilder::PushRaw(const T& value) {
235 index += (sizeof(T) + 3) / 4; // round up to word length 246 index += (sizeof(T) + 3) / 4; // round up to word length
236} 247}
237 248
238template <> 249inline void ResponseBuilder::PushImpl(ResultCode value) {
239inline void ResponseBuilder::Push(ResultCode value) {
240 // Result codes are actually 64-bit in the IPC buffer, but only the high part is discarded. 250 // Result codes are actually 64-bit in the IPC buffer, but only the high part is discarded.
241 Push(value.raw); 251 Push(value.raw);
242 Push<u32>(0); 252 Push<u32>(0);
243} 253}
244 254
245template <> 255inline void ResponseBuilder::PushImpl(s8 value) {
246inline void ResponseBuilder::Push(s8 value) {
247 PushRaw(value); 256 PushRaw(value);
248} 257}
249 258
250template <> 259inline void ResponseBuilder::PushImpl(s16 value) {
251inline void ResponseBuilder::Push(s16 value) {
252 PushRaw(value); 260 PushRaw(value);
253} 261}
254 262
255template <> 263inline void ResponseBuilder::PushImpl(s64 value) {
256inline void ResponseBuilder::Push(s64 value) { 264 PushImpl(static_cast<u32>(value));
257 Push(static_cast<u32>(value)); 265 PushImpl(static_cast<u32>(value >> 32));
258 Push(static_cast<u32>(value >> 32));
259} 266}
260 267
261template <> 268inline void ResponseBuilder::PushImpl(u8 value) {
262inline void ResponseBuilder::Push(u8 value) {
263 PushRaw(value); 269 PushRaw(value);
264} 270}
265 271
266template <> 272inline void ResponseBuilder::PushImpl(u16 value) {
267inline void ResponseBuilder::Push(u16 value) {
268 PushRaw(value); 273 PushRaw(value);
269} 274}
270 275
271template <> 276inline void ResponseBuilder::PushImpl(u64 value) {
272inline void ResponseBuilder::Push(u64 value) { 277 PushImpl(static_cast<u32>(value));
273 Push(static_cast<u32>(value)); 278 PushImpl(static_cast<u32>(value >> 32));
274 Push(static_cast<u32>(value >> 32));
275} 279}
276 280
277template <> 281inline void ResponseBuilder::PushImpl(float value) {
278inline void ResponseBuilder::Push(float value) {
279 u32 integral; 282 u32 integral;
280 std::memcpy(&integral, &value, sizeof(u32)); 283 std::memcpy(&integral, &value, sizeof(u32));
281 Push(integral); 284 PushImpl(integral);
282} 285}
283 286
284template <> 287inline void ResponseBuilder::PushImpl(double value) {
285inline void ResponseBuilder::Push(double value) {
286 u64 integral; 288 u64 integral;
287 std::memcpy(&integral, &value, sizeof(u64)); 289 std::memcpy(&integral, &value, sizeof(u64));
288 Push(integral); 290 PushImpl(integral);
289} 291}
290 292
291template <> 293inline void ResponseBuilder::PushImpl(bool value) {
292inline void ResponseBuilder::Push(bool value) { 294 PushImpl(static_cast<u8>(value));
293 Push(static_cast<u8>(value));
294} 295}
295 296
296template <typename First, typename... Other> 297template <typename First, typename... Other>
diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp
index b882eaa0f..20ffa7d47 100644
--- a/src/core/hle/kernel/address_arbiter.cpp
+++ b/src/core/hle/kernel/address_arbiter.cpp
@@ -12,8 +12,9 @@
12#include "core/hle/kernel/address_arbiter.h" 12#include "core/hle/kernel/address_arbiter.h"
13#include "core/hle/kernel/errors.h" 13#include "core/hle/kernel/errors.h"
14#include "core/hle/kernel/handle_table.h" 14#include "core/hle/kernel/handle_table.h"
15#include "core/hle/kernel/k_scheduler.h"
16#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
15#include "core/hle/kernel/kernel.h" 17#include "core/hle/kernel/kernel.h"
16#include "core/hle/kernel/scheduler.h"
17#include "core/hle/kernel/thread.h" 18#include "core/hle/kernel/thread.h"
18#include "core/hle/kernel/time_manager.h" 19#include "core/hle/kernel/time_manager.h"
19#include "core/hle/result.h" 20#include "core/hle/result.h"
@@ -58,7 +59,7 @@ ResultCode AddressArbiter::SignalToAddress(VAddr address, SignalType type, s32 v
58} 59}
59 60
60ResultCode AddressArbiter::SignalToAddressOnly(VAddr address, s32 num_to_wake) { 61ResultCode AddressArbiter::SignalToAddressOnly(VAddr address, s32 num_to_wake) {
61 SchedulerLock lock(system.Kernel()); 62 KScopedSchedulerLock lock(system.Kernel());
62 const std::vector<std::shared_ptr<Thread>> waiting_threads = 63 const std::vector<std::shared_ptr<Thread>> waiting_threads =
63 GetThreadsWaitingOnAddress(address); 64 GetThreadsWaitingOnAddress(address);
64 WakeThreads(waiting_threads, num_to_wake); 65 WakeThreads(waiting_threads, num_to_wake);
@@ -67,7 +68,7 @@ ResultCode AddressArbiter::SignalToAddressOnly(VAddr address, s32 num_to_wake) {
67 68
68ResultCode AddressArbiter::IncrementAndSignalToAddressIfEqual(VAddr address, s32 value, 69ResultCode AddressArbiter::IncrementAndSignalToAddressIfEqual(VAddr address, s32 value,
69 s32 num_to_wake) { 70 s32 num_to_wake) {
70 SchedulerLock lock(system.Kernel()); 71 KScopedSchedulerLock lock(system.Kernel());
71 auto& memory = system.Memory(); 72 auto& memory = system.Memory();
72 73
73 // Ensure that we can write to the address. 74 // Ensure that we can write to the address.
@@ -92,7 +93,7 @@ ResultCode AddressArbiter::IncrementAndSignalToAddressIfEqual(VAddr address, s32
92 93
93ResultCode AddressArbiter::ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr address, s32 value, 94ResultCode AddressArbiter::ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr address, s32 value,
94 s32 num_to_wake) { 95 s32 num_to_wake) {
95 SchedulerLock lock(system.Kernel()); 96 KScopedSchedulerLock lock(system.Kernel());
96 auto& memory = system.Memory(); 97 auto& memory = system.Memory();
97 98
98 // Ensure that we can write to the address. 99 // Ensure that we can write to the address.
@@ -153,11 +154,11 @@ ResultCode AddressArbiter::WaitForAddressIfLessThan(VAddr address, s32 value, s6
153 bool should_decrement) { 154 bool should_decrement) {
154 auto& memory = system.Memory(); 155 auto& memory = system.Memory();
155 auto& kernel = system.Kernel(); 156 auto& kernel = system.Kernel();
156 Thread* current_thread = system.CurrentScheduler().GetCurrentThread(); 157 Thread* current_thread = kernel.CurrentScheduler()->GetCurrentThread();
157 158
158 Handle event_handle = InvalidHandle; 159 Handle event_handle = InvalidHandle;
159 { 160 {
160 SchedulerLockAndSleep lock(kernel, event_handle, current_thread, timeout); 161 KScopedSchedulerLockAndSleep lock(kernel, event_handle, current_thread, timeout);
161 162
162 if (current_thread->IsPendingTermination()) { 163 if (current_thread->IsPendingTermination()) {
163 lock.CancelSleep(); 164 lock.CancelSleep();
@@ -210,7 +211,7 @@ ResultCode AddressArbiter::WaitForAddressIfLessThan(VAddr address, s32 value, s6
210 } 211 }
211 212
212 { 213 {
213 SchedulerLock lock(kernel); 214 KScopedSchedulerLock lock(kernel);
214 if (current_thread->IsWaitingForArbitration()) { 215 if (current_thread->IsWaitingForArbitration()) {
215 RemoveThread(SharedFrom(current_thread)); 216 RemoveThread(SharedFrom(current_thread));
216 current_thread->WaitForArbitration(false); 217 current_thread->WaitForArbitration(false);
@@ -223,11 +224,11 @@ ResultCode AddressArbiter::WaitForAddressIfLessThan(VAddr address, s32 value, s6
223ResultCode AddressArbiter::WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout) { 224ResultCode AddressArbiter::WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout) {
224 auto& memory = system.Memory(); 225 auto& memory = system.Memory();
225 auto& kernel = system.Kernel(); 226 auto& kernel = system.Kernel();
226 Thread* current_thread = system.CurrentScheduler().GetCurrentThread(); 227 Thread* current_thread = kernel.CurrentScheduler()->GetCurrentThread();
227 228
228 Handle event_handle = InvalidHandle; 229 Handle event_handle = InvalidHandle;
229 { 230 {
230 SchedulerLockAndSleep lock(kernel, event_handle, current_thread, timeout); 231 KScopedSchedulerLockAndSleep lock(kernel, event_handle, current_thread, timeout);
231 232
232 if (current_thread->IsPendingTermination()) { 233 if (current_thread->IsPendingTermination()) {
233 lock.CancelSleep(); 234 lock.CancelSleep();
@@ -265,7 +266,7 @@ ResultCode AddressArbiter::WaitForAddressIfEqual(VAddr address, s32 value, s64 t
265 } 266 }
266 267
267 { 268 {
268 SchedulerLock lock(kernel); 269 KScopedSchedulerLock lock(kernel);
269 if (current_thread->IsWaitingForArbitration()) { 270 if (current_thread->IsWaitingForArbitration()) {
270 RemoveThread(SharedFrom(current_thread)); 271 RemoveThread(SharedFrom(current_thread));
271 current_thread->WaitForArbitration(false); 272 current_thread->WaitForArbitration(false);
@@ -275,12 +276,6 @@ ResultCode AddressArbiter::WaitForAddressIfEqual(VAddr address, s32 value, s64 t
275 return current_thread->GetSignalingResult(); 276 return current_thread->GetSignalingResult();
276} 277}
277 278
278void AddressArbiter::HandleWakeupThread(std::shared_ptr<Thread> thread) {
279 ASSERT(thread->GetStatus() == ThreadStatus::WaitArb);
280 RemoveThread(thread);
281 thread->SetArbiterWaitAddress(0);
282}
283
284void AddressArbiter::InsertThread(std::shared_ptr<Thread> thread) { 279void AddressArbiter::InsertThread(std::shared_ptr<Thread> thread) {
285 const VAddr arb_addr = thread->GetArbiterWaitAddress(); 280 const VAddr arb_addr = thread->GetArbiterWaitAddress();
286 std::list<std::shared_ptr<Thread>>& thread_list = arb_threads[arb_addr]; 281 std::list<std::shared_ptr<Thread>>& thread_list = arb_threads[arb_addr];
diff --git a/src/core/hle/kernel/address_arbiter.h b/src/core/hle/kernel/address_arbiter.h
index 0b05d533c..b91edc67d 100644
--- a/src/core/hle/kernel/address_arbiter.h
+++ b/src/core/hle/kernel/address_arbiter.h
@@ -50,9 +50,6 @@ public:
50 /// Waits on an address with a particular arbitration type. 50 /// Waits on an address with a particular arbitration type.
51 ResultCode WaitForAddress(VAddr address, ArbitrationType type, s32 value, s64 timeout_ns); 51 ResultCode WaitForAddress(VAddr address, ArbitrationType type, s32 value, s64 timeout_ns);
52 52
53 /// Removes a thread from the container and resets its address arbiter adress to 0
54 void HandleWakeupThread(std::shared_ptr<Thread> thread);
55
56private: 53private:
57 /// Signals an address being waited on. 54 /// Signals an address being waited on.
58 ResultCode SignalToAddressOnly(VAddr address, s32 num_to_wake); 55 ResultCode SignalToAddressOnly(VAddr address, s32 num_to_wake);
diff --git a/src/core/hle/kernel/global_scheduler_context.cpp b/src/core/hle/kernel/global_scheduler_context.cpp
new file mode 100644
index 000000000..a133e8ed0
--- /dev/null
+++ b/src/core/hle/kernel/global_scheduler_context.cpp
@@ -0,0 +1,52 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <mutex>
6
7#include "common/assert.h"
8#include "core/core.h"
9#include "core/hle/kernel/global_scheduler_context.h"
10#include "core/hle/kernel/k_scheduler.h"
11#include "core/hle/kernel/kernel.h"
12
13namespace Kernel {
14
15GlobalSchedulerContext::GlobalSchedulerContext(KernelCore& kernel)
16 : kernel{kernel}, scheduler_lock{kernel} {}
17
18GlobalSchedulerContext::~GlobalSchedulerContext() = default;
19
20void GlobalSchedulerContext::AddThread(std::shared_ptr<Thread> thread) {
21 std::scoped_lock lock{global_list_guard};
22 thread_list.push_back(std::move(thread));
23}
24
25void GlobalSchedulerContext::RemoveThread(std::shared_ptr<Thread> thread) {
26 std::scoped_lock lock{global_list_guard};
27 thread_list.erase(std::remove(thread_list.begin(), thread_list.end(), thread),
28 thread_list.end());
29}
30
31void GlobalSchedulerContext::PreemptThreads() {
32 // The priority levels at which the global scheduler preempts threads every 10 ms. They are
33 // ordered from Core 0 to Core 3.
34 static constexpr std::array<u32, Core::Hardware::NUM_CPU_CORES> preemption_priorities{
35 59,
36 59,
37 59,
38 63,
39 };
40
41 ASSERT(IsLocked());
42 for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) {
43 const u32 priority = preemption_priorities[core_id];
44 kernel.Scheduler(core_id).RotateScheduledQueue(core_id, priority);
45 }
46}
47
48bool GlobalSchedulerContext::IsLocked() const {
49 return scheduler_lock.IsLockedByCurrentThread();
50}
51
52} // namespace Kernel
diff --git a/src/core/hle/kernel/global_scheduler_context.h b/src/core/hle/kernel/global_scheduler_context.h
new file mode 100644
index 000000000..5c7b89290
--- /dev/null
+++ b/src/core/hle/kernel/global_scheduler_context.h
@@ -0,0 +1,81 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <atomic>
8#include <vector>
9
10#include "common/common_types.h"
11#include "common/spin_lock.h"
12#include "core/hardware_properties.h"
13#include "core/hle/kernel/k_priority_queue.h"
14#include "core/hle/kernel/k_scheduler_lock.h"
15#include "core/hle/kernel/thread.h"
16
17namespace Kernel {
18
19class KernelCore;
20class SchedulerLock;
21
22using KSchedulerPriorityQueue =
23 KPriorityQueue<Thread, Core::Hardware::NUM_CPU_CORES, THREADPRIO_LOWEST, THREADPRIO_HIGHEST>;
24constexpr s32 HighestCoreMigrationAllowedPriority = 2;
25
26class GlobalSchedulerContext final {
27 friend class KScheduler;
28
29public:
30 using LockType = KAbstractSchedulerLock<KScheduler>;
31
32 explicit GlobalSchedulerContext(KernelCore& kernel);
33 ~GlobalSchedulerContext();
34
35 /// Adds a new thread to the scheduler
36 void AddThread(std::shared_ptr<Thread> thread);
37
38 /// Removes a thread from the scheduler
39 void RemoveThread(std::shared_ptr<Thread> thread);
40
41 /// Returns a list of all threads managed by the scheduler
42 [[nodiscard]] const std::vector<std::shared_ptr<Thread>>& GetThreadList() const {
43 return thread_list;
44 }
45
46 /**
47 * Rotates the scheduling queues of threads at a preemption priority and then does
48 * some core rebalancing. Preemption priorities can be found in the array
49 * 'preemption_priorities'.
50 *
51 * @note This operation happens every 10ms.
52 */
53 void PreemptThreads();
54
55 /// Returns true if the global scheduler lock is acquired
56 bool IsLocked() const;
57
58 [[nodiscard]] LockType& SchedulerLock() {
59 return scheduler_lock;
60 }
61
62 [[nodiscard]] const LockType& SchedulerLock() const {
63 return scheduler_lock;
64 }
65
66private:
67 friend class KScopedSchedulerLock;
68 friend class KScopedSchedulerLockAndSleep;
69
70 KernelCore& kernel;
71
72 std::atomic_bool scheduler_update_needed{};
73 KSchedulerPriorityQueue priority_queue;
74 LockType scheduler_lock;
75
76 /// Lists all thread ids that aren't deleted/etc.
77 std::vector<std::shared_ptr<Thread>> thread_list;
78 Common::SpinLock global_list_guard{};
79};
80
81} // namespace Kernel
diff --git a/src/core/hle/kernel/handle_table.cpp b/src/core/hle/kernel/handle_table.cpp
index fb30b6f8b..40988b0fd 100644
--- a/src/core/hle/kernel/handle_table.cpp
+++ b/src/core/hle/kernel/handle_table.cpp
@@ -8,9 +8,9 @@
8#include "core/core.h" 8#include "core/core.h"
9#include "core/hle/kernel/errors.h" 9#include "core/hle/kernel/errors.h"
10#include "core/hle/kernel/handle_table.h" 10#include "core/hle/kernel/handle_table.h"
11#include "core/hle/kernel/k_scheduler.h"
11#include "core/hle/kernel/kernel.h" 12#include "core/hle/kernel/kernel.h"
12#include "core/hle/kernel/process.h" 13#include "core/hle/kernel/process.h"
13#include "core/hle/kernel/scheduler.h"
14#include "core/hle/kernel/thread.h" 14#include "core/hle/kernel/thread.h"
15 15
16namespace Kernel { 16namespace Kernel {
@@ -105,7 +105,7 @@ bool HandleTable::IsValid(Handle handle) const {
105 105
106std::shared_ptr<Object> HandleTable::GetGeneric(Handle handle) const { 106std::shared_ptr<Object> HandleTable::GetGeneric(Handle handle) const {
107 if (handle == CurrentThread) { 107 if (handle == CurrentThread) {
108 return SharedFrom(kernel.CurrentScheduler().GetCurrentThread()); 108 return SharedFrom(kernel.CurrentScheduler()->GetCurrentThread());
109 } else if (handle == CurrentProcess) { 109 } else if (handle == CurrentProcess) {
110 return SharedFrom(kernel.CurrentProcess()); 110 return SharedFrom(kernel.CurrentProcess());
111 } 111 }
@@ -118,7 +118,7 @@ std::shared_ptr<Object> HandleTable::GetGeneric(Handle handle) const {
118 118
119void HandleTable::Clear() { 119void HandleTable::Clear() {
120 for (u16 i = 0; i < table_size; ++i) { 120 for (u16 i = 0; i < table_size; ++i) {
121 generations[i] = i + 1; 121 generations[i] = static_cast<u16>(i + 1);
122 objects[i] = nullptr; 122 objects[i] = nullptr;
123 } 123 }
124 next_free_slot = 0; 124 next_free_slot = 0;
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp
index 81f85643b..83decf6cf 100644
--- a/src/core/hle/kernel/hle_ipc.cpp
+++ b/src/core/hle/kernel/hle_ipc.cpp
@@ -17,11 +17,12 @@
17#include "core/hle/kernel/errors.h" 17#include "core/hle/kernel/errors.h"
18#include "core/hle/kernel/handle_table.h" 18#include "core/hle/kernel/handle_table.h"
19#include "core/hle/kernel/hle_ipc.h" 19#include "core/hle/kernel/hle_ipc.h"
20#include "core/hle/kernel/k_scheduler.h"
21#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
20#include "core/hle/kernel/kernel.h" 22#include "core/hle/kernel/kernel.h"
21#include "core/hle/kernel/object.h" 23#include "core/hle/kernel/object.h"
22#include "core/hle/kernel/process.h" 24#include "core/hle/kernel/process.h"
23#include "core/hle/kernel/readable_event.h" 25#include "core/hle/kernel/readable_event.h"
24#include "core/hle/kernel/scheduler.h"
25#include "core/hle/kernel/server_session.h" 26#include "core/hle/kernel/server_session.h"
26#include "core/hle/kernel/thread.h" 27#include "core/hle/kernel/thread.h"
27#include "core/hle/kernel/time_manager.h" 28#include "core/hle/kernel/time_manager.h"
@@ -45,44 +46,6 @@ void SessionRequestHandler::ClientDisconnected(
45 boost::range::remove_erase(connected_sessions, server_session); 46 boost::range::remove_erase(connected_sessions, server_session);
46} 47}
47 48
48std::shared_ptr<WritableEvent> HLERequestContext::SleepClientThread(
49 const std::string& reason, u64 timeout, WakeupCallback&& callback,
50 std::shared_ptr<WritableEvent> writable_event) {
51 // Put the client thread to sleep until the wait event is signaled or the timeout expires.
52
53 if (!writable_event) {
54 // Create event if not provided
55 const auto pair = WritableEvent::CreateEventPair(kernel, "HLE Pause Event: " + reason);
56 writable_event = pair.writable;
57 }
58
59 {
60 Handle event_handle = InvalidHandle;
61 SchedulerLockAndSleep lock(kernel, event_handle, thread.get(), timeout);
62 thread->SetHLECallback(
63 [context = *this, callback](std::shared_ptr<Thread> thread) mutable -> bool {
64 ThreadWakeupReason reason = thread->GetSignalingResult() == RESULT_TIMEOUT
65 ? ThreadWakeupReason::Timeout
66 : ThreadWakeupReason::Signal;
67 callback(thread, context, reason);
68 context.WriteToOutgoingCommandBuffer(*thread);
69 return true;
70 });
71 const auto readable_event{writable_event->GetReadableEvent()};
72 writable_event->Clear();
73 thread->SetHLESyncObject(readable_event.get());
74 thread->SetStatus(ThreadStatus::WaitHLEEvent);
75 thread->SetSynchronizationResults(nullptr, RESULT_TIMEOUT);
76 readable_event->AddWaitingThread(thread);
77 lock.Release();
78 thread->SetHLETimeEvent(event_handle);
79 }
80
81 is_thread_waiting = true;
82
83 return writable_event;
84}
85
86HLERequestContext::HLERequestContext(KernelCore& kernel, Core::Memory::Memory& memory, 49HLERequestContext::HLERequestContext(KernelCore& kernel, Core::Memory::Memory& memory,
87 std::shared_ptr<ServerSession> server_session, 50 std::shared_ptr<ServerSession> server_session,
88 std::shared_ptr<Thread> thread) 51 std::shared_ptr<Thread> thread)
diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h
index f3277b766..b112e1ebd 100644
--- a/src/core/hle/kernel/hle_ipc.h
+++ b/src/core/hle/kernel/hle_ipc.h
@@ -24,6 +24,10 @@ namespace Core::Memory {
24class Memory; 24class Memory;
25} 25}
26 26
27namespace IPC {
28class ResponseBuilder;
29}
30
27namespace Service { 31namespace Service {
28class ServiceFrameworkBase; 32class ServiceFrameworkBase;
29} 33}
@@ -125,23 +129,6 @@ public:
125 using WakeupCallback = std::function<void( 129 using WakeupCallback = std::function<void(
126 std::shared_ptr<Thread> thread, HLERequestContext& context, ThreadWakeupReason reason)>; 130 std::shared_ptr<Thread> thread, HLERequestContext& context, ThreadWakeupReason reason)>;
127 131
128 /**
129 * Puts the specified guest thread to sleep until the returned event is signaled or until the
130 * specified timeout expires.
131 * @param reason Reason for pausing the thread, to be used for debugging purposes.
132 * @param timeout Timeout in nanoseconds after which the thread will be awoken and the callback
133 * invoked with a Timeout reason.
134 * @param callback Callback to be invoked when the thread is resumed. This callback must write
135 * the entire command response once again, regardless of the state of it before this function
136 * was called.
137 * @param writable_event Event to use to wake up the thread. If unspecified, an event will be
138 * created.
139 * @returns Event that when signaled will resume the thread and call the callback function.
140 */
141 std::shared_ptr<WritableEvent> SleepClientThread(
142 const std::string& reason, u64 timeout, WakeupCallback&& callback,
143 std::shared_ptr<WritableEvent> writable_event = nullptr);
144
145 /// Populates this context with data from the requesting process/thread. 132 /// Populates this context with data from the requesting process/thread.
146 ResultCode PopulateFromIncomingCommandBuffer(const HandleTable& handle_table, 133 ResultCode PopulateFromIncomingCommandBuffer(const HandleTable& handle_table,
147 u32_le* src_cmdbuf); 134 u32_le* src_cmdbuf);
@@ -287,6 +274,8 @@ public:
287 } 274 }
288 275
289private: 276private:
277 friend class IPC::ResponseBuilder;
278
290 void ParseCommandBuffer(const HandleTable& handle_table, u32_le* src_cmdbuf, bool incoming); 279 void ParseCommandBuffer(const HandleTable& handle_table, u32_le* src_cmdbuf, bool incoming);
291 280
292 std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf; 281 std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf;
diff --git a/src/core/hle/kernel/k_affinity_mask.h b/src/core/hle/kernel/k_affinity_mask.h
new file mode 100644
index 000000000..dd73781cd
--- /dev/null
+++ b/src/core/hle/kernel/k_affinity_mask.h
@@ -0,0 +1,58 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5// This file references various implementation details from Atmosphere, an open-source firmware for
6// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX.
7
8#pragma once
9
10#include "common/assert.h"
11#include "common/common_types.h"
12#include "core/hardware_properties.h"
13
14namespace Kernel {
15
16class KAffinityMask {
17public:
18 constexpr KAffinityMask() = default;
19
20 [[nodiscard]] constexpr u64 GetAffinityMask() const {
21 return this->mask;
22 }
23
24 constexpr void SetAffinityMask(u64 new_mask) {
25 ASSERT((new_mask & ~AllowedAffinityMask) == 0);
26 this->mask = new_mask;
27 }
28
29 [[nodiscard]] constexpr bool GetAffinity(s32 core) const {
30 return this->mask & GetCoreBit(core);
31 }
32
33 constexpr void SetAffinity(s32 core, bool set) {
34 ASSERT(0 <= core && core < static_cast<s32>(Core::Hardware::NUM_CPU_CORES));
35
36 if (set) {
37 this->mask |= GetCoreBit(core);
38 } else {
39 this->mask &= ~GetCoreBit(core);
40 }
41 }
42
43 constexpr void SetAll() {
44 this->mask = AllowedAffinityMask;
45 }
46
47private:
48 [[nodiscard]] static constexpr u64 GetCoreBit(s32 core) {
49 ASSERT(0 <= core && core < static_cast<s32>(Core::Hardware::NUM_CPU_CORES));
50 return (1ULL << core);
51 }
52
53 static constexpr u64 AllowedAffinityMask = (1ULL << Core::Hardware::NUM_CPU_CORES) - 1;
54
55 u64 mask{};
56};
57
58} // namespace Kernel
diff --git a/src/core/hle/kernel/k_priority_queue.h b/src/core/hle/kernel/k_priority_queue.h
new file mode 100644
index 000000000..99fb8fe93
--- /dev/null
+++ b/src/core/hle/kernel/k_priority_queue.h
@@ -0,0 +1,451 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5// This file references various implementation details from Atmosphere, an open-source firmware for
6// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX.
7
8#pragma once
9
10#include <array>
11#include <concepts>
12
13#include "common/assert.h"
14#include "common/bit_set.h"
15#include "common/bit_util.h"
16#include "common/common_types.h"
17#include "common/concepts.h"
18
19namespace Kernel {
20
21class Thread;
22
23template <typename T>
24concept KPriorityQueueAffinityMask = !std::is_reference_v<T> && requires(T & t) {
25 { t.GetAffinityMask() }
26 ->Common::ConvertibleTo<u64>;
27 {t.SetAffinityMask(std::declval<u64>())};
28
29 { t.GetAffinity(std::declval<int32_t>()) }
30 ->std::same_as<bool>;
31 {t.SetAffinity(std::declval<int32_t>(), std::declval<bool>())};
32 {t.SetAll()};
33};
34
35template <typename T>
36concept KPriorityQueueMember = !std::is_reference_v<T> && requires(T & t) {
37 {typename T::QueueEntry()};
38 {(typename T::QueueEntry()).Initialize()};
39 {(typename T::QueueEntry()).SetPrev(std::addressof(t))};
40 {(typename T::QueueEntry()).SetNext(std::addressof(t))};
41 { (typename T::QueueEntry()).GetNext() }
42 ->std::same_as<T*>;
43 { (typename T::QueueEntry()).GetPrev() }
44 ->std::same_as<T*>;
45 { t.GetPriorityQueueEntry(std::declval<s32>()) }
46 ->std::same_as<typename T::QueueEntry&>;
47
48 {t.GetAffinityMask()};
49 { typename std::remove_cvref<decltype(t.GetAffinityMask())>::type() }
50 ->KPriorityQueueAffinityMask;
51
52 { t.GetActiveCore() }
53 ->Common::ConvertibleTo<s32>;
54 { t.GetPriority() }
55 ->Common::ConvertibleTo<s32>;
56};
57
58template <typename Member, size_t _NumCores, int LowestPriority, int HighestPriority>
59requires KPriorityQueueMember<Member> class KPriorityQueue {
60public:
61 using AffinityMaskType = typename std::remove_cv_t<
62 typename std::remove_reference<decltype(std::declval<Member>().GetAffinityMask())>::type>;
63
64 static_assert(LowestPriority >= 0);
65 static_assert(HighestPriority >= 0);
66 static_assert(LowestPriority >= HighestPriority);
67 static constexpr size_t NumPriority = LowestPriority - HighestPriority + 1;
68 static constexpr size_t NumCores = _NumCores;
69
70 static constexpr bool IsValidCore(s32 core) {
71 return 0 <= core && core < static_cast<s32>(NumCores);
72 }
73
74 static constexpr bool IsValidPriority(s32 priority) {
75 return HighestPriority <= priority && priority <= LowestPriority + 1;
76 }
77
78private:
79 using Entry = typename Member::QueueEntry;
80
81public:
82 class KPerCoreQueue {
83 private:
84 std::array<Entry, NumCores> root{};
85
86 public:
87 constexpr KPerCoreQueue() {
88 for (auto& per_core_root : root) {
89 per_core_root.Initialize();
90 }
91 }
92
93 constexpr bool PushBack(s32 core, Member* member) {
94 // Get the entry associated with the member.
95 Entry& member_entry = member->GetPriorityQueueEntry(core);
96
97 // Get the entry associated with the end of the queue.
98 Member* tail = this->root[core].GetPrev();
99 Entry& tail_entry =
100 (tail != nullptr) ? tail->GetPriorityQueueEntry(core) : this->root[core];
101
102 // Link the entries.
103 member_entry.SetPrev(tail);
104 member_entry.SetNext(nullptr);
105 tail_entry.SetNext(member);
106 this->root[core].SetPrev(member);
107
108 return tail == nullptr;
109 }
110
111 constexpr bool PushFront(s32 core, Member* member) {
112 // Get the entry associated with the member.
113 Entry& member_entry = member->GetPriorityQueueEntry(core);
114
115 // Get the entry associated with the front of the queue.
116 Member* head = this->root[core].GetNext();
117 Entry& head_entry =
118 (head != nullptr) ? head->GetPriorityQueueEntry(core) : this->root[core];
119
120 // Link the entries.
121 member_entry.SetPrev(nullptr);
122 member_entry.SetNext(head);
123 head_entry.SetPrev(member);
124 this->root[core].SetNext(member);
125
126 return (head == nullptr);
127 }
128
129 constexpr bool Remove(s32 core, Member* member) {
130 // Get the entry associated with the member.
131 Entry& member_entry = member->GetPriorityQueueEntry(core);
132
133 // Get the entries associated with next and prev.
134 Member* prev = member_entry.GetPrev();
135 Member* next = member_entry.GetNext();
136 Entry& prev_entry =
137 (prev != nullptr) ? prev->GetPriorityQueueEntry(core) : this->root[core];
138 Entry& next_entry =
139 (next != nullptr) ? next->GetPriorityQueueEntry(core) : this->root[core];
140
141 // Unlink.
142 prev_entry.SetNext(next);
143 next_entry.SetPrev(prev);
144
145 return (this->GetFront(core) == nullptr);
146 }
147
148 constexpr Member* GetFront(s32 core) const {
149 return this->root[core].GetNext();
150 }
151 };
152
153 class KPriorityQueueImpl {
154 public:
155 constexpr KPriorityQueueImpl() = default;
156
157 constexpr void PushBack(s32 priority, s32 core, Member* member) {
158 ASSERT(IsValidCore(core));
159 ASSERT(IsValidPriority(priority));
160
161 if (priority > LowestPriority) {
162 return;
163 }
164
165 if (this->queues[priority].PushBack(core, member)) {
166 this->available_priorities[core].SetBit(priority);
167 }
168 }
169
170 constexpr void PushFront(s32 priority, s32 core, Member* member) {
171 ASSERT(IsValidCore(core));
172 ASSERT(IsValidPriority(priority));
173
174 if (priority > LowestPriority) {
175 return;
176 }
177
178 if (this->queues[priority].PushFront(core, member)) {
179 this->available_priorities[core].SetBit(priority);
180 }
181 }
182
183 constexpr void Remove(s32 priority, s32 core, Member* member) {
184 ASSERT(IsValidCore(core));
185 ASSERT(IsValidPriority(priority));
186
187 if (priority > LowestPriority) {
188 return;
189 }
190
191 if (this->queues[priority].Remove(core, member)) {
192 this->available_priorities[core].ClearBit(priority);
193 }
194 }
195
196 constexpr Member* GetFront(s32 core) const {
197 ASSERT(IsValidCore(core));
198
199 const s32 priority =
200 static_cast<s32>(this->available_priorities[core].CountLeadingZero());
201 if (priority <= LowestPriority) {
202 return this->queues[priority].GetFront(core);
203 } else {
204 return nullptr;
205 }
206 }
207
208 constexpr Member* GetFront(s32 priority, s32 core) const {
209 ASSERT(IsValidCore(core));
210 ASSERT(IsValidPriority(priority));
211
212 if (priority <= LowestPriority) {
213 return this->queues[priority].GetFront(core);
214 } else {
215 return nullptr;
216 }
217 }
218
219 constexpr Member* GetNext(s32 core, const Member* member) const {
220 ASSERT(IsValidCore(core));
221
222 Member* next = member->GetPriorityQueueEntry(core).GetNext();
223 if (next == nullptr) {
224 const s32 priority = static_cast<s32>(
225 this->available_priorities[core].GetNextSet(member->GetPriority()));
226 if (priority <= LowestPriority) {
227 next = this->queues[priority].GetFront(core);
228 }
229 }
230 return next;
231 }
232
233 constexpr void MoveToFront(s32 priority, s32 core, Member* member) {
234 ASSERT(IsValidCore(core));
235 ASSERT(IsValidPriority(priority));
236
237 if (priority <= LowestPriority) {
238 this->queues[priority].Remove(core, member);
239 this->queues[priority].PushFront(core, member);
240 }
241 }
242
243 constexpr Member* MoveToBack(s32 priority, s32 core, Member* member) {
244 ASSERT(IsValidCore(core));
245 ASSERT(IsValidPriority(priority));
246
247 if (priority <= LowestPriority) {
248 this->queues[priority].Remove(core, member);
249 this->queues[priority].PushBack(core, member);
250 return this->queues[priority].GetFront(core);
251 } else {
252 return nullptr;
253 }
254 }
255
256 private:
257 std::array<KPerCoreQueue, NumPriority> queues{};
258 std::array<Common::BitSet64<NumPriority>, NumCores> available_priorities{};
259 };
260
261private:
262 KPriorityQueueImpl scheduled_queue;
263 KPriorityQueueImpl suggested_queue;
264
265private:
266 constexpr void ClearAffinityBit(u64& affinity, s32 core) {
267 affinity &= ~(u64(1) << core);
268 }
269
270 constexpr s32 GetNextCore(u64& affinity) {
271 const s32 core = Common::CountTrailingZeroes64(affinity);
272 ClearAffinityBit(affinity, core);
273 return core;
274 }
275
276 constexpr void PushBack(s32 priority, Member* member) {
277 ASSERT(IsValidPriority(priority));
278
279 // Push onto the scheduled queue for its core, if we can.
280 u64 affinity = member->GetAffinityMask().GetAffinityMask();
281 if (const s32 core = member->GetActiveCore(); core >= 0) {
282 this->scheduled_queue.PushBack(priority, core, member);
283 ClearAffinityBit(affinity, core);
284 }
285
286 // And suggest the thread for all other cores.
287 while (affinity) {
288 this->suggested_queue.PushBack(priority, GetNextCore(affinity), member);
289 }
290 }
291
292 constexpr void PushFront(s32 priority, Member* member) {
293 ASSERT(IsValidPriority(priority));
294
295 // Push onto the scheduled queue for its core, if we can.
296 u64 affinity = member->GetAffinityMask().GetAffinityMask();
297 if (const s32 core = member->GetActiveCore(); core >= 0) {
298 this->scheduled_queue.PushFront(priority, core, member);
299 ClearAffinityBit(affinity, core);
300 }
301
302 // And suggest the thread for all other cores.
303 // Note: Nintendo pushes onto the back of the suggested queue, not the front.
304 while (affinity) {
305 this->suggested_queue.PushBack(priority, GetNextCore(affinity), member);
306 }
307 }
308
309 constexpr void Remove(s32 priority, Member* member) {
310 ASSERT(IsValidPriority(priority));
311
312 // Remove from the scheduled queue for its core.
313 u64 affinity = member->GetAffinityMask().GetAffinityMask();
314 if (const s32 core = member->GetActiveCore(); core >= 0) {
315 this->scheduled_queue.Remove(priority, core, member);
316 ClearAffinityBit(affinity, core);
317 }
318
319 // Remove from the suggested queue for all other cores.
320 while (affinity) {
321 this->suggested_queue.Remove(priority, GetNextCore(affinity), member);
322 }
323 }
324
325public:
326 constexpr KPriorityQueue() = default;
327
328 // Getters.
329 constexpr Member* GetScheduledFront(s32 core) const {
330 return this->scheduled_queue.GetFront(core);
331 }
332
333 constexpr Member* GetScheduledFront(s32 core, s32 priority) const {
334 return this->scheduled_queue.GetFront(priority, core);
335 }
336
337 constexpr Member* GetSuggestedFront(s32 core) const {
338 return this->suggested_queue.GetFront(core);
339 }
340
341 constexpr Member* GetSuggestedFront(s32 core, s32 priority) const {
342 return this->suggested_queue.GetFront(priority, core);
343 }
344
345 constexpr Member* GetScheduledNext(s32 core, const Member* member) const {
346 return this->scheduled_queue.GetNext(core, member);
347 }
348
349 constexpr Member* GetSuggestedNext(s32 core, const Member* member) const {
350 return this->suggested_queue.GetNext(core, member);
351 }
352
353 constexpr Member* GetSamePriorityNext(s32 core, const Member* member) const {
354 return member->GetPriorityQueueEntry(core).GetNext();
355 }
356
357 // Mutators.
358 constexpr void PushBack(Member* member) {
359 this->PushBack(member->GetPriority(), member);
360 }
361
362 constexpr void Remove(Member* member) {
363 this->Remove(member->GetPriority(), member);
364 }
365
366 constexpr void MoveToScheduledFront(Member* member) {
367 this->scheduled_queue.MoveToFront(member->GetPriority(), member->GetActiveCore(), member);
368 }
369
370 constexpr Thread* MoveToScheduledBack(Member* member) {
371 return this->scheduled_queue.MoveToBack(member->GetPriority(), member->GetActiveCore(),
372 member);
373 }
374
375 // First class fancy operations.
376 constexpr void ChangePriority(s32 prev_priority, bool is_running, Member* member) {
377 ASSERT(IsValidPriority(prev_priority));
378
379 // Remove the member from the queues.
380 const s32 new_priority = member->GetPriority();
381 this->Remove(prev_priority, member);
382
383 // And enqueue. If the member is running, we want to keep it running.
384 if (is_running) {
385 this->PushFront(new_priority, member);
386 } else {
387 this->PushBack(new_priority, member);
388 }
389 }
390
391 constexpr void ChangeAffinityMask(s32 prev_core, const AffinityMaskType& prev_affinity,
392 Member* member) {
393 // Get the new information.
394 const s32 priority = member->GetPriority();
395 const AffinityMaskType& new_affinity = member->GetAffinityMask();
396 const s32 new_core = member->GetActiveCore();
397
398 // Remove the member from all queues it was in before.
399 for (s32 core = 0; core < static_cast<s32>(NumCores); core++) {
400 if (prev_affinity.GetAffinity(core)) {
401 if (core == prev_core) {
402 this->scheduled_queue.Remove(priority, core, member);
403 } else {
404 this->suggested_queue.Remove(priority, core, member);
405 }
406 }
407 }
408
409 // And add the member to all queues it should be in now.
410 for (s32 core = 0; core < static_cast<s32>(NumCores); core++) {
411 if (new_affinity.GetAffinity(core)) {
412 if (core == new_core) {
413 this->scheduled_queue.PushBack(priority, core, member);
414 } else {
415 this->suggested_queue.PushBack(priority, core, member);
416 }
417 }
418 }
419 }
420
421 constexpr void ChangeCore(s32 prev_core, Member* member, bool to_front = false) {
422 // Get the new information.
423 const s32 new_core = member->GetActiveCore();
424 const s32 priority = member->GetPriority();
425
426 // We don't need to do anything if the core is the same.
427 if (prev_core != new_core) {
428 // Remove from the scheduled queue for the previous core.
429 if (prev_core >= 0) {
430 this->scheduled_queue.Remove(priority, prev_core, member);
431 }
432
433 // Remove from the suggested queue and add to the scheduled queue for the new core.
434 if (new_core >= 0) {
435 this->suggested_queue.Remove(priority, new_core, member);
436 if (to_front) {
437 this->scheduled_queue.PushFront(priority, new_core, member);
438 } else {
439 this->scheduled_queue.PushBack(priority, new_core, member);
440 }
441 }
442
443 // Add to the suggested queue for the previous core.
444 if (prev_core >= 0) {
445 this->suggested_queue.PushBack(priority, prev_core, member);
446 }
447 }
448 }
449};
450
451} // namespace Kernel
diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp
new file mode 100644
index 000000000..c5fd82a6b
--- /dev/null
+++ b/src/core/hle/kernel/k_scheduler.cpp
@@ -0,0 +1,784 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5// This file references various implementation details from Atmosphere, an open-source firmware for
6// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX.
7
8#include "common/assert.h"
9#include "common/bit_util.h"
10#include "common/fiber.h"
11#include "common/logging/log.h"
12#include "core/arm/arm_interface.h"
13#include "core/core.h"
14#include "core/core_timing.h"
15#include "core/cpu_manager.h"
16#include "core/hle/kernel/k_scheduler.h"
17#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
18#include "core/hle/kernel/kernel.h"
19#include "core/hle/kernel/physical_core.h"
20#include "core/hle/kernel/process.h"
21#include "core/hle/kernel/thread.h"
22#include "core/hle/kernel/time_manager.h"
23
24namespace Kernel {
25
26static void IncrementScheduledCount(Kernel::Thread* thread) {
27 if (auto process = thread->GetOwnerProcess(); process) {
28 process->IncrementScheduledCount();
29 }
30}
31
32void KScheduler::RescheduleCores(KernelCore& kernel, u64 cores_pending_reschedule,
33 Core::EmuThreadHandle global_thread) {
34 u32 current_core = global_thread.host_handle;
35 bool must_context_switch = global_thread.guest_handle != InvalidHandle &&
36 (current_core < Core::Hardware::NUM_CPU_CORES);
37
38 while (cores_pending_reschedule != 0) {
39 u32 core = Common::CountTrailingZeroes64(cores_pending_reschedule);
40 ASSERT(core < Core::Hardware::NUM_CPU_CORES);
41 if (!must_context_switch || core != current_core) {
42 auto& phys_core = kernel.PhysicalCore(core);
43 phys_core.Interrupt();
44 } else {
45 must_context_switch = true;
46 }
47 cores_pending_reschedule &= ~(1ULL << core);
48 }
49 if (must_context_switch) {
50 auto core_scheduler = kernel.CurrentScheduler();
51 kernel.ExitSVCProfile();
52 core_scheduler->RescheduleCurrentCore();
53 kernel.EnterSVCProfile();
54 }
55}
56
57u64 KScheduler::UpdateHighestPriorityThread(Thread* highest_thread) {
58 std::scoped_lock lock{guard};
59 if (Thread* prev_highest_thread = this->state.highest_priority_thread;
60 prev_highest_thread != highest_thread) {
61 if (prev_highest_thread != nullptr) {
62 IncrementScheduledCount(prev_highest_thread);
63 prev_highest_thread->SetLastScheduledTick(system.CoreTiming().GetCPUTicks());
64 }
65 if (this->state.should_count_idle) {
66 if (highest_thread != nullptr) {
67 // if (Process* process = highest_thread->GetOwnerProcess(); process != nullptr) {
68 // process->SetRunningThread(this->core_id, highest_thread,
69 // this->state.idle_count);
70 //}
71 } else {
72 this->state.idle_count++;
73 }
74 }
75
76 this->state.highest_priority_thread = highest_thread;
77 this->state.needs_scheduling = true;
78 return (1ULL << this->core_id);
79 } else {
80 return 0;
81 }
82}
83
84u64 KScheduler::UpdateHighestPriorityThreadsImpl(KernelCore& kernel) {
85 ASSERT(kernel.GlobalSchedulerContext().IsLocked());
86
87 // Clear that we need to update.
88 ClearSchedulerUpdateNeeded(kernel);
89
90 u64 cores_needing_scheduling = 0, idle_cores = 0;
91 Thread* top_threads[Core::Hardware::NUM_CPU_CORES];
92 auto& priority_queue = GetPriorityQueue(kernel);
93
94 /// We want to go over all cores, finding the highest priority thread and determining if
95 /// scheduling is needed for that core.
96 for (size_t core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) {
97 Thread* top_thread = priority_queue.GetScheduledFront(static_cast<s32>(core_id));
98 if (top_thread != nullptr) {
99 // If the thread has no waiters, we need to check if the process has a thread pinned.
100 // TODO(bunnei): Implement thread pinning
101 } else {
102 idle_cores |= (1ULL << core_id);
103 }
104
105 top_threads[core_id] = top_thread;
106 cores_needing_scheduling |=
107 kernel.Scheduler(core_id).UpdateHighestPriorityThread(top_threads[core_id]);
108 }
109
110 // Idle cores are bad. We're going to try to migrate threads to each idle core in turn.
111 while (idle_cores != 0) {
112 u32 core_id = Common::CountTrailingZeroes64(idle_cores);
113 if (Thread* suggested = priority_queue.GetSuggestedFront(core_id); suggested != nullptr) {
114 s32 migration_candidates[Core::Hardware::NUM_CPU_CORES];
115 size_t num_candidates = 0;
116
117 // While we have a suggested thread, try to migrate it!
118 while (suggested != nullptr) {
119 // Check if the suggested thread is the top thread on its core.
120 const s32 suggested_core = suggested->GetActiveCore();
121 if (Thread* top_thread =
122 (suggested_core >= 0) ? top_threads[suggested_core] : nullptr;
123 top_thread != suggested) {
124 // Make sure we're not dealing with threads too high priority for migration.
125 if (top_thread != nullptr &&
126 top_thread->GetPriority() < HighestCoreMigrationAllowedPriority) {
127 break;
128 }
129
130 // The suggested thread isn't bound to its core, so we can migrate it!
131 suggested->SetActiveCore(core_id);
132 priority_queue.ChangeCore(suggested_core, suggested);
133
134 top_threads[core_id] = suggested;
135 cores_needing_scheduling |=
136 kernel.Scheduler(core_id).UpdateHighestPriorityThread(top_threads[core_id]);
137 break;
138 }
139
140 // Note this core as a candidate for migration.
141 ASSERT(num_candidates < Core::Hardware::NUM_CPU_CORES);
142 migration_candidates[num_candidates++] = suggested_core;
143 suggested = priority_queue.GetSuggestedNext(core_id, suggested);
144 }
145
146 // If suggested is nullptr, we failed to migrate a specific thread. So let's try all our
147 // candidate cores' top threads.
148 if (suggested == nullptr) {
149 for (size_t i = 0; i < num_candidates; i++) {
150 // Check if there's some other thread that can run on the candidate core.
151 const s32 candidate_core = migration_candidates[i];
152 suggested = top_threads[candidate_core];
153 if (Thread* next_on_candidate_core =
154 priority_queue.GetScheduledNext(candidate_core, suggested);
155 next_on_candidate_core != nullptr) {
156 // The candidate core can run some other thread! We'll migrate its current
157 // top thread to us.
158 top_threads[candidate_core] = next_on_candidate_core;
159 cores_needing_scheduling |=
160 kernel.Scheduler(candidate_core)
161 .UpdateHighestPriorityThread(top_threads[candidate_core]);
162
163 // Perform the migration.
164 suggested->SetActiveCore(core_id);
165 priority_queue.ChangeCore(candidate_core, suggested);
166
167 top_threads[core_id] = suggested;
168 cores_needing_scheduling |=
169 kernel.Scheduler(core_id).UpdateHighestPriorityThread(
170 top_threads[core_id]);
171 break;
172 }
173 }
174 }
175 }
176
177 idle_cores &= ~(1ULL << core_id);
178 }
179
180 return cores_needing_scheduling;
181}
182
183void KScheduler::OnThreadStateChanged(KernelCore& kernel, Thread* thread, u32 old_state) {
184 ASSERT(kernel.GlobalSchedulerContext().IsLocked());
185
186 // Check if the state has changed, because if it hasn't there's nothing to do.
187 const auto cur_state = thread->scheduling_state;
188 if (cur_state == old_state) {
189 return;
190 }
191
192 // Update the priority queues.
193 if (old_state == static_cast<u32>(ThreadSchedStatus::Runnable)) {
194 // If we were previously runnable, then we're not runnable now, and we should remove.
195 GetPriorityQueue(kernel).Remove(thread);
196 IncrementScheduledCount(thread);
197 SetSchedulerUpdateNeeded(kernel);
198 } else if (cur_state == static_cast<u32>(ThreadSchedStatus::Runnable)) {
199 // If we're now runnable, then we weren't previously, and we should add.
200 GetPriorityQueue(kernel).PushBack(thread);
201 IncrementScheduledCount(thread);
202 SetSchedulerUpdateNeeded(kernel);
203 }
204}
205
206void KScheduler::OnThreadPriorityChanged(KernelCore& kernel, Thread* thread, Thread* current_thread,
207 u32 old_priority) {
208
209 ASSERT(kernel.GlobalSchedulerContext().IsLocked());
210
211 // If the thread is runnable, we want to change its priority in the queue.
212 if (thread->scheduling_state == static_cast<u32>(ThreadSchedStatus::Runnable)) {
213 GetPriorityQueue(kernel).ChangePriority(
214 old_priority, thread == kernel.CurrentScheduler()->GetCurrentThread(), thread);
215 IncrementScheduledCount(thread);
216 SetSchedulerUpdateNeeded(kernel);
217 }
218}
219
220void KScheduler::OnThreadAffinityMaskChanged(KernelCore& kernel, Thread* thread,
221 const KAffinityMask& old_affinity, s32 old_core) {
222 ASSERT(kernel.GlobalSchedulerContext().IsLocked());
223
224 // If the thread is runnable, we want to change its affinity in the queue.
225 if (thread->scheduling_state == static_cast<u32>(ThreadSchedStatus::Runnable)) {
226 GetPriorityQueue(kernel).ChangeAffinityMask(old_core, old_affinity, thread);
227 IncrementScheduledCount(thread);
228 SetSchedulerUpdateNeeded(kernel);
229 }
230}
231
232void KScheduler::RotateScheduledQueue(s32 core_id, s32 priority) {
233 ASSERT(system.GlobalSchedulerContext().IsLocked());
234
235 // Get a reference to the priority queue.
236 auto& kernel = system.Kernel();
237 auto& priority_queue = GetPriorityQueue(kernel);
238
239 // Rotate the front of the queue to the end.
240 Thread* top_thread = priority_queue.GetScheduledFront(core_id, priority);
241 Thread* next_thread = nullptr;
242 if (top_thread != nullptr) {
243 next_thread = priority_queue.MoveToScheduledBack(top_thread);
244 if (next_thread != top_thread) {
245 IncrementScheduledCount(top_thread);
246 IncrementScheduledCount(next_thread);
247 }
248 }
249
250 // While we have a suggested thread, try to migrate it!
251 {
252 Thread* suggested = priority_queue.GetSuggestedFront(core_id, priority);
253 while (suggested != nullptr) {
254 // Check if the suggested thread is the top thread on its core.
255 const s32 suggested_core = suggested->GetActiveCore();
256 if (Thread* top_on_suggested_core =
257 (suggested_core >= 0) ? priority_queue.GetScheduledFront(suggested_core)
258 : nullptr;
259 top_on_suggested_core != suggested) {
260 // If the next thread is a new thread that has been waiting longer than our
261 // suggestion, we prefer it to our suggestion.
262 if (top_thread != next_thread && next_thread != nullptr &&
263 next_thread->GetLastScheduledTick() < suggested->GetLastScheduledTick()) {
264 suggested = nullptr;
265 break;
266 }
267
268 // If we're allowed to do a migration, do one.
269 // NOTE: Unlike migrations in UpdateHighestPriorityThread, this moves the suggestion
270 // to the front of the queue.
271 if (top_on_suggested_core == nullptr ||
272 top_on_suggested_core->GetPriority() >= HighestCoreMigrationAllowedPriority) {
273 suggested->SetActiveCore(core_id);
274 priority_queue.ChangeCore(suggested_core, suggested, true);
275 IncrementScheduledCount(suggested);
276 break;
277 }
278 }
279
280 // Get the next suggestion.
281 suggested = priority_queue.GetSamePriorityNext(core_id, suggested);
282 }
283 }
284
285 // Now that we might have migrated a thread with the same priority, check if we can do better.
286
287 {
288 Thread* best_thread = priority_queue.GetScheduledFront(core_id);
289 if (best_thread == GetCurrentThread()) {
290 best_thread = priority_queue.GetScheduledNext(core_id, best_thread);
291 }
292
293 // If the best thread we can choose has a priority the same or worse than ours, try to
294 // migrate a higher priority thread.
295 if (best_thread != nullptr && best_thread->GetPriority() >= static_cast<u32>(priority)) {
296 Thread* suggested = priority_queue.GetSuggestedFront(core_id);
297 while (suggested != nullptr) {
298 // If the suggestion's priority is the same as ours, don't bother.
299 if (suggested->GetPriority() >= best_thread->GetPriority()) {
300 break;
301 }
302
303 // Check if the suggested thread is the top thread on its core.
304 const s32 suggested_core = suggested->GetActiveCore();
305 if (Thread* top_on_suggested_core =
306 (suggested_core >= 0) ? priority_queue.GetScheduledFront(suggested_core)
307 : nullptr;
308 top_on_suggested_core != suggested) {
309 // If we're allowed to do a migration, do one.
310 // NOTE: Unlike migrations in UpdateHighestPriorityThread, this moves the
311 // suggestion to the front of the queue.
312 if (top_on_suggested_core == nullptr ||
313 top_on_suggested_core->GetPriority() >=
314 HighestCoreMigrationAllowedPriority) {
315 suggested->SetActiveCore(core_id);
316 priority_queue.ChangeCore(suggested_core, suggested, true);
317 IncrementScheduledCount(suggested);
318 break;
319 }
320 }
321
322 // Get the next suggestion.
323 suggested = priority_queue.GetSuggestedNext(core_id, suggested);
324 }
325 }
326 }
327
328 // After a rotation, we need a scheduler update.
329 SetSchedulerUpdateNeeded(kernel);
330}
331
332bool KScheduler::CanSchedule(KernelCore& kernel) {
333 return kernel.CurrentScheduler()->GetCurrentThread()->GetDisableDispatchCount() <= 1;
334}
335
336bool KScheduler::IsSchedulerUpdateNeeded(const KernelCore& kernel) {
337 return kernel.GlobalSchedulerContext().scheduler_update_needed.load(std::memory_order_acquire);
338}
339
340void KScheduler::SetSchedulerUpdateNeeded(KernelCore& kernel) {
341 kernel.GlobalSchedulerContext().scheduler_update_needed.store(true, std::memory_order_release);
342}
343
344void KScheduler::ClearSchedulerUpdateNeeded(KernelCore& kernel) {
345 kernel.GlobalSchedulerContext().scheduler_update_needed.store(false, std::memory_order_release);
346}
347
348void KScheduler::DisableScheduling(KernelCore& kernel) {
349 if (auto* scheduler = kernel.CurrentScheduler(); scheduler) {
350 ASSERT(scheduler->GetCurrentThread()->GetDisableDispatchCount() >= 0);
351 scheduler->GetCurrentThread()->DisableDispatch();
352 }
353}
354
355void KScheduler::EnableScheduling(KernelCore& kernel, u64 cores_needing_scheduling,
356 Core::EmuThreadHandle global_thread) {
357 if (auto* scheduler = kernel.CurrentScheduler(); scheduler) {
358 scheduler->GetCurrentThread()->EnableDispatch();
359 }
360 RescheduleCores(kernel, cores_needing_scheduling, global_thread);
361}
362
363u64 KScheduler::UpdateHighestPriorityThreads(KernelCore& kernel) {
364 if (IsSchedulerUpdateNeeded(kernel)) {
365 return UpdateHighestPriorityThreadsImpl(kernel);
366 } else {
367 return 0;
368 }
369}
370
371KSchedulerPriorityQueue& KScheduler::GetPriorityQueue(KernelCore& kernel) {
372 return kernel.GlobalSchedulerContext().priority_queue;
373}
374
375void KScheduler::YieldWithoutCoreMigration() {
376 auto& kernel = system.Kernel();
377
378 // Validate preconditions.
379 ASSERT(CanSchedule(kernel));
380 ASSERT(kernel.CurrentProcess() != nullptr);
381
382 // Get the current thread and process.
383 Thread& cur_thread = *GetCurrentThread();
384 Process& cur_process = *kernel.CurrentProcess();
385
386 // If the thread's yield count matches, there's nothing for us to do.
387 if (cur_thread.GetYieldScheduleCount() == cur_process.GetScheduledCount()) {
388 return;
389 }
390
391 // Get a reference to the priority queue.
392 auto& priority_queue = GetPriorityQueue(kernel);
393
394 // Perform the yield.
395 {
396 KScopedSchedulerLock lock(kernel);
397
398 const auto cur_state = cur_thread.scheduling_state;
399 if (cur_state == static_cast<u32>(ThreadSchedStatus::Runnable)) {
400 // Put the current thread at the back of the queue.
401 Thread* next_thread = priority_queue.MoveToScheduledBack(std::addressof(cur_thread));
402 IncrementScheduledCount(std::addressof(cur_thread));
403
404 // If the next thread is different, we have an update to perform.
405 if (next_thread != std::addressof(cur_thread)) {
406 SetSchedulerUpdateNeeded(kernel);
407 } else {
408 // Otherwise, set the thread's yield count so that we won't waste work until the
409 // process is scheduled again.
410 cur_thread.SetYieldScheduleCount(cur_process.GetScheduledCount());
411 }
412 }
413 }
414}
415
416void KScheduler::YieldWithCoreMigration() {
417 auto& kernel = system.Kernel();
418
419 // Validate preconditions.
420 ASSERT(CanSchedule(kernel));
421 ASSERT(kernel.CurrentProcess() != nullptr);
422
423 // Get the current thread and process.
424 Thread& cur_thread = *GetCurrentThread();
425 Process& cur_process = *kernel.CurrentProcess();
426
427 // If the thread's yield count matches, there's nothing for us to do.
428 if (cur_thread.GetYieldScheduleCount() == cur_process.GetScheduledCount()) {
429 return;
430 }
431
432 // Get a reference to the priority queue.
433 auto& priority_queue = GetPriorityQueue(kernel);
434
435 // Perform the yield.
436 {
437 KScopedSchedulerLock lock(kernel);
438
439 const auto cur_state = cur_thread.scheduling_state;
440 if (cur_state == static_cast<u32>(ThreadSchedStatus::Runnable)) {
441 // Get the current active core.
442 const s32 core_id = cur_thread.GetActiveCore();
443
444 // Put the current thread at the back of the queue.
445 Thread* next_thread = priority_queue.MoveToScheduledBack(std::addressof(cur_thread));
446 IncrementScheduledCount(std::addressof(cur_thread));
447
448 // While we have a suggested thread, try to migrate it!
449 bool recheck = false;
450 Thread* suggested = priority_queue.GetSuggestedFront(core_id);
451 while (suggested != nullptr) {
452 // Check if the suggested thread is the thread running on its core.
453 const s32 suggested_core = suggested->GetActiveCore();
454
455 if (Thread* running_on_suggested_core =
456 (suggested_core >= 0)
457 ? kernel.Scheduler(suggested_core).state.highest_priority_thread
458 : nullptr;
459 running_on_suggested_core != suggested) {
460 // If the current thread's priority is higher than our suggestion's we prefer
461 // the next thread to the suggestion. We also prefer the next thread when the
462 // current thread's priority is equal to the suggestions, but the next thread
463 // has been waiting longer.
464 if ((suggested->GetPriority() > cur_thread.GetPriority()) ||
465 (suggested->GetPriority() == cur_thread.GetPriority() &&
466 next_thread != std::addressof(cur_thread) &&
467 next_thread->GetLastScheduledTick() < suggested->GetLastScheduledTick())) {
468 suggested = nullptr;
469 break;
470 }
471
472 // If we're allowed to do a migration, do one.
473 // NOTE: Unlike migrations in UpdateHighestPriorityThread, this moves the
474 // suggestion to the front of the queue.
475 if (running_on_suggested_core == nullptr ||
476 running_on_suggested_core->GetPriority() >=
477 HighestCoreMigrationAllowedPriority) {
478 suggested->SetActiveCore(core_id);
479 priority_queue.ChangeCore(suggested_core, suggested, true);
480 IncrementScheduledCount(suggested);
481 break;
482 } else {
483 // We couldn't perform a migration, but we should check again on a future
484 // yield.
485 recheck = true;
486 }
487 }
488
489 // Get the next suggestion.
490 suggested = priority_queue.GetSuggestedNext(core_id, suggested);
491 }
492
493 // If we still have a suggestion or the next thread is different, we have an update to
494 // perform.
495 if (suggested != nullptr || next_thread != std::addressof(cur_thread)) {
496 SetSchedulerUpdateNeeded(kernel);
497 } else if (!recheck) {
498 // Otherwise if we don't need to re-check, set the thread's yield count so that we
499 // won't waste work until the process is scheduled again.
500 cur_thread.SetYieldScheduleCount(cur_process.GetScheduledCount());
501 }
502 }
503 }
504}
505
506void KScheduler::YieldToAnyThread() {
507 auto& kernel = system.Kernel();
508
509 // Validate preconditions.
510 ASSERT(CanSchedule(kernel));
511 ASSERT(kernel.CurrentProcess() != nullptr);
512
513 // Get the current thread and process.
514 Thread& cur_thread = *GetCurrentThread();
515 Process& cur_process = *kernel.CurrentProcess();
516
517 // If the thread's yield count matches, there's nothing for us to do.
518 if (cur_thread.GetYieldScheduleCount() == cur_process.GetScheduledCount()) {
519 return;
520 }
521
522 // Get a reference to the priority queue.
523 auto& priority_queue = GetPriorityQueue(kernel);
524
525 // Perform the yield.
526 {
527 KScopedSchedulerLock lock(kernel);
528
529 const auto cur_state = cur_thread.scheduling_state;
530 if (cur_state == static_cast<u32>(ThreadSchedStatus::Runnable)) {
531 // Get the current active core.
532 const s32 core_id = cur_thread.GetActiveCore();
533
534 // Migrate the current thread to core -1.
535 cur_thread.SetActiveCore(-1);
536 priority_queue.ChangeCore(core_id, std::addressof(cur_thread));
537 IncrementScheduledCount(std::addressof(cur_thread));
538
539 // If there's nothing scheduled, we can try to perform a migration.
540 if (priority_queue.GetScheduledFront(core_id) == nullptr) {
541 // While we have a suggested thread, try to migrate it!
542 Thread* suggested = priority_queue.GetSuggestedFront(core_id);
543 while (suggested != nullptr) {
544 // Check if the suggested thread is the top thread on its core.
545 const s32 suggested_core = suggested->GetActiveCore();
546 if (Thread* top_on_suggested_core =
547 (suggested_core >= 0) ? priority_queue.GetScheduledFront(suggested_core)
548 : nullptr;
549 top_on_suggested_core != suggested) {
550 // If we're allowed to do a migration, do one.
551 if (top_on_suggested_core == nullptr ||
552 top_on_suggested_core->GetPriority() >=
553 HighestCoreMigrationAllowedPriority) {
554 suggested->SetActiveCore(core_id);
555 priority_queue.ChangeCore(suggested_core, suggested);
556 IncrementScheduledCount(suggested);
557 }
558
559 // Regardless of whether we migrated, we had a candidate, so we're done.
560 break;
561 }
562
563 // Get the next suggestion.
564 suggested = priority_queue.GetSuggestedNext(core_id, suggested);
565 }
566
567 // If the suggestion is different from the current thread, we need to perform an
568 // update.
569 if (suggested != std::addressof(cur_thread)) {
570 SetSchedulerUpdateNeeded(kernel);
571 } else {
572 // Otherwise, set the thread's yield count so that we won't waste work until the
573 // process is scheduled again.
574 cur_thread.SetYieldScheduleCount(cur_process.GetScheduledCount());
575 }
576 } else {
577 // Otherwise, we have an update to perform.
578 SetSchedulerUpdateNeeded(kernel);
579 }
580 }
581 }
582}
583
584KScheduler::KScheduler(Core::System& system, std::size_t core_id)
585 : system(system), core_id(core_id) {
586 switch_fiber = std::make_shared<Common::Fiber>(OnSwitch, this);
587 this->state.needs_scheduling = true;
588 this->state.interrupt_task_thread_runnable = false;
589 this->state.should_count_idle = false;
590 this->state.idle_count = 0;
591 this->state.idle_thread_stack = nullptr;
592 this->state.highest_priority_thread = nullptr;
593}
594
595KScheduler::~KScheduler() = default;
596
597Thread* KScheduler::GetCurrentThread() const {
598 if (current_thread) {
599 return current_thread;
600 }
601 return idle_thread;
602}
603
604u64 KScheduler::GetLastContextSwitchTicks() const {
605 return last_context_switch_time;
606}
607
608void KScheduler::RescheduleCurrentCore() {
609 ASSERT(GetCurrentThread()->GetDisableDispatchCount() == 1);
610
611 auto& phys_core = system.Kernel().PhysicalCore(core_id);
612 if (phys_core.IsInterrupted()) {
613 phys_core.ClearInterrupt();
614 }
615 guard.lock();
616 if (this->state.needs_scheduling) {
617 Schedule();
618 } else {
619 guard.unlock();
620 }
621}
622
623void KScheduler::OnThreadStart() {
624 SwitchContextStep2();
625}
626
627void KScheduler::Unload(Thread* thread) {
628 if (thread) {
629 thread->SetIsRunning(false);
630 if (thread->IsContinuousOnSVC() && !thread->IsHLEThread()) {
631 system.ArmInterface(core_id).ExceptionalExit();
632 thread->SetContinuousOnSVC(false);
633 }
634 if (!thread->IsHLEThread() && !thread->HasExited()) {
635 Core::ARM_Interface& cpu_core = system.ArmInterface(core_id);
636 cpu_core.SaveContext(thread->GetContext32());
637 cpu_core.SaveContext(thread->GetContext64());
638 // Save the TPIDR_EL0 system register in case it was modified.
639 thread->SetTPIDR_EL0(cpu_core.GetTPIDR_EL0());
640 cpu_core.ClearExclusiveState();
641 }
642 thread->context_guard.unlock();
643 }
644}
645
646void KScheduler::Reload(Thread* thread) {
647 if (thread) {
648 ASSERT_MSG(thread->GetSchedulingStatus() == ThreadSchedStatus::Runnable,
649 "Thread must be runnable.");
650
651 // Cancel any outstanding wakeup events for this thread
652 thread->SetIsRunning(true);
653 thread->SetWasRunning(false);
654
655 auto* const thread_owner_process = thread->GetOwnerProcess();
656 if (thread_owner_process != nullptr) {
657 system.Kernel().MakeCurrentProcess(thread_owner_process);
658 }
659 if (!thread->IsHLEThread()) {
660 Core::ARM_Interface& cpu_core = system.ArmInterface(core_id);
661 cpu_core.LoadContext(thread->GetContext32());
662 cpu_core.LoadContext(thread->GetContext64());
663 cpu_core.SetTlsAddress(thread->GetTLSAddress());
664 cpu_core.SetTPIDR_EL0(thread->GetTPIDR_EL0());
665 cpu_core.ClearExclusiveState();
666 }
667 }
668}
669
670void KScheduler::SwitchContextStep2() {
671 // Load context of new thread
672 Reload(current_thread);
673
674 RescheduleCurrentCore();
675}
676
677void KScheduler::ScheduleImpl() {
678 Thread* previous_thread = current_thread;
679 current_thread = state.highest_priority_thread;
680
681 this->state.needs_scheduling = false;
682
683 if (current_thread == previous_thread) {
684 guard.unlock();
685 return;
686 }
687
688 Process* const previous_process = system.Kernel().CurrentProcess();
689
690 UpdateLastContextSwitchTime(previous_thread, previous_process);
691
692 // Save context for previous thread
693 Unload(previous_thread);
694
695 std::shared_ptr<Common::Fiber>* old_context;
696 if (previous_thread != nullptr) {
697 old_context = &previous_thread->GetHostContext();
698 } else {
699 old_context = &idle_thread->GetHostContext();
700 }
701 guard.unlock();
702
703 Common::Fiber::YieldTo(*old_context, switch_fiber);
704 /// When a thread wakes up, the scheduler may have changed to other in another core.
705 auto& next_scheduler = *system.Kernel().CurrentScheduler();
706 next_scheduler.SwitchContextStep2();
707}
708
709void KScheduler::OnSwitch(void* this_scheduler) {
710 KScheduler* sched = static_cast<KScheduler*>(this_scheduler);
711 sched->SwitchToCurrent();
712}
713
714void KScheduler::SwitchToCurrent() {
715 while (true) {
716 {
717 std::scoped_lock lock{guard};
718 current_thread = state.highest_priority_thread;
719 this->state.needs_scheduling = false;
720 }
721 const auto is_switch_pending = [this] {
722 std::scoped_lock lock{guard};
723 return state.needs_scheduling.load(std::memory_order_relaxed);
724 };
725 do {
726 if (current_thread != nullptr && !current_thread->IsHLEThread()) {
727 current_thread->context_guard.lock();
728 if (!current_thread->IsRunnable()) {
729 current_thread->context_guard.unlock();
730 break;
731 }
732 if (static_cast<u32>(current_thread->GetProcessorID()) != core_id) {
733 current_thread->context_guard.unlock();
734 break;
735 }
736 }
737 std::shared_ptr<Common::Fiber>* next_context;
738 if (current_thread != nullptr) {
739 next_context = &current_thread->GetHostContext();
740 } else {
741 next_context = &idle_thread->GetHostContext();
742 }
743 Common::Fiber::YieldTo(switch_fiber, *next_context);
744 } while (!is_switch_pending());
745 }
746}
747
748void KScheduler::UpdateLastContextSwitchTime(Thread* thread, Process* process) {
749 const u64 prev_switch_ticks = last_context_switch_time;
750 const u64 most_recent_switch_ticks = system.CoreTiming().GetCPUTicks();
751 const u64 update_ticks = most_recent_switch_ticks - prev_switch_ticks;
752
753 if (thread != nullptr) {
754 thread->UpdateCPUTimeTicks(update_ticks);
755 }
756
757 if (process != nullptr) {
758 process->UpdateCPUTimeTicks(update_ticks);
759 }
760
761 last_context_switch_time = most_recent_switch_ticks;
762}
763
764void KScheduler::Initialize() {
765 std::string name = "Idle Thread Id:" + std::to_string(core_id);
766 std::function<void(void*)> init_func = Core::CpuManager::GetIdleThreadStartFunc();
767 void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater();
768 ThreadType type = static_cast<ThreadType>(THREADTYPE_KERNEL | THREADTYPE_HLE | THREADTYPE_IDLE);
769 auto thread_res = Thread::Create(system, type, name, 0, 64, 0, static_cast<u32>(core_id), 0,
770 nullptr, std::move(init_func), init_func_parameter);
771 idle_thread = thread_res.Unwrap().get();
772
773 {
774 KScopedSchedulerLock lock{system.Kernel()};
775 idle_thread->SetStatus(ThreadStatus::Ready);
776 }
777}
778
779KScopedSchedulerLock::KScopedSchedulerLock(KernelCore& kernel)
780 : KScopedLock(kernel.GlobalSchedulerContext().SchedulerLock()) {}
781
782KScopedSchedulerLock::~KScopedSchedulerLock() = default;
783
784} // namespace Kernel
diff --git a/src/core/hle/kernel/k_scheduler.h b/src/core/hle/kernel/k_scheduler.h
new file mode 100644
index 000000000..e84abc84c
--- /dev/null
+++ b/src/core/hle/kernel/k_scheduler.h
@@ -0,0 +1,201 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5// This file references various implementation details from Atmosphere, an open-source firmware for
6// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX.
7
8#pragma once
9
10#include <atomic>
11
12#include "common/common_types.h"
13#include "common/spin_lock.h"
14#include "core/hle/kernel/global_scheduler_context.h"
15#include "core/hle/kernel/k_priority_queue.h"
16#include "core/hle/kernel/k_scheduler_lock.h"
17#include "core/hle/kernel/k_scoped_lock.h"
18
19namespace Common {
20class Fiber;
21}
22
23namespace Core {
24class System;
25}
26
27namespace Kernel {
28
29class KernelCore;
30class Process;
31class SchedulerLock;
32class Thread;
33
34class KScheduler final {
35public:
36 explicit KScheduler(Core::System& system, std::size_t core_id);
37 ~KScheduler();
38
39 /// Reschedules to the next available thread (call after current thread is suspended)
40 void RescheduleCurrentCore();
41
42 /// Reschedules cores pending reschedule, to be called on EnableScheduling.
43 static void RescheduleCores(KernelCore& kernel, u64 cores_pending_reschedule,
44 Core::EmuThreadHandle global_thread);
45
46 /// The next two are for SingleCore Only.
47 /// Unload current thread before preempting core.
48 void Unload(Thread* thread);
49
50 /// Reload current thread after core preemption.
51 void Reload(Thread* thread);
52
53 /// Gets the current running thread
54 [[nodiscard]] Thread* GetCurrentThread() const;
55
56 /// Gets the timestamp for the last context switch in ticks.
57 [[nodiscard]] u64 GetLastContextSwitchTicks() const;
58
59 [[nodiscard]] bool ContextSwitchPending() const {
60 return state.needs_scheduling.load(std::memory_order_relaxed);
61 }
62
63 void Initialize();
64
65 void OnThreadStart();
66
67 [[nodiscard]] std::shared_ptr<Common::Fiber>& ControlContext() {
68 return switch_fiber;
69 }
70
71 [[nodiscard]] const std::shared_ptr<Common::Fiber>& ControlContext() const {
72 return switch_fiber;
73 }
74
75 [[nodiscard]] u64 UpdateHighestPriorityThread(Thread* highest_thread);
76
77 /**
78 * Takes a thread and moves it to the back of the it's priority list.
79 *
80 * @note This operation can be redundant and no scheduling is changed if marked as so.
81 */
82 void YieldWithoutCoreMigration();
83
84 /**
85 * Takes a thread and moves it to the back of the it's priority list.
86 * Afterwards, tries to pick a suggested thread from the suggested queue that has worse time or
87 * a better priority than the next thread in the core.
88 *
89 * @note This operation can be redundant and no scheduling is changed if marked as so.
90 */
91 void YieldWithCoreMigration();
92
93 /**
94 * Takes a thread and moves it out of the scheduling queue.
95 * and into the suggested queue. If no thread can be scheduled afterwards in that core,
96 * a suggested thread is obtained instead.
97 *
98 * @note This operation can be redundant and no scheduling is changed if marked as so.
99 */
100 void YieldToAnyThread();
101
102 /// Notify the scheduler a thread's status has changed.
103 static void OnThreadStateChanged(KernelCore& kernel, Thread* thread, u32 old_state);
104
105 /// Notify the scheduler a thread's priority has changed.
106 static void OnThreadPriorityChanged(KernelCore& kernel, Thread* thread, Thread* current_thread,
107 u32 old_priority);
108
109 /// Notify the scheduler a thread's core and/or affinity mask has changed.
110 static void OnThreadAffinityMaskChanged(KernelCore& kernel, Thread* thread,
111 const KAffinityMask& old_affinity, s32 old_core);
112
113 static bool CanSchedule(KernelCore& kernel);
114 static bool IsSchedulerUpdateNeeded(const KernelCore& kernel);
115 static void SetSchedulerUpdateNeeded(KernelCore& kernel);
116 static void ClearSchedulerUpdateNeeded(KernelCore& kernel);
117 static void DisableScheduling(KernelCore& kernel);
118 static void EnableScheduling(KernelCore& kernel, u64 cores_needing_scheduling,
119 Core::EmuThreadHandle global_thread);
120 [[nodiscard]] static u64 UpdateHighestPriorityThreads(KernelCore& kernel);
121
122private:
123 friend class GlobalSchedulerContext;
124
125 /**
126 * Takes care of selecting the new scheduled threads in three steps:
127 *
128 * 1. First a thread is selected from the top of the priority queue. If no thread
129 * is obtained then we move to step two, else we are done.
130 *
131 * 2. Second we try to get a suggested thread that's not assigned to any core or
132 * that is not the top thread in that core.
133 *
134 * 3. Third is no suggested thread is found, we do a second pass and pick a running
135 * thread in another core and swap it with its current thread.
136 *
137 * returns the cores needing scheduling.
138 */
139 [[nodiscard]] static u64 UpdateHighestPriorityThreadsImpl(KernelCore& kernel);
140
141 [[nodiscard]] static KSchedulerPriorityQueue& GetPriorityQueue(KernelCore& kernel);
142
143 void RotateScheduledQueue(s32 core_id, s32 priority);
144
145 void Schedule() {
146 ASSERT(GetCurrentThread()->GetDisableDispatchCount() == 1);
147 this->ScheduleImpl();
148 }
149
150 /// Switches the CPU's active thread context to that of the specified thread
151 void ScheduleImpl();
152
153 /// When a thread wakes up, it must run this through it's new scheduler
154 void SwitchContextStep2();
155
156 /**
157 * Called on every context switch to update the internal timestamp
158 * This also updates the running time ticks for the given thread and
159 * process using the following difference:
160 *
161 * ticks += most_recent_ticks - last_context_switch_ticks
162 *
163 * The internal tick timestamp for the scheduler is simply the
164 * most recent tick count retrieved. No special arithmetic is
165 * applied to it.
166 */
167 void UpdateLastContextSwitchTime(Thread* thread, Process* process);
168
169 static void OnSwitch(void* this_scheduler);
170 void SwitchToCurrent();
171
172 Thread* current_thread{};
173 Thread* idle_thread{};
174
175 std::shared_ptr<Common::Fiber> switch_fiber{};
176
177 struct SchedulingState {
178 std::atomic<bool> needs_scheduling;
179 bool interrupt_task_thread_runnable{};
180 bool should_count_idle{};
181 u64 idle_count{};
182 Thread* highest_priority_thread{};
183 void* idle_thread_stack{};
184 };
185
186 SchedulingState state;
187
188 Core::System& system;
189 u64 last_context_switch_time{};
190 const std::size_t core_id;
191
192 Common::SpinLock guard{};
193};
194
195class KScopedSchedulerLock : KScopedLock<GlobalSchedulerContext::LockType> {
196public:
197 explicit KScopedSchedulerLock(KernelCore& kernel);
198 ~KScopedSchedulerLock();
199};
200
201} // namespace Kernel
diff --git a/src/core/hle/kernel/k_scheduler_lock.h b/src/core/hle/kernel/k_scheduler_lock.h
new file mode 100644
index 000000000..2f1c1f691
--- /dev/null
+++ b/src/core/hle/kernel/k_scheduler_lock.h
@@ -0,0 +1,75 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5// This file references various implementation details from Atmosphere, an open-source firmware for
6// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX.
7
8#pragma once
9
10#include "common/assert.h"
11#include "common/spin_lock.h"
12#include "core/hardware_properties.h"
13#include "core/hle/kernel/kernel.h"
14
15namespace Kernel {
16
17class KernelCore;
18
19template <typename SchedulerType>
20class KAbstractSchedulerLock {
21public:
22 explicit KAbstractSchedulerLock(KernelCore& kernel) : kernel{kernel} {}
23
24 bool IsLockedByCurrentThread() const {
25 return this->owner_thread == kernel.GetCurrentEmuThreadID();
26 }
27
28 void Lock() {
29 if (this->IsLockedByCurrentThread()) {
30 // If we already own the lock, we can just increment the count.
31 ASSERT(this->lock_count > 0);
32 this->lock_count++;
33 } else {
34 // Otherwise, we want to disable scheduling and acquire the spinlock.
35 SchedulerType::DisableScheduling(kernel);
36 this->spin_lock.lock();
37
38 // For debug, ensure that our state is valid.
39 ASSERT(this->lock_count == 0);
40 ASSERT(this->owner_thread == Core::EmuThreadHandle::InvalidHandle());
41
42 // Increment count, take ownership.
43 this->lock_count = 1;
44 this->owner_thread = kernel.GetCurrentEmuThreadID();
45 }
46 }
47
48 void Unlock() {
49 ASSERT(this->IsLockedByCurrentThread());
50 ASSERT(this->lock_count > 0);
51
52 // Release an instance of the lock.
53 if ((--this->lock_count) == 0) {
54 // We're no longer going to hold the lock. Take note of what cores need scheduling.
55 const u64 cores_needing_scheduling =
56 SchedulerType::UpdateHighestPriorityThreads(kernel);
57 Core::EmuThreadHandle leaving_thread = owner_thread;
58
59 // Note that we no longer hold the lock, and unlock the spinlock.
60 this->owner_thread = Core::EmuThreadHandle::InvalidHandle();
61 this->spin_lock.unlock();
62
63 // Enable scheduling, and perform a rescheduling operation.
64 SchedulerType::EnableScheduling(kernel, cores_needing_scheduling, leaving_thread);
65 }
66 }
67
68private:
69 KernelCore& kernel;
70 Common::SpinLock spin_lock{};
71 s32 lock_count{};
72 Core::EmuThreadHandle owner_thread{Core::EmuThreadHandle::InvalidHandle()};
73};
74
75} // namespace Kernel
diff --git a/src/core/hle/kernel/k_scoped_lock.h b/src/core/hle/kernel/k_scoped_lock.h
new file mode 100644
index 000000000..d7cc557b2
--- /dev/null
+++ b/src/core/hle/kernel/k_scoped_lock.h
@@ -0,0 +1,41 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5// This file references various implementation details from Atmosphere, an open-source firmware for
6// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX.
7
8#pragma once
9
10#include "common/common_types.h"
11
12namespace Kernel {
13
14template <typename T>
15concept KLockable = !std::is_reference_v<T> && requires(T & t) {
16 { t.Lock() }
17 ->std::same_as<void>;
18 { t.Unlock() }
19 ->std::same_as<void>;
20};
21
22template <typename T>
23requires KLockable<T> class KScopedLock {
24public:
25 explicit KScopedLock(T* l) : lock_ptr(l) {
26 this->lock_ptr->Lock();
27 }
28 explicit KScopedLock(T& l) : KScopedLock(std::addressof(l)) { /* ... */
29 }
30 ~KScopedLock() {
31 this->lock_ptr->Unlock();
32 }
33
34 KScopedLock(const KScopedLock&) = delete;
35 KScopedLock(KScopedLock&&) = delete;
36
37private:
38 T* lock_ptr;
39};
40
41} // 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
new file mode 100644
index 000000000..2bb3817fa
--- /dev/null
+++ b/src/core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h
@@ -0,0 +1,50 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5// This file references various implementation details from Atmosphere, an open-source firmware for
6// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX.
7
8#pragma once
9
10#include "common/common_types.h"
11#include "core/hle/kernel/handle_table.h"
12#include "core/hle/kernel/kernel.h"
13#include "core/hle/kernel/thread.h"
14#include "core/hle/kernel/time_manager.h"
15
16namespace Kernel {
17
18class KScopedSchedulerLockAndSleep {
19public:
20 explicit KScopedSchedulerLockAndSleep(KernelCore& kernel, Handle& event_handle, Thread* t,
21 s64 timeout)
22 : kernel(kernel), event_handle(event_handle), thread(t), timeout_tick(timeout) {
23 event_handle = InvalidHandle;
24
25 // Lock the scheduler.
26 kernel.GlobalSchedulerContext().scheduler_lock.Lock();
27 }
28
29 ~KScopedSchedulerLockAndSleep() {
30 // Register the sleep.
31 if (this->timeout_tick > 0) {
32 kernel.TimeManager().ScheduleTimeEvent(event_handle, this->thread, this->timeout_tick);
33 }
34
35 // Unlock the scheduler.
36 kernel.GlobalSchedulerContext().scheduler_lock.Unlock();
37 }
38
39 void CancelSleep() {
40 this->timeout_tick = 0;
41 }
42
43private:
44 KernelCore& kernel;
45 Handle& event_handle;
46 Thread* thread{};
47 s64 timeout_tick{};
48};
49
50} // namespace Kernel
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index f2b0fe2fd..e8ece8164 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -7,15 +7,15 @@
7#include <bitset> 7#include <bitset>
8#include <functional> 8#include <functional>
9#include <memory> 9#include <memory>
10#include <mutex>
11#include <thread> 10#include <thread>
12#include <unordered_map> 11#include <unordered_set>
13#include <utility> 12#include <utility>
14 13
15#include "common/assert.h" 14#include "common/assert.h"
16#include "common/logging/log.h" 15#include "common/logging/log.h"
17#include "common/microprofile.h" 16#include "common/microprofile.h"
18#include "common/thread.h" 17#include "common/thread.h"
18#include "common/thread_worker.h"
19#include "core/arm/arm_interface.h" 19#include "core/arm/arm_interface.h"
20#include "core/arm/cpu_interrupt_handler.h" 20#include "core/arm/cpu_interrupt_handler.h"
21#include "core/arm/exclusive_monitor.h" 21#include "core/arm/exclusive_monitor.h"
@@ -28,6 +28,7 @@
28#include "core/hle/kernel/client_port.h" 28#include "core/hle/kernel/client_port.h"
29#include "core/hle/kernel/errors.h" 29#include "core/hle/kernel/errors.h"
30#include "core/hle/kernel/handle_table.h" 30#include "core/hle/kernel/handle_table.h"
31#include "core/hle/kernel/k_scheduler.h"
31#include "core/hle/kernel/kernel.h" 32#include "core/hle/kernel/kernel.h"
32#include "core/hle/kernel/memory/memory_layout.h" 33#include "core/hle/kernel/memory/memory_layout.h"
33#include "core/hle/kernel/memory/memory_manager.h" 34#include "core/hle/kernel/memory/memory_manager.h"
@@ -35,7 +36,7 @@
35#include "core/hle/kernel/physical_core.h" 36#include "core/hle/kernel/physical_core.h"
36#include "core/hle/kernel/process.h" 37#include "core/hle/kernel/process.h"
37#include "core/hle/kernel/resource_limit.h" 38#include "core/hle/kernel/resource_limit.h"
38#include "core/hle/kernel/scheduler.h" 39#include "core/hle/kernel/service_thread.h"
39#include "core/hle/kernel/shared_memory.h" 40#include "core/hle/kernel/shared_memory.h"
40#include "core/hle/kernel/synchronization.h" 41#include "core/hle/kernel/synchronization.h"
41#include "core/hle/kernel/thread.h" 42#include "core/hle/kernel/thread.h"
@@ -50,17 +51,20 @@ namespace Kernel {
50 51
51struct KernelCore::Impl { 52struct KernelCore::Impl {
52 explicit Impl(Core::System& system, KernelCore& kernel) 53 explicit Impl(Core::System& system, KernelCore& kernel)
53 : global_scheduler{kernel}, synchronization{system}, time_manager{system}, 54 : synchronization{system}, time_manager{system}, global_handle_table{kernel}, system{
54 global_handle_table{kernel}, system{system} {} 55 system} {}
55 56
56 void SetMulticore(bool is_multicore) { 57 void SetMulticore(bool is_multicore) {
57 this->is_multicore = is_multicore; 58 this->is_multicore = is_multicore;
58 } 59 }
59 60
60 void Initialize(KernelCore& kernel) { 61 void Initialize(KernelCore& kernel) {
61 Shutdown();
62 RegisterHostThread(); 62 RegisterHostThread();
63 63
64 global_scheduler_context = std::make_unique<Kernel::GlobalSchedulerContext>(kernel);
65 service_thread_manager =
66 std::make_unique<Common::ThreadWorker>(1, "yuzu:ServiceThreadManager");
67
64 InitializePhysicalCores(); 68 InitializePhysicalCores();
65 InitializeSystemResourceLimit(kernel); 69 InitializeSystemResourceLimit(kernel);
66 InitializeMemoryLayout(); 70 InitializeMemoryLayout();
@@ -69,7 +73,19 @@ struct KernelCore::Impl {
69 InitializeSuspendThreads(); 73 InitializeSuspendThreads();
70 } 74 }
71 75
76 void InitializeCores() {
77 for (auto& core : cores) {
78 core.Initialize(current_process->Is64BitProcess());
79 }
80 }
81
72 void Shutdown() { 82 void Shutdown() {
83 process_list.clear();
84
85 // Ensures all service threads gracefully shutdown
86 service_thread_manager.reset();
87 service_threads.clear();
88
73 next_object_id = 0; 89 next_object_id = 0;
74 next_kernel_process_id = Process::InitialKIPIDMin; 90 next_kernel_process_id = Process::InitialKIPIDMin;
75 next_user_process_id = Process::ProcessIDMin; 91 next_user_process_id = Process::ProcessIDMin;
@@ -81,41 +97,30 @@ struct KernelCore::Impl {
81 } 97 }
82 } 98 }
83 99
84 for (std::size_t i = 0; i < cores.size(); i++) {
85 cores[i].Shutdown();
86 schedulers[i].reset();
87 }
88 cores.clear(); 100 cores.clear();
89 101
90 registered_core_threads.reset();
91
92 process_list.clear();
93 current_process = nullptr; 102 current_process = nullptr;
94 103
95 system_resource_limit = nullptr; 104 system_resource_limit = nullptr;
96 105
97 global_handle_table.Clear(); 106 global_handle_table.Clear();
98 preemption_event = nullptr;
99 107
100 global_scheduler.Shutdown(); 108 preemption_event = nullptr;
101 109
102 named_ports.clear(); 110 named_ports.clear();
103 111
104 for (auto& core : cores) {
105 core.Shutdown();
106 }
107 cores.clear();
108
109 exclusive_monitor.reset(); 112 exclusive_monitor.reset();
110 host_thread_ids.clear(); 113
114 // Next host thead ID to use, 0-3 IDs represent core threads, >3 represent others
115 next_host_thread_id = Core::Hardware::NUM_CPU_CORES;
111 } 116 }
112 117
113 void InitializePhysicalCores() { 118 void InitializePhysicalCores() {
114 exclusive_monitor = 119 exclusive_monitor =
115 Core::MakeExclusiveMonitor(system.Memory(), Core::Hardware::NUM_CPU_CORES); 120 Core::MakeExclusiveMonitor(system.Memory(), Core::Hardware::NUM_CPU_CORES);
116 for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { 121 for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
117 schedulers[i] = std::make_unique<Kernel::Scheduler>(system, i); 122 schedulers[i] = std::make_unique<Kernel::KScheduler>(system, i);
118 cores.emplace_back(system, i, *schedulers[i], interrupts[i]); 123 cores.emplace_back(i, system, *schedulers[i], interrupts);
119 } 124 }
120 } 125 }
121 126
@@ -147,8 +152,8 @@ struct KernelCore::Impl {
147 preemption_event = Core::Timing::CreateEvent( 152 preemption_event = Core::Timing::CreateEvent(
148 "PreemptionCallback", [this, &kernel](std::uintptr_t, std::chrono::nanoseconds) { 153 "PreemptionCallback", [this, &kernel](std::uintptr_t, std::chrono::nanoseconds) {
149 { 154 {
150 SchedulerLock lock(kernel); 155 KScopedSchedulerLock lock(kernel);
151 global_scheduler.PreemptThreads(); 156 global_scheduler_context->PreemptThreads();
152 } 157 }
153 const auto time_interval = std::chrono::nanoseconds{ 158 const auto time_interval = std::chrono::nanoseconds{
154 Core::Timing::msToCycles(std::chrono::milliseconds(10))}; 159 Core::Timing::msToCycles(std::chrono::milliseconds(10))};
@@ -177,63 +182,62 @@ struct KernelCore::Impl {
177 182
178 void MakeCurrentProcess(Process* process) { 183 void MakeCurrentProcess(Process* process) {
179 current_process = process; 184 current_process = process;
180
181 if (process == nullptr) { 185 if (process == nullptr) {
182 return; 186 return;
183 } 187 }
184 188
185 u32 core_id = GetCurrentHostThreadID(); 189 const u32 core_id = GetCurrentHostThreadID();
186 if (core_id < Core::Hardware::NUM_CPU_CORES) { 190 if (core_id < Core::Hardware::NUM_CPU_CORES) {
187 system.Memory().SetCurrentPageTable(*process, core_id); 191 system.Memory().SetCurrentPageTable(*process, core_id);
188 } 192 }
189 } 193 }
190 194
195 /// Creates a new host thread ID, should only be called by GetHostThreadId
196 u32 AllocateHostThreadId(std::optional<std::size_t> core_id) {
197 if (core_id) {
198 // The first for slots are reserved for CPU core threads
199 ASSERT(*core_id < Core::Hardware::NUM_CPU_CORES);
200 return static_cast<u32>(*core_id);
201 } else {
202 return next_host_thread_id++;
203 }
204 }
205
206 /// Gets the host thread ID for the caller, allocating a new one if this is the first time
207 u32 GetHostThreadId(std::optional<std::size_t> core_id = std::nullopt) {
208 const thread_local auto host_thread_id{AllocateHostThreadId(core_id)};
209 return host_thread_id;
210 }
211
212 /// Registers a CPU core thread by allocating a host thread ID for it
191 void RegisterCoreThread(std::size_t core_id) { 213 void RegisterCoreThread(std::size_t core_id) {
192 std::unique_lock lock{register_thread_mutex}; 214 ASSERT(core_id < Core::Hardware::NUM_CPU_CORES);
215 const auto this_id = GetHostThreadId(core_id);
193 if (!is_multicore) { 216 if (!is_multicore) {
194 single_core_thread_id = std::this_thread::get_id(); 217 single_core_thread_id = this_id;
195 } 218 }
196 const std::thread::id this_id = std::this_thread::get_id();
197 const auto it = host_thread_ids.find(this_id);
198 ASSERT(core_id < Core::Hardware::NUM_CPU_CORES);
199 ASSERT(it == host_thread_ids.end());
200 ASSERT(!registered_core_threads[core_id]);
201 host_thread_ids[this_id] = static_cast<u32>(core_id);
202 registered_core_threads.set(core_id);
203 } 219 }
204 220
221 /// Registers a new host thread by allocating a host thread ID for it
205 void RegisterHostThread() { 222 void RegisterHostThread() {
206 std::unique_lock lock{register_thread_mutex}; 223 [[maybe_unused]] const auto this_id = GetHostThreadId();
207 const std::thread::id this_id = std::this_thread::get_id();
208 const auto it = host_thread_ids.find(this_id);
209 if (it != host_thread_ids.end()) {
210 return;
211 }
212 host_thread_ids[this_id] = registered_thread_ids++;
213 } 224 }
214 225
215 u32 GetCurrentHostThreadID() const { 226 [[nodiscard]] u32 GetCurrentHostThreadID() {
216 const std::thread::id this_id = std::this_thread::get_id(); 227 const auto this_id = GetHostThreadId();
217 if (!is_multicore) { 228 if (!is_multicore && single_core_thread_id == this_id) {
218 if (single_core_thread_id == this_id) { 229 return static_cast<u32>(system.GetCpuManager().CurrentCore());
219 return static_cast<u32>(system.GetCpuManager().CurrentCore());
220 }
221 }
222 std::unique_lock lock{register_thread_mutex};
223 const auto it = host_thread_ids.find(this_id);
224 if (it == host_thread_ids.end()) {
225 return Core::INVALID_HOST_THREAD_ID;
226 } 230 }
227 return it->second; 231 return this_id;
228 } 232 }
229 233
230 Core::EmuThreadHandle GetCurrentEmuThreadID() const { 234 [[nodiscard]] Core::EmuThreadHandle GetCurrentEmuThreadID() {
231 Core::EmuThreadHandle result = Core::EmuThreadHandle::InvalidHandle(); 235 Core::EmuThreadHandle result = Core::EmuThreadHandle::InvalidHandle();
232 result.host_handle = GetCurrentHostThreadID(); 236 result.host_handle = GetCurrentHostThreadID();
233 if (result.host_handle >= Core::Hardware::NUM_CPU_CORES) { 237 if (result.host_handle >= Core::Hardware::NUM_CPU_CORES) {
234 return result; 238 return result;
235 } 239 }
236 const Kernel::Scheduler& sched = cores[result.host_handle].Scheduler(); 240 const Kernel::KScheduler& sched = cores[result.host_handle].Scheduler();
237 const Kernel::Thread* current = sched.GetCurrentThread(); 241 const Kernel::Thread* current = sched.GetCurrentThread();
238 if (current != nullptr && !current->IsPhantomMode()) { 242 if (current != nullptr && !current->IsPhantomMode()) {
239 result.guest_handle = current->GetGlobalHandle(); 243 result.guest_handle = current->GetGlobalHandle();
@@ -302,7 +306,7 @@ struct KernelCore::Impl {
302 // Lists all processes that exist in the current session. 306 // Lists all processes that exist in the current session.
303 std::vector<std::shared_ptr<Process>> process_list; 307 std::vector<std::shared_ptr<Process>> process_list;
304 Process* current_process = nullptr; 308 Process* current_process = nullptr;
305 Kernel::GlobalScheduler global_scheduler; 309 std::unique_ptr<Kernel::GlobalSchedulerContext> global_scheduler_context;
306 Kernel::Synchronization synchronization; 310 Kernel::Synchronization synchronization;
307 Kernel::TimeManager time_manager; 311 Kernel::TimeManager time_manager;
308 312
@@ -321,11 +325,8 @@ struct KernelCore::Impl {
321 std::unique_ptr<Core::ExclusiveMonitor> exclusive_monitor; 325 std::unique_ptr<Core::ExclusiveMonitor> exclusive_monitor;
322 std::vector<Kernel::PhysicalCore> cores; 326 std::vector<Kernel::PhysicalCore> cores;
323 327
324 // 0-3 IDs represent core threads, >3 represent others 328 // Next host thead ID to use, 0-3 IDs represent core threads, >3 represent others
325 std::unordered_map<std::thread::id, u32> host_thread_ids; 329 std::atomic<u32> next_host_thread_id{Core::Hardware::NUM_CPU_CORES};
326 u32 registered_thread_ids{Core::Hardware::NUM_CPU_CORES};
327 std::bitset<Core::Hardware::NUM_CPU_CORES> registered_core_threads;
328 mutable std::mutex register_thread_mutex;
329 330
330 // Kernel memory management 331 // Kernel memory management
331 std::unique_ptr<Memory::MemoryManager> memory_manager; 332 std::unique_ptr<Memory::MemoryManager> memory_manager;
@@ -337,12 +338,19 @@ struct KernelCore::Impl {
337 std::shared_ptr<Kernel::SharedMemory> irs_shared_mem; 338 std::shared_ptr<Kernel::SharedMemory> irs_shared_mem;
338 std::shared_ptr<Kernel::SharedMemory> time_shared_mem; 339 std::shared_ptr<Kernel::SharedMemory> time_shared_mem;
339 340
341 // Threads used for services
342 std::unordered_set<std::shared_ptr<Kernel::ServiceThread>> service_threads;
343
344 // Service threads are managed by a worker thread, so that a calling service thread can queue up
345 // the release of itself
346 std::unique_ptr<Common::ThreadWorker> service_thread_manager;
347
340 std::array<std::shared_ptr<Thread>, Core::Hardware::NUM_CPU_CORES> suspend_threads{}; 348 std::array<std::shared_ptr<Thread>, Core::Hardware::NUM_CPU_CORES> suspend_threads{};
341 std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES> interrupts{}; 349 std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES> interrupts{};
342 std::array<std::unique_ptr<Kernel::Scheduler>, Core::Hardware::NUM_CPU_CORES> schedulers{}; 350 std::array<std::unique_ptr<Kernel::KScheduler>, Core::Hardware::NUM_CPU_CORES> schedulers{};
343 351
344 bool is_multicore{}; 352 bool is_multicore{};
345 std::thread::id single_core_thread_id{}; 353 u32 single_core_thread_id{};
346 354
347 std::array<u64, Core::Hardware::NUM_CPU_CORES> svc_ticks{}; 355 std::array<u64, Core::Hardware::NUM_CPU_CORES> svc_ticks{};
348 356
@@ -363,6 +371,10 @@ void KernelCore::Initialize() {
363 impl->Initialize(*this); 371 impl->Initialize(*this);
364} 372}
365 373
374void KernelCore::InitializeCores() {
375 impl->InitializeCores();
376}
377
366void KernelCore::Shutdown() { 378void KernelCore::Shutdown() {
367 impl->Shutdown(); 379 impl->Shutdown();
368} 380}
@@ -395,19 +407,19 @@ const std::vector<std::shared_ptr<Process>>& KernelCore::GetProcessList() const
395 return impl->process_list; 407 return impl->process_list;
396} 408}
397 409
398Kernel::GlobalScheduler& KernelCore::GlobalScheduler() { 410Kernel::GlobalSchedulerContext& KernelCore::GlobalSchedulerContext() {
399 return impl->global_scheduler; 411 return *impl->global_scheduler_context;
400} 412}
401 413
402const Kernel::GlobalScheduler& KernelCore::GlobalScheduler() const { 414const Kernel::GlobalSchedulerContext& KernelCore::GlobalSchedulerContext() const {
403 return impl->global_scheduler; 415 return *impl->global_scheduler_context;
404} 416}
405 417
406Kernel::Scheduler& KernelCore::Scheduler(std::size_t id) { 418Kernel::KScheduler& KernelCore::Scheduler(std::size_t id) {
407 return *impl->schedulers[id]; 419 return *impl->schedulers[id];
408} 420}
409 421
410const Kernel::Scheduler& KernelCore::Scheduler(std::size_t id) const { 422const Kernel::KScheduler& KernelCore::Scheduler(std::size_t id) const {
411 return *impl->schedulers[id]; 423 return *impl->schedulers[id];
412} 424}
413 425
@@ -431,16 +443,13 @@ const Kernel::PhysicalCore& KernelCore::CurrentPhysicalCore() const {
431 return impl->cores[core_id]; 443 return impl->cores[core_id];
432} 444}
433 445
434Kernel::Scheduler& KernelCore::CurrentScheduler() { 446Kernel::KScheduler* KernelCore::CurrentScheduler() {
435 u32 core_id = impl->GetCurrentHostThreadID(); 447 u32 core_id = impl->GetCurrentHostThreadID();
436 ASSERT(core_id < Core::Hardware::NUM_CPU_CORES); 448 if (core_id >= Core::Hardware::NUM_CPU_CORES) {
437 return *impl->schedulers[core_id]; 449 // This is expected when called from not a guest thread
438} 450 return {};
439 451 }
440const Kernel::Scheduler& KernelCore::CurrentScheduler() const { 452 return impl->schedulers[core_id].get();
441 u32 core_id = impl->GetCurrentHostThreadID();
442 ASSERT(core_id < Core::Hardware::NUM_CPU_CORES);
443 return *impl->schedulers[core_id];
444} 453}
445 454
446std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES>& KernelCore::Interrupts() { 455std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES>& KernelCore::Interrupts() {
@@ -477,12 +486,17 @@ const Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() const {
477} 486}
478 487
479void KernelCore::InvalidateAllInstructionCaches() { 488void KernelCore::InvalidateAllInstructionCaches() {
480 auto& threads = GlobalScheduler().GetThreadList(); 489 for (auto& physical_core : impl->cores) {
481 for (auto& thread : threads) { 490 physical_core.ArmInterface().ClearInstructionCache();
482 if (!thread->IsHLEThread()) { 491 }
483 auto& arm_interface = thread->ArmInterface(); 492}
484 arm_interface.ClearInstructionCache(); 493
494void KernelCore::InvalidateCpuInstructionCacheRange(VAddr addr, std::size_t size) {
495 for (auto& physical_core : impl->cores) {
496 if (!physical_core.IsInitialized()) {
497 continue;
485 } 498 }
499 physical_core.ArmInterface().InvalidateCacheRange(addr, size);
486 } 500 }
487} 501}
488 502
@@ -598,7 +612,7 @@ const Kernel::SharedMemory& KernelCore::GetTimeSharedMem() const {
598void KernelCore::Suspend(bool in_suspention) { 612void KernelCore::Suspend(bool in_suspention) {
599 const bool should_suspend = exception_exited || in_suspention; 613 const bool should_suspend = exception_exited || in_suspention;
600 { 614 {
601 SchedulerLock lock(*this); 615 KScopedSchedulerLock lock(*this);
602 ThreadStatus status = should_suspend ? ThreadStatus::Ready : ThreadStatus::WaitSleep; 616 ThreadStatus status = should_suspend ? ThreadStatus::Ready : ThreadStatus::WaitSleep;
603 for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { 617 for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
604 impl->suspend_threads[i]->SetStatus(status); 618 impl->suspend_threads[i]->SetStatus(status);
@@ -625,4 +639,19 @@ void KernelCore::ExitSVCProfile() {
625 MicroProfileLeave(MICROPROFILE_TOKEN(Kernel_SVC), impl->svc_ticks[core]); 639 MicroProfileLeave(MICROPROFILE_TOKEN(Kernel_SVC), impl->svc_ticks[core]);
626} 640}
627 641
642std::weak_ptr<Kernel::ServiceThread> KernelCore::CreateServiceThread(const std::string& name) {
643 auto service_thread = std::make_shared<Kernel::ServiceThread>(*this, 1, name);
644 impl->service_thread_manager->QueueWork(
645 [this, service_thread] { impl->service_threads.emplace(service_thread); });
646 return service_thread;
647}
648
649void KernelCore::ReleaseServiceThread(std::weak_ptr<Kernel::ServiceThread> service_thread) {
650 impl->service_thread_manager->QueueWork([this, service_thread] {
651 if (auto strong_ptr = service_thread.lock()) {
652 impl->service_threads.erase(strong_ptr);
653 }
654 });
655}
656
628} // namespace Kernel 657} // namespace Kernel
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 16285c3f0..e3169f5a7 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -35,13 +35,14 @@ class SlabHeap;
35 35
36class AddressArbiter; 36class AddressArbiter;
37class ClientPort; 37class ClientPort;
38class GlobalScheduler; 38class GlobalSchedulerContext;
39class HandleTable; 39class HandleTable;
40class PhysicalCore; 40class PhysicalCore;
41class Process; 41class Process;
42class ResourceLimit; 42class ResourceLimit;
43class Scheduler; 43class KScheduler;
44class SharedMemory; 44class SharedMemory;
45class ServiceThread;
45class Synchronization; 46class Synchronization;
46class Thread; 47class Thread;
47class TimeManager; 48class TimeManager;
@@ -74,6 +75,9 @@ public:
74 /// Resets the kernel to a clean slate for use. 75 /// Resets the kernel to a clean slate for use.
75 void Initialize(); 76 void Initialize();
76 77
78 /// Initializes the CPU cores.
79 void InitializeCores();
80
77 /// Clears all resources in use by the kernel instance. 81 /// Clears all resources in use by the kernel instance.
78 void Shutdown(); 82 void Shutdown();
79 83
@@ -99,16 +103,16 @@ public:
99 const std::vector<std::shared_ptr<Process>>& GetProcessList() const; 103 const std::vector<std::shared_ptr<Process>>& GetProcessList() const;
100 104
101 /// Gets the sole instance of the global scheduler 105 /// Gets the sole instance of the global scheduler
102 Kernel::GlobalScheduler& GlobalScheduler(); 106 Kernel::GlobalSchedulerContext& GlobalSchedulerContext();
103 107
104 /// Gets the sole instance of the global scheduler 108 /// Gets the sole instance of the global scheduler
105 const Kernel::GlobalScheduler& GlobalScheduler() const; 109 const Kernel::GlobalSchedulerContext& GlobalSchedulerContext() const;
106 110
107 /// Gets the sole instance of the Scheduler assoviated with cpu core 'id' 111 /// Gets the sole instance of the Scheduler assoviated with cpu core 'id'
108 Kernel::Scheduler& Scheduler(std::size_t id); 112 Kernel::KScheduler& Scheduler(std::size_t id);
109 113
110 /// Gets the sole instance of the Scheduler assoviated with cpu core 'id' 114 /// Gets the sole instance of the Scheduler assoviated with cpu core 'id'
111 const Kernel::Scheduler& Scheduler(std::size_t id) const; 115 const Kernel::KScheduler& Scheduler(std::size_t id) const;
112 116
113 /// Gets the an instance of the respective physical CPU core. 117 /// Gets the an instance of the respective physical CPU core.
114 Kernel::PhysicalCore& PhysicalCore(std::size_t id); 118 Kernel::PhysicalCore& PhysicalCore(std::size_t id);
@@ -117,10 +121,7 @@ public:
117 const Kernel::PhysicalCore& PhysicalCore(std::size_t id) const; 121 const Kernel::PhysicalCore& PhysicalCore(std::size_t id) const;
118 122
119 /// Gets the sole instance of the Scheduler at the current running core. 123 /// Gets the sole instance of the Scheduler at the current running core.
120 Kernel::Scheduler& CurrentScheduler(); 124 Kernel::KScheduler* CurrentScheduler();
121
122 /// Gets the sole instance of the Scheduler at the current running core.
123 const Kernel::Scheduler& CurrentScheduler() const;
124 125
125 /// Gets the an instance of the current physical CPU core. 126 /// Gets the an instance of the current physical CPU core.
126 Kernel::PhysicalCore& CurrentPhysicalCore(); 127 Kernel::PhysicalCore& CurrentPhysicalCore();
@@ -153,6 +154,8 @@ public:
153 154
154 void InvalidateAllInstructionCaches(); 155 void InvalidateAllInstructionCaches();
155 156
157 void InvalidateCpuInstructionCacheRange(VAddr addr, std::size_t size);
158
156 /// Adds a port to the named port table 159 /// Adds a port to the named port table
157 void AddNamedPort(std::string name, std::shared_ptr<ClientPort> port); 160 void AddNamedPort(std::string name, std::shared_ptr<ClientPort> port);
158 161
@@ -225,6 +228,22 @@ public:
225 228
226 void ExitSVCProfile(); 229 void ExitSVCProfile();
227 230
231 /**
232 * Creates an HLE service thread, which are used to execute service routines asynchronously.
233 * While these are allocated per ServerSession, these need to be owned and managed outside of
234 * ServerSession to avoid a circular dependency.
235 * @param name String name for the ServerSession creating this thread, used for debug purposes.
236 * @returns The a weak pointer newly created service thread.
237 */
238 std::weak_ptr<Kernel::ServiceThread> CreateServiceThread(const std::string& name);
239
240 /**
241 * Releases a HLE service thread, instructing KernelCore to free it. This should be called when
242 * the ServerSession associated with the thread is destroyed.
243 * @param service_thread Service thread to release.
244 */
245 void ReleaseServiceThread(std::weak_ptr<Kernel::ServiceThread> service_thread);
246
228private: 247private:
229 friend class Object; 248 friend class Object;
230 friend class Process; 249 friend class Process;
diff --git a/src/core/hle/kernel/memory/address_space_info.cpp b/src/core/hle/kernel/memory/address_space_info.cpp
index e4288cab4..6cf43ba24 100644
--- a/src/core/hle/kernel/memory/address_space_info.cpp
+++ b/src/core/hle/kernel/memory/address_space_info.cpp
@@ -96,6 +96,7 @@ u64 AddressSpaceInfo::GetAddressSpaceStart(std::size_t width, Type type) {
96 return AddressSpaceInfos[AddressSpaceIndices39Bit[index]].address; 96 return AddressSpaceInfos[AddressSpaceIndices39Bit[index]].address;
97 } 97 }
98 UNREACHABLE(); 98 UNREACHABLE();
99 return 0;
99} 100}
100 101
101std::size_t AddressSpaceInfo::GetAddressSpaceSize(std::size_t width, Type type) { 102std::size_t AddressSpaceInfo::GetAddressSpaceSize(std::size_t width, Type type) {
@@ -112,6 +113,7 @@ std::size_t AddressSpaceInfo::GetAddressSpaceSize(std::size_t width, Type type)
112 return AddressSpaceInfos[AddressSpaceIndices39Bit[index]].size; 113 return AddressSpaceInfos[AddressSpaceIndices39Bit[index]].size;
113 } 114 }
114 UNREACHABLE(); 115 UNREACHABLE();
116 return 0;
115} 117}
116 118
117} // namespace Kernel::Memory 119} // namespace Kernel::Memory
diff --git a/src/core/hle/kernel/memory/memory_block.h b/src/core/hle/kernel/memory/memory_block.h
index 9d7839d08..83acece1e 100644
--- a/src/core/hle/kernel/memory/memory_block.h
+++ b/src/core/hle/kernel/memory/memory_block.h
@@ -73,12 +73,12 @@ enum class MemoryState : u32 {
73 ThreadLocal = 73 ThreadLocal =
74 static_cast<u32>(Svc::MemoryState::ThreadLocal) | FlagMapped | FlagReferenceCounted, 74 static_cast<u32>(Svc::MemoryState::ThreadLocal) | FlagMapped | FlagReferenceCounted,
75 75
76 Transfered = static_cast<u32>(Svc::MemoryState::Transfered) | FlagsMisc | 76 Transferred = static_cast<u32>(Svc::MemoryState::Transferred) | FlagsMisc |
77 FlagCanAlignedDeviceMap | FlagCanChangeAttribute | FlagCanUseIpc | 77 FlagCanAlignedDeviceMap | FlagCanChangeAttribute | FlagCanUseIpc |
78 FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc, 78 FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc,
79 79
80 SharedTransfered = static_cast<u32>(Svc::MemoryState::SharedTransfered) | FlagsMisc | 80 SharedTransferred = static_cast<u32>(Svc::MemoryState::SharedTransferred) | FlagsMisc |
81 FlagCanAlignedDeviceMap | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc, 81 FlagCanAlignedDeviceMap | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc,
82 82
83 SharedCode = static_cast<u32>(Svc::MemoryState::SharedCode) | FlagMapped | 83 SharedCode = static_cast<u32>(Svc::MemoryState::SharedCode) | FlagMapped |
84 FlagReferenceCounted | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc, 84 FlagReferenceCounted | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc,
@@ -111,8 +111,8 @@ static_assert(static_cast<u32>(MemoryState::AliasCodeData) == 0x03FFBD09);
111static_assert(static_cast<u32>(MemoryState::Ipc) == 0x005C3C0A); 111static_assert(static_cast<u32>(MemoryState::Ipc) == 0x005C3C0A);
112static_assert(static_cast<u32>(MemoryState::Stack) == 0x005C3C0B); 112static_assert(static_cast<u32>(MemoryState::Stack) == 0x005C3C0B);
113static_assert(static_cast<u32>(MemoryState::ThreadLocal) == 0x0040200C); 113static_assert(static_cast<u32>(MemoryState::ThreadLocal) == 0x0040200C);
114static_assert(static_cast<u32>(MemoryState::Transfered) == 0x015C3C0D); 114static_assert(static_cast<u32>(MemoryState::Transferred) == 0x015C3C0D);
115static_assert(static_cast<u32>(MemoryState::SharedTransfered) == 0x005C380E); 115static_assert(static_cast<u32>(MemoryState::SharedTransferred) == 0x005C380E);
116static_assert(static_cast<u32>(MemoryState::SharedCode) == 0x0040380F); 116static_assert(static_cast<u32>(MemoryState::SharedCode) == 0x0040380F);
117static_assert(static_cast<u32>(MemoryState::Inaccessible) == 0x00000010); 117static_assert(static_cast<u32>(MemoryState::Inaccessible) == 0x00000010);
118static_assert(static_cast<u32>(MemoryState::NonSecureIpc) == 0x005C3811); 118static_assert(static_cast<u32>(MemoryState::NonSecureIpc) == 0x005C3811);
@@ -222,9 +222,9 @@ public:
222 222
223public: 223public:
224 constexpr MemoryBlock() = default; 224 constexpr MemoryBlock() = default;
225 constexpr MemoryBlock(VAddr addr, std::size_t num_pages, MemoryState state, 225 constexpr MemoryBlock(VAddr addr_, std::size_t num_pages_, MemoryState state_,
226 MemoryPermission perm, MemoryAttribute attribute) 226 MemoryPermission perm_, MemoryAttribute attribute_)
227 : addr{addr}, num_pages(num_pages), state{state}, perm{perm}, attribute{attribute} {} 227 : addr{addr_}, num_pages(num_pages_), state{state_}, perm{perm_}, attribute{attribute_} {}
228 228
229 constexpr VAddr GetAddress() const { 229 constexpr VAddr GetAddress() const {
230 return addr; 230 return addr;
diff --git a/src/core/hle/kernel/memory/memory_block_manager.h b/src/core/hle/kernel/memory/memory_block_manager.h
index 6e1d41075..f57d1bbcc 100644
--- a/src/core/hle/kernel/memory/memory_block_manager.h
+++ b/src/core/hle/kernel/memory/memory_block_manager.h
@@ -57,8 +57,8 @@ public:
57private: 57private:
58 void MergeAdjacent(iterator it, iterator& next_it); 58 void MergeAdjacent(iterator it, iterator& next_it);
59 59
60 const VAddr start_addr; 60 [[maybe_unused]] const VAddr start_addr;
61 const VAddr end_addr; 61 [[maybe_unused]] const VAddr end_addr;
62 62
63 MemoryBlockTree memory_block_tree; 63 MemoryBlockTree memory_block_tree;
64}; 64};
diff --git a/src/core/hle/kernel/memory/page_table.cpp b/src/core/hle/kernel/memory/page_table.cpp
index a3fadb533..080886554 100644
--- a/src/core/hle/kernel/memory/page_table.cpp
+++ b/src/core/hle/kernel/memory/page_table.cpp
@@ -265,7 +265,7 @@ ResultCode PageTable::InitializeForProcess(FileSys::ProgramAddressSpaceType as_t
265 physical_memory_usage = 0; 265 physical_memory_usage = 0;
266 memory_pool = pool; 266 memory_pool = pool;
267 267
268 page_table_impl.Resize(address_space_width, PageBits, true); 268 page_table_impl.Resize(address_space_width, PageBits);
269 269
270 return InitializeMemoryLayout(start, end); 270 return InitializeMemoryLayout(start, end);
271} 271}
@@ -670,6 +670,11 @@ ResultCode PageTable::SetCodeMemoryPermission(VAddr addr, std::size_t size, Memo
670 return RESULT_SUCCESS; 670 return RESULT_SUCCESS;
671 } 671 }
672 672
673 if ((prev_perm & MemoryPermission::Execute) != (perm & MemoryPermission::Execute)) {
674 // Memory execution state is changing, invalidate CPU cache range
675 system.InvalidateCpuInstructionCacheRange(addr, size);
676 }
677
673 const std::size_t num_pages{size / PageSize}; 678 const std::size_t num_pages{size / PageSize};
674 const OperationType operation{(perm & MemoryPermission::Execute) != MemoryPermission::None 679 const OperationType operation{(perm & MemoryPermission::Execute) != MemoryPermission::None
675 ? OperationType::ChangePermissionsAndRefresh 680 ? OperationType::ChangePermissionsAndRefresh
@@ -1002,8 +1007,8 @@ constexpr VAddr PageTable::GetRegionAddress(MemoryState state) const {
1002 case MemoryState::Shared: 1007 case MemoryState::Shared:
1003 case MemoryState::AliasCode: 1008 case MemoryState::AliasCode:
1004 case MemoryState::AliasCodeData: 1009 case MemoryState::AliasCodeData:
1005 case MemoryState::Transfered: 1010 case MemoryState::Transferred:
1006 case MemoryState::SharedTransfered: 1011 case MemoryState::SharedTransferred:
1007 case MemoryState::SharedCode: 1012 case MemoryState::SharedCode:
1008 case MemoryState::GeneratedCode: 1013 case MemoryState::GeneratedCode:
1009 case MemoryState::CodeOut: 1014 case MemoryState::CodeOut:
@@ -1037,8 +1042,8 @@ constexpr std::size_t PageTable::GetRegionSize(MemoryState state) const {
1037 case MemoryState::Shared: 1042 case MemoryState::Shared:
1038 case MemoryState::AliasCode: 1043 case MemoryState::AliasCode:
1039 case MemoryState::AliasCodeData: 1044 case MemoryState::AliasCodeData:
1040 case MemoryState::Transfered: 1045 case MemoryState::Transferred:
1041 case MemoryState::SharedTransfered: 1046 case MemoryState::SharedTransferred:
1042 case MemoryState::SharedCode: 1047 case MemoryState::SharedCode:
1043 case MemoryState::GeneratedCode: 1048 case MemoryState::GeneratedCode:
1044 case MemoryState::CodeOut: 1049 case MemoryState::CodeOut:
@@ -1075,8 +1080,8 @@ constexpr bool PageTable::CanContain(VAddr addr, std::size_t size, MemoryState s
1075 case MemoryState::AliasCodeData: 1080 case MemoryState::AliasCodeData:
1076 case MemoryState::Stack: 1081 case MemoryState::Stack:
1077 case MemoryState::ThreadLocal: 1082 case MemoryState::ThreadLocal:
1078 case MemoryState::Transfered: 1083 case MemoryState::Transferred:
1079 case MemoryState::SharedTransfered: 1084 case MemoryState::SharedTransferred:
1080 case MemoryState::SharedCode: 1085 case MemoryState::SharedCode:
1081 case MemoryState::GeneratedCode: 1086 case MemoryState::GeneratedCode:
1082 case MemoryState::CodeOut: 1087 case MemoryState::CodeOut:
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp
index 8f6c944d1..4f8075e0e 100644
--- a/src/core/hle/kernel/mutex.cpp
+++ b/src/core/hle/kernel/mutex.cpp
@@ -11,11 +11,11 @@
11#include "core/core.h" 11#include "core/core.h"
12#include "core/hle/kernel/errors.h" 12#include "core/hle/kernel/errors.h"
13#include "core/hle/kernel/handle_table.h" 13#include "core/hle/kernel/handle_table.h"
14#include "core/hle/kernel/k_scheduler.h"
14#include "core/hle/kernel/kernel.h" 15#include "core/hle/kernel/kernel.h"
15#include "core/hle/kernel/mutex.h" 16#include "core/hle/kernel/mutex.h"
16#include "core/hle/kernel/object.h" 17#include "core/hle/kernel/object.h"
17#include "core/hle/kernel/process.h" 18#include "core/hle/kernel/process.h"
18#include "core/hle/kernel/scheduler.h"
19#include "core/hle/kernel/thread.h" 19#include "core/hle/kernel/thread.h"
20#include "core/hle/result.h" 20#include "core/hle/result.h"
21#include "core/memory.h" 21#include "core/memory.h"
@@ -73,9 +73,9 @@ ResultCode Mutex::TryAcquire(VAddr address, Handle holding_thread_handle,
73 73
74 auto& kernel = system.Kernel(); 74 auto& kernel = system.Kernel();
75 std::shared_ptr<Thread> current_thread = 75 std::shared_ptr<Thread> current_thread =
76 SharedFrom(kernel.CurrentScheduler().GetCurrentThread()); 76 SharedFrom(kernel.CurrentScheduler()->GetCurrentThread());
77 { 77 {
78 SchedulerLock lock(kernel); 78 KScopedSchedulerLock lock(kernel);
79 // The mutex address must be 4-byte aligned 79 // The mutex address must be 4-byte aligned
80 if ((address % sizeof(u32)) != 0) { 80 if ((address % sizeof(u32)) != 0) {
81 return ERR_INVALID_ADDRESS; 81 return ERR_INVALID_ADDRESS;
@@ -114,7 +114,7 @@ ResultCode Mutex::TryAcquire(VAddr address, Handle holding_thread_handle,
114 } 114 }
115 115
116 { 116 {
117 SchedulerLock lock(kernel); 117 KScopedSchedulerLock lock(kernel);
118 auto* owner = current_thread->GetLockOwner(); 118 auto* owner = current_thread->GetLockOwner();
119 if (owner != nullptr) { 119 if (owner != nullptr) {
120 owner->RemoveMutexWaiter(current_thread); 120 owner->RemoveMutexWaiter(current_thread);
@@ -153,10 +153,10 @@ std::pair<ResultCode, std::shared_ptr<Thread>> Mutex::Unlock(std::shared_ptr<Thr
153 153
154ResultCode Mutex::Release(VAddr address) { 154ResultCode Mutex::Release(VAddr address) {
155 auto& kernel = system.Kernel(); 155 auto& kernel = system.Kernel();
156 SchedulerLock lock(kernel); 156 KScopedSchedulerLock lock(kernel);
157 157
158 std::shared_ptr<Thread> current_thread = 158 std::shared_ptr<Thread> current_thread =
159 SharedFrom(kernel.CurrentScheduler().GetCurrentThread()); 159 SharedFrom(kernel.CurrentScheduler()->GetCurrentThread());
160 160
161 auto [result, new_owner] = Unlock(current_thread, address); 161 auto [result, new_owner] = Unlock(current_thread, address);
162 162
diff --git a/src/core/hle/kernel/physical_core.cpp b/src/core/hle/kernel/physical_core.cpp
index c6bbdb080..7fea45f96 100644
--- a/src/core/hle/kernel/physical_core.cpp
+++ b/src/core/hle/kernel/physical_core.cpp
@@ -2,54 +2,60 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/assert.h"
6#include "common/logging/log.h"
7#include "common/spin_lock.h" 5#include "common/spin_lock.h"
8#include "core/arm/arm_interface.h" 6#include "core/arm/cpu_interrupt_handler.h"
9#ifdef ARCHITECTURE_x86_64
10#include "core/arm/dynarmic/arm_dynarmic_32.h" 7#include "core/arm/dynarmic/arm_dynarmic_32.h"
11#include "core/arm/dynarmic/arm_dynarmic_64.h" 8#include "core/arm/dynarmic/arm_dynarmic_64.h"
12#endif
13#include "core/arm/cpu_interrupt_handler.h"
14#include "core/arm/exclusive_monitor.h"
15#include "core/arm/unicorn/arm_unicorn.h"
16#include "core/core.h" 9#include "core/core.h"
10#include "core/hle/kernel/k_scheduler.h"
11#include "core/hle/kernel/kernel.h"
17#include "core/hle/kernel/physical_core.h" 12#include "core/hle/kernel/physical_core.h"
18#include "core/hle/kernel/scheduler.h"
19#include "core/hle/kernel/thread.h"
20 13
21namespace Kernel { 14namespace Kernel {
22 15
23PhysicalCore::PhysicalCore(Core::System& system, std::size_t id, Kernel::Scheduler& scheduler, 16PhysicalCore::PhysicalCore(std::size_t core_index, Core::System& system,
24 Core::CPUInterruptHandler& interrupt_handler) 17 Kernel::KScheduler& scheduler, Core::CPUInterrupts& interrupts)
25 : interrupt_handler{interrupt_handler}, core_index{id}, scheduler{scheduler} { 18 : core_index{core_index}, system{system}, scheduler{scheduler},
26 19 interrupts{interrupts}, guard{std::make_unique<Common::SpinLock>()} {}
27 guard = std::make_unique<Common::SpinLock>();
28}
29 20
30PhysicalCore::~PhysicalCore() = default; 21PhysicalCore::~PhysicalCore() = default;
31 22
32void PhysicalCore::Idle() { 23void PhysicalCore::Initialize([[maybe_unused]] bool is_64_bit) {
33 interrupt_handler.AwaitInterrupt(); 24#ifdef ARCHITECTURE_x86_64
25 auto& kernel = system.Kernel();
26 if (is_64_bit) {
27 arm_interface = std::make_unique<Core::ARM_Dynarmic_64>(
28 system, interrupts, kernel.IsMulticore(), kernel.GetExclusiveMonitor(), core_index);
29 } else {
30 arm_interface = std::make_unique<Core::ARM_Dynarmic_32>(
31 system, interrupts, kernel.IsMulticore(), kernel.GetExclusiveMonitor(), core_index);
32 }
33#else
34#error Platform not supported yet.
35#endif
34} 36}
35 37
36void PhysicalCore::Shutdown() { 38void PhysicalCore::Run() {
37 scheduler.Shutdown(); 39 arm_interface->Run();
40}
41
42void PhysicalCore::Idle() {
43 interrupts[core_index].AwaitInterrupt();
38} 44}
39 45
40bool PhysicalCore::IsInterrupted() const { 46bool PhysicalCore::IsInterrupted() const {
41 return interrupt_handler.IsInterrupted(); 47 return interrupts[core_index].IsInterrupted();
42} 48}
43 49
44void PhysicalCore::Interrupt() { 50void PhysicalCore::Interrupt() {
45 guard->lock(); 51 guard->lock();
46 interrupt_handler.SetInterrupt(true); 52 interrupts[core_index].SetInterrupt(true);
47 guard->unlock(); 53 guard->unlock();
48} 54}
49 55
50void PhysicalCore::ClearInterrupt() { 56void PhysicalCore::ClearInterrupt() {
51 guard->lock(); 57 guard->lock();
52 interrupt_handler.SetInterrupt(false); 58 interrupts[core_index].SetInterrupt(false);
53 guard->unlock(); 59 guard->unlock();
54} 60}
55 61
diff --git a/src/core/hle/kernel/physical_core.h b/src/core/hle/kernel/physical_core.h
index d7a7a951c..f2b0911aa 100644
--- a/src/core/hle/kernel/physical_core.h
+++ b/src/core/hle/kernel/physical_core.h
@@ -4,19 +4,21 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <array>
7#include <cstddef> 8#include <cstddef>
8#include <memory> 9#include <memory>
9 10
11#include "core/arm/arm_interface.h"
12
10namespace Common { 13namespace Common {
11class SpinLock; 14class SpinLock;
12} 15}
13 16
14namespace Kernel { 17namespace Kernel {
15class Scheduler; 18class KScheduler;
16} // namespace Kernel 19} // namespace Kernel
17 20
18namespace Core { 21namespace Core {
19class ARM_Interface;
20class CPUInterruptHandler; 22class CPUInterruptHandler;
21class ExclusiveMonitor; 23class ExclusiveMonitor;
22class System; 24class System;
@@ -26,17 +28,24 @@ namespace Kernel {
26 28
27class PhysicalCore { 29class PhysicalCore {
28public: 30public:
29 PhysicalCore(Core::System& system, std::size_t id, Kernel::Scheduler& scheduler, 31 PhysicalCore(std::size_t core_index, Core::System& system, Kernel::KScheduler& scheduler,
30 Core::CPUInterruptHandler& interrupt_handler); 32 Core::CPUInterrupts& interrupts);
31 ~PhysicalCore(); 33 ~PhysicalCore();
32 34
33 PhysicalCore(const PhysicalCore&) = delete; 35 PhysicalCore(const PhysicalCore&) = delete;
34 PhysicalCore& operator=(const PhysicalCore&) = delete; 36 PhysicalCore& operator=(const PhysicalCore&) = delete;
35 37
36 PhysicalCore(PhysicalCore&&) = default; 38 PhysicalCore(PhysicalCore&&) = default;
37 PhysicalCore& operator=(PhysicalCore&&) = default; 39 PhysicalCore& operator=(PhysicalCore&&) = delete;
40
41 /// Initialize the core for the specified parameters.
42 void Initialize(bool is_64_bit);
43
44 /// Execute current jit state
45 void Run();
38 46
39 void Idle(); 47 void Idle();
48
40 /// Interrupt this physical core. 49 /// Interrupt this physical core.
41 void Interrupt(); 50 void Interrupt();
42 51
@@ -46,8 +55,17 @@ public:
46 /// Check if this core is interrupted 55 /// Check if this core is interrupted
47 bool IsInterrupted() const; 56 bool IsInterrupted() const;
48 57
49 // Shutdown this physical core. 58 bool IsInitialized() const {
50 void Shutdown(); 59 return arm_interface != nullptr;
60 }
61
62 Core::ARM_Interface& ArmInterface() {
63 return *arm_interface;
64 }
65
66 const Core::ARM_Interface& ArmInterface() const {
67 return *arm_interface;
68 }
51 69
52 bool IsMainCore() const { 70 bool IsMainCore() const {
53 return core_index == 0; 71 return core_index == 0;
@@ -61,19 +79,21 @@ public:
61 return core_index; 79 return core_index;
62 } 80 }
63 81
64 Kernel::Scheduler& Scheduler() { 82 Kernel::KScheduler& Scheduler() {
65 return scheduler; 83 return scheduler;
66 } 84 }
67 85
68 const Kernel::Scheduler& Scheduler() const { 86 const Kernel::KScheduler& Scheduler() const {
69 return scheduler; 87 return scheduler;
70 } 88 }
71 89
72private: 90private:
73 Core::CPUInterruptHandler& interrupt_handler; 91 const std::size_t core_index;
74 std::size_t core_index; 92 Core::System& system;
75 Kernel::Scheduler& scheduler; 93 Kernel::KScheduler& scheduler;
94 Core::CPUInterrupts& interrupts;
76 std::unique_ptr<Common::SpinLock> guard; 95 std::unique_ptr<Common::SpinLock> guard;
96 std::unique_ptr<Core::ARM_Interface> arm_interface;
77}; 97};
78 98
79} // namespace Kernel 99} // namespace Kernel
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index ff9d9248b..b905b486a 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -4,6 +4,7 @@
4 4
5#include <algorithm> 5#include <algorithm>
6#include <bitset> 6#include <bitset>
7#include <ctime>
7#include <memory> 8#include <memory>
8#include <random> 9#include <random>
9#include "common/alignment.h" 10#include "common/alignment.h"
@@ -14,13 +15,13 @@
14#include "core/file_sys/program_metadata.h" 15#include "core/file_sys/program_metadata.h"
15#include "core/hle/kernel/code_set.h" 16#include "core/hle/kernel/code_set.h"
16#include "core/hle/kernel/errors.h" 17#include "core/hle/kernel/errors.h"
18#include "core/hle/kernel/k_scheduler.h"
17#include "core/hle/kernel/kernel.h" 19#include "core/hle/kernel/kernel.h"
18#include "core/hle/kernel/memory/memory_block_manager.h" 20#include "core/hle/kernel/memory/memory_block_manager.h"
19#include "core/hle/kernel/memory/page_table.h" 21#include "core/hle/kernel/memory/page_table.h"
20#include "core/hle/kernel/memory/slab_heap.h" 22#include "core/hle/kernel/memory/slab_heap.h"
21#include "core/hle/kernel/process.h" 23#include "core/hle/kernel/process.h"
22#include "core/hle/kernel/resource_limit.h" 24#include "core/hle/kernel/resource_limit.h"
23#include "core/hle/kernel/scheduler.h"
24#include "core/hle/kernel/thread.h" 25#include "core/hle/kernel/thread.h"
25#include "core/hle/lock.h" 26#include "core/hle/lock.h"
26#include "core/memory.h" 27#include "core/memory.h"
@@ -53,7 +54,7 @@ void SetupMainThread(Core::System& system, Process& owner_process, u32 priority,
53 auto& kernel = system.Kernel(); 54 auto& kernel = system.Kernel();
54 // Threads by default are dormant, wake up the main thread so it runs when the scheduler fires 55 // Threads by default are dormant, wake up the main thread so it runs when the scheduler fires
55 { 56 {
56 SchedulerLock lock{kernel}; 57 KScopedSchedulerLock lock{kernel};
57 thread->SetStatus(ThreadStatus::Ready); 58 thread->SetStatus(ThreadStatus::Ready);
58 } 59 }
59} 60}
@@ -123,7 +124,7 @@ std::shared_ptr<Process> Process::Create(Core::System& system, std::string name,
123 : kernel.CreateNewUserProcessID(); 124 : kernel.CreateNewUserProcessID();
124 process->capabilities.InitializeForMetadatalessProcess(); 125 process->capabilities.InitializeForMetadatalessProcess();
125 126
126 std::mt19937 rng(Settings::values.rng_seed.GetValue().value_or(0)); 127 std::mt19937 rng(Settings::values.rng_seed.GetValue().value_or(std::time(nullptr)));
127 std::uniform_int_distribution<u64> distribution; 128 std::uniform_int_distribution<u64> distribution;
128 std::generate(process->random_entropy.begin(), process->random_entropy.end(), 129 std::generate(process->random_entropy.begin(), process->random_entropy.end(),
129 [&] { return distribution(rng); }); 130 [&] { return distribution(rng); });
@@ -212,7 +213,7 @@ void Process::UnregisterThread(const Thread* thread) {
212} 213}
213 214
214ResultCode Process::ClearSignalState() { 215ResultCode Process::ClearSignalState() {
215 SchedulerLock lock(system.Kernel()); 216 KScopedSchedulerLock lock(system.Kernel());
216 if (status == ProcessStatus::Exited) { 217 if (status == ProcessStatus::Exited) {
217 LOG_ERROR(Kernel, "called on a terminated process instance."); 218 LOG_ERROR(Kernel, "called on a terminated process instance.");
218 return ERR_INVALID_STATE; 219 return ERR_INVALID_STATE;
@@ -313,7 +314,7 @@ void Process::PrepareForTermination() {
313 if (thread->GetOwnerProcess() != this) 314 if (thread->GetOwnerProcess() != this)
314 continue; 315 continue;
315 316
316 if (thread.get() == system.CurrentScheduler().GetCurrentThread()) 317 if (thread.get() == kernel.CurrentScheduler()->GetCurrentThread())
317 continue; 318 continue;
318 319
319 // TODO(Subv): When are the other running/ready threads terminated? 320 // TODO(Subv): When are the other running/ready threads terminated?
@@ -324,7 +325,7 @@ void Process::PrepareForTermination() {
324 } 325 }
325 }; 326 };
326 327
327 stop_threads(system.GlobalScheduler().GetThreadList()); 328 stop_threads(system.GlobalSchedulerContext().GetThreadList());
328 329
329 FreeTLSRegion(tls_region_address); 330 FreeTLSRegion(tls_region_address);
330 tls_region_address = 0; 331 tls_region_address = 0;
@@ -346,7 +347,7 @@ static auto FindTLSPageWithAvailableSlots(std::vector<TLSPage>& tls_pages) {
346} 347}
347 348
348VAddr Process::CreateTLSRegion() { 349VAddr Process::CreateTLSRegion() {
349 SchedulerLock lock(system.Kernel()); 350 KScopedSchedulerLock lock(system.Kernel());
350 if (auto tls_page_iter{FindTLSPageWithAvailableSlots(tls_pages)}; 351 if (auto tls_page_iter{FindTLSPageWithAvailableSlots(tls_pages)};
351 tls_page_iter != tls_pages.cend()) { 352 tls_page_iter != tls_pages.cend()) {
352 return *tls_page_iter->ReserveSlot(); 353 return *tls_page_iter->ReserveSlot();
@@ -377,7 +378,7 @@ VAddr Process::CreateTLSRegion() {
377} 378}
378 379
379void Process::FreeTLSRegion(VAddr tls_address) { 380void Process::FreeTLSRegion(VAddr tls_address) {
380 SchedulerLock lock(system.Kernel()); 381 KScopedSchedulerLock lock(system.Kernel());
381 const VAddr aligned_address = Common::AlignDown(tls_address, Core::Memory::PAGE_SIZE); 382 const VAddr aligned_address = Common::AlignDown(tls_address, Core::Memory::PAGE_SIZE);
382 auto iter = 383 auto iter =
383 std::find_if(tls_pages.begin(), tls_pages.end(), [aligned_address](const auto& page) { 384 std::find_if(tls_pages.begin(), tls_pages.end(), [aligned_address](const auto& page) {
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h
index f45cb5674..e412e58aa 100644
--- a/src/core/hle/kernel/process.h
+++ b/src/core/hle/kernel/process.h
@@ -216,6 +216,16 @@ public:
216 total_process_running_time_ticks += ticks; 216 total_process_running_time_ticks += ticks;
217 } 217 }
218 218
219 /// Gets the process schedule count, used for thread yelding
220 s64 GetScheduledCount() const {
221 return schedule_count;
222 }
223
224 /// Increments the process schedule count, used for thread yielding.
225 void IncrementScheduledCount() {
226 ++schedule_count;
227 }
228
219 /// Gets 8 bytes of random data for svcGetInfo RandomEntropy 229 /// Gets 8 bytes of random data for svcGetInfo RandomEntropy
220 u64 GetRandomEntropy(std::size_t index) const { 230 u64 GetRandomEntropy(std::size_t index) const {
221 return random_entropy.at(index); 231 return random_entropy.at(index);
@@ -397,6 +407,9 @@ private:
397 /// Name of this process 407 /// Name of this process
398 std::string name; 408 std::string name;
399 409
410 /// Schedule count of this process
411 s64 schedule_count{};
412
400 /// System context 413 /// System context
401 Core::System& system; 414 Core::System& system;
402}; 415};
diff --git a/src/core/hle/kernel/process_capability.cpp b/src/core/hle/kernel/process_capability.cpp
index 63880f13d..0f128c586 100644
--- a/src/core/hle/kernel/process_capability.cpp
+++ b/src/core/hle/kernel/process_capability.cpp
@@ -199,7 +199,7 @@ ResultCode ProcessCapabilities::ParseSingleFlagCapability(u32& set_flags, u32& s
199 break; 199 break;
200 } 200 }
201 201
202 LOG_ERROR(Kernel, "Invalid capability type! type={}", static_cast<u32>(type)); 202 LOG_ERROR(Kernel, "Invalid capability type! type={}", type);
203 return ERR_INVALID_CAPABILITY_DESCRIPTOR; 203 return ERR_INVALID_CAPABILITY_DESCRIPTOR;
204} 204}
205 205
diff --git a/src/core/hle/kernel/readable_event.cpp b/src/core/hle/kernel/readable_event.cpp
index 6e286419e..cea262ce0 100644
--- a/src/core/hle/kernel/readable_event.cpp
+++ b/src/core/hle/kernel/readable_event.cpp
@@ -6,10 +6,10 @@
6#include "common/assert.h" 6#include "common/assert.h"
7#include "common/logging/log.h" 7#include "common/logging/log.h"
8#include "core/hle/kernel/errors.h" 8#include "core/hle/kernel/errors.h"
9#include "core/hle/kernel/k_scheduler.h"
9#include "core/hle/kernel/kernel.h" 10#include "core/hle/kernel/kernel.h"
10#include "core/hle/kernel/object.h" 11#include "core/hle/kernel/object.h"
11#include "core/hle/kernel/readable_event.h" 12#include "core/hle/kernel/readable_event.h"
12#include "core/hle/kernel/scheduler.h"
13#include "core/hle/kernel/thread.h" 13#include "core/hle/kernel/thread.h"
14 14
15namespace Kernel { 15namespace Kernel {
@@ -39,7 +39,7 @@ void ReadableEvent::Clear() {
39} 39}
40 40
41ResultCode ReadableEvent::Reset() { 41ResultCode ReadableEvent::Reset() {
42 SchedulerLock lock(kernel); 42 KScopedSchedulerLock lock(kernel);
43 if (!is_signaled) { 43 if (!is_signaled) {
44 LOG_TRACE(Kernel, "Handle is not signaled! object_id={}, object_type={}, object_name={}", 44 LOG_TRACE(Kernel, "Handle is not signaled! object_id={}, object_type={}, object_name={}",
45 GetObjectId(), GetTypeName(), GetName()); 45 GetObjectId(), GetTypeName(), GetName());
diff --git a/src/core/hle/kernel/resource_limit.cpp b/src/core/hle/kernel/resource_limit.cpp
index 212e442f4..7bf50339d 100644
--- a/src/core/hle/kernel/resource_limit.cpp
+++ b/src/core/hle/kernel/resource_limit.cpp
@@ -65,8 +65,8 @@ ResultCode ResourceLimit::SetLimitValue(ResourceType resource, s64 value) {
65 limit[index] = value; 65 limit[index] = value;
66 return RESULT_SUCCESS; 66 return RESULT_SUCCESS;
67 } else { 67 } else {
68 LOG_ERROR(Kernel, "Limit value is too large! resource={}, value={}, index={}", 68 LOG_ERROR(Kernel, "Limit value is too large! resource={}, value={}, index={}", resource,
69 static_cast<u32>(resource), value, index); 69 value, index);
70 return ERR_INVALID_STATE; 70 return ERR_INVALID_STATE;
71 } 71 }
72} 72}
diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp
deleted file mode 100644
index 5cbd3b912..000000000
--- a/src/core/hle/kernel/scheduler.cpp
+++ /dev/null
@@ -1,849 +0,0 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4//
5// SelectThreads, Yield functions originally by TuxSH.
6// licensed under GPLv2 or later under exception provided by the author.
7
8#include <algorithm>
9#include <mutex>
10#include <set>
11#include <unordered_set>
12#include <utility>
13
14#include "common/assert.h"
15#include "common/bit_util.h"
16#include "common/fiber.h"
17#include "common/logging/log.h"
18#include "core/arm/arm_interface.h"
19#include "core/core.h"
20#include "core/core_timing.h"
21#include "core/cpu_manager.h"
22#include "core/hle/kernel/kernel.h"
23#include "core/hle/kernel/physical_core.h"
24#include "core/hle/kernel/process.h"
25#include "core/hle/kernel/scheduler.h"
26#include "core/hle/kernel/time_manager.h"
27
28namespace Kernel {
29
30GlobalScheduler::GlobalScheduler(KernelCore& kernel) : kernel{kernel} {}
31
32GlobalScheduler::~GlobalScheduler() = default;
33
34void GlobalScheduler::AddThread(std::shared_ptr<Thread> thread) {
35 std::scoped_lock lock{global_list_guard};
36 thread_list.push_back(std::move(thread));
37}
38
39void GlobalScheduler::RemoveThread(std::shared_ptr<Thread> thread) {
40 std::scoped_lock lock{global_list_guard};
41 thread_list.erase(std::remove(thread_list.begin(), thread_list.end(), thread),
42 thread_list.end());
43}
44
45u32 GlobalScheduler::SelectThreads() {
46 ASSERT(is_locked);
47 const auto update_thread = [](Thread* thread, Scheduler& sched) {
48 std::scoped_lock lock{sched.guard};
49 if (thread != sched.selected_thread_set.get()) {
50 if (thread == nullptr) {
51 ++sched.idle_selection_count;
52 }
53 sched.selected_thread_set = SharedFrom(thread);
54 }
55 const bool reschedule_pending =
56 sched.is_context_switch_pending || (sched.selected_thread_set != sched.current_thread);
57 sched.is_context_switch_pending = reschedule_pending;
58 std::atomic_thread_fence(std::memory_order_seq_cst);
59 return reschedule_pending;
60 };
61 if (!is_reselection_pending.load()) {
62 return 0;
63 }
64 std::array<Thread*, Core::Hardware::NUM_CPU_CORES> top_threads{};
65
66 u32 idle_cores{};
67
68 // Step 1: Get top thread in schedule queue.
69 for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
70 Thread* top_thread =
71 scheduled_queue[core].empty() ? nullptr : scheduled_queue[core].front();
72 if (top_thread != nullptr) {
73 // TODO(Blinkhawk): Implement Thread Pinning
74 } else {
75 idle_cores |= (1ul << core);
76 }
77 top_threads[core] = top_thread;
78 }
79
80 while (idle_cores != 0) {
81 u32 core_id = Common::CountTrailingZeroes32(idle_cores);
82
83 if (!suggested_queue[core_id].empty()) {
84 std::array<s32, Core::Hardware::NUM_CPU_CORES> migration_candidates{};
85 std::size_t num_candidates = 0;
86 auto iter = suggested_queue[core_id].begin();
87 Thread* suggested = nullptr;
88 // Step 2: Try selecting a suggested thread.
89 while (iter != suggested_queue[core_id].end()) {
90 suggested = *iter;
91 iter++;
92 s32 suggested_core_id = suggested->GetProcessorID();
93 Thread* top_thread =
94 suggested_core_id >= 0 ? top_threads[suggested_core_id] : nullptr;
95 if (top_thread != suggested) {
96 if (top_thread != nullptr &&
97 top_thread->GetPriority() < THREADPRIO_MAX_CORE_MIGRATION) {
98 suggested = nullptr;
99 break;
100 // There's a too high thread to do core migration, cancel
101 }
102 TransferToCore(suggested->GetPriority(), static_cast<s32>(core_id), suggested);
103 break;
104 }
105 suggested = nullptr;
106 migration_candidates[num_candidates++] = suggested_core_id;
107 }
108 // Step 3: Select a suggested thread from another core
109 if (suggested == nullptr) {
110 for (std::size_t i = 0; i < num_candidates; i++) {
111 s32 candidate_core = migration_candidates[i];
112 suggested = top_threads[candidate_core];
113 auto it = scheduled_queue[candidate_core].begin();
114 it++;
115 Thread* next = it != scheduled_queue[candidate_core].end() ? *it : nullptr;
116 if (next != nullptr) {
117 TransferToCore(suggested->GetPriority(), static_cast<s32>(core_id),
118 suggested);
119 top_threads[candidate_core] = next;
120 break;
121 } else {
122 suggested = nullptr;
123 }
124 }
125 }
126 top_threads[core_id] = suggested;
127 }
128
129 idle_cores &= ~(1ul << core_id);
130 }
131 u32 cores_needing_context_switch{};
132 for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
133 Scheduler& sched = kernel.Scheduler(core);
134 ASSERT(top_threads[core] == nullptr ||
135 static_cast<u32>(top_threads[core]->GetProcessorID()) == core);
136 if (update_thread(top_threads[core], sched)) {
137 cores_needing_context_switch |= (1ul << core);
138 }
139 }
140 return cores_needing_context_switch;
141}
142
143bool GlobalScheduler::YieldThread(Thread* yielding_thread) {
144 ASSERT(is_locked);
145 // Note: caller should use critical section, etc.
146 if (!yielding_thread->IsRunnable()) {
147 // Normally this case shouldn't happen except for SetThreadActivity.
148 is_reselection_pending.store(true, std::memory_order_release);
149 return false;
150 }
151 const u32 core_id = static_cast<u32>(yielding_thread->GetProcessorID());
152 const u32 priority = yielding_thread->GetPriority();
153
154 // Yield the thread
155 Reschedule(priority, core_id, yielding_thread);
156 const Thread* const winner = scheduled_queue[core_id].front();
157 if (kernel.GetCurrentHostThreadID() != core_id) {
158 is_reselection_pending.store(true, std::memory_order_release);
159 }
160
161 return AskForReselectionOrMarkRedundant(yielding_thread, winner);
162}
163
164bool GlobalScheduler::YieldThreadAndBalanceLoad(Thread* yielding_thread) {
165 ASSERT(is_locked);
166 // Note: caller should check if !thread.IsSchedulerOperationRedundant and use critical section,
167 // etc.
168 if (!yielding_thread->IsRunnable()) {
169 // Normally this case shouldn't happen except for SetThreadActivity.
170 is_reselection_pending.store(true, std::memory_order_release);
171 return false;
172 }
173 const u32 core_id = static_cast<u32>(yielding_thread->GetProcessorID());
174 const u32 priority = yielding_thread->GetPriority();
175
176 // Yield the thread
177 Reschedule(priority, core_id, yielding_thread);
178
179 std::array<Thread*, Core::Hardware::NUM_CPU_CORES> current_threads;
180 for (std::size_t i = 0; i < current_threads.size(); i++) {
181 current_threads[i] = scheduled_queue[i].empty() ? nullptr : scheduled_queue[i].front();
182 }
183
184 Thread* next_thread = scheduled_queue[core_id].front(priority);
185 Thread* winner = nullptr;
186 for (auto& thread : suggested_queue[core_id]) {
187 const s32 source_core = thread->GetProcessorID();
188 if (source_core >= 0) {
189 if (current_threads[source_core] != nullptr) {
190 if (thread == current_threads[source_core] ||
191 current_threads[source_core]->GetPriority() < min_regular_priority) {
192 continue;
193 }
194 }
195 }
196 if (next_thread->GetLastRunningTicks() >= thread->GetLastRunningTicks() ||
197 next_thread->GetPriority() < thread->GetPriority()) {
198 if (thread->GetPriority() <= priority) {
199 winner = thread;
200 break;
201 }
202 }
203 }
204
205 if (winner != nullptr) {
206 if (winner != yielding_thread) {
207 TransferToCore(winner->GetPriority(), s32(core_id), winner);
208 }
209 } else {
210 winner = next_thread;
211 }
212
213 if (kernel.GetCurrentHostThreadID() != core_id) {
214 is_reselection_pending.store(true, std::memory_order_release);
215 }
216
217 return AskForReselectionOrMarkRedundant(yielding_thread, winner);
218}
219
220bool GlobalScheduler::YieldThreadAndWaitForLoadBalancing(Thread* yielding_thread) {
221 ASSERT(is_locked);
222 // Note: caller should check if !thread.IsSchedulerOperationRedundant and use critical section,
223 // etc.
224 if (!yielding_thread->IsRunnable()) {
225 // Normally this case shouldn't happen except for SetThreadActivity.
226 is_reselection_pending.store(true, std::memory_order_release);
227 return false;
228 }
229 Thread* winner = nullptr;
230 const u32 core_id = static_cast<u32>(yielding_thread->GetProcessorID());
231
232 // Remove the thread from its scheduled mlq, put it on the corresponding "suggested" one instead
233 TransferToCore(yielding_thread->GetPriority(), -1, yielding_thread);
234
235 // If the core is idle, perform load balancing, excluding the threads that have just used this
236 // function...
237 if (scheduled_queue[core_id].empty()) {
238 // Here, "current_threads" is calculated after the ""yield"", unlike yield -1
239 std::array<Thread*, Core::Hardware::NUM_CPU_CORES> current_threads;
240 for (std::size_t i = 0; i < current_threads.size(); i++) {
241 current_threads[i] = scheduled_queue[i].empty() ? nullptr : scheduled_queue[i].front();
242 }
243 for (auto& thread : suggested_queue[core_id]) {
244 const s32 source_core = thread->GetProcessorID();
245 if (source_core < 0 || thread == current_threads[source_core]) {
246 continue;
247 }
248 if (current_threads[source_core] == nullptr ||
249 current_threads[source_core]->GetPriority() >= min_regular_priority) {
250 winner = thread;
251 }
252 break;
253 }
254 if (winner != nullptr) {
255 if (winner != yielding_thread) {
256 TransferToCore(winner->GetPriority(), static_cast<s32>(core_id), winner);
257 }
258 } else {
259 winner = yielding_thread;
260 }
261 } else {
262 winner = scheduled_queue[core_id].front();
263 }
264
265 if (kernel.GetCurrentHostThreadID() != core_id) {
266 is_reselection_pending.store(true, std::memory_order_release);
267 }
268
269 return AskForReselectionOrMarkRedundant(yielding_thread, winner);
270}
271
272void GlobalScheduler::PreemptThreads() {
273 ASSERT(is_locked);
274 for (std::size_t core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) {
275 const u32 priority = preemption_priorities[core_id];
276
277 if (scheduled_queue[core_id].size(priority) > 0) {
278 if (scheduled_queue[core_id].size(priority) > 1) {
279 scheduled_queue[core_id].front(priority)->IncrementYieldCount();
280 }
281 scheduled_queue[core_id].yield(priority);
282 if (scheduled_queue[core_id].size(priority) > 1) {
283 scheduled_queue[core_id].front(priority)->IncrementYieldCount();
284 }
285 }
286
287 Thread* current_thread =
288 scheduled_queue[core_id].empty() ? nullptr : scheduled_queue[core_id].front();
289 Thread* winner = nullptr;
290 for (auto& thread : suggested_queue[core_id]) {
291 const s32 source_core = thread->GetProcessorID();
292 if (thread->GetPriority() != priority) {
293 continue;
294 }
295 if (source_core >= 0) {
296 Thread* next_thread = scheduled_queue[source_core].empty()
297 ? nullptr
298 : scheduled_queue[source_core].front();
299 if (next_thread != nullptr && next_thread->GetPriority() < 2) {
300 break;
301 }
302 if (next_thread == thread) {
303 continue;
304 }
305 }
306 if (current_thread != nullptr &&
307 current_thread->GetLastRunningTicks() >= thread->GetLastRunningTicks()) {
308 winner = thread;
309 break;
310 }
311 }
312
313 if (winner != nullptr) {
314 TransferToCore(winner->GetPriority(), s32(core_id), winner);
315 current_thread =
316 winner->GetPriority() <= current_thread->GetPriority() ? winner : current_thread;
317 }
318
319 if (current_thread != nullptr && current_thread->GetPriority() > priority) {
320 for (auto& thread : suggested_queue[core_id]) {
321 const s32 source_core = thread->GetProcessorID();
322 if (thread->GetPriority() < priority) {
323 continue;
324 }
325 if (source_core >= 0) {
326 Thread* next_thread = scheduled_queue[source_core].empty()
327 ? nullptr
328 : scheduled_queue[source_core].front();
329 if (next_thread != nullptr && next_thread->GetPriority() < 2) {
330 break;
331 }
332 if (next_thread == thread) {
333 continue;
334 }
335 }
336 if (current_thread != nullptr &&
337 current_thread->GetLastRunningTicks() >= thread->GetLastRunningTicks()) {
338 winner = thread;
339 break;
340 }
341 }
342
343 if (winner != nullptr) {
344 TransferToCore(winner->GetPriority(), s32(core_id), winner);
345 current_thread = winner;
346 }
347 }
348
349 is_reselection_pending.store(true, std::memory_order_release);
350 }
351}
352
353void GlobalScheduler::EnableInterruptAndSchedule(u32 cores_pending_reschedule,
354 Core::EmuThreadHandle global_thread) {
355 u32 current_core = global_thread.host_handle;
356 bool must_context_switch = global_thread.guest_handle != InvalidHandle &&
357 (current_core < Core::Hardware::NUM_CPU_CORES);
358 while (cores_pending_reschedule != 0) {
359 u32 core = Common::CountTrailingZeroes32(cores_pending_reschedule);
360 ASSERT(core < Core::Hardware::NUM_CPU_CORES);
361 if (!must_context_switch || core != current_core) {
362 auto& phys_core = kernel.PhysicalCore(core);
363 phys_core.Interrupt();
364 } else {
365 must_context_switch = true;
366 }
367 cores_pending_reschedule &= ~(1ul << core);
368 }
369 if (must_context_switch) {
370 auto& core_scheduler = kernel.CurrentScheduler();
371 kernel.ExitSVCProfile();
372 core_scheduler.TryDoContextSwitch();
373 kernel.EnterSVCProfile();
374 }
375}
376
377void GlobalScheduler::Suggest(u32 priority, std::size_t core, Thread* thread) {
378 ASSERT(is_locked);
379 suggested_queue[core].add(thread, priority);
380}
381
382void GlobalScheduler::Unsuggest(u32 priority, std::size_t core, Thread* thread) {
383 ASSERT(is_locked);
384 suggested_queue[core].remove(thread, priority);
385}
386
387void GlobalScheduler::Schedule(u32 priority, std::size_t core, Thread* thread) {
388 ASSERT(is_locked);
389 ASSERT_MSG(thread->GetProcessorID() == s32(core), "Thread must be assigned to this core.");
390 scheduled_queue[core].add(thread, priority);
391}
392
393void GlobalScheduler::SchedulePrepend(u32 priority, std::size_t core, Thread* thread) {
394 ASSERT(is_locked);
395 ASSERT_MSG(thread->GetProcessorID() == s32(core), "Thread must be assigned to this core.");
396 scheduled_queue[core].add(thread, priority, false);
397}
398
399void GlobalScheduler::Reschedule(u32 priority, std::size_t core, Thread* thread) {
400 ASSERT(is_locked);
401 scheduled_queue[core].remove(thread, priority);
402 scheduled_queue[core].add(thread, priority);
403}
404
405void GlobalScheduler::Unschedule(u32 priority, std::size_t core, Thread* thread) {
406 ASSERT(is_locked);
407 scheduled_queue[core].remove(thread, priority);
408}
409
410void GlobalScheduler::TransferToCore(u32 priority, s32 destination_core, Thread* thread) {
411 ASSERT(is_locked);
412 const bool schedulable = thread->GetPriority() < THREADPRIO_COUNT;
413 const s32 source_core = thread->GetProcessorID();
414 if (source_core == destination_core || !schedulable) {
415 return;
416 }
417 thread->SetProcessorID(destination_core);
418 if (source_core >= 0) {
419 Unschedule(priority, static_cast<u32>(source_core), thread);
420 }
421 if (destination_core >= 0) {
422 Unsuggest(priority, static_cast<u32>(destination_core), thread);
423 Schedule(priority, static_cast<u32>(destination_core), thread);
424 }
425 if (source_core >= 0) {
426 Suggest(priority, static_cast<u32>(source_core), thread);
427 }
428}
429
430bool GlobalScheduler::AskForReselectionOrMarkRedundant(Thread* current_thread,
431 const Thread* winner) {
432 if (current_thread == winner) {
433 current_thread->IncrementYieldCount();
434 return true;
435 } else {
436 is_reselection_pending.store(true, std::memory_order_release);
437 return false;
438 }
439}
440
441void GlobalScheduler::AdjustSchedulingOnStatus(Thread* thread, u32 old_flags) {
442 if (old_flags == thread->scheduling_state) {
443 return;
444 }
445 ASSERT(is_locked);
446
447 if (old_flags == static_cast<u32>(ThreadSchedStatus::Runnable)) {
448 // In this case the thread was running, now it's pausing/exitting
449 if (thread->processor_id >= 0) {
450 Unschedule(thread->current_priority, static_cast<u32>(thread->processor_id), thread);
451 }
452
453 for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
454 if (core != static_cast<u32>(thread->processor_id) &&
455 ((thread->affinity_mask >> core) & 1) != 0) {
456 Unsuggest(thread->current_priority, core, thread);
457 }
458 }
459 } else if (thread->scheduling_state == static_cast<u32>(ThreadSchedStatus::Runnable)) {
460 // The thread is now set to running from being stopped
461 if (thread->processor_id >= 0) {
462 Schedule(thread->current_priority, static_cast<u32>(thread->processor_id), thread);
463 }
464
465 for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
466 if (core != static_cast<u32>(thread->processor_id) &&
467 ((thread->affinity_mask >> core) & 1) != 0) {
468 Suggest(thread->current_priority, core, thread);
469 }
470 }
471 }
472
473 SetReselectionPending();
474}
475
476void GlobalScheduler::AdjustSchedulingOnPriority(Thread* thread, u32 old_priority) {
477 if (thread->scheduling_state != static_cast<u32>(ThreadSchedStatus::Runnable)) {
478 return;
479 }
480 ASSERT(is_locked);
481 if (thread->processor_id >= 0) {
482 Unschedule(old_priority, static_cast<u32>(thread->processor_id), thread);
483 }
484
485 for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
486 if (core != static_cast<u32>(thread->processor_id) &&
487 ((thread->affinity_mask >> core) & 1) != 0) {
488 Unsuggest(old_priority, core, thread);
489 }
490 }
491
492 if (thread->processor_id >= 0) {
493 if (thread == kernel.CurrentScheduler().GetCurrentThread()) {
494 SchedulePrepend(thread->current_priority, static_cast<u32>(thread->processor_id),
495 thread);
496 } else {
497 Schedule(thread->current_priority, static_cast<u32>(thread->processor_id), thread);
498 }
499 }
500
501 for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
502 if (core != static_cast<u32>(thread->processor_id) &&
503 ((thread->affinity_mask >> core) & 1) != 0) {
504 Suggest(thread->current_priority, core, thread);
505 }
506 }
507 thread->IncrementYieldCount();
508 SetReselectionPending();
509}
510
511void GlobalScheduler::AdjustSchedulingOnAffinity(Thread* thread, u64 old_affinity_mask,
512 s32 old_core) {
513 if (thread->scheduling_state != static_cast<u32>(ThreadSchedStatus::Runnable) ||
514 thread->current_priority >= THREADPRIO_COUNT) {
515 return;
516 }
517 ASSERT(is_locked);
518
519 for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
520 if (((old_affinity_mask >> core) & 1) != 0) {
521 if (core == static_cast<u32>(old_core)) {
522 Unschedule(thread->current_priority, core, thread);
523 } else {
524 Unsuggest(thread->current_priority, core, thread);
525 }
526 }
527 }
528
529 for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
530 if (((thread->affinity_mask >> core) & 1) != 0) {
531 if (core == static_cast<u32>(thread->processor_id)) {
532 Schedule(thread->current_priority, core, thread);
533 } else {
534 Suggest(thread->current_priority, core, thread);
535 }
536 }
537 }
538
539 thread->IncrementYieldCount();
540 SetReselectionPending();
541}
542
543void GlobalScheduler::Shutdown() {
544 for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
545 scheduled_queue[core].clear();
546 suggested_queue[core].clear();
547 }
548 thread_list.clear();
549}
550
551void GlobalScheduler::Lock() {
552 Core::EmuThreadHandle current_thread = kernel.GetCurrentEmuThreadID();
553 ASSERT(!current_thread.IsInvalid());
554 if (current_thread == current_owner) {
555 ++scope_lock;
556 } else {
557 inner_lock.lock();
558 is_locked = true;
559 current_owner = current_thread;
560 ASSERT(current_owner != Core::EmuThreadHandle::InvalidHandle());
561 scope_lock = 1;
562 }
563}
564
565void GlobalScheduler::Unlock() {
566 if (--scope_lock != 0) {
567 ASSERT(scope_lock > 0);
568 return;
569 }
570 u32 cores_pending_reschedule = SelectThreads();
571 Core::EmuThreadHandle leaving_thread = current_owner;
572 current_owner = Core::EmuThreadHandle::InvalidHandle();
573 scope_lock = 1;
574 is_locked = false;
575 inner_lock.unlock();
576 EnableInterruptAndSchedule(cores_pending_reschedule, leaving_thread);
577}
578
579Scheduler::Scheduler(Core::System& system, std::size_t core_id) : system(system), core_id(core_id) {
580 switch_fiber = std::make_shared<Common::Fiber>(std::function<void(void*)>(OnSwitch), this);
581}
582
583Scheduler::~Scheduler() = default;
584
585bool Scheduler::HaveReadyThreads() const {
586 return system.GlobalScheduler().HaveReadyThreads(core_id);
587}
588
589Thread* Scheduler::GetCurrentThread() const {
590 if (current_thread) {
591 return current_thread.get();
592 }
593 return idle_thread.get();
594}
595
596Thread* Scheduler::GetSelectedThread() const {
597 return selected_thread.get();
598}
599
600u64 Scheduler::GetLastContextSwitchTicks() const {
601 return last_context_switch_time;
602}
603
604void Scheduler::TryDoContextSwitch() {
605 auto& phys_core = system.Kernel().CurrentPhysicalCore();
606 if (phys_core.IsInterrupted()) {
607 phys_core.ClearInterrupt();
608 }
609 guard.lock();
610 if (is_context_switch_pending) {
611 SwitchContext();
612 } else {
613 guard.unlock();
614 }
615}
616
617void Scheduler::OnThreadStart() {
618 SwitchContextStep2();
619}
620
621void Scheduler::Unload() {
622 Thread* thread = current_thread.get();
623 if (thread) {
624 thread->SetContinuousOnSVC(false);
625 thread->last_running_ticks = system.CoreTiming().GetCPUTicks();
626 thread->SetIsRunning(false);
627 if (!thread->IsHLEThread() && !thread->HasExited()) {
628 Core::ARM_Interface& cpu_core = thread->ArmInterface();
629 cpu_core.SaveContext(thread->GetContext32());
630 cpu_core.SaveContext(thread->GetContext64());
631 // Save the TPIDR_EL0 system register in case it was modified.
632 thread->SetTPIDR_EL0(cpu_core.GetTPIDR_EL0());
633 cpu_core.ClearExclusiveState();
634 }
635 thread->context_guard.unlock();
636 }
637}
638
639void Scheduler::Reload() {
640 Thread* thread = current_thread.get();
641 if (thread) {
642 ASSERT_MSG(thread->GetSchedulingStatus() == ThreadSchedStatus::Runnable,
643 "Thread must be runnable.");
644
645 // Cancel any outstanding wakeup events for this thread
646 thread->SetIsRunning(true);
647 thread->SetWasRunning(false);
648 thread->last_running_ticks = system.CoreTiming().GetCPUTicks();
649
650 auto* const thread_owner_process = thread->GetOwnerProcess();
651 if (thread_owner_process != nullptr) {
652 system.Kernel().MakeCurrentProcess(thread_owner_process);
653 }
654 if (!thread->IsHLEThread()) {
655 Core::ARM_Interface& cpu_core = thread->ArmInterface();
656 cpu_core.LoadContext(thread->GetContext32());
657 cpu_core.LoadContext(thread->GetContext64());
658 cpu_core.SetTlsAddress(thread->GetTLSAddress());
659 cpu_core.SetTPIDR_EL0(thread->GetTPIDR_EL0());
660 cpu_core.ChangeProcessorID(this->core_id);
661 cpu_core.ClearExclusiveState();
662 }
663 }
664}
665
666void Scheduler::SwitchContextStep2() {
667 // Load context of new thread
668 if (selected_thread) {
669 ASSERT_MSG(selected_thread->GetSchedulingStatus() == ThreadSchedStatus::Runnable,
670 "Thread must be runnable.");
671
672 // Cancel any outstanding wakeup events for this thread
673 selected_thread->SetIsRunning(true);
674 selected_thread->last_running_ticks = system.CoreTiming().GetCPUTicks();
675 selected_thread->SetWasRunning(false);
676
677 auto* const thread_owner_process = current_thread->GetOwnerProcess();
678 if (thread_owner_process != nullptr) {
679 system.Kernel().MakeCurrentProcess(thread_owner_process);
680 }
681 if (!selected_thread->IsHLEThread()) {
682 Core::ARM_Interface& cpu_core = selected_thread->ArmInterface();
683 cpu_core.LoadContext(selected_thread->GetContext32());
684 cpu_core.LoadContext(selected_thread->GetContext64());
685 cpu_core.SetTlsAddress(selected_thread->GetTLSAddress());
686 cpu_core.SetTPIDR_EL0(selected_thread->GetTPIDR_EL0());
687 cpu_core.ChangeProcessorID(this->core_id);
688 cpu_core.ClearExclusiveState();
689 }
690 }
691
692 TryDoContextSwitch();
693}
694
695void Scheduler::SwitchContext() {
696 current_thread_prev = current_thread;
697 selected_thread = selected_thread_set;
698 Thread* previous_thread = current_thread_prev.get();
699 Thread* new_thread = selected_thread.get();
700 current_thread = selected_thread;
701
702 is_context_switch_pending = false;
703
704 if (new_thread == previous_thread) {
705 guard.unlock();
706 return;
707 }
708
709 Process* const previous_process = system.Kernel().CurrentProcess();
710
711 UpdateLastContextSwitchTime(previous_thread, previous_process);
712
713 // Save context for previous thread
714 if (previous_thread) {
715 if (new_thread != nullptr && new_thread->IsSuspendThread()) {
716 previous_thread->SetWasRunning(true);
717 }
718 previous_thread->SetContinuousOnSVC(false);
719 previous_thread->last_running_ticks = system.CoreTiming().GetCPUTicks();
720 previous_thread->SetIsRunning(false);
721 if (!previous_thread->IsHLEThread() && !previous_thread->HasExited()) {
722 Core::ARM_Interface& cpu_core = previous_thread->ArmInterface();
723 cpu_core.SaveContext(previous_thread->GetContext32());
724 cpu_core.SaveContext(previous_thread->GetContext64());
725 // Save the TPIDR_EL0 system register in case it was modified.
726 previous_thread->SetTPIDR_EL0(cpu_core.GetTPIDR_EL0());
727 cpu_core.ClearExclusiveState();
728 }
729 previous_thread->context_guard.unlock();
730 }
731
732 std::shared_ptr<Common::Fiber>* old_context;
733 if (previous_thread != nullptr) {
734 old_context = &previous_thread->GetHostContext();
735 } else {
736 old_context = &idle_thread->GetHostContext();
737 }
738 guard.unlock();
739
740 Common::Fiber::YieldTo(*old_context, switch_fiber);
741 /// When a thread wakes up, the scheduler may have changed to other in another core.
742 auto& next_scheduler = system.Kernel().CurrentScheduler();
743 next_scheduler.SwitchContextStep2();
744}
745
746void Scheduler::OnSwitch(void* this_scheduler) {
747 Scheduler* sched = static_cast<Scheduler*>(this_scheduler);
748 sched->SwitchToCurrent();
749}
750
751void Scheduler::SwitchToCurrent() {
752 while (true) {
753 {
754 std::scoped_lock lock{guard};
755 selected_thread = selected_thread_set;
756 current_thread = selected_thread;
757 is_context_switch_pending = false;
758 }
759 const auto is_switch_pending = [this] {
760 std::scoped_lock lock{guard};
761 return is_context_switch_pending;
762 };
763 do {
764 if (current_thread != nullptr && !current_thread->IsHLEThread()) {
765 current_thread->context_guard.lock();
766 if (!current_thread->IsRunnable()) {
767 current_thread->context_guard.unlock();
768 break;
769 }
770 if (current_thread->GetProcessorID() != core_id) {
771 current_thread->context_guard.unlock();
772 break;
773 }
774 }
775 std::shared_ptr<Common::Fiber>* next_context;
776 if (current_thread != nullptr) {
777 next_context = &current_thread->GetHostContext();
778 } else {
779 next_context = &idle_thread->GetHostContext();
780 }
781 Common::Fiber::YieldTo(switch_fiber, *next_context);
782 } while (!is_switch_pending());
783 }
784}
785
786void Scheduler::UpdateLastContextSwitchTime(Thread* thread, Process* process) {
787 const u64 prev_switch_ticks = last_context_switch_time;
788 const u64 most_recent_switch_ticks = system.CoreTiming().GetCPUTicks();
789 const u64 update_ticks = most_recent_switch_ticks - prev_switch_ticks;
790
791 if (thread != nullptr) {
792 thread->UpdateCPUTimeTicks(update_ticks);
793 }
794
795 if (process != nullptr) {
796 process->UpdateCPUTimeTicks(update_ticks);
797 }
798
799 last_context_switch_time = most_recent_switch_ticks;
800}
801
802void Scheduler::Initialize() {
803 std::string name = "Idle Thread Id:" + std::to_string(core_id);
804 std::function<void(void*)> init_func = Core::CpuManager::GetIdleThreadStartFunc();
805 void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater();
806 ThreadType type = static_cast<ThreadType>(THREADTYPE_KERNEL | THREADTYPE_HLE | THREADTYPE_IDLE);
807 auto thread_res = Thread::Create(system, type, name, 0, 64, 0, static_cast<u32>(core_id), 0,
808 nullptr, std::move(init_func), init_func_parameter);
809 idle_thread = std::move(thread_res).Unwrap();
810}
811
812void Scheduler::Shutdown() {
813 current_thread = nullptr;
814 selected_thread = nullptr;
815}
816
817SchedulerLock::SchedulerLock(KernelCore& kernel) : kernel{kernel} {
818 kernel.GlobalScheduler().Lock();
819}
820
821SchedulerLock::~SchedulerLock() {
822 kernel.GlobalScheduler().Unlock();
823}
824
825SchedulerLockAndSleep::SchedulerLockAndSleep(KernelCore& kernel, Handle& event_handle,
826 Thread* time_task, s64 nanoseconds)
827 : SchedulerLock{kernel}, event_handle{event_handle}, time_task{time_task}, nanoseconds{
828 nanoseconds} {
829 event_handle = InvalidHandle;
830}
831
832SchedulerLockAndSleep::~SchedulerLockAndSleep() {
833 if (sleep_cancelled) {
834 return;
835 }
836 auto& time_manager = kernel.TimeManager();
837 time_manager.ScheduleTimeEvent(event_handle, time_task, nanoseconds);
838}
839
840void SchedulerLockAndSleep::Release() {
841 if (sleep_cancelled) {
842 return;
843 }
844 auto& time_manager = kernel.TimeManager();
845 time_manager.ScheduleTimeEvent(event_handle, time_task, nanoseconds);
846 sleep_cancelled = true;
847}
848
849} // namespace Kernel
diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h
deleted file mode 100644
index b6f04dcea..000000000
--- a/src/core/hle/kernel/scheduler.h
+++ /dev/null
@@ -1,318 +0,0 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <atomic>
8#include <memory>
9#include <mutex>
10#include <vector>
11
12#include "common/common_types.h"
13#include "common/multi_level_queue.h"
14#include "common/spin_lock.h"
15#include "core/hardware_properties.h"
16#include "core/hle/kernel/thread.h"
17
18namespace Common {
19class Fiber;
20}
21
22namespace Core {
23class ARM_Interface;
24class System;
25} // namespace Core
26
27namespace Kernel {
28
29class KernelCore;
30class Process;
31class SchedulerLock;
32
33class GlobalScheduler final {
34public:
35 explicit GlobalScheduler(KernelCore& kernel);
36 ~GlobalScheduler();
37
38 /// Adds a new thread to the scheduler
39 void AddThread(std::shared_ptr<Thread> thread);
40
41 /// Removes a thread from the scheduler
42 void RemoveThread(std::shared_ptr<Thread> thread);
43
44 /// Returns a list of all threads managed by the scheduler
45 const std::vector<std::shared_ptr<Thread>>& GetThreadList() const {
46 return thread_list;
47 }
48
49 /// Notify the scheduler a thread's status has changed.
50 void AdjustSchedulingOnStatus(Thread* thread, u32 old_flags);
51
52 /// Notify the scheduler a thread's priority has changed.
53 void AdjustSchedulingOnPriority(Thread* thread, u32 old_priority);
54
55 /// Notify the scheduler a thread's core and/or affinity mask has changed.
56 void AdjustSchedulingOnAffinity(Thread* thread, u64 old_affinity_mask, s32 old_core);
57
58 /**
59 * Takes care of selecting the new scheduled threads in three steps:
60 *
61 * 1. First a thread is selected from the top of the priority queue. If no thread
62 * is obtained then we move to step two, else we are done.
63 *
64 * 2. Second we try to get a suggested thread that's not assigned to any core or
65 * that is not the top thread in that core.
66 *
67 * 3. Third is no suggested thread is found, we do a second pass and pick a running
68 * thread in another core and swap it with its current thread.
69 *
70 * returns the cores needing scheduling.
71 */
72 u32 SelectThreads();
73
74 bool HaveReadyThreads(std::size_t core_id) const {
75 return !scheduled_queue[core_id].empty();
76 }
77
78 /**
79 * Takes a thread and moves it to the back of the it's priority list.
80 *
81 * @note This operation can be redundant and no scheduling is changed if marked as so.
82 */
83 bool YieldThread(Thread* thread);
84
85 /**
86 * Takes a thread and moves it to the back of the it's priority list.
87 * Afterwards, tries to pick a suggested thread from the suggested queue that has worse time or
88 * a better priority than the next thread in the core.
89 *
90 * @note This operation can be redundant and no scheduling is changed if marked as so.
91 */
92 bool YieldThreadAndBalanceLoad(Thread* thread);
93
94 /**
95 * Takes a thread and moves it out of the scheduling queue.
96 * and into the suggested queue. If no thread can be scheduled afterwards in that core,
97 * a suggested thread is obtained instead.
98 *
99 * @note This operation can be redundant and no scheduling is changed if marked as so.
100 */
101 bool YieldThreadAndWaitForLoadBalancing(Thread* thread);
102
103 /**
104 * Rotates the scheduling queues of threads at a preemption priority and then does
105 * some core rebalancing. Preemption priorities can be found in the array
106 * 'preemption_priorities'.
107 *
108 * @note This operation happens every 10ms.
109 */
110 void PreemptThreads();
111
112 u32 CpuCoresCount() const {
113 return Core::Hardware::NUM_CPU_CORES;
114 }
115
116 void SetReselectionPending() {
117 is_reselection_pending.store(true, std::memory_order_release);
118 }
119
120 bool IsReselectionPending() const {
121 return is_reselection_pending.load(std::memory_order_acquire);
122 }
123
124 void Shutdown();
125
126private:
127 friend class SchedulerLock;
128
129 /// Lock the scheduler to the current thread.
130 void Lock();
131
132 /// Unlocks the scheduler, reselects threads, interrupts cores for rescheduling
133 /// and reschedules current core if needed.
134 void Unlock();
135
136 void EnableInterruptAndSchedule(u32 cores_pending_reschedule,
137 Core::EmuThreadHandle global_thread);
138
139 /**
140 * Add a thread to the suggested queue of a cpu core. Suggested threads may be
141 * picked if no thread is scheduled to run on the core.
142 */
143 void Suggest(u32 priority, std::size_t core, Thread* thread);
144
145 /**
146 * Remove a thread to the suggested queue of a cpu core. Suggested threads may be
147 * picked if no thread is scheduled to run on the core.
148 */
149 void Unsuggest(u32 priority, std::size_t core, Thread* thread);
150
151 /**
152 * Add a thread to the scheduling queue of a cpu core. The thread is added at the
153 * back the queue in its priority level.
154 */
155 void Schedule(u32 priority, std::size_t core, Thread* thread);
156
157 /**
158 * Add a thread to the scheduling queue of a cpu core. The thread is added at the
159 * front the queue in its priority level.
160 */
161 void SchedulePrepend(u32 priority, std::size_t core, Thread* thread);
162
163 /// Reschedule an already scheduled thread based on a new priority
164 void Reschedule(u32 priority, std::size_t core, Thread* thread);
165
166 /// Unschedules a thread.
167 void Unschedule(u32 priority, std::size_t core, Thread* thread);
168
169 /**
170 * Transfers a thread into an specific core. If the destination_core is -1
171 * it will be unscheduled from its source code and added into its suggested
172 * queue.
173 */
174 void TransferToCore(u32 priority, s32 destination_core, Thread* thread);
175
176 bool AskForReselectionOrMarkRedundant(Thread* current_thread, const Thread* winner);
177
178 static constexpr u32 min_regular_priority = 2;
179 std::array<Common::MultiLevelQueue<Thread*, THREADPRIO_COUNT>, Core::Hardware::NUM_CPU_CORES>
180 scheduled_queue;
181 std::array<Common::MultiLevelQueue<Thread*, THREADPRIO_COUNT>, Core::Hardware::NUM_CPU_CORES>
182 suggested_queue;
183 std::atomic<bool> is_reselection_pending{false};
184
185 // The priority levels at which the global scheduler preempts threads every 10 ms. They are
186 // ordered from Core 0 to Core 3.
187 std::array<u32, Core::Hardware::NUM_CPU_CORES> preemption_priorities = {59, 59, 59, 62};
188
189 /// Scheduler lock mechanisms.
190 bool is_locked{};
191 std::mutex inner_lock;
192 std::atomic<s64> scope_lock{};
193 Core::EmuThreadHandle current_owner{Core::EmuThreadHandle::InvalidHandle()};
194
195 Common::SpinLock global_list_guard{};
196
197 /// Lists all thread ids that aren't deleted/etc.
198 std::vector<std::shared_ptr<Thread>> thread_list;
199 KernelCore& kernel;
200};
201
202class Scheduler final {
203public:
204 explicit Scheduler(Core::System& system, std::size_t core_id);
205 ~Scheduler();
206
207 /// Returns whether there are any threads that are ready to run.
208 bool HaveReadyThreads() const;
209
210 /// Reschedules to the next available thread (call after current thread is suspended)
211 void TryDoContextSwitch();
212
213 /// The next two are for SingleCore Only.
214 /// Unload current thread before preempting core.
215 void Unload();
216 /// Reload current thread after core preemption.
217 void Reload();
218
219 /// Gets the current running thread
220 Thread* GetCurrentThread() const;
221
222 /// Gets the currently selected thread from the top of the multilevel queue
223 Thread* GetSelectedThread() const;
224
225 /// Gets the timestamp for the last context switch in ticks.
226 u64 GetLastContextSwitchTicks() const;
227
228 bool ContextSwitchPending() const {
229 return is_context_switch_pending;
230 }
231
232 void Initialize();
233
234 /// Shutdowns the scheduler.
235 void Shutdown();
236
237 void OnThreadStart();
238
239 std::shared_ptr<Common::Fiber>& ControlContext() {
240 return switch_fiber;
241 }
242
243 const std::shared_ptr<Common::Fiber>& ControlContext() const {
244 return switch_fiber;
245 }
246
247private:
248 friend class GlobalScheduler;
249
250 /// Switches the CPU's active thread context to that of the specified thread
251 void SwitchContext();
252
253 /// When a thread wakes up, it must run this through it's new scheduler
254 void SwitchContextStep2();
255
256 /**
257 * Called on every context switch to update the internal timestamp
258 * This also updates the running time ticks for the given thread and
259 * process using the following difference:
260 *
261 * ticks += most_recent_ticks - last_context_switch_ticks
262 *
263 * The internal tick timestamp for the scheduler is simply the
264 * most recent tick count retrieved. No special arithmetic is
265 * applied to it.
266 */
267 void UpdateLastContextSwitchTime(Thread* thread, Process* process);
268
269 static void OnSwitch(void* this_scheduler);
270 void SwitchToCurrent();
271
272 std::shared_ptr<Thread> current_thread = nullptr;
273 std::shared_ptr<Thread> selected_thread = nullptr;
274 std::shared_ptr<Thread> current_thread_prev = nullptr;
275 std::shared_ptr<Thread> selected_thread_set = nullptr;
276 std::shared_ptr<Thread> idle_thread = nullptr;
277
278 std::shared_ptr<Common::Fiber> switch_fiber = nullptr;
279
280 Core::System& system;
281 u64 last_context_switch_time = 0;
282 u64 idle_selection_count = 0;
283 const std::size_t core_id;
284
285 Common::SpinLock guard{};
286
287 bool is_context_switch_pending = false;
288};
289
290class SchedulerLock {
291public:
292 [[nodiscard]] explicit SchedulerLock(KernelCore& kernel);
293 ~SchedulerLock();
294
295protected:
296 KernelCore& kernel;
297};
298
299class SchedulerLockAndSleep : public SchedulerLock {
300public:
301 explicit SchedulerLockAndSleep(KernelCore& kernel, Handle& event_handle, Thread* time_task,
302 s64 nanoseconds);
303 ~SchedulerLockAndSleep();
304
305 void CancelSleep() {
306 sleep_cancelled = true;
307 }
308
309 void Release();
310
311private:
312 Handle& event_handle;
313 Thread* time_task;
314 s64 nanoseconds;
315 bool sleep_cancelled{};
316};
317
318} // namespace Kernel
diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp
index 8c19f2534..b40fe3916 100644
--- a/src/core/hle/kernel/server_session.cpp
+++ b/src/core/hle/kernel/server_session.cpp
@@ -14,9 +14,9 @@
14#include "core/hle/kernel/client_session.h" 14#include "core/hle/kernel/client_session.h"
15#include "core/hle/kernel/handle_table.h" 15#include "core/hle/kernel/handle_table.h"
16#include "core/hle/kernel/hle_ipc.h" 16#include "core/hle/kernel/hle_ipc.h"
17#include "core/hle/kernel/k_scheduler.h"
17#include "core/hle/kernel/kernel.h" 18#include "core/hle/kernel/kernel.h"
18#include "core/hle/kernel/process.h" 19#include "core/hle/kernel/process.h"
19#include "core/hle/kernel/scheduler.h"
20#include "core/hle/kernel/server_session.h" 20#include "core/hle/kernel/server_session.h"
21#include "core/hle/kernel/session.h" 21#include "core/hle/kernel/session.h"
22#include "core/hle/kernel/thread.h" 22#include "core/hle/kernel/thread.h"
@@ -25,19 +25,19 @@
25namespace Kernel { 25namespace Kernel {
26 26
27ServerSession::ServerSession(KernelCore& kernel) : SynchronizationObject{kernel} {} 27ServerSession::ServerSession(KernelCore& kernel) : SynchronizationObject{kernel} {}
28ServerSession::~ServerSession() = default; 28
29ServerSession::~ServerSession() {
30 kernel.ReleaseServiceThread(service_thread);
31}
29 32
30ResultVal<std::shared_ptr<ServerSession>> ServerSession::Create(KernelCore& kernel, 33ResultVal<std::shared_ptr<ServerSession>> ServerSession::Create(KernelCore& kernel,
31 std::shared_ptr<Session> parent, 34 std::shared_ptr<Session> parent,
32 std::string name) { 35 std::string name) {
33 std::shared_ptr<ServerSession> session{std::make_shared<ServerSession>(kernel)}; 36 std::shared_ptr<ServerSession> session{std::make_shared<ServerSession>(kernel)};
34 37
35 session->request_event =
36 Core::Timing::CreateEvent(name, [session](std::uintptr_t, std::chrono::nanoseconds) {
37 session->CompleteSyncRequest();
38 });
39 session->name = std::move(name); 38 session->name = std::move(name);
40 session->parent = std::move(parent); 39 session->parent = std::move(parent);
40 session->service_thread = kernel.CreateServiceThread(session->name);
41 41
42 return MakeResult(std::move(session)); 42 return MakeResult(std::move(session));
43} 43}
@@ -130,8 +130,7 @@ ResultCode ServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& con
130 } 130 }
131 } 131 }
132 132
133 LOG_CRITICAL(IPC, "Unknown domain command={}", 133 LOG_CRITICAL(IPC, "Unknown domain command={}", domain_message_header.command.Value());
134 static_cast<int>(domain_message_header.command.Value()));
135 ASSERT(false); 134 ASSERT(false);
136 return RESULT_SUCCESS; 135 return RESULT_SUCCESS;
137} 136}
@@ -143,16 +142,16 @@ ResultCode ServerSession::QueueSyncRequest(std::shared_ptr<Thread> thread,
143 std::make_shared<HLERequestContext>(kernel, memory, SharedFrom(this), std::move(thread)); 142 std::make_shared<HLERequestContext>(kernel, memory, SharedFrom(this), std::move(thread));
144 143
145 context->PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf); 144 context->PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf);
146 request_queue.Push(std::move(context)); 145
146 if (auto strong_ptr = service_thread.lock()) {
147 strong_ptr->QueueSyncRequest(*this, std::move(context));
148 return RESULT_SUCCESS;
149 }
147 150
148 return RESULT_SUCCESS; 151 return RESULT_SUCCESS;
149} 152}
150 153
151ResultCode ServerSession::CompleteSyncRequest() { 154ResultCode ServerSession::CompleteSyncRequest(HLERequestContext& context) {
152 ASSERT(!request_queue.Empty());
153
154 auto& context = *request_queue.Front();
155
156 ResultCode result = RESULT_SUCCESS; 155 ResultCode result = RESULT_SUCCESS;
157 // If the session has been converted to a domain, handle the domain request 156 // If the session has been converted to a domain, handle the domain request
158 if (IsDomain() && context.HasDomainMessageHeader()) { 157 if (IsDomain() && context.HasDomainMessageHeader()) {
@@ -171,25 +170,20 @@ ResultCode ServerSession::CompleteSyncRequest() {
171 170
172 // Some service requests require the thread to block 171 // Some service requests require the thread to block
173 { 172 {
174 SchedulerLock lock(kernel); 173 KScopedSchedulerLock lock(kernel);
175 if (!context.IsThreadWaiting()) { 174 if (!context.IsThreadWaiting()) {
176 context.GetThread().ResumeFromWait(); 175 context.GetThread().ResumeFromWait();
177 context.GetThread().SetSynchronizationResults(nullptr, result); 176 context.GetThread().SetSynchronizationResults(nullptr, result);
178 } 177 }
179 } 178 }
180 179
181 request_queue.Pop();
182
183 return result; 180 return result;
184} 181}
185 182
186ResultCode ServerSession::HandleSyncRequest(std::shared_ptr<Thread> thread, 183ResultCode ServerSession::HandleSyncRequest(std::shared_ptr<Thread> thread,
187 Core::Memory::Memory& memory, 184 Core::Memory::Memory& memory,
188 Core::Timing::CoreTiming& core_timing) { 185 Core::Timing::CoreTiming& core_timing) {
189 const ResultCode result = QueueSyncRequest(std::move(thread), memory); 186 return QueueSyncRequest(std::move(thread), memory);
190 const auto delay = std::chrono::nanoseconds{kernel.IsMulticore() ? 0 : 20000};
191 core_timing.ScheduleEvent(delay, request_event, {});
192 return result;
193} 187}
194 188
195} // namespace Kernel 189} // namespace Kernel
diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h
index d23e9ec68..e8d1d99ea 100644
--- a/src/core/hle/kernel/server_session.h
+++ b/src/core/hle/kernel/server_session.h
@@ -10,6 +10,7 @@
10#include <vector> 10#include <vector>
11 11
12#include "common/threadsafe_queue.h" 12#include "common/threadsafe_queue.h"
13#include "core/hle/kernel/service_thread.h"
13#include "core/hle/kernel/synchronization_object.h" 14#include "core/hle/kernel/synchronization_object.h"
14#include "core/hle/result.h" 15#include "core/hle/result.h"
15 16
@@ -43,6 +44,8 @@ class Thread;
43 * TLS buffer and control is transferred back to it. 44 * TLS buffer and control is transferred back to it.
44 */ 45 */
45class ServerSession final : public SynchronizationObject { 46class ServerSession final : public SynchronizationObject {
47 friend class ServiceThread;
48
46public: 49public:
47 explicit ServerSession(KernelCore& kernel); 50 explicit ServerSession(KernelCore& kernel);
48 ~ServerSession() override; 51 ~ServerSession() override;
@@ -132,7 +135,7 @@ private:
132 ResultCode QueueSyncRequest(std::shared_ptr<Thread> thread, Core::Memory::Memory& memory); 135 ResultCode QueueSyncRequest(std::shared_ptr<Thread> thread, Core::Memory::Memory& memory);
133 136
134 /// Completes a sync request from the emulated application. 137 /// Completes a sync request from the emulated application.
135 ResultCode CompleteSyncRequest(); 138 ResultCode CompleteSyncRequest(HLERequestContext& context);
136 139
137 /// Handles a SyncRequest to a domain, forwarding the request to the proper object or closing an 140 /// Handles a SyncRequest to a domain, forwarding the request to the proper object or closing an
138 /// object handle. 141 /// object handle.
@@ -163,11 +166,8 @@ private:
163 /// The name of this session (optional) 166 /// The name of this session (optional)
164 std::string name; 167 std::string name;
165 168
166 /// Core timing event used to schedule the service request at some point in the future 169 /// Thread to dispatch service requests
167 std::shared_ptr<Core::Timing::EventType> request_event; 170 std::weak_ptr<ServiceThread> service_thread;
168
169 /// Queue of scheduled service requests
170 Common::MPSCQueue<std::shared_ptr<Kernel::HLERequestContext>> request_queue;
171}; 171};
172 172
173} // namespace Kernel 173} // namespace Kernel
diff --git a/src/core/hle/kernel/service_thread.cpp b/src/core/hle/kernel/service_thread.cpp
new file mode 100644
index 000000000..ee46f3e21
--- /dev/null
+++ b/src/core/hle/kernel/service_thread.cpp
@@ -0,0 +1,110 @@
1// Copyright 2020 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <condition_variable>
6#include <functional>
7#include <mutex>
8#include <thread>
9#include <vector>
10#include <queue>
11
12#include "common/assert.h"
13#include "common/scope_exit.h"
14#include "common/thread.h"
15#include "core/core.h"
16#include "core/hle/kernel/kernel.h"
17#include "core/hle/kernel/server_session.h"
18#include "core/hle/kernel/service_thread.h"
19#include "core/hle/lock.h"
20#include "video_core/renderer_base.h"
21
22namespace Kernel {
23
24class ServiceThread::Impl final {
25public:
26 explicit Impl(KernelCore& kernel, std::size_t num_threads, const std::string& name);
27 ~Impl();
28
29 void QueueSyncRequest(ServerSession& session, std::shared_ptr<HLERequestContext>&& context);
30
31private:
32 std::vector<std::thread> threads;
33 std::queue<std::function<void()>> requests;
34 std::mutex queue_mutex;
35 std::condition_variable condition;
36 const std::string service_name;
37 bool stop{};
38};
39
40ServiceThread::Impl::Impl(KernelCore& kernel, std::size_t num_threads, const std::string& name)
41 : service_name{name} {
42 for (std::size_t i = 0; i < num_threads; ++i)
43 threads.emplace_back([this, &kernel] {
44 Common::SetCurrentThreadName(std::string{"yuzu:HleService:" + service_name}.c_str());
45
46 // Wait for first request before trying to acquire a render context
47 {
48 std::unique_lock lock{queue_mutex};
49 condition.wait(lock, [this] { return stop || !requests.empty(); });
50 }
51
52 kernel.RegisterHostThread();
53
54 while (true) {
55 std::function<void()> task;
56
57 {
58 std::unique_lock lock{queue_mutex};
59 condition.wait(lock, [this] { return stop || !requests.empty(); });
60 if (stop || requests.empty()) {
61 return;
62 }
63 task = std::move(requests.front());
64 requests.pop();
65 }
66
67 task();
68 }
69 });
70}
71
72void ServiceThread::Impl::QueueSyncRequest(ServerSession& session,
73 std::shared_ptr<HLERequestContext>&& context) {
74 {
75 std::unique_lock lock{queue_mutex};
76
77 // ServerSession owns the service thread, so we cannot caption a strong pointer here in the
78 // event that the ServerSession is terminated.
79 std::weak_ptr<ServerSession> weak_ptr{SharedFrom(&session)};
80 requests.emplace([weak_ptr, context{std::move(context)}]() {
81 if (auto strong_ptr = weak_ptr.lock()) {
82 strong_ptr->CompleteSyncRequest(*context);
83 }
84 });
85 }
86 condition.notify_one();
87}
88
89ServiceThread::Impl::~Impl() {
90 {
91 std::unique_lock lock{queue_mutex};
92 stop = true;
93 }
94 condition.notify_all();
95 for (std::thread& thread : threads) {
96 thread.join();
97 }
98}
99
100ServiceThread::ServiceThread(KernelCore& kernel, std::size_t num_threads, const std::string& name)
101 : impl{std::make_unique<Impl>(kernel, num_threads, name)} {}
102
103ServiceThread::~ServiceThread() = default;
104
105void ServiceThread::QueueSyncRequest(ServerSession& session,
106 std::shared_ptr<HLERequestContext>&& context) {
107 impl->QueueSyncRequest(session, std::move(context));
108}
109
110} // namespace Kernel
diff --git a/src/core/hle/kernel/service_thread.h b/src/core/hle/kernel/service_thread.h
new file mode 100644
index 000000000..025ab8fb5
--- /dev/null
+++ b/src/core/hle/kernel/service_thread.h
@@ -0,0 +1,28 @@
1// Copyright 2020 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <memory>
8#include <string>
9
10namespace Kernel {
11
12class HLERequestContext;
13class KernelCore;
14class ServerSession;
15
16class ServiceThread final {
17public:
18 explicit ServiceThread(KernelCore& kernel, std::size_t num_threads, const std::string& name);
19 ~ServiceThread();
20
21 void QueueSyncRequest(ServerSession& session, std::shared_ptr<HLERequestContext>&& context);
22
23private:
24 class Impl;
25 std::unique_ptr<Impl> impl;
26};
27
28} // namespace Kernel
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index bafd1ced7..de3ed25da 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -24,6 +24,8 @@
24#include "core/hle/kernel/client_session.h" 24#include "core/hle/kernel/client_session.h"
25#include "core/hle/kernel/errors.h" 25#include "core/hle/kernel/errors.h"
26#include "core/hle/kernel/handle_table.h" 26#include "core/hle/kernel/handle_table.h"
27#include "core/hle/kernel/k_scheduler.h"
28#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
27#include "core/hle/kernel/kernel.h" 29#include "core/hle/kernel/kernel.h"
28#include "core/hle/kernel/memory/memory_block.h" 30#include "core/hle/kernel/memory/memory_block.h"
29#include "core/hle/kernel/memory/page_table.h" 31#include "core/hle/kernel/memory/page_table.h"
@@ -32,7 +34,6 @@
32#include "core/hle/kernel/process.h" 34#include "core/hle/kernel/process.h"
33#include "core/hle/kernel/readable_event.h" 35#include "core/hle/kernel/readable_event.h"
34#include "core/hle/kernel/resource_limit.h" 36#include "core/hle/kernel/resource_limit.h"
35#include "core/hle/kernel/scheduler.h"
36#include "core/hle/kernel/shared_memory.h" 37#include "core/hle/kernel/shared_memory.h"
37#include "core/hle/kernel/svc.h" 38#include "core/hle/kernel/svc.h"
38#include "core/hle/kernel/svc_types.h" 39#include "core/hle/kernel/svc_types.h"
@@ -234,8 +235,7 @@ static ResultCode SetMemoryAttribute(Core::System& system, VAddr address, u64 si
234 235
235static ResultCode SetMemoryAttribute32(Core::System& system, u32 address, u32 size, u32 mask, 236static ResultCode SetMemoryAttribute32(Core::System& system, u32 address, u32 size, u32 mask,
236 u32 attribute) { 237 u32 attribute) {
237 return SetMemoryAttribute(system, static_cast<VAddr>(address), static_cast<std::size_t>(size), 238 return SetMemoryAttribute(system, address, size, mask, attribute);
238 mask, attribute);
239} 239}
240 240
241/// Maps a memory range into a different range. 241/// Maps a memory range into a different range.
@@ -255,8 +255,7 @@ static ResultCode MapMemory(Core::System& system, VAddr dst_addr, VAddr src_addr
255} 255}
256 256
257static ResultCode MapMemory32(Core::System& system, u32 dst_addr, u32 src_addr, u32 size) { 257static ResultCode MapMemory32(Core::System& system, u32 dst_addr, u32 src_addr, u32 size) {
258 return MapMemory(system, static_cast<VAddr>(dst_addr), static_cast<VAddr>(src_addr), 258 return MapMemory(system, dst_addr, src_addr, size);
259 static_cast<std::size_t>(size));
260} 259}
261 260
262/// Unmaps a region that was previously mapped with svcMapMemory 261/// Unmaps a region that was previously mapped with svcMapMemory
@@ -276,8 +275,7 @@ static ResultCode UnmapMemory(Core::System& system, VAddr dst_addr, VAddr src_ad
276} 275}
277 276
278static ResultCode UnmapMemory32(Core::System& system, u32 dst_addr, u32 src_addr, u32 size) { 277static ResultCode UnmapMemory32(Core::System& system, u32 dst_addr, u32 src_addr, u32 size) {
279 return UnmapMemory(system, static_cast<VAddr>(dst_addr), static_cast<VAddr>(src_addr), 278 return UnmapMemory(system, dst_addr, src_addr, size);
280 static_cast<std::size_t>(size));
281} 279}
282 280
283/// Connect to an OS service given the port name, returns the handle to the port to out 281/// Connect to an OS service given the port name, returns the handle to the port to out
@@ -332,7 +330,8 @@ static ResultCode ConnectToNamedPort32(Core::System& system, Handle* out_handle,
332 330
333/// Makes a blocking IPC call to an OS service. 331/// Makes a blocking IPC call to an OS service.
334static ResultCode SendSyncRequest(Core::System& system, Handle handle) { 332static ResultCode SendSyncRequest(Core::System& system, Handle handle) {
335 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); 333 auto& kernel = system.Kernel();
334 const auto& handle_table = kernel.CurrentProcess()->GetHandleTable();
336 std::shared_ptr<ClientSession> session = handle_table.Get<ClientSession>(handle); 335 std::shared_ptr<ClientSession> session = handle_table.Get<ClientSession>(handle);
337 if (!session) { 336 if (!session) {
338 LOG_ERROR(Kernel_SVC, "called with invalid handle=0x{:08X}", handle); 337 LOG_ERROR(Kernel_SVC, "called with invalid handle=0x{:08X}", handle);
@@ -341,9 +340,9 @@ static ResultCode SendSyncRequest(Core::System& system, Handle handle) {
341 340
342 LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName()); 341 LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName());
343 342
344 auto thread = system.CurrentScheduler().GetCurrentThread(); 343 auto thread = kernel.CurrentScheduler()->GetCurrentThread();
345 { 344 {
346 SchedulerLock lock(system.Kernel()); 345 KScopedSchedulerLock lock(kernel);
347 thread->InvalidateHLECallback(); 346 thread->InvalidateHLECallback();
348 thread->SetStatus(ThreadStatus::WaitIPC); 347 thread->SetStatus(ThreadStatus::WaitIPC);
349 session->SendSyncRequest(SharedFrom(thread), system.Memory(), system.CoreTiming()); 348 session->SendSyncRequest(SharedFrom(thread), system.Memory(), system.CoreTiming());
@@ -352,12 +351,12 @@ static ResultCode SendSyncRequest(Core::System& system, Handle handle) {
352 if (thread->HasHLECallback()) { 351 if (thread->HasHLECallback()) {
353 Handle event_handle = thread->GetHLETimeEvent(); 352 Handle event_handle = thread->GetHLETimeEvent();
354 if (event_handle != InvalidHandle) { 353 if (event_handle != InvalidHandle) {
355 auto& time_manager = system.Kernel().TimeManager(); 354 auto& time_manager = kernel.TimeManager();
356 time_manager.UnscheduleTimeEvent(event_handle); 355 time_manager.UnscheduleTimeEvent(event_handle);
357 } 356 }
358 357
359 { 358 {
360 SchedulerLock lock(system.Kernel()); 359 KScopedSchedulerLock lock(kernel);
361 auto* sync_object = thread->GetHLESyncObject(); 360 auto* sync_object = thread->GetHLESyncObject();
362 sync_object->RemoveWaitingThread(SharedFrom(thread)); 361 sync_object->RemoveWaitingThread(SharedFrom(thread));
363 } 362 }
@@ -531,8 +530,7 @@ static ResultCode ArbitrateLock(Core::System& system, Handle holding_thread_hand
531 530
532static ResultCode ArbitrateLock32(Core::System& system, Handle holding_thread_handle, 531static ResultCode ArbitrateLock32(Core::System& system, Handle holding_thread_handle,
533 u32 mutex_addr, Handle requesting_thread_handle) { 532 u32 mutex_addr, Handle requesting_thread_handle) {
534 return ArbitrateLock(system, holding_thread_handle, static_cast<VAddr>(mutex_addr), 533 return ArbitrateLock(system, holding_thread_handle, mutex_addr, requesting_thread_handle);
535 requesting_thread_handle);
536} 534}
537 535
538/// Unlock a mutex 536/// Unlock a mutex
@@ -555,7 +553,7 @@ static ResultCode ArbitrateUnlock(Core::System& system, VAddr mutex_addr) {
555} 553}
556 554
557static ResultCode ArbitrateUnlock32(Core::System& system, u32 mutex_addr) { 555static ResultCode ArbitrateUnlock32(Core::System& system, u32 mutex_addr) {
558 return ArbitrateUnlock(system, static_cast<VAddr>(mutex_addr)); 556 return ArbitrateUnlock(system, mutex_addr);
559} 557}
560 558
561enum class BreakType : u32 { 559enum class BreakType : u32 {
@@ -658,7 +656,6 @@ static void Break(Core::System& system, u32 reason, u64 info1, u64 info2) {
658 info2, has_dumped_buffer ? std::make_optional(debug_buffer) : std::nullopt); 656 info2, has_dumped_buffer ? std::make_optional(debug_buffer) : std::nullopt);
659 657
660 if (!break_reason.signal_debugger) { 658 if (!break_reason.signal_debugger) {
661 SchedulerLock lock(system.Kernel());
662 LOG_CRITICAL( 659 LOG_CRITICAL(
663 Debug_Emulated, 660 Debug_Emulated,
664 "Emulated program broke execution! reason=0x{:016X}, info1=0x{:016X}, info2=0x{:016X}", 661 "Emulated program broke execution! reason=0x{:016X}, info1=0x{:016X}, info2=0x{:016X}",
@@ -666,22 +663,18 @@ static void Break(Core::System& system, u32 reason, u64 info1, u64 info2) {
666 663
667 handle_debug_buffer(info1, info2); 664 handle_debug_buffer(info1, info2);
668 665
669 auto* const current_thread = system.CurrentScheduler().GetCurrentThread(); 666 auto* const current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread();
670 const auto thread_processor_id = current_thread->GetProcessorID(); 667 const auto thread_processor_id = current_thread->GetProcessorID();
671 system.ArmInterface(static_cast<std::size_t>(thread_processor_id)).LogBacktrace(); 668 system.ArmInterface(static_cast<std::size_t>(thread_processor_id)).LogBacktrace();
672
673 // Kill the current thread
674 system.Kernel().ExceptionalExit();
675 current_thread->Stop();
676 } 669 }
677} 670}
678 671
679static void Break32(Core::System& system, u32 reason, u32 info1, u32 info2) { 672static void Break32(Core::System& system, u32 reason, u32 info1, u32 info2) {
680 Break(system, reason, static_cast<u64>(info1), static_cast<u64>(info2)); 673 Break(system, reason, info1, info2);
681} 674}
682 675
683/// Used to output a message on a debug hardware unit - does nothing on a retail unit 676/// Used to output a message on a debug hardware unit - does nothing on a retail unit
684static void OutputDebugString([[maybe_unused]] Core::System& system, VAddr address, u64 len) { 677static void OutputDebugString(Core::System& system, VAddr address, u64 len) {
685 if (len == 0) { 678 if (len == 0) {
686 return; 679 return;
687 } 680 }
@@ -922,7 +915,7 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha
922 } 915 }
923 916
924 const auto& core_timing = system.CoreTiming(); 917 const auto& core_timing = system.CoreTiming();
925 const auto& scheduler = system.CurrentScheduler(); 918 const auto& scheduler = *system.Kernel().CurrentScheduler();
926 const auto* const current_thread = scheduler.GetCurrentThread(); 919 const auto* const current_thread = scheduler.GetCurrentThread();
927 const bool same_thread = current_thread == thread.get(); 920 const bool same_thread = current_thread == thread.get();
928 921
@@ -948,7 +941,7 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha
948 941
949static ResultCode GetInfo32(Core::System& system, u32* result_low, u32* result_high, u32 sub_id_low, 942static ResultCode GetInfo32(Core::System& system, u32* result_low, u32* result_high, u32 sub_id_low,
950 u32 info_id, u32 handle, u32 sub_id_high) { 943 u32 info_id, u32 handle, u32 sub_id_high) {
951 const u64 sub_id{static_cast<u64>(sub_id_low | (static_cast<u64>(sub_id_high) << 32))}; 944 const u64 sub_id{u64{sub_id_low} | (u64{sub_id_high} << 32)};
952 u64 res_value{}; 945 u64 res_value{};
953 946
954 const ResultCode result{GetInfo(system, &res_value, info_id, handle, sub_id)}; 947 const ResultCode result{GetInfo(system, &res_value, info_id, handle, sub_id)};
@@ -1009,7 +1002,7 @@ static ResultCode MapPhysicalMemory(Core::System& system, VAddr addr, u64 size)
1009} 1002}
1010 1003
1011static ResultCode MapPhysicalMemory32(Core::System& system, u32 addr, u32 size) { 1004static ResultCode MapPhysicalMemory32(Core::System& system, u32 addr, u32 size) {
1012 return MapPhysicalMemory(system, static_cast<VAddr>(addr), static_cast<std::size_t>(size)); 1005 return MapPhysicalMemory(system, addr, size);
1013} 1006}
1014 1007
1015/// Unmaps memory previously mapped via MapPhysicalMemory 1008/// Unmaps memory previously mapped via MapPhysicalMemory
@@ -1063,7 +1056,7 @@ static ResultCode UnmapPhysicalMemory(Core::System& system, VAddr addr, u64 size
1063} 1056}
1064 1057
1065static ResultCode UnmapPhysicalMemory32(Core::System& system, u32 addr, u32 size) { 1058static ResultCode UnmapPhysicalMemory32(Core::System& system, u32 addr, u32 size) {
1066 return UnmapPhysicalMemory(system, static_cast<VAddr>(addr), static_cast<std::size_t>(size)); 1059 return UnmapPhysicalMemory(system, addr, size);
1067} 1060}
1068 1061
1069/// Sets the thread activity 1062/// Sets the thread activity
@@ -1090,7 +1083,7 @@ static ResultCode SetThreadActivity(Core::System& system, Handle handle, u32 act
1090 return ERR_INVALID_HANDLE; 1083 return ERR_INVALID_HANDLE;
1091 } 1084 }
1092 1085
1093 if (thread.get() == system.CurrentScheduler().GetCurrentThread()) { 1086 if (thread.get() == system.Kernel().CurrentScheduler()->GetCurrentThread()) {
1094 LOG_ERROR(Kernel_SVC, "The thread handle specified is the current running thread"); 1087 LOG_ERROR(Kernel_SVC, "The thread handle specified is the current running thread");
1095 return ERR_BUSY; 1088 return ERR_BUSY;
1096 } 1089 }
@@ -1123,7 +1116,7 @@ static ResultCode GetThreadContext(Core::System& system, VAddr thread_context, H
1123 return ERR_INVALID_HANDLE; 1116 return ERR_INVALID_HANDLE;
1124 } 1117 }
1125 1118
1126 if (thread.get() == system.CurrentScheduler().GetCurrentThread()) { 1119 if (thread.get() == system.Kernel().CurrentScheduler()->GetCurrentThread()) {
1127 LOG_ERROR(Kernel_SVC, "The thread handle specified is the current running thread"); 1120 LOG_ERROR(Kernel_SVC, "The thread handle specified is the current running thread");
1128 return ERR_BUSY; 1121 return ERR_BUSY;
1129 } 1122 }
@@ -1144,7 +1137,7 @@ static ResultCode GetThreadContext(Core::System& system, VAddr thread_context, H
1144} 1137}
1145 1138
1146static ResultCode GetThreadContext32(Core::System& system, u32 thread_context, Handle handle) { 1139static ResultCode GetThreadContext32(Core::System& system, u32 thread_context, Handle handle) {
1147 return GetThreadContext(system, static_cast<VAddr>(thread_context), handle); 1140 return GetThreadContext(system, thread_context, handle);
1148} 1141}
1149 1142
1150/// Gets the priority for the specified thread 1143/// Gets the priority for the specified thread
@@ -1281,8 +1274,7 @@ static ResultCode MapSharedMemory(Core::System& system, Handle shared_memory_han
1281 1274
1282static ResultCode MapSharedMemory32(Core::System& system, Handle shared_memory_handle, u32 addr, 1275static ResultCode MapSharedMemory32(Core::System& system, Handle shared_memory_handle, u32 addr,
1283 u32 size, u32 permissions) { 1276 u32 size, u32 permissions) {
1284 return MapSharedMemory(system, shared_memory_handle, static_cast<VAddr>(addr), 1277 return MapSharedMemory(system, shared_memory_handle, addr, size, permissions);
1285 static_cast<std::size_t>(size), permissions);
1286} 1278}
1287 1279
1288static ResultCode QueryProcessMemory(Core::System& system, VAddr memory_info_address, 1280static ResultCode QueryProcessMemory(Core::System& system, VAddr memory_info_address,
@@ -1480,7 +1472,7 @@ static void ExitProcess(Core::System& system) {
1480 current_process->PrepareForTermination(); 1472 current_process->PrepareForTermination();
1481 1473
1482 // Kill the current thread 1474 // Kill the current thread
1483 system.CurrentScheduler().GetCurrentThread()->Stop(); 1475 system.Kernel().CurrentScheduler()->GetCurrentThread()->Stop();
1484} 1476}
1485 1477
1486static void ExitProcess32(Core::System& system) { 1478static void ExitProcess32(Core::System& system) {
@@ -1552,8 +1544,7 @@ static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr e
1552 1544
1553static ResultCode CreateThread32(Core::System& system, Handle* out_handle, u32 priority, 1545static ResultCode CreateThread32(Core::System& system, Handle* out_handle, u32 priority,
1554 u32 entry_point, u32 arg, u32 stack_top, s32 processor_id) { 1546 u32 entry_point, u32 arg, u32 stack_top, s32 processor_id) {
1555 return CreateThread(system, out_handle, static_cast<VAddr>(entry_point), static_cast<u64>(arg), 1547 return CreateThread(system, out_handle, entry_point, arg, stack_top, priority, processor_id);
1556 static_cast<VAddr>(stack_top), priority, processor_id);
1557} 1548}
1558 1549
1559/// Starts the thread for the provided handle 1550/// Starts the thread for the provided handle
@@ -1581,8 +1572,8 @@ static ResultCode StartThread32(Core::System& system, Handle thread_handle) {
1581static void ExitThread(Core::System& system) { 1572static void ExitThread(Core::System& system) {
1582 LOG_DEBUG(Kernel_SVC, "called, pc=0x{:08X}", system.CurrentArmInterface().GetPC()); 1573 LOG_DEBUG(Kernel_SVC, "called, pc=0x{:08X}", system.CurrentArmInterface().GetPC());
1583 1574
1584 auto* const current_thread = system.CurrentScheduler().GetCurrentThread(); 1575 auto* const current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread();
1585 system.GlobalScheduler().RemoveThread(SharedFrom(current_thread)); 1576 system.GlobalSchedulerContext().RemoveThread(SharedFrom(current_thread));
1586 current_thread->Stop(); 1577 current_thread->Stop();
1587} 1578}
1588 1579
@@ -1592,53 +1583,39 @@ static void ExitThread32(Core::System& system) {
1592 1583
1593/// Sleep the current thread 1584/// Sleep the current thread
1594static void SleepThread(Core::System& system, s64 nanoseconds) { 1585static void SleepThread(Core::System& system, s64 nanoseconds) {
1595 LOG_DEBUG(Kernel_SVC, "called nanoseconds={}", nanoseconds); 1586 LOG_TRACE(Kernel_SVC, "called nanoseconds={}", nanoseconds);
1596 1587
1597 enum class SleepType : s64 { 1588 enum class SleepType : s64 {
1598 YieldWithoutLoadBalancing = 0, 1589 YieldWithoutCoreMigration = 0,
1599 YieldWithLoadBalancing = -1, 1590 YieldWithCoreMigration = -1,
1600 YieldAndWaitForLoadBalancing = -2, 1591 YieldAndWaitForLoadBalancing = -2,
1601 }; 1592 };
1602 1593
1603 auto& scheduler = system.CurrentScheduler(); 1594 auto& scheduler = *system.Kernel().CurrentScheduler();
1604 auto* const current_thread = scheduler.GetCurrentThread();
1605 bool is_redundant = false;
1606
1607 if (nanoseconds <= 0) { 1595 if (nanoseconds <= 0) {
1608 switch (static_cast<SleepType>(nanoseconds)) { 1596 switch (static_cast<SleepType>(nanoseconds)) {
1609 case SleepType::YieldWithoutLoadBalancing: { 1597 case SleepType::YieldWithoutCoreMigration: {
1610 auto pair = current_thread->YieldSimple(); 1598 scheduler.YieldWithoutCoreMigration();
1611 is_redundant = pair.second;
1612 break; 1599 break;
1613 } 1600 }
1614 case SleepType::YieldWithLoadBalancing: { 1601 case SleepType::YieldWithCoreMigration: {
1615 auto pair = current_thread->YieldAndBalanceLoad(); 1602 scheduler.YieldWithCoreMigration();
1616 is_redundant = pair.second;
1617 break; 1603 break;
1618 } 1604 }
1619 case SleepType::YieldAndWaitForLoadBalancing: { 1605 case SleepType::YieldAndWaitForLoadBalancing: {
1620 auto pair = current_thread->YieldAndWaitForLoadBalancing(); 1606 scheduler.YieldToAnyThread();
1621 is_redundant = pair.second;
1622 break; 1607 break;
1623 } 1608 }
1624 default: 1609 default:
1625 UNREACHABLE_MSG("Unimplemented sleep yield type '{:016X}'!", nanoseconds); 1610 UNREACHABLE_MSG("Unimplemented sleep yield type '{:016X}'!", nanoseconds);
1626 } 1611 }
1627 } else { 1612 } else {
1628 current_thread->Sleep(nanoseconds); 1613 scheduler.GetCurrentThread()->Sleep(nanoseconds);
1629 }
1630
1631 if (is_redundant && !system.Kernel().IsMulticore()) {
1632 system.Kernel().ExitSVCProfile();
1633 system.CoreTiming().AddTicks(1000U);
1634 system.GetCpuManager().PreemptSingleCore();
1635 system.Kernel().EnterSVCProfile();
1636 } 1614 }
1637} 1615}
1638 1616
1639static void SleepThread32(Core::System& system, u32 nanoseconds_low, u32 nanoseconds_high) { 1617static void SleepThread32(Core::System& system, u32 nanoseconds_low, u32 nanoseconds_high) {
1640 const s64 nanoseconds = static_cast<s64>(static_cast<u64>(nanoseconds_low) | 1618 const auto nanoseconds = static_cast<s64>(u64{nanoseconds_low} | (u64{nanoseconds_high} << 32));
1641 (static_cast<u64>(nanoseconds_high) << 32));
1642 SleepThread(system, nanoseconds); 1619 SleepThread(system, nanoseconds);
1643} 1620}
1644 1621
@@ -1668,10 +1645,10 @@ static ResultCode WaitProcessWideKeyAtomic(Core::System& system, VAddr mutex_add
1668 ASSERT(condition_variable_addr == Common::AlignDown(condition_variable_addr, 4)); 1645 ASSERT(condition_variable_addr == Common::AlignDown(condition_variable_addr, 4));
1669 auto& kernel = system.Kernel(); 1646 auto& kernel = system.Kernel();
1670 Handle event_handle; 1647 Handle event_handle;
1671 Thread* current_thread = system.CurrentScheduler().GetCurrentThread(); 1648 Thread* current_thread = kernel.CurrentScheduler()->GetCurrentThread();
1672 auto* const current_process = system.Kernel().CurrentProcess(); 1649 auto* const current_process = kernel.CurrentProcess();
1673 { 1650 {
1674 SchedulerLockAndSleep lock(kernel, event_handle, current_thread, nano_seconds); 1651 KScopedSchedulerLockAndSleep lock(kernel, event_handle, current_thread, nano_seconds);
1675 const auto& handle_table = current_process->GetHandleTable(); 1652 const auto& handle_table = current_process->GetHandleTable();
1676 std::shared_ptr<Thread> thread = handle_table.Get<Thread>(thread_handle); 1653 std::shared_ptr<Thread> thread = handle_table.Get<Thread>(thread_handle);
1677 ASSERT(thread); 1654 ASSERT(thread);
@@ -1707,7 +1684,7 @@ static ResultCode WaitProcessWideKeyAtomic(Core::System& system, VAddr mutex_add
1707 } 1684 }
1708 1685
1709 { 1686 {
1710 SchedulerLock lock(kernel); 1687 KScopedSchedulerLock lock(kernel);
1711 1688
1712 auto* owner = current_thread->GetLockOwner(); 1689 auto* owner = current_thread->GetLockOwner();
1713 if (owner != nullptr) { 1690 if (owner != nullptr) {
@@ -1724,10 +1701,8 @@ static ResultCode WaitProcessWideKeyAtomic(Core::System& system, VAddr mutex_add
1724static ResultCode WaitProcessWideKeyAtomic32(Core::System& system, u32 mutex_addr, 1701static ResultCode WaitProcessWideKeyAtomic32(Core::System& system, u32 mutex_addr,
1725 u32 condition_variable_addr, Handle thread_handle, 1702 u32 condition_variable_addr, Handle thread_handle,
1726 u32 nanoseconds_low, u32 nanoseconds_high) { 1703 u32 nanoseconds_low, u32 nanoseconds_high) {
1727 const s64 nanoseconds = 1704 const auto nanoseconds = static_cast<s64>(nanoseconds_low | (u64{nanoseconds_high} << 32));
1728 static_cast<s64>(nanoseconds_low | (static_cast<u64>(nanoseconds_high) << 32)); 1705 return WaitProcessWideKeyAtomic(system, mutex_addr, condition_variable_addr, thread_handle,
1729 return WaitProcessWideKeyAtomic(system, static_cast<VAddr>(mutex_addr),
1730 static_cast<VAddr>(condition_variable_addr), thread_handle,
1731 nanoseconds); 1706 nanoseconds);
1732} 1707}
1733 1708
@@ -1740,7 +1715,7 @@ static void SignalProcessWideKey(Core::System& system, VAddr condition_variable_
1740 1715
1741 // Retrieve a list of all threads that are waiting for this condition variable. 1716 // Retrieve a list of all threads that are waiting for this condition variable.
1742 auto& kernel = system.Kernel(); 1717 auto& kernel = system.Kernel();
1743 SchedulerLock lock(kernel); 1718 KScopedSchedulerLock lock(kernel);
1744 auto* const current_process = kernel.CurrentProcess(); 1719 auto* const current_process = kernel.CurrentProcess();
1745 std::vector<std::shared_ptr<Thread>> waiting_threads = 1720 std::vector<std::shared_ptr<Thread>> waiting_threads =
1746 current_process->GetConditionVariableThreads(condition_variable_addr); 1721 current_process->GetConditionVariableThreads(condition_variable_addr);
@@ -1833,8 +1808,8 @@ static ResultCode WaitForAddress(Core::System& system, VAddr address, u32 type,
1833 1808
1834static ResultCode WaitForAddress32(Core::System& system, u32 address, u32 type, s32 value, 1809static ResultCode WaitForAddress32(Core::System& system, u32 address, u32 type, s32 value,
1835 u32 timeout_low, u32 timeout_high) { 1810 u32 timeout_low, u32 timeout_high) {
1836 s64 timeout = static_cast<s64>(timeout_low | (static_cast<u64>(timeout_high) << 32)); 1811 const auto timeout = static_cast<s64>(timeout_low | (u64{timeout_high} << 32));
1837 return WaitForAddress(system, static_cast<VAddr>(address), type, value, timeout); 1812 return WaitForAddress(system, address, type, value, timeout);
1838} 1813}
1839 1814
1840// Signals to an address (via Address Arbiter) 1815// Signals to an address (via Address Arbiter)
@@ -1862,7 +1837,7 @@ static ResultCode SignalToAddress(Core::System& system, VAddr address, u32 type,
1862 1837
1863static ResultCode SignalToAddress32(Core::System& system, u32 address, u32 type, s32 value, 1838static ResultCode SignalToAddress32(Core::System& system, u32 address, u32 type, s32 value,
1864 s32 num_to_wake) { 1839 s32 num_to_wake) {
1865 return SignalToAddress(system, static_cast<VAddr>(address), type, value, num_to_wake); 1840 return SignalToAddress(system, address, type, value, num_to_wake);
1866} 1841}
1867 1842
1868static void KernelDebug([[maybe_unused]] Core::System& system, 1843static void KernelDebug([[maybe_unused]] Core::System& system,
@@ -1893,7 +1868,7 @@ static u64 GetSystemTick(Core::System& system) {
1893} 1868}
1894 1869
1895static void GetSystemTick32(Core::System& system, u32* time_low, u32* time_high) { 1870static void GetSystemTick32(Core::System& system, u32* time_low, u32* time_high) {
1896 u64 time = GetSystemTick(system); 1871 const auto time = GetSystemTick(system);
1897 *time_low = static_cast<u32>(time); 1872 *time_low = static_cast<u32>(time);
1898 *time_high = static_cast<u32>(time >> 32); 1873 *time_high = static_cast<u32>(time >> 32);
1899} 1874}
@@ -1984,8 +1959,7 @@ static ResultCode CreateTransferMemory(Core::System& system, Handle* handle, VAd
1984 1959
1985static ResultCode CreateTransferMemory32(Core::System& system, Handle* handle, u32 addr, u32 size, 1960static ResultCode CreateTransferMemory32(Core::System& system, Handle* handle, u32 addr, u32 size,
1986 u32 permissions) { 1961 u32 permissions) {
1987 return CreateTransferMemory(system, handle, static_cast<VAddr>(addr), 1962 return CreateTransferMemory(system, handle, addr, size, permissions);
1988 static_cast<std::size_t>(size), permissions);
1989} 1963}
1990 1964
1991static ResultCode GetThreadCoreMask(Core::System& system, Handle thread_handle, u32* core, 1965static ResultCode GetThreadCoreMask(Core::System& system, Handle thread_handle, u32* core,
@@ -2003,7 +1977,7 @@ static ResultCode GetThreadCoreMask(Core::System& system, Handle thread_handle,
2003 } 1977 }
2004 1978
2005 *core = thread->GetIdealCore(); 1979 *core = thread->GetIdealCore();
2006 *mask = thread->GetAffinityMask(); 1980 *mask = thread->GetAffinityMask().GetAffinityMask();
2007 1981
2008 return RESULT_SUCCESS; 1982 return RESULT_SUCCESS;
2009} 1983}
@@ -2075,8 +2049,7 @@ static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle,
2075 2049
2076static ResultCode SetThreadCoreMask32(Core::System& system, Handle thread_handle, u32 core, 2050static ResultCode SetThreadCoreMask32(Core::System& system, Handle thread_handle, u32 core,
2077 u32 affinity_mask_low, u32 affinity_mask_high) { 2051 u32 affinity_mask_low, u32 affinity_mask_high) {
2078 const u64 affinity_mask = 2052 const auto affinity_mask = u64{affinity_mask_low} | (u64{affinity_mask_high} << 32);
2079 static_cast<u64>(affinity_mask_low) | (static_cast<u64>(affinity_mask_high) << 32);
2080 return SetThreadCoreMask(system, thread_handle, core, affinity_mask); 2053 return SetThreadCoreMask(system, thread_handle, core, affinity_mask);
2081} 2054}
2082 2055
@@ -2341,9 +2314,10 @@ static ResultCode GetThreadList(Core::System& system, u32* out_num_threads, VAdd
2341 return RESULT_SUCCESS; 2314 return RESULT_SUCCESS;
2342} 2315}
2343 2316
2344static ResultCode FlushProcessDataCache32(Core::System& system, Handle handle, u32 address, 2317static ResultCode FlushProcessDataCache32([[maybe_unused]] Core::System& system,
2345 u32 size) { 2318 [[maybe_unused]] Handle handle,
2346 // Note(Blinkhawk): For emulation purposes of the data cache this is mostly a nope 2319 [[maybe_unused]] u32 address, [[maybe_unused]] u32 size) {
2320 // Note(Blinkhawk): For emulation purposes of the data cache this is mostly a no-op,
2347 // as all emulation is done in the same cache level in host architecture, thus data cache 2321 // as all emulation is done in the same cache level in host architecture, thus data cache
2348 // does not need flushing. 2322 // does not need flushing.
2349 LOG_DEBUG(Kernel_SVC, "called"); 2323 LOG_DEBUG(Kernel_SVC, "called");
@@ -2639,6 +2613,9 @@ void Call(Core::System& system, u32 immediate) {
2639 auto& kernel = system.Kernel(); 2613 auto& kernel = system.Kernel();
2640 kernel.EnterSVCProfile(); 2614 kernel.EnterSVCProfile();
2641 2615
2616 auto* thread = kernel.CurrentScheduler()->GetCurrentThread();
2617 thread->SetContinuousOnSVC(true);
2618
2642 const FunctionDef* info = system.CurrentProcess()->Is64BitProcess() ? GetSVCInfo64(immediate) 2619 const FunctionDef* info = system.CurrentProcess()->Is64BitProcess() ? GetSVCInfo64(immediate)
2643 : GetSVCInfo32(immediate); 2620 : GetSVCInfo32(immediate);
2644 if (info) { 2621 if (info) {
@@ -2652,6 +2629,12 @@ void Call(Core::System& system, u32 immediate) {
2652 } 2629 }
2653 2630
2654 kernel.ExitSVCProfile(); 2631 kernel.ExitSVCProfile();
2632
2633 if (!thread->IsContinuousOnSVC()) {
2634 auto* host_context = thread->GetHostContext().get();
2635 host_context->Rewind();
2636 }
2637
2655 system.EnterDynarmicProfile(); 2638 system.EnterDynarmicProfile();
2656} 2639}
2657 2640
diff --git a/src/core/hle/kernel/svc_types.h b/src/core/hle/kernel/svc_types.h
index 986724beb..11e1d8e2d 100644
--- a/src/core/hle/kernel/svc_types.h
+++ b/src/core/hle/kernel/svc_types.h
@@ -23,8 +23,8 @@ enum class MemoryState : u32 {
23 Ipc = 0x0A, 23 Ipc = 0x0A,
24 Stack = 0x0B, 24 Stack = 0x0B,
25 ThreadLocal = 0x0C, 25 ThreadLocal = 0x0C,
26 Transfered = 0x0D, 26 Transferred = 0x0D,
27 SharedTransfered = 0x0E, 27 SharedTransferred = 0x0E,
28 SharedCode = 0x0F, 28 SharedCode = 0x0F,
29 Inaccessible = 0x10, 29 Inaccessible = 0x10,
30 NonSecureIpc = 0x11, 30 NonSecureIpc = 0x11,
diff --git a/src/core/hle/kernel/synchronization.cpp b/src/core/hle/kernel/synchronization.cpp
index 8b875d853..d3f520ea2 100644
--- a/src/core/hle/kernel/synchronization.cpp
+++ b/src/core/hle/kernel/synchronization.cpp
@@ -5,8 +5,9 @@
5#include "core/core.h" 5#include "core/core.h"
6#include "core/hle/kernel/errors.h" 6#include "core/hle/kernel/errors.h"
7#include "core/hle/kernel/handle_table.h" 7#include "core/hle/kernel/handle_table.h"
8#include "core/hle/kernel/k_scheduler.h"
9#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
8#include "core/hle/kernel/kernel.h" 10#include "core/hle/kernel/kernel.h"
9#include "core/hle/kernel/scheduler.h"
10#include "core/hle/kernel/synchronization.h" 11#include "core/hle/kernel/synchronization.h"
11#include "core/hle/kernel/synchronization_object.h" 12#include "core/hle/kernel/synchronization_object.h"
12#include "core/hle/kernel/thread.h" 13#include "core/hle/kernel/thread.h"
@@ -18,7 +19,7 @@ Synchronization::Synchronization(Core::System& system) : system{system} {}
18 19
19void Synchronization::SignalObject(SynchronizationObject& obj) const { 20void Synchronization::SignalObject(SynchronizationObject& obj) const {
20 auto& kernel = system.Kernel(); 21 auto& kernel = system.Kernel();
21 SchedulerLock lock(kernel); 22 KScopedSchedulerLock lock(kernel);
22 if (obj.IsSignaled()) { 23 if (obj.IsSignaled()) {
23 for (auto thread : obj.GetWaitingThreads()) { 24 for (auto thread : obj.GetWaitingThreads()) {
24 if (thread->GetSchedulingStatus() == ThreadSchedStatus::Paused) { 25 if (thread->GetSchedulingStatus() == ThreadSchedStatus::Paused) {
@@ -37,10 +38,10 @@ void Synchronization::SignalObject(SynchronizationObject& obj) const {
37std::pair<ResultCode, Handle> Synchronization::WaitFor( 38std::pair<ResultCode, Handle> Synchronization::WaitFor(
38 std::vector<std::shared_ptr<SynchronizationObject>>& sync_objects, s64 nano_seconds) { 39 std::vector<std::shared_ptr<SynchronizationObject>>& sync_objects, s64 nano_seconds) {
39 auto& kernel = system.Kernel(); 40 auto& kernel = system.Kernel();
40 auto* const thread = system.CurrentScheduler().GetCurrentThread(); 41 auto* const thread = kernel.CurrentScheduler()->GetCurrentThread();
41 Handle event_handle = InvalidHandle; 42 Handle event_handle = InvalidHandle;
42 { 43 {
43 SchedulerLockAndSleep lock(kernel, event_handle, thread, nano_seconds); 44 KScopedSchedulerLockAndSleep lock(kernel, event_handle, thread, nano_seconds);
44 const auto itr = 45 const auto itr =
45 std::find_if(sync_objects.begin(), sync_objects.end(), 46 std::find_if(sync_objects.begin(), sync_objects.end(),
46 [thread](const std::shared_ptr<SynchronizationObject>& object) { 47 [thread](const std::shared_ptr<SynchronizationObject>& object) {
@@ -89,7 +90,7 @@ std::pair<ResultCode, Handle> Synchronization::WaitFor(
89 } 90 }
90 91
91 { 92 {
92 SchedulerLock lock(kernel); 93 KScopedSchedulerLock lock(kernel);
93 ResultCode signaling_result = thread->GetSignalingResult(); 94 ResultCode signaling_result = thread->GetSignalingResult();
94 SynchronizationObject* signaling_object = thread->GetSignalingObject(); 95 SynchronizationObject* signaling_object = thread->GetSignalingObject();
95 thread->SetSynchronizationObjects(nullptr); 96 thread->SetSynchronizationObjects(nullptr);
diff --git a/src/core/hle/kernel/synchronization_object.h b/src/core/hle/kernel/synchronization_object.h
index f89b24204..7408ed51f 100644
--- a/src/core/hle/kernel/synchronization_object.h
+++ b/src/core/hle/kernel/synchronization_object.h
@@ -4,6 +4,7 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <atomic>
7#include <memory> 8#include <memory>
8#include <vector> 9#include <vector>
9 10
@@ -56,7 +57,7 @@ public:
56 void ClearWaitingThreads(); 57 void ClearWaitingThreads();
57 58
58protected: 59protected:
59 bool is_signaled{}; // Tells if this sync object is signalled; 60 std::atomic_bool is_signaled{}; // Tells if this sync object is signaled
60 61
61private: 62private:
62 /// Threads waiting for this object to become available 63 /// Threads waiting for this object to become available
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index d132aba34..a4f9e0d97 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -12,17 +12,16 @@
12#include "common/fiber.h" 12#include "common/fiber.h"
13#include "common/logging/log.h" 13#include "common/logging/log.h"
14#include "common/thread_queue_list.h" 14#include "common/thread_queue_list.h"
15#include "core/arm/arm_interface.h"
16#include "core/arm/unicorn/arm_unicorn.h"
17#include "core/core.h" 15#include "core/core.h"
18#include "core/cpu_manager.h" 16#include "core/cpu_manager.h"
19#include "core/hardware_properties.h" 17#include "core/hardware_properties.h"
20#include "core/hle/kernel/errors.h" 18#include "core/hle/kernel/errors.h"
21#include "core/hle/kernel/handle_table.h" 19#include "core/hle/kernel/handle_table.h"
20#include "core/hle/kernel/k_scheduler.h"
21#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
22#include "core/hle/kernel/kernel.h" 22#include "core/hle/kernel/kernel.h"
23#include "core/hle/kernel/object.h" 23#include "core/hle/kernel/object.h"
24#include "core/hle/kernel/process.h" 24#include "core/hle/kernel/process.h"
25#include "core/hle/kernel/scheduler.h"
26#include "core/hle/kernel/thread.h" 25#include "core/hle/kernel/thread.h"
27#include "core/hle/kernel/time_manager.h" 26#include "core/hle/kernel/time_manager.h"
28#include "core/hle/result.h" 27#include "core/hle/result.h"
@@ -52,7 +51,7 @@ Thread::~Thread() = default;
52 51
53void Thread::Stop() { 52void Thread::Stop() {
54 { 53 {
55 SchedulerLock lock(kernel); 54 KScopedSchedulerLock lock(kernel);
56 SetStatus(ThreadStatus::Dead); 55 SetStatus(ThreadStatus::Dead);
57 Signal(); 56 Signal();
58 kernel.GlobalHandleTable().Close(global_handle); 57 kernel.GlobalHandleTable().Close(global_handle);
@@ -63,14 +62,13 @@ void Thread::Stop() {
63 // Mark the TLS slot in the thread's page as free. 62 // Mark the TLS slot in the thread's page as free.
64 owner_process->FreeTLSRegion(tls_address); 63 owner_process->FreeTLSRegion(tls_address);
65 } 64 }
66 arm_interface.reset();
67 has_exited = true; 65 has_exited = true;
68 } 66 }
69 global_handle = 0; 67 global_handle = 0;
70} 68}
71 69
72void Thread::ResumeFromWait() { 70void Thread::ResumeFromWait() {
73 SchedulerLock lock(kernel); 71 KScopedSchedulerLock lock(kernel);
74 switch (status) { 72 switch (status) {
75 case ThreadStatus::Paused: 73 case ThreadStatus::Paused:
76 case ThreadStatus::WaitSynch: 74 case ThreadStatus::WaitSynch:
@@ -91,10 +89,6 @@ void Thread::ResumeFromWait() {
91 // before actually resuming. We can ignore subsequent wakeups if the thread status has 89 // before actually resuming. We can ignore subsequent wakeups if the thread status has
92 // already been set to ThreadStatus::Ready. 90 // already been set to ThreadStatus::Ready.
93 return; 91 return;
94
95 case ThreadStatus::Running:
96 DEBUG_ASSERT_MSG(false, "Thread with object id {} has already resumed.", GetObjectId());
97 return;
98 case ThreadStatus::Dead: 92 case ThreadStatus::Dead:
99 // This should never happen, as threads must complete before being stopped. 93 // This should never happen, as threads must complete before being stopped.
100 DEBUG_ASSERT_MSG(false, "Thread with object id {} cannot be resumed because it's DEAD.", 94 DEBUG_ASSERT_MSG(false, "Thread with object id {} cannot be resumed because it's DEAD.",
@@ -106,19 +100,18 @@ void Thread::ResumeFromWait() {
106} 100}
107 101
108void Thread::OnWakeUp() { 102void Thread::OnWakeUp() {
109 SchedulerLock lock(kernel); 103 KScopedSchedulerLock lock(kernel);
110
111 SetStatus(ThreadStatus::Ready); 104 SetStatus(ThreadStatus::Ready);
112} 105}
113 106
114ResultCode Thread::Start() { 107ResultCode Thread::Start() {
115 SchedulerLock lock(kernel); 108 KScopedSchedulerLock lock(kernel);
116 SetStatus(ThreadStatus::Ready); 109 SetStatus(ThreadStatus::Ready);
117 return RESULT_SUCCESS; 110 return RESULT_SUCCESS;
118} 111}
119 112
120void Thread::CancelWait() { 113void Thread::CancelWait() {
121 SchedulerLock lock(kernel); 114 KScopedSchedulerLock lock(kernel);
122 if (GetSchedulingStatus() != ThreadSchedStatus::Paused || !is_waiting_on_sync) { 115 if (GetSchedulingStatus() != ThreadSchedStatus::Paused || !is_waiting_on_sync) {
123 is_sync_cancelled = true; 116 is_sync_cancelled = true;
124 return; 117 return;
@@ -193,12 +186,14 @@ ResultVal<std::shared_ptr<Thread>> Thread::Create(Core::System& system, ThreadTy
193 thread->status = ThreadStatus::Dormant; 186 thread->status = ThreadStatus::Dormant;
194 thread->entry_point = entry_point; 187 thread->entry_point = entry_point;
195 thread->stack_top = stack_top; 188 thread->stack_top = stack_top;
189 thread->disable_count = 1;
196 thread->tpidr_el0 = 0; 190 thread->tpidr_el0 = 0;
197 thread->nominal_priority = thread->current_priority = priority; 191 thread->nominal_priority = thread->current_priority = priority;
198 thread->last_running_ticks = 0; 192 thread->schedule_count = -1;
193 thread->last_scheduled_tick = 0;
199 thread->processor_id = processor_id; 194 thread->processor_id = processor_id;
200 thread->ideal_core = processor_id; 195 thread->ideal_core = processor_id;
201 thread->affinity_mask = 1ULL << processor_id; 196 thread->affinity_mask.SetAffinity(processor_id, true);
202 thread->wait_objects = nullptr; 197 thread->wait_objects = nullptr;
203 thread->mutex_wait_address = 0; 198 thread->mutex_wait_address = 0;
204 thread->condvar_wait_address = 0; 199 thread->condvar_wait_address = 0;
@@ -208,7 +203,7 @@ ResultVal<std::shared_ptr<Thread>> Thread::Create(Core::System& system, ThreadTy
208 thread->owner_process = owner_process; 203 thread->owner_process = owner_process;
209 thread->type = type_flags; 204 thread->type = type_flags;
210 if ((type_flags & THREADTYPE_IDLE) == 0) { 205 if ((type_flags & THREADTYPE_IDLE) == 0) {
211 auto& scheduler = kernel.GlobalScheduler(); 206 auto& scheduler = kernel.GlobalSchedulerContext();
212 scheduler.AddThread(thread); 207 scheduler.AddThread(thread);
213 } 208 }
214 if (owner_process) { 209 if (owner_process) {
@@ -217,33 +212,10 @@ ResultVal<std::shared_ptr<Thread>> Thread::Create(Core::System& system, ThreadTy
217 } else { 212 } else {
218 thread->tls_address = 0; 213 thread->tls_address = 0;
219 } 214 }
215
220 // TODO(peachum): move to ScheduleThread() when scheduler is added so selected core is used 216 // TODO(peachum): move to ScheduleThread() when scheduler is added so selected core is used
221 // to initialize the context 217 // to initialize the context
222 thread->arm_interface.reset();
223 if ((type_flags & THREADTYPE_HLE) == 0) { 218 if ((type_flags & THREADTYPE_HLE) == 0) {
224#ifdef ARCHITECTURE_x86_64
225 if (owner_process && !owner_process->Is64BitProcess()) {
226 thread->arm_interface = std::make_unique<Core::ARM_Dynarmic_32>(
227 system, kernel.Interrupts(), kernel.IsMulticore(), kernel.GetExclusiveMonitor(),
228 processor_id);
229 } else {
230 thread->arm_interface = std::make_unique<Core::ARM_Dynarmic_64>(
231 system, kernel.Interrupts(), kernel.IsMulticore(), kernel.GetExclusiveMonitor(),
232 processor_id);
233 }
234
235#else
236 if (owner_process && !owner_process->Is64BitProcess()) {
237 thread->arm_interface = std::make_shared<Core::ARM_Unicorn>(
238 system, kernel.Interrupts(), kernel.IsMulticore(), ARM_Unicorn::Arch::AArch32,
239 processor_id);
240 } else {
241 thread->arm_interface = std::make_shared<Core::ARM_Unicorn>(
242 system, kernel.Interrupts(), kernel.IsMulticore(), ARM_Unicorn::Arch::AArch64,
243 processor_id);
244 }
245 LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available");
246#endif
247 ResetThreadContext32(thread->context_32, static_cast<u32>(stack_top), 219 ResetThreadContext32(thread->context_32, static_cast<u32>(stack_top),
248 static_cast<u32>(entry_point), static_cast<u32>(arg)); 220 static_cast<u32>(entry_point), static_cast<u32>(arg));
249 ResetThreadContext64(thread->context_64, stack_top, entry_point, arg); 221 ResetThreadContext64(thread->context_64, stack_top, entry_point, arg);
@@ -255,7 +227,7 @@ ResultVal<std::shared_ptr<Thread>> Thread::Create(Core::System& system, ThreadTy
255} 227}
256 228
257void Thread::SetPriority(u32 priority) { 229void Thread::SetPriority(u32 priority) {
258 SchedulerLock lock(kernel); 230 KScopedSchedulerLock lock(kernel);
259 ASSERT_MSG(priority <= THREADPRIO_LOWEST && priority >= THREADPRIO_HIGHEST, 231 ASSERT_MSG(priority <= THREADPRIO_LOWEST && priority >= THREADPRIO_HIGHEST,
260 "Invalid priority value."); 232 "Invalid priority value.");
261 nominal_priority = priority; 233 nominal_priority = priority;
@@ -279,14 +251,6 @@ VAddr Thread::GetCommandBufferAddress() const {
279 return GetTLSAddress() + command_header_offset; 251 return GetTLSAddress() + command_header_offset;
280} 252}
281 253
282Core::ARM_Interface& Thread::ArmInterface() {
283 return *arm_interface;
284}
285
286const Core::ARM_Interface& Thread::ArmInterface() const {
287 return *arm_interface;
288}
289
290void Thread::SetStatus(ThreadStatus new_status) { 254void Thread::SetStatus(ThreadStatus new_status) {
291 if (new_status == status) { 255 if (new_status == status) {
292 return; 256 return;
@@ -294,7 +258,6 @@ void Thread::SetStatus(ThreadStatus new_status) {
294 258
295 switch (new_status) { 259 switch (new_status) {
296 case ThreadStatus::Ready: 260 case ThreadStatus::Ready:
297 case ThreadStatus::Running:
298 SetSchedulingStatus(ThreadSchedStatus::Runnable); 261 SetSchedulingStatus(ThreadSchedStatus::Runnable);
299 break; 262 break;
300 case ThreadStatus::Dormant: 263 case ThreadStatus::Dormant:
@@ -401,7 +364,7 @@ bool Thread::InvokeHLECallback(std::shared_ptr<Thread> thread) {
401} 364}
402 365
403ResultCode Thread::SetActivity(ThreadActivity value) { 366ResultCode Thread::SetActivity(ThreadActivity value) {
404 SchedulerLock lock(kernel); 367 KScopedSchedulerLock lock(kernel);
405 368
406 auto sched_status = GetSchedulingStatus(); 369 auto sched_status = GetSchedulingStatus();
407 370
@@ -430,7 +393,7 @@ ResultCode Thread::SetActivity(ThreadActivity value) {
430ResultCode Thread::Sleep(s64 nanoseconds) { 393ResultCode Thread::Sleep(s64 nanoseconds) {
431 Handle event_handle{}; 394 Handle event_handle{};
432 { 395 {
433 SchedulerLockAndSleep lock(kernel, event_handle, this, nanoseconds); 396 KScopedSchedulerLockAndSleep lock(kernel, event_handle, this, nanoseconds);
434 SetStatus(ThreadStatus::WaitSleep); 397 SetStatus(ThreadStatus::WaitSleep);
435 } 398 }
436 399
@@ -441,39 +404,12 @@ ResultCode Thread::Sleep(s64 nanoseconds) {
441 return RESULT_SUCCESS; 404 return RESULT_SUCCESS;
442} 405}
443 406
444std::pair<ResultCode, bool> Thread::YieldSimple() {
445 bool is_redundant = false;
446 {
447 SchedulerLock lock(kernel);
448 is_redundant = kernel.GlobalScheduler().YieldThread(this);
449 }
450 return {RESULT_SUCCESS, is_redundant};
451}
452
453std::pair<ResultCode, bool> Thread::YieldAndBalanceLoad() {
454 bool is_redundant = false;
455 {
456 SchedulerLock lock(kernel);
457 is_redundant = kernel.GlobalScheduler().YieldThreadAndBalanceLoad(this);
458 }
459 return {RESULT_SUCCESS, is_redundant};
460}
461
462std::pair<ResultCode, bool> Thread::YieldAndWaitForLoadBalancing() {
463 bool is_redundant = false;
464 {
465 SchedulerLock lock(kernel);
466 is_redundant = kernel.GlobalScheduler().YieldThreadAndWaitForLoadBalancing(this);
467 }
468 return {RESULT_SUCCESS, is_redundant};
469}
470
471void Thread::AddSchedulingFlag(ThreadSchedFlags flag) { 407void Thread::AddSchedulingFlag(ThreadSchedFlags flag) {
472 const u32 old_state = scheduling_state; 408 const u32 old_state = scheduling_state;
473 pausing_state |= static_cast<u32>(flag); 409 pausing_state |= static_cast<u32>(flag);
474 const u32 base_scheduling = static_cast<u32>(GetSchedulingStatus()); 410 const u32 base_scheduling = static_cast<u32>(GetSchedulingStatus());
475 scheduling_state = base_scheduling | pausing_state; 411 scheduling_state = base_scheduling | pausing_state;
476 kernel.GlobalScheduler().AdjustSchedulingOnStatus(this, old_state); 412 KScheduler::OnThreadStateChanged(kernel, this, old_state);
477} 413}
478 414
479void Thread::RemoveSchedulingFlag(ThreadSchedFlags flag) { 415void Thread::RemoveSchedulingFlag(ThreadSchedFlags flag) {
@@ -481,23 +417,24 @@ void Thread::RemoveSchedulingFlag(ThreadSchedFlags flag) {
481 pausing_state &= ~static_cast<u32>(flag); 417 pausing_state &= ~static_cast<u32>(flag);
482 const u32 base_scheduling = static_cast<u32>(GetSchedulingStatus()); 418 const u32 base_scheduling = static_cast<u32>(GetSchedulingStatus());
483 scheduling_state = base_scheduling | pausing_state; 419 scheduling_state = base_scheduling | pausing_state;
484 kernel.GlobalScheduler().AdjustSchedulingOnStatus(this, old_state); 420 KScheduler::OnThreadStateChanged(kernel, this, old_state);
485} 421}
486 422
487void Thread::SetSchedulingStatus(ThreadSchedStatus new_status) { 423void Thread::SetSchedulingStatus(ThreadSchedStatus new_status) {
488 const u32 old_state = scheduling_state; 424 const u32 old_state = scheduling_state;
489 scheduling_state = (scheduling_state & static_cast<u32>(ThreadSchedMasks::HighMask)) | 425 scheduling_state = (scheduling_state & static_cast<u32>(ThreadSchedMasks::HighMask)) |
490 static_cast<u32>(new_status); 426 static_cast<u32>(new_status);
491 kernel.GlobalScheduler().AdjustSchedulingOnStatus(this, old_state); 427 KScheduler::OnThreadStateChanged(kernel, this, old_state);
492} 428}
493 429
494void Thread::SetCurrentPriority(u32 new_priority) { 430void Thread::SetCurrentPriority(u32 new_priority) {
495 const u32 old_priority = std::exchange(current_priority, new_priority); 431 const u32 old_priority = std::exchange(current_priority, new_priority);
496 kernel.GlobalScheduler().AdjustSchedulingOnPriority(this, old_priority); 432 KScheduler::OnThreadPriorityChanged(kernel, this, kernel.CurrentScheduler()->GetCurrentThread(),
433 old_priority);
497} 434}
498 435
499ResultCode Thread::SetCoreAndAffinityMask(s32 new_core, u64 new_affinity_mask) { 436ResultCode Thread::SetCoreAndAffinityMask(s32 new_core, u64 new_affinity_mask) {
500 SchedulerLock lock(kernel); 437 KScopedSchedulerLock lock(kernel);
501 const auto HighestSetCore = [](u64 mask, u32 max_cores) { 438 const auto HighestSetCore = [](u64 mask, u32 max_cores) {
502 for (s32 core = static_cast<s32>(max_cores - 1); core >= 0; core--) { 439 for (s32 core = static_cast<s32>(max_cores - 1); core >= 0; core--) {
503 if (((mask >> core) & 1) != 0) { 440 if (((mask >> core) & 1) != 0) {
@@ -518,20 +455,21 @@ ResultCode Thread::SetCoreAndAffinityMask(s32 new_core, u64 new_affinity_mask) {
518 } 455 }
519 if (use_override) { 456 if (use_override) {
520 ideal_core_override = new_core; 457 ideal_core_override = new_core;
521 affinity_mask_override = new_affinity_mask;
522 } else { 458 } else {
523 const u64 old_affinity_mask = std::exchange(affinity_mask, new_affinity_mask); 459 const auto old_affinity_mask = affinity_mask;
460 affinity_mask.SetAffinityMask(new_affinity_mask);
524 ideal_core = new_core; 461 ideal_core = new_core;
525 if (old_affinity_mask != new_affinity_mask) { 462 if (old_affinity_mask.GetAffinityMask() != new_affinity_mask) {
526 const s32 old_core = processor_id; 463 const s32 old_core = processor_id;
527 if (processor_id >= 0 && ((affinity_mask >> processor_id) & 1) == 0) { 464 if (processor_id >= 0 && !affinity_mask.GetAffinity(processor_id)) {
528 if (static_cast<s32>(ideal_core) < 0) { 465 if (static_cast<s32>(ideal_core) < 0) {
529 processor_id = HighestSetCore(affinity_mask, Core::Hardware::NUM_CPU_CORES); 466 processor_id = HighestSetCore(affinity_mask.GetAffinityMask(),
467 Core::Hardware::NUM_CPU_CORES);
530 } else { 468 } else {
531 processor_id = ideal_core; 469 processor_id = ideal_core;
532 } 470 }
533 } 471 }
534 kernel.GlobalScheduler().AdjustSchedulingOnAffinity(this, old_affinity_mask, old_core); 472 KScheduler::OnThreadAffinityMaskChanged(kernel, this, old_affinity_mask, old_core);
535 } 473 }
536 } 474 }
537 return RESULT_SUCCESS; 475 return RESULT_SUCCESS;
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index 8daf79fac..11ef29888 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -4,6 +4,7 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <array>
7#include <functional> 8#include <functional>
8#include <string> 9#include <string>
9#include <utility> 10#include <utility>
@@ -12,6 +13,7 @@
12#include "common/common_types.h" 13#include "common/common_types.h"
13#include "common/spin_lock.h" 14#include "common/spin_lock.h"
14#include "core/arm/arm_interface.h" 15#include "core/arm/arm_interface.h"
16#include "core/hle/kernel/k_affinity_mask.h"
15#include "core/hle/kernel/object.h" 17#include "core/hle/kernel/object.h"
16#include "core/hle/kernel/synchronization_object.h" 18#include "core/hle/kernel/synchronization_object.h"
17#include "core/hle/result.h" 19#include "core/hle/result.h"
@@ -27,10 +29,10 @@ class System;
27 29
28namespace Kernel { 30namespace Kernel {
29 31
30class GlobalScheduler; 32class GlobalSchedulerContext;
31class KernelCore; 33class KernelCore;
32class Process; 34class Process;
33class Scheduler; 35class KScheduler;
34 36
35enum ThreadPriority : u32 { 37enum ThreadPriority : u32 {
36 THREADPRIO_HIGHEST = 0, ///< Highest thread priority 38 THREADPRIO_HIGHEST = 0, ///< Highest thread priority
@@ -72,7 +74,6 @@ enum ThreadProcessorId : s32 {
72}; 74};
73 75
74enum class ThreadStatus { 76enum class ThreadStatus {
75 Running, ///< Currently running
76 Ready, ///< Ready to run 77 Ready, ///< Ready to run
77 Paused, ///< Paused by SetThreadActivity or debug 78 Paused, ///< Paused by SetThreadActivity or debug
78 WaitHLEEvent, ///< Waiting for hle event to finish 79 WaitHLEEvent, ///< Waiting for hle event to finish
@@ -248,10 +249,6 @@ public:
248 249
249 void SetSynchronizationResults(SynchronizationObject* object, ResultCode result); 250 void SetSynchronizationResults(SynchronizationObject* object, ResultCode result);
250 251
251 Core::ARM_Interface& ArmInterface();
252
253 const Core::ARM_Interface& ArmInterface() const;
254
255 SynchronizationObject* GetSignalingObject() const { 252 SynchronizationObject* GetSignalingObject() const {
256 return signaling_object; 253 return signaling_object;
257 } 254 }
@@ -350,8 +347,12 @@ public:
350 347
351 void SetStatus(ThreadStatus new_status); 348 void SetStatus(ThreadStatus new_status);
352 349
353 u64 GetLastRunningTicks() const { 350 s64 GetLastScheduledTick() const {
354 return last_running_ticks; 351 return this->last_scheduled_tick;
352 }
353
354 void SetLastScheduledTick(s64 tick) {
355 this->last_scheduled_tick = tick;
355 } 356 }
356 357
357 u64 GetTotalCPUTimeTicks() const { 358 u64 GetTotalCPUTimeTicks() const {
@@ -366,10 +367,18 @@ public:
366 return processor_id; 367 return processor_id;
367 } 368 }
368 369
370 s32 GetActiveCore() const {
371 return GetProcessorID();
372 }
373
369 void SetProcessorID(s32 new_core) { 374 void SetProcessorID(s32 new_core) {
370 processor_id = new_core; 375 processor_id = new_core;
371 } 376 }
372 377
378 void SetActiveCore(s32 new_core) {
379 processor_id = new_core;
380 }
381
373 Process* GetOwnerProcess() { 382 Process* GetOwnerProcess() {
374 return owner_process; 383 return owner_process;
375 } 384 }
@@ -474,7 +483,7 @@ public:
474 return ideal_core; 483 return ideal_core;
475 } 484 }
476 485
477 u64 GetAffinityMask() const { 486 const KAffinityMask& GetAffinityMask() const {
478 return affinity_mask; 487 return affinity_mask;
479 } 488 }
480 489
@@ -483,21 +492,12 @@ public:
483 /// Sleeps this thread for the given amount of nanoseconds. 492 /// Sleeps this thread for the given amount of nanoseconds.
484 ResultCode Sleep(s64 nanoseconds); 493 ResultCode Sleep(s64 nanoseconds);
485 494
486 /// Yields this thread without rebalancing loads. 495 s64 GetYieldScheduleCount() const {
487 std::pair<ResultCode, bool> YieldSimple(); 496 return this->schedule_count;
488
489 /// Yields this thread and does a load rebalancing.
490 std::pair<ResultCode, bool> YieldAndBalanceLoad();
491
492 /// Yields this thread and if the core is left idle, loads are rebalanced
493 std::pair<ResultCode, bool> YieldAndWaitForLoadBalancing();
494
495 void IncrementYieldCount() {
496 yield_count++;
497 } 497 }
498 498
499 u64 GetYieldCount() const { 499 void SetYieldScheduleCount(s64 count) {
500 return yield_count; 500 this->schedule_count = count;
501 } 501 }
502 502
503 ThreadSchedStatus GetSchedulingStatus() const { 503 ThreadSchedStatus GetSchedulingStatus() const {
@@ -573,9 +573,59 @@ public:
573 return has_exited; 573 return has_exited;
574 } 574 }
575 575
576 class QueueEntry {
577 public:
578 constexpr QueueEntry() = default;
579
580 constexpr void Initialize() {
581 this->prev = nullptr;
582 this->next = nullptr;
583 }
584
585 constexpr Thread* GetPrev() const {
586 return this->prev;
587 }
588 constexpr Thread* GetNext() const {
589 return this->next;
590 }
591 constexpr void SetPrev(Thread* thread) {
592 this->prev = thread;
593 }
594 constexpr void SetNext(Thread* thread) {
595 this->next = thread;
596 }
597
598 private:
599 Thread* prev{};
600 Thread* next{};
601 };
602
603 QueueEntry& GetPriorityQueueEntry(s32 core) {
604 return this->per_core_priority_queue_entry[core];
605 }
606
607 const QueueEntry& GetPriorityQueueEntry(s32 core) const {
608 return this->per_core_priority_queue_entry[core];
609 }
610
611 s32 GetDisableDispatchCount() const {
612 return disable_count;
613 }
614
615 void DisableDispatch() {
616 ASSERT(GetDisableDispatchCount() >= 0);
617 disable_count++;
618 }
619
620 void EnableDispatch() {
621 ASSERT(GetDisableDispatchCount() > 0);
622 disable_count--;
623 }
624
576private: 625private:
577 friend class GlobalScheduler; 626 friend class GlobalSchedulerContext;
578 friend class Scheduler; 627 friend class KScheduler;
628 friend class Process;
579 629
580 void SetSchedulingStatus(ThreadSchedStatus new_status); 630 void SetSchedulingStatus(ThreadSchedStatus new_status);
581 void AddSchedulingFlag(ThreadSchedFlags flag); 631 void AddSchedulingFlag(ThreadSchedFlags flag);
@@ -586,15 +636,16 @@ private:
586 Common::SpinLock context_guard{}; 636 Common::SpinLock context_guard{};
587 ThreadContext32 context_32{}; 637 ThreadContext32 context_32{};
588 ThreadContext64 context_64{}; 638 ThreadContext64 context_64{};
589 std::unique_ptr<Core::ARM_Interface> arm_interface{};
590 std::shared_ptr<Common::Fiber> host_context{}; 639 std::shared_ptr<Common::Fiber> host_context{};
591 640
592 u64 thread_id = 0;
593
594 ThreadStatus status = ThreadStatus::Dormant; 641 ThreadStatus status = ThreadStatus::Dormant;
642 u32 scheduling_state = 0;
643
644 u64 thread_id = 0;
595 645
596 VAddr entry_point = 0; 646 VAddr entry_point = 0;
597 VAddr stack_top = 0; 647 VAddr stack_top = 0;
648 std::atomic_int disable_count = 0;
598 649
599 ThreadType type; 650 ThreadType type;
600 651
@@ -608,9 +659,8 @@ private:
608 u32 current_priority = 0; 659 u32 current_priority = 0;
609 660
610 u64 total_cpu_time_ticks = 0; ///< Total CPU running ticks. 661 u64 total_cpu_time_ticks = 0; ///< Total CPU running ticks.
611 u64 last_running_ticks = 0; ///< CPU tick when thread was last running 662 s64 schedule_count{};
612 u64 yield_count = 0; ///< Number of redundant yields carried by this thread. 663 s64 last_scheduled_tick{};
613 ///< a redundant yield is one where no scheduling is changed
614 664
615 s32 processor_id = 0; 665 s32 processor_id = 0;
616 666
@@ -652,16 +702,16 @@ private:
652 Handle hle_time_event; 702 Handle hle_time_event;
653 SynchronizationObject* hle_object; 703 SynchronizationObject* hle_object;
654 704
655 Scheduler* scheduler = nullptr; 705 KScheduler* scheduler = nullptr;
706
707 std::array<QueueEntry, Core::Hardware::NUM_CPU_CORES> per_core_priority_queue_entry{};
656 708
657 u32 ideal_core{0xFFFFFFFF}; 709 u32 ideal_core{0xFFFFFFFF};
658 u64 affinity_mask{0x1}; 710 KAffinityMask affinity_mask{};
659 711
660 s32 ideal_core_override = -1; 712 s32 ideal_core_override = -1;
661 u64 affinity_mask_override = 0x1;
662 u32 affinity_override_count = 0; 713 u32 affinity_override_count = 0;
663 714
664 u32 scheduling_state = 0;
665 u32 pausing_state = 0; 715 u32 pausing_state = 0;
666 bool is_running = false; 716 bool is_running = false;
667 bool is_waiting_on_sync = false; 717 bool is_waiting_on_sync = false;
diff --git a/src/core/hle/kernel/time_manager.cpp b/src/core/hle/kernel/time_manager.cpp
index 95f2446c9..79628e2b4 100644
--- a/src/core/hle/kernel/time_manager.cpp
+++ b/src/core/hle/kernel/time_manager.cpp
@@ -7,8 +7,8 @@
7#include "core/core_timing.h" 7#include "core/core_timing.h"
8#include "core/core_timing_util.h" 8#include "core/core_timing_util.h"
9#include "core/hle/kernel/handle_table.h" 9#include "core/hle/kernel/handle_table.h"
10#include "core/hle/kernel/k_scheduler.h"
10#include "core/hle/kernel/kernel.h" 11#include "core/hle/kernel/kernel.h"
11#include "core/hle/kernel/scheduler.h"
12#include "core/hle/kernel/thread.h" 12#include "core/hle/kernel/thread.h"
13#include "core/hle/kernel/time_manager.h" 13#include "core/hle/kernel/time_manager.h"
14 14
@@ -18,17 +18,27 @@ TimeManager::TimeManager(Core::System& system_) : system{system_} {
18 time_manager_event_type = Core::Timing::CreateEvent( 18 time_manager_event_type = Core::Timing::CreateEvent(
19 "Kernel::TimeManagerCallback", 19 "Kernel::TimeManagerCallback",
20 [this](std::uintptr_t thread_handle, std::chrono::nanoseconds) { 20 [this](std::uintptr_t thread_handle, std::chrono::nanoseconds) {
21 const SchedulerLock lock(system.Kernel()); 21 const KScopedSchedulerLock lock(system.Kernel());
22 const auto proper_handle = static_cast<Handle>(thread_handle); 22 const auto proper_handle = static_cast<Handle>(thread_handle);
23 if (cancelled_events[proper_handle]) { 23
24 return; 24 std::shared_ptr<Thread> thread;
25 {
26 std::lock_guard lock{mutex};
27 if (cancelled_events[proper_handle]) {
28 return;
29 }
30 thread = system.Kernel().RetrieveThreadFromGlobalHandleTable(proper_handle);
31 }
32
33 if (thread) {
34 // Thread can be null if process has exited
35 thread->OnWakeUp();
25 } 36 }
26 auto thread = this->system.Kernel().RetrieveThreadFromGlobalHandleTable(proper_handle);
27 thread->OnWakeUp();
28 }); 37 });
29} 38}
30 39
31void TimeManager::ScheduleTimeEvent(Handle& event_handle, Thread* timetask, s64 nanoseconds) { 40void TimeManager::ScheduleTimeEvent(Handle& event_handle, Thread* timetask, s64 nanoseconds) {
41 std::lock_guard lock{mutex};
32 event_handle = timetask->GetGlobalHandle(); 42 event_handle = timetask->GetGlobalHandle();
33 if (nanoseconds > 0) { 43 if (nanoseconds > 0) {
34 ASSERT(timetask); 44 ASSERT(timetask);
@@ -43,6 +53,7 @@ void TimeManager::ScheduleTimeEvent(Handle& event_handle, Thread* timetask, s64
43} 53}
44 54
45void TimeManager::UnscheduleTimeEvent(Handle event_handle) { 55void TimeManager::UnscheduleTimeEvent(Handle event_handle) {
56 std::lock_guard lock{mutex};
46 if (event_handle == InvalidHandle) { 57 if (event_handle == InvalidHandle) {
47 return; 58 return;
48 } 59 }
@@ -51,7 +62,8 @@ void TimeManager::UnscheduleTimeEvent(Handle event_handle) {
51} 62}
52 63
53void TimeManager::CancelTimeEvent(Thread* time_task) { 64void TimeManager::CancelTimeEvent(Thread* time_task) {
54 Handle event_handle = time_task->GetGlobalHandle(); 65 std::lock_guard lock{mutex};
66 const Handle event_handle = time_task->GetGlobalHandle();
55 UnscheduleTimeEvent(event_handle); 67 UnscheduleTimeEvent(event_handle);
56} 68}
57 69
diff --git a/src/core/hle/kernel/time_manager.h b/src/core/hle/kernel/time_manager.h
index 307a18765..f39df39a0 100644
--- a/src/core/hle/kernel/time_manager.h
+++ b/src/core/hle/kernel/time_manager.h
@@ -5,6 +5,7 @@
5#pragma once 5#pragma once
6 6
7#include <memory> 7#include <memory>
8#include <mutex>
8#include <unordered_map> 9#include <unordered_map>
9 10
10#include "core/hle/kernel/object.h" 11#include "core/hle/kernel/object.h"
@@ -42,6 +43,7 @@ private:
42 Core::System& system; 43 Core::System& system;
43 std::shared_ptr<Core::Timing::EventType> time_manager_event_type; 44 std::shared_ptr<Core::Timing::EventType> time_manager_event_type;
44 std::unordered_map<Handle, bool> cancelled_events; 45 std::unordered_map<Handle, bool> cancelled_events;
46 std::mutex mutex;
45}; 47};
46 48
47} // namespace Kernel 49} // namespace Kernel
diff --git a/src/core/hle/result.h b/src/core/hle/result.h
index b6bdbd988..8feda7ad7 100644
--- a/src/core/hle/result.h
+++ b/src/core/hle/result.h
@@ -119,7 +119,7 @@ union ResultCode {
119 BitField<0, 9, ErrorModule> module; 119 BitField<0, 9, ErrorModule> module;
120 BitField<9, 13, u32> description; 120 BitField<9, 13, u32> description;
121 121
122 constexpr explicit ResultCode(u32 raw) : raw(raw) {} 122 constexpr explicit ResultCode(u32 raw_) : raw(raw_) {}
123 123
124 constexpr ResultCode(ErrorModule module_, u32 description_) 124 constexpr ResultCode(ErrorModule module_, u32 description_)
125 : raw(module.FormatValue(module_) | description.FormatValue(description_)) {} 125 : raw(module.FormatValue(module_) | description.FormatValue(description_)) {}
diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp
index 6b1613510..6981f8ee7 100644
--- a/src/core/hle/service/acc/acc.cpp
+++ b/src/core/hle/service/acc/acc.cpp
@@ -11,6 +11,7 @@
11#include "common/string_util.h" 11#include "common/string_util.h"
12#include "common/swap.h" 12#include "common/swap.h"
13#include "core/constants.h" 13#include "core/constants.h"
14#include "core/core.h"
14#include "core/core_timing.h" 15#include "core/core_timing.h"
15#include "core/file_sys/control_metadata.h" 16#include "core/file_sys/control_metadata.h"
16#include "core/file_sys/patch_manager.h" 17#include "core/file_sys/patch_manager.h"
@@ -46,8 +47,8 @@ static constexpr u32 SanitizeJPEGSize(std::size_t size) {
46 47
47class IManagerForSystemService final : public ServiceFramework<IManagerForSystemService> { 48class IManagerForSystemService final : public ServiceFramework<IManagerForSystemService> {
48public: 49public:
49 explicit IManagerForSystemService(Common::UUID user_id) 50 explicit IManagerForSystemService(Core::System& system_, Common::UUID)
50 : ServiceFramework("IManagerForSystemService") { 51 : ServiceFramework{system_, "IManagerForSystemService"} {
51 // clang-format off 52 // clang-format off
52 static const FunctionInfo functions[] = { 53 static const FunctionInfo functions[] = {
53 {0, nullptr, "CheckAvailability"}, 54 {0, nullptr, "CheckAvailability"},
@@ -82,8 +83,8 @@ public:
82// 3.0.0+ 83// 3.0.0+
83class IFloatingRegistrationRequest final : public ServiceFramework<IFloatingRegistrationRequest> { 84class IFloatingRegistrationRequest final : public ServiceFramework<IFloatingRegistrationRequest> {
84public: 85public:
85 explicit IFloatingRegistrationRequest(Common::UUID user_id) 86 explicit IFloatingRegistrationRequest(Core::System& system_, Common::UUID)
86 : ServiceFramework("IFloatingRegistrationRequest") { 87 : ServiceFramework{system_, "IFloatingRegistrationRequest"} {
87 // clang-format off 88 // clang-format off
88 static const FunctionInfo functions[] = { 89 static const FunctionInfo functions[] = {
89 {0, nullptr, "GetSessionId"}, 90 {0, nullptr, "GetSessionId"},
@@ -107,7 +108,8 @@ public:
107 108
108class IAdministrator final : public ServiceFramework<IAdministrator> { 109class IAdministrator final : public ServiceFramework<IAdministrator> {
109public: 110public:
110 explicit IAdministrator(Common::UUID user_id) : ServiceFramework("IAdministrator") { 111 explicit IAdministrator(Core::System& system_, Common::UUID)
112 : ServiceFramework{system_, "IAdministrator"} {
111 // clang-format off 113 // clang-format off
112 static const FunctionInfo functions[] = { 114 static const FunctionInfo functions[] = {
113 {0, nullptr, "CheckAvailability"}, 115 {0, nullptr, "CheckAvailability"},
@@ -164,8 +166,8 @@ public:
164 166
165class IAuthorizationRequest final : public ServiceFramework<IAuthorizationRequest> { 167class IAuthorizationRequest final : public ServiceFramework<IAuthorizationRequest> {
166public: 168public:
167 explicit IAuthorizationRequest(Common::UUID user_id) 169 explicit IAuthorizationRequest(Core::System& system_, Common::UUID)
168 : ServiceFramework("IAuthorizationRequest") { 170 : ServiceFramework{system_, "IAuthorizationRequest"} {
169 // clang-format off 171 // clang-format off
170 static const FunctionInfo functions[] = { 172 static const FunctionInfo functions[] = {
171 {0, nullptr, "GetSessionId"}, 173 {0, nullptr, "GetSessionId"},
@@ -183,7 +185,8 @@ public:
183 185
184class IOAuthProcedure final : public ServiceFramework<IOAuthProcedure> { 186class IOAuthProcedure final : public ServiceFramework<IOAuthProcedure> {
185public: 187public:
186 explicit IOAuthProcedure(Common::UUID user_id) : ServiceFramework("IOAuthProcedure") { 188 explicit IOAuthProcedure(Core::System& system_, Common::UUID)
189 : ServiceFramework{system_, "IOAuthProcedure"} {
187 // clang-format off 190 // clang-format off
188 static const FunctionInfo functions[] = { 191 static const FunctionInfo functions[] = {
189 {0, nullptr, "PrepareAsync"}, 192 {0, nullptr, "PrepareAsync"},
@@ -201,8 +204,8 @@ public:
201// 3.0.0+ 204// 3.0.0+
202class IOAuthProcedureForExternalNsa final : public ServiceFramework<IOAuthProcedureForExternalNsa> { 205class IOAuthProcedureForExternalNsa final : public ServiceFramework<IOAuthProcedureForExternalNsa> {
203public: 206public:
204 explicit IOAuthProcedureForExternalNsa(Common::UUID user_id) 207 explicit IOAuthProcedureForExternalNsa(Core::System& system_, Common::UUID)
205 : ServiceFramework("IOAuthProcedureForExternalNsa") { 208 : ServiceFramework{system_, "IOAuthProcedureForExternalNsa"} {
206 // clang-format off 209 // clang-format off
207 static const FunctionInfo functions[] = { 210 static const FunctionInfo functions[] = {
208 {0, nullptr, "PrepareAsync"}, 211 {0, nullptr, "PrepareAsync"},
@@ -224,8 +227,8 @@ public:
224class IOAuthProcedureForNintendoAccountLinkage final 227class IOAuthProcedureForNintendoAccountLinkage final
225 : public ServiceFramework<IOAuthProcedureForNintendoAccountLinkage> { 228 : public ServiceFramework<IOAuthProcedureForNintendoAccountLinkage> {
226public: 229public:
227 explicit IOAuthProcedureForNintendoAccountLinkage(Common::UUID user_id) 230 explicit IOAuthProcedureForNintendoAccountLinkage(Core::System& system_, Common::UUID)
228 : ServiceFramework("IOAuthProcedureForNintendoAccountLinkage") { 231 : ServiceFramework{system_, "IOAuthProcedureForNintendoAccountLinkage"} {
229 // clang-format off 232 // clang-format off
230 static const FunctionInfo functions[] = { 233 static const FunctionInfo functions[] = {
231 {0, nullptr, "PrepareAsync"}, 234 {0, nullptr, "PrepareAsync"},
@@ -245,7 +248,8 @@ public:
245 248
246class INotifier final : public ServiceFramework<INotifier> { 249class INotifier final : public ServiceFramework<INotifier> {
247public: 250public:
248 explicit INotifier(Common::UUID user_id) : ServiceFramework("INotifier") { 251 explicit INotifier(Core::System& system_, Common::UUID)
252 : ServiceFramework{system_, "INotifier"} {
249 // clang-format off 253 // clang-format off
250 static const FunctionInfo functions[] = { 254 static const FunctionInfo functions[] = {
251 {0, nullptr, "GetSystemEvent"}, 255 {0, nullptr, "GetSystemEvent"},
@@ -258,9 +262,9 @@ public:
258 262
259class IProfileCommon : public ServiceFramework<IProfileCommon> { 263class IProfileCommon : public ServiceFramework<IProfileCommon> {
260public: 264public:
261 explicit IProfileCommon(const char* name, bool editor_commands, Common::UUID user_id, 265 explicit IProfileCommon(Core::System& system_, const char* name, bool editor_commands,
262 ProfileManager& profile_manager) 266 Common::UUID user_id_, ProfileManager& profile_manager_)
263 : ServiceFramework(name), profile_manager(profile_manager), user_id(user_id) { 267 : ServiceFramework{system_, name}, profile_manager{profile_manager_}, user_id{user_id_} {
264 static const FunctionInfo functions[] = { 268 static const FunctionInfo functions[] = {
265 {0, &IProfileCommon::Get, "Get"}, 269 {0, &IProfileCommon::Get, "Get"},
266 {1, &IProfileCommon::GetBase, "GetBase"}, 270 {1, &IProfileCommon::GetBase, "GetBase"},
@@ -426,19 +430,21 @@ protected:
426 430
427class IProfile final : public IProfileCommon { 431class IProfile final : public IProfileCommon {
428public: 432public:
429 IProfile(Common::UUID user_id, ProfileManager& profile_manager) 433 explicit IProfile(Core::System& system_, Common::UUID user_id_,
430 : IProfileCommon("IProfile", false, user_id, profile_manager) {} 434 ProfileManager& profile_manager_)
435 : IProfileCommon{system_, "IProfile", false, user_id_, profile_manager_} {}
431}; 436};
432 437
433class IProfileEditor final : public IProfileCommon { 438class IProfileEditor final : public IProfileCommon {
434public: 439public:
435 IProfileEditor(Common::UUID user_id, ProfileManager& profile_manager) 440 explicit IProfileEditor(Core::System& system_, Common::UUID user_id_,
436 : IProfileCommon("IProfileEditor", true, user_id, profile_manager) {} 441 ProfileManager& profile_manager_)
442 : IProfileCommon{system_, "IProfileEditor", true, user_id_, profile_manager_} {}
437}; 443};
438 444
439class IAsyncContext final : public ServiceFramework<IAsyncContext> { 445class IAsyncContext final : public ServiceFramework<IAsyncContext> {
440public: 446public:
441 explicit IAsyncContext(Common::UUID user_id) : ServiceFramework("IAsyncContext") { 447 explicit IAsyncContext(Core::System& system_) : ServiceFramework{system_, "IAsyncContext"} {
442 // clang-format off 448 // clang-format off
443 static const FunctionInfo functions[] = { 449 static const FunctionInfo functions[] = {
444 {0, nullptr, "GetSystemEvent"}, 450 {0, nullptr, "GetSystemEvent"},
@@ -454,7 +460,8 @@ public:
454 460
455class ISessionObject final : public ServiceFramework<ISessionObject> { 461class ISessionObject final : public ServiceFramework<ISessionObject> {
456public: 462public:
457 explicit ISessionObject(Common::UUID user_id) : ServiceFramework("ISessionObject") { 463 explicit ISessionObject(Core::System& system_, Common::UUID)
464 : ServiceFramework{system_, "ISessionObject"} {
458 // clang-format off 465 // clang-format off
459 static const FunctionInfo functions[] = { 466 static const FunctionInfo functions[] = {
460 {999, nullptr, "Dummy"}, 467 {999, nullptr, "Dummy"},
@@ -467,7 +474,8 @@ public:
467 474
468class IGuestLoginRequest final : public ServiceFramework<IGuestLoginRequest> { 475class IGuestLoginRequest final : public ServiceFramework<IGuestLoginRequest> {
469public: 476public:
470 explicit IGuestLoginRequest(Common::UUID) : ServiceFramework("IGuestLoginRequest") { 477 explicit IGuestLoginRequest(Core::System& system_, Common::UUID)
478 : ServiceFramework{system_, "IGuestLoginRequest"} {
471 // clang-format off 479 // clang-format off
472 static const FunctionInfo functions[] = { 480 static const FunctionInfo functions[] = {
473 {0, nullptr, "GetSessionId"}, 481 {0, nullptr, "GetSessionId"},
@@ -486,8 +494,8 @@ public:
486 494
487class IManagerForApplication final : public ServiceFramework<IManagerForApplication> { 495class IManagerForApplication final : public ServiceFramework<IManagerForApplication> {
488public: 496public:
489 explicit IManagerForApplication(Common::UUID user_id) 497 explicit IManagerForApplication(Core::System& system_, Common::UUID user_id_)
490 : ServiceFramework("IManagerForApplication"), user_id(user_id) { 498 : ServiceFramework{system_, "IManagerForApplication"}, user_id{user_id_} {
491 // clang-format off 499 // clang-format off
492 static const FunctionInfo functions[] = { 500 static const FunctionInfo functions[] = {
493 {0, &IManagerForApplication::CheckAvailability, "CheckAvailability"}, 501 {0, &IManagerForApplication::CheckAvailability, "CheckAvailability"},
@@ -496,7 +504,7 @@ public:
496 {3, nullptr, "LoadIdTokenCache"}, 504 {3, nullptr, "LoadIdTokenCache"},
497 {130, nullptr, "GetNintendoAccountUserResourceCacheForApplication"}, 505 {130, nullptr, "GetNintendoAccountUserResourceCacheForApplication"},
498 {150, nullptr, "CreateAuthorizationRequest"}, 506 {150, nullptr, "CreateAuthorizationRequest"},
499 {160, nullptr, "StoreOpenContext"}, 507 {160, &IManagerForApplication::StoreOpenContext, "StoreOpenContext"},
500 {170, nullptr, "LoadNetworkServiceLicenseKindAsync"}, 508 {170, nullptr, "LoadNetworkServiceLicenseKindAsync"},
501 }; 509 };
502 // clang-format on 510 // clang-format on
@@ -520,6 +528,12 @@ private:
520 rb.PushRaw<u64>(user_id.GetNintendoID()); 528 rb.PushRaw<u64>(user_id.GetNintendoID());
521 } 529 }
522 530
531 void StoreOpenContext(Kernel::HLERequestContext& ctx) {
532 LOG_WARNING(Service_ACC, "(STUBBED) called");
533 IPC::ResponseBuilder rb{ctx, 2};
534 rb.Push(RESULT_SUCCESS);
535 }
536
523 Common::UUID user_id; 537 Common::UUID user_id;
524}; 538};
525 539
@@ -527,8 +541,8 @@ private:
527class IAsyncNetworkServiceLicenseKindContext final 541class IAsyncNetworkServiceLicenseKindContext final
528 : public ServiceFramework<IAsyncNetworkServiceLicenseKindContext> { 542 : public ServiceFramework<IAsyncNetworkServiceLicenseKindContext> {
529public: 543public:
530 explicit IAsyncNetworkServiceLicenseKindContext(Common::UUID user_id) 544 explicit IAsyncNetworkServiceLicenseKindContext(Core::System& system_, Common::UUID)
531 : ServiceFramework("IAsyncNetworkServiceLicenseKindContext") { 545 : ServiceFramework{system_, "IAsyncNetworkServiceLicenseKindContext"} {
532 // clang-format off 546 // clang-format off
533 static const FunctionInfo functions[] = { 547 static const FunctionInfo functions[] = {
534 {0, nullptr, "GetSystemEvent"}, 548 {0, nullptr, "GetSystemEvent"},
@@ -547,8 +561,8 @@ public:
547class IOAuthProcedureForUserRegistration final 561class IOAuthProcedureForUserRegistration final
548 : public ServiceFramework<IOAuthProcedureForUserRegistration> { 562 : public ServiceFramework<IOAuthProcedureForUserRegistration> {
549public: 563public:
550 explicit IOAuthProcedureForUserRegistration(Common::UUID user_id) 564 explicit IOAuthProcedureForUserRegistration(Core::System& system_, Common::UUID)
551 : ServiceFramework("IOAuthProcedureForUserRegistration") { 565 : ServiceFramework{system_, "IOAuthProcedureForUserRegistration"} {
552 // clang-format off 566 // clang-format off
553 static const FunctionInfo functions[] = { 567 static const FunctionInfo functions[] = {
554 {0, nullptr, "PrepareAsync"}, 568 {0, nullptr, "PrepareAsync"},
@@ -571,7 +585,7 @@ public:
571 585
572class DAUTH_O final : public ServiceFramework<DAUTH_O> { 586class DAUTH_O final : public ServiceFramework<DAUTH_O> {
573public: 587public:
574 explicit DAUTH_O(Common::UUID) : ServiceFramework("dauth:o") { 588 explicit DAUTH_O(Core::System& system_, Common::UUID) : ServiceFramework{system_, "dauth:o"} {
575 // clang-format off 589 // clang-format off
576 static const FunctionInfo functions[] = { 590 static const FunctionInfo functions[] = {
577 {0, nullptr, "EnsureAuthenticationTokenCacheAsync"}, // [5.0.0-5.1.0] GeneratePostData 591 {0, nullptr, "EnsureAuthenticationTokenCacheAsync"}, // [5.0.0-5.1.0] GeneratePostData
@@ -590,7 +604,8 @@ public:
590// 6.0.0+ 604// 6.0.0+
591class IAsyncResult final : public ServiceFramework<IAsyncResult> { 605class IAsyncResult final : public ServiceFramework<IAsyncResult> {
592public: 606public:
593 explicit IAsyncResult(Common::UUID user_id) : ServiceFramework("IAsyncResult") { 607 explicit IAsyncResult(Core::System& system_, Common::UUID)
608 : ServiceFramework{system_, "IAsyncResult"} {
594 // clang-format off 609 // clang-format off
595 static const FunctionInfo functions[] = { 610 static const FunctionInfo functions[] = {
596 {0, nullptr, "GetResult"}, 611 {0, nullptr, "GetResult"},
@@ -649,7 +664,7 @@ void Module::Interface::GetProfile(Kernel::HLERequestContext& ctx) {
649 664
650 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 665 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
651 rb.Push(RESULT_SUCCESS); 666 rb.Push(RESULT_SUCCESS);
652 rb.PushIpcInterface<IProfile>(user_id, *profile_manager); 667 rb.PushIpcInterface<IProfile>(system, user_id, *profile_manager);
653} 668}
654 669
655void Module::Interface::IsUserRegistrationRequestPermitted(Kernel::HLERequestContext& ctx) { 670void Module::Interface::IsUserRegistrationRequestPermitted(Kernel::HLERequestContext& ctx) {
@@ -724,7 +739,7 @@ void Module::Interface::GetBaasAccountManagerForApplication(Kernel::HLERequestCo
724 LOG_DEBUG(Service_ACC, "called"); 739 LOG_DEBUG(Service_ACC, "called");
725 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 740 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
726 rb.Push(RESULT_SUCCESS); 741 rb.Push(RESULT_SUCCESS);
727 rb.PushIpcInterface<IManagerForApplication>(profile_manager->GetLastOpenedUser()); 742 rb.PushIpcInterface<IManagerForApplication>(system, profile_manager->GetLastOpenedUser());
728} 743}
729 744
730void Module::Interface::IsUserAccountSwitchLocked(Kernel::HLERequestContext& ctx) { 745void Module::Interface::IsUserAccountSwitchLocked(Kernel::HLERequestContext& ctx) {
@@ -735,8 +750,10 @@ void Module::Interface::IsUserAccountSwitchLocked(Kernel::HLERequestContext& ctx
735 bool is_locked = false; 750 bool is_locked = false;
736 751
737 if (res != Loader::ResultStatus::Success) { 752 if (res != Loader::ResultStatus::Success) {
738 FileSys::PatchManager pm{system.CurrentProcess()->GetTitleID()}; 753 const FileSys::PatchManager pm{system.CurrentProcess()->GetTitleID(),
739 auto nacp_unique = pm.GetControlMetadata().first; 754 system.GetFileSystemController(),
755 system.GetContentProvider()};
756 const auto nacp_unique = pm.GetControlMetadata().first;
740 757
741 if (nacp_unique != nullptr) { 758 if (nacp_unique != nullptr) {
742 is_locked = nacp_unique->GetUserAccountSwitchLock(); 759 is_locked = nacp_unique->GetUserAccountSwitchLock();
@@ -760,7 +777,7 @@ void Module::Interface::GetProfileEditor(Kernel::HLERequestContext& ctx) {
760 777
761 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 778 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
762 rb.Push(RESULT_SUCCESS); 779 rb.Push(RESULT_SUCCESS);
763 rb.PushIpcInterface<IProfileEditor>(user_id, *profile_manager); 780 rb.PushIpcInterface<IProfileEditor>(system, user_id, *profile_manager);
764} 781}
765 782
766void Module::Interface::ListQualifiedUsers(Kernel::HLERequestContext& ctx) { 783void Module::Interface::ListQualifiedUsers(Kernel::HLERequestContext& ctx) {
@@ -782,7 +799,7 @@ void Module::Interface::LoadOpenContext(Kernel::HLERequestContext& ctx) {
782 // TODO: Find the differences between this and GetBaasAccountManagerForApplication 799 // TODO: Find the differences between this and GetBaasAccountManagerForApplication
783 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 800 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
784 rb.Push(RESULT_SUCCESS); 801 rb.Push(RESULT_SUCCESS);
785 rb.PushIpcInterface<IManagerForApplication>(profile_manager->GetLastOpenedUser()); 802 rb.PushIpcInterface<IManagerForApplication>(system, profile_manager->GetLastOpenedUser());
786} 803}
787 804
788void Module::Interface::ListOpenContextStoredUsers(Kernel::HLERequestContext& ctx) { 805void Module::Interface::ListOpenContextStoredUsers(Kernel::HLERequestContext& ctx) {
@@ -818,11 +835,11 @@ void Module::Interface::TrySelectUserWithoutInteraction(Kernel::HLERequestContex
818 rb.PushRaw<u128>(profile_manager->GetUser(0)->uuid); 835 rb.PushRaw<u128>(profile_manager->GetUser(0)->uuid);
819} 836}
820 837
821Module::Interface::Interface(std::shared_ptr<Module> module, 838Module::Interface::Interface(std::shared_ptr<Module> module_,
822 std::shared_ptr<ProfileManager> profile_manager, Core::System& system, 839 std::shared_ptr<ProfileManager> profile_manager_,
823 const char* name) 840 Core::System& system_, const char* name)
824 : ServiceFramework(name), module(std::move(module)), 841 : ServiceFramework{system_, name}, module{std::move(module_)}, profile_manager{std::move(
825 profile_manager(std::move(profile_manager)), system(system) {} 842 profile_manager_)} {}
826 843
827Module::Interface::~Interface() = default; 844Module::Interface::~Interface() = default;
828 845
diff --git a/src/core/hle/service/acc/acc.h b/src/core/hle/service/acc/acc.h
index c611efd89..ab8edc049 100644
--- a/src/core/hle/service/acc/acc.h
+++ b/src/core/hle/service/acc/acc.h
@@ -15,8 +15,8 @@ class Module final {
15public: 15public:
16 class Interface : public ServiceFramework<Interface> { 16 class Interface : public ServiceFramework<Interface> {
17 public: 17 public:
18 explicit Interface(std::shared_ptr<Module> module, 18 explicit Interface(std::shared_ptr<Module> module_,
19 std::shared_ptr<ProfileManager> profile_manager, Core::System& system, 19 std::shared_ptr<ProfileManager> profile_manager_, Core::System& system_,
20 const char* name); 20 const char* name);
21 ~Interface() override; 21 ~Interface() override;
22 22
@@ -60,7 +60,6 @@ public:
60 protected: 60 protected:
61 std::shared_ptr<Module> module; 61 std::shared_ptr<Module> module;
62 std::shared_ptr<ProfileManager> profile_manager; 62 std::shared_ptr<ProfileManager> profile_manager;
63 Core::System& system;
64 }; 63 };
65}; 64};
66 65
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index d7a81f64a..c9808060a 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -64,7 +64,7 @@ struct LaunchParameterAccountPreselectedUser {
64static_assert(sizeof(LaunchParameterAccountPreselectedUser) == 0x88); 64static_assert(sizeof(LaunchParameterAccountPreselectedUser) == 0x88);
65 65
66IWindowController::IWindowController(Core::System& system_) 66IWindowController::IWindowController(Core::System& system_)
67 : ServiceFramework("IWindowController"), system{system_} { 67 : ServiceFramework{system_, "IWindowController"} {
68 // clang-format off 68 // clang-format off
69 static const FunctionInfo functions[] = { 69 static const FunctionInfo functions[] = {
70 {0, nullptr, "CreateWindow"}, 70 {0, nullptr, "CreateWindow"},
@@ -99,7 +99,8 @@ void IWindowController::AcquireForegroundRights(Kernel::HLERequestContext& ctx)
99 rb.Push(RESULT_SUCCESS); 99 rb.Push(RESULT_SUCCESS);
100} 100}
101 101
102IAudioController::IAudioController() : ServiceFramework("IAudioController") { 102IAudioController::IAudioController(Core::System& system_)
103 : ServiceFramework{system_, "IAudioController"} {
103 // clang-format off 104 // clang-format off
104 static const FunctionInfo functions[] = { 105 static const FunctionInfo functions[] = {
105 {0, &IAudioController::SetExpectedMasterVolume, "SetExpectedMasterVolume"}, 106 {0, &IAudioController::SetExpectedMasterVolume, "SetExpectedMasterVolume"},
@@ -180,7 +181,8 @@ void IAudioController::SetTransparentAudioRate(Kernel::HLERequestContext& ctx) {
180 rb.Push(RESULT_SUCCESS); 181 rb.Push(RESULT_SUCCESS);
181} 182}
182 183
183IDisplayController::IDisplayController() : ServiceFramework("IDisplayController") { 184IDisplayController::IDisplayController(Core::System& system_)
185 : ServiceFramework{system_, "IDisplayController"} {
184 // clang-format off 186 // clang-format off
185 static const FunctionInfo functions[] = { 187 static const FunctionInfo functions[] = {
186 {0, nullptr, "GetLastForegroundCaptureImage"}, 188 {0, nullptr, "GetLastForegroundCaptureImage"},
@@ -219,7 +221,8 @@ IDisplayController::IDisplayController() : ServiceFramework("IDisplayController"
219 221
220IDisplayController::~IDisplayController() = default; 222IDisplayController::~IDisplayController() = default;
221 223
222IDebugFunctions::IDebugFunctions() : ServiceFramework{"IDebugFunctions"} { 224IDebugFunctions::IDebugFunctions(Core::System& system_)
225 : ServiceFramework{system_, "IDebugFunctions"} {
223 // clang-format off 226 // clang-format off
224 static const FunctionInfo functions[] = { 227 static const FunctionInfo functions[] = {
225 {0, nullptr, "NotifyMessageToHomeMenuForDebug"}, 228 {0, nullptr, "NotifyMessageToHomeMenuForDebug"},
@@ -246,9 +249,8 @@ IDebugFunctions::IDebugFunctions() : ServiceFramework{"IDebugFunctions"} {
246 249
247IDebugFunctions::~IDebugFunctions() = default; 250IDebugFunctions::~IDebugFunctions() = default;
248 251
249ISelfController::ISelfController(Core::System& system, 252ISelfController::ISelfController(Core::System& system_, NVFlinger::NVFlinger& nvflinger_)
250 std::shared_ptr<NVFlinger::NVFlinger> nvflinger) 253 : ServiceFramework{system_, "ISelfController"}, nvflinger{nvflinger_} {
251 : ServiceFramework("ISelfController"), system(system), nvflinger(std::move(nvflinger)) {
252 // clang-format off 254 // clang-format off
253 static const FunctionInfo functions[] = { 255 static const FunctionInfo functions[] = {
254 {0, &ISelfController::Exit, "Exit"}, 256 {0, &ISelfController::Exit, "Exit"},
@@ -458,8 +460,8 @@ void ISelfController::CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx)
458 460
459 // TODO(Subv): Find out how AM determines the display to use, for now just 461 // TODO(Subv): Find out how AM determines the display to use, for now just
460 // create the layer in the Default display. 462 // create the layer in the Default display.
461 const auto display_id = nvflinger->OpenDisplay("Default"); 463 const auto display_id = nvflinger.OpenDisplay("Default");
462 const auto layer_id = nvflinger->CreateLayer(*display_id); 464 const auto layer_id = nvflinger.CreateLayer(*display_id);
463 465
464 IPC::ResponseBuilder rb{ctx, 4}; 466 IPC::ResponseBuilder rb{ctx, 4};
465 rb.Push(RESULT_SUCCESS); 467 rb.Push(RESULT_SUCCESS);
@@ -476,8 +478,8 @@ void ISelfController::CreateManagedDisplaySeparableLayer(Kernel::HLERequestConte
476 // Outputting 1 layer id instead of the expected 2 has not been observed to cause any adverse 478 // Outputting 1 layer id instead of the expected 2 has not been observed to cause any adverse
477 // side effects. 479 // side effects.
478 // TODO: Support multiple layers 480 // TODO: Support multiple layers
479 const auto display_id = nvflinger->OpenDisplay("Default"); 481 const auto display_id = nvflinger.OpenDisplay("Default");
480 const auto layer_id = nvflinger->CreateLayer(*display_id); 482 const auto layer_id = nvflinger.CreateLayer(*display_id);
481 483
482 IPC::ResponseBuilder rb{ctx, 4}; 484 IPC::ResponseBuilder rb{ctx, 4};
483 rb.Push(RESULT_SUCCESS); 485 rb.Push(RESULT_SUCCESS);
@@ -558,14 +560,14 @@ void ISelfController::GetAccumulatedSuspendedTickChangedEvent(Kernel::HLERequest
558 560
559AppletMessageQueue::AppletMessageQueue(Kernel::KernelCore& kernel) { 561AppletMessageQueue::AppletMessageQueue(Kernel::KernelCore& kernel) {
560 on_new_message = 562 on_new_message =
561 Kernel::WritableEvent::CreateEventPair(kernel, "AMMessageQueue:OnMessageRecieved"); 563 Kernel::WritableEvent::CreateEventPair(kernel, "AMMessageQueue:OnMessageReceived");
562 on_operation_mode_changed = 564 on_operation_mode_changed =
563 Kernel::WritableEvent::CreateEventPair(kernel, "AMMessageQueue:OperationModeChanged"); 565 Kernel::WritableEvent::CreateEventPair(kernel, "AMMessageQueue:OperationModeChanged");
564} 566}
565 567
566AppletMessageQueue::~AppletMessageQueue() = default; 568AppletMessageQueue::~AppletMessageQueue() = default;
567 569
568const std::shared_ptr<Kernel::ReadableEvent>& AppletMessageQueue::GetMesssageRecieveEvent() const { 570const std::shared_ptr<Kernel::ReadableEvent>& AppletMessageQueue::GetMessageReceiveEvent() const {
569 return on_new_message.readable; 571 return on_new_message.readable;
570} 572}
571 573
@@ -606,9 +608,9 @@ void AppletMessageQueue::RequestExit() {
606 PushMessage(AppletMessage::ExitRequested); 608 PushMessage(AppletMessage::ExitRequested);
607} 609}
608 610
609ICommonStateGetter::ICommonStateGetter(Core::System& system, 611ICommonStateGetter::ICommonStateGetter(Core::System& system_,
610 std::shared_ptr<AppletMessageQueue> msg_queue) 612 std::shared_ptr<AppletMessageQueue> msg_queue_)
611 : ServiceFramework("ICommonStateGetter"), system(system), msg_queue(std::move(msg_queue)) { 613 : ServiceFramework{system_, "ICommonStateGetter"}, msg_queue{std::move(msg_queue_)} {
612 // clang-format off 614 // clang-format off
613 static const FunctionInfo functions[] = { 615 static const FunctionInfo functions[] = {
614 {0, &ICommonStateGetter::GetEventHandle, "GetEventHandle"}, 616 {0, &ICommonStateGetter::GetEventHandle, "GetEventHandle"},
@@ -673,7 +675,7 @@ void ICommonStateGetter::GetEventHandle(Kernel::HLERequestContext& ctx) {
673 675
674 IPC::ResponseBuilder rb{ctx, 2, 1}; 676 IPC::ResponseBuilder rb{ctx, 2, 1};
675 rb.Push(RESULT_SUCCESS); 677 rb.Push(RESULT_SUCCESS);
676 rb.PushCopyObjects(msg_queue->GetMesssageRecieveEvent()); 678 rb.PushCopyObjects(msg_queue->GetMessageReceiveEvent());
677} 679}
678 680
679void ICommonStateGetter::ReceiveMessage(Kernel::HLERequestContext& ctx) { 681void ICommonStateGetter::ReceiveMessage(Kernel::HLERequestContext& ctx) {
@@ -751,7 +753,7 @@ void ICommonStateGetter::GetDefaultDisplayResolution(Kernel::HLERequestContext&
751 IPC::ResponseBuilder rb{ctx, 4}; 753 IPC::ResponseBuilder rb{ctx, 4};
752 rb.Push(RESULT_SUCCESS); 754 rb.Push(RESULT_SUCCESS);
753 755
754 if (Settings::values.use_docked_mode) { 756 if (Settings::values.use_docked_mode.GetValue()) {
755 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth) * 757 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth) *
756 static_cast<u32>(Settings::values.resolution_factor.GetValue())); 758 static_cast<u32>(Settings::values.resolution_factor.GetValue()));
757 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight) * 759 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight) *
@@ -796,8 +798,9 @@ private:
796 std::vector<u8> buffer; 798 std::vector<u8> buffer;
797}; 799};
798 800
799IStorage::IStorage(std::vector<u8>&& buffer) 801IStorage::IStorage(Core::System& system_, std::vector<u8>&& buffer)
800 : ServiceFramework("IStorage"), impl{std::make_shared<StorageDataImpl>(std::move(buffer))} { 802 : ServiceFramework{system_, "IStorage"}, impl{std::make_shared<StorageDataImpl>(
803 std::move(buffer))} {
801 Register(); 804 Register();
802} 805}
803 806
@@ -820,11 +823,11 @@ void IStorage::Open(Kernel::HLERequestContext& ctx) {
820 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 823 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
821 824
822 rb.Push(RESULT_SUCCESS); 825 rb.Push(RESULT_SUCCESS);
823 rb.PushIpcInterface<IStorageAccessor>(*this); 826 rb.PushIpcInterface<IStorageAccessor>(system, *this);
824} 827}
825 828
826void ICommonStateGetter::GetOperationMode(Kernel::HLERequestContext& ctx) { 829void ICommonStateGetter::GetOperationMode(Kernel::HLERequestContext& ctx) {
827 const bool use_docked_mode{Settings::values.use_docked_mode}; 830 const bool use_docked_mode{Settings::values.use_docked_mode.GetValue()};
828 LOG_DEBUG(Service_AM, "called, use_docked_mode={}", use_docked_mode); 831 LOG_DEBUG(Service_AM, "called, use_docked_mode={}", use_docked_mode);
829 832
830 IPC::ResponseBuilder rb{ctx, 3}; 833 IPC::ResponseBuilder rb{ctx, 3};
@@ -842,8 +845,8 @@ void ICommonStateGetter::GetPerformanceMode(Kernel::HLERequestContext& ctx) {
842 845
843class ILibraryAppletAccessor final : public ServiceFramework<ILibraryAppletAccessor> { 846class ILibraryAppletAccessor final : public ServiceFramework<ILibraryAppletAccessor> {
844public: 847public:
845 explicit ILibraryAppletAccessor(std::shared_ptr<Applets::Applet> applet) 848 explicit ILibraryAppletAccessor(Core::System& system_, std::shared_ptr<Applets::Applet> applet_)
846 : ServiceFramework("ILibraryAppletAccessor"), applet(std::move(applet)) { 849 : ServiceFramework{system_, "ILibraryAppletAccessor"}, applet{std::move(applet_)} {
847 // clang-format off 850 // clang-format off
848 static const FunctionInfo functions[] = { 851 static const FunctionInfo functions[] = {
849 {0, &ILibraryAppletAccessor::GetAppletStateChangedEvent, "GetAppletStateChangedEvent"}, 852 {0, &ILibraryAppletAccessor::GetAppletStateChangedEvent, "GetAppletStateChangedEvent"},
@@ -998,8 +1001,8 @@ private:
998 std::shared_ptr<Applets::Applet> applet; 1001 std::shared_ptr<Applets::Applet> applet;
999}; 1002};
1000 1003
1001IStorageAccessor::IStorageAccessor(IStorage& storage) 1004IStorageAccessor::IStorageAccessor(Core::System& system_, IStorage& backing_)
1002 : ServiceFramework("IStorageAccessor"), backing(storage) { 1005 : ServiceFramework{system_, "IStorageAccessor"}, backing{backing_} {
1003 // clang-format off 1006 // clang-format off
1004 static const FunctionInfo functions[] = { 1007 static const FunctionInfo functions[] = {
1005 {0, &IStorageAccessor::GetSize, "GetSize"}, 1008 {0, &IStorageAccessor::GetSize, "GetSize"},
@@ -1070,7 +1073,7 @@ void IStorageAccessor::Read(Kernel::HLERequestContext& ctx) {
1070} 1073}
1071 1074
1072ILibraryAppletCreator::ILibraryAppletCreator(Core::System& system_) 1075ILibraryAppletCreator::ILibraryAppletCreator(Core::System& system_)
1073 : ServiceFramework("ILibraryAppletCreator"), system{system_} { 1076 : ServiceFramework{system_, "ILibraryAppletCreator"} {
1074 static const FunctionInfo functions[] = { 1077 static const FunctionInfo functions[] = {
1075 {0, &ILibraryAppletCreator::CreateLibraryApplet, "CreateLibraryApplet"}, 1078 {0, &ILibraryAppletCreator::CreateLibraryApplet, "CreateLibraryApplet"},
1076 {1, nullptr, "TerminateAllLibraryApplets"}, 1079 {1, nullptr, "TerminateAllLibraryApplets"},
@@ -1089,14 +1092,14 @@ void ILibraryAppletCreator::CreateLibraryApplet(Kernel::HLERequestContext& ctx)
1089 const auto applet_id = rp.PopRaw<Applets::AppletId>(); 1092 const auto applet_id = rp.PopRaw<Applets::AppletId>();
1090 const auto applet_mode = rp.PopRaw<u32>(); 1093 const auto applet_mode = rp.PopRaw<u32>();
1091 1094
1092 LOG_DEBUG(Service_AM, "called with applet_id={:08X}, applet_mode={:08X}", 1095 LOG_DEBUG(Service_AM, "called with applet_id={:08X}, applet_mode={:08X}", applet_id,
1093 static_cast<u32>(applet_id), applet_mode); 1096 applet_mode);
1094 1097
1095 const auto& applet_manager{system.GetAppletManager()}; 1098 const auto& applet_manager{system.GetAppletManager()};
1096 const auto applet = applet_manager.GetApplet(applet_id); 1099 const auto applet = applet_manager.GetApplet(applet_id);
1097 1100
1098 if (applet == nullptr) { 1101 if (applet == nullptr) {
1099 LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", static_cast<u32>(applet_id)); 1102 LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", applet_id);
1100 1103
1101 IPC::ResponseBuilder rb{ctx, 2}; 1104 IPC::ResponseBuilder rb{ctx, 2};
1102 rb.Push(RESULT_UNKNOWN); 1105 rb.Push(RESULT_UNKNOWN);
@@ -1106,7 +1109,7 @@ void ILibraryAppletCreator::CreateLibraryApplet(Kernel::HLERequestContext& ctx)
1106 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 1109 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
1107 1110
1108 rb.Push(RESULT_SUCCESS); 1111 rb.Push(RESULT_SUCCESS);
1109 rb.PushIpcInterface<AM::ILibraryAppletAccessor>(applet); 1112 rb.PushIpcInterface<ILibraryAppletAccessor>(system, applet);
1110} 1113}
1111 1114
1112void ILibraryAppletCreator::CreateStorage(Kernel::HLERequestContext& ctx) { 1115void ILibraryAppletCreator::CreateStorage(Kernel::HLERequestContext& ctx) {
@@ -1118,7 +1121,7 @@ void ILibraryAppletCreator::CreateStorage(Kernel::HLERequestContext& ctx) {
1118 1121
1119 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 1122 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
1120 rb.Push(RESULT_SUCCESS); 1123 rb.Push(RESULT_SUCCESS);
1121 rb.PushIpcInterface<AM::IStorage>(std::move(buffer)); 1124 rb.PushIpcInterface<IStorage>(system, std::move(buffer));
1122} 1125}
1123 1126
1124void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContext& ctx) { 1127void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContext& ctx) {
@@ -1145,11 +1148,11 @@ void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContex
1145 1148
1146 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 1149 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
1147 rb.Push(RESULT_SUCCESS); 1150 rb.Push(RESULT_SUCCESS);
1148 rb.PushIpcInterface<IStorage>(std::move(memory)); 1151 rb.PushIpcInterface<IStorage>(system, std::move(memory));
1149} 1152}
1150 1153
1151IApplicationFunctions::IApplicationFunctions(Core::System& system_) 1154IApplicationFunctions::IApplicationFunctions(Core::System& system_)
1152 : ServiceFramework("IApplicationFunctions"), system{system_} { 1155 : ServiceFramework{system_, "IApplicationFunctions"} {
1153 // clang-format off 1156 // clang-format off
1154 static const FunctionInfo functions[] = { 1157 static const FunctionInfo functions[] = {
1155 {1, &IApplicationFunctions::PopLaunchParameter, "PopLaunchParameter"}, 1158 {1, &IApplicationFunctions::PopLaunchParameter, "PopLaunchParameter"},
@@ -1189,9 +1192,9 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_)
1189 {102, &IApplicationFunctions::SetApplicationCopyrightVisibility, "SetApplicationCopyrightVisibility"}, 1192 {102, &IApplicationFunctions::SetApplicationCopyrightVisibility, "SetApplicationCopyrightVisibility"},
1190 {110, &IApplicationFunctions::QueryApplicationPlayStatistics, "QueryApplicationPlayStatistics"}, 1193 {110, &IApplicationFunctions::QueryApplicationPlayStatistics, "QueryApplicationPlayStatistics"},
1191 {111, &IApplicationFunctions::QueryApplicationPlayStatisticsByUid, "QueryApplicationPlayStatisticsByUid"}, 1194 {111, &IApplicationFunctions::QueryApplicationPlayStatisticsByUid, "QueryApplicationPlayStatisticsByUid"},
1192 {120, nullptr, "ExecuteProgram"}, 1195 {120, &IApplicationFunctions::ExecuteProgram, "ExecuteProgram"},
1193 {121, nullptr, "ClearUserChannel"}, 1196 {121, &IApplicationFunctions::ClearUserChannel, "ClearUserChannel"},
1194 {122, nullptr, "UnpopToUserChannel"}, 1197 {122, &IApplicationFunctions::UnpopToUserChannel, "UnpopToUserChannel"},
1195 {123, &IApplicationFunctions::GetPreviousProgramIndex, "GetPreviousProgramIndex"}, 1198 {123, &IApplicationFunctions::GetPreviousProgramIndex, "GetPreviousProgramIndex"},
1196 {124, nullptr, "EnableApplicationAllThreadDumpOnCrash"}, 1199 {124, nullptr, "EnableApplicationAllThreadDumpOnCrash"},
1197 {130, &IApplicationFunctions::GetGpuErrorDetectedSystemEvent, "GetGpuErrorDetectedSystemEvent"}, 1200 {130, &IApplicationFunctions::GetGpuErrorDetectedSystemEvent, "GetGpuErrorDetectedSystemEvent"},
@@ -1201,6 +1204,8 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_)
1201 {151, nullptr, "TryPopFromNotificationStorageChannel"}, 1204 {151, nullptr, "TryPopFromNotificationStorageChannel"},
1202 {160, nullptr, "GetHealthWarningDisappearedSystemEvent"}, 1205 {160, nullptr, "GetHealthWarningDisappearedSystemEvent"},
1203 {170, nullptr, "SetHdcpAuthenticationActivated"}, 1206 {170, nullptr, "SetHdcpAuthenticationActivated"},
1207 {180, nullptr, "GetLaunchRequiredVersion"},
1208 {181, nullptr, "UpgradeLaunchRequiredVersion"},
1204 {500, nullptr, "StartContinuousRecordingFlushForDebug"}, 1209 {500, nullptr, "StartContinuousRecordingFlushForDebug"},
1205 {1000, nullptr, "CreateMovieMaker"}, 1210 {1000, nullptr, "CreateMovieMaker"},
1206 {1001, nullptr, "PrepareForJit"}, 1211 {1001, nullptr, "PrepareForJit"},
@@ -1285,7 +1290,7 @@ void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) {
1285 IPC::RequestParser rp{ctx}; 1290 IPC::RequestParser rp{ctx};
1286 const auto kind = rp.PopEnum<LaunchParameterKind>(); 1291 const auto kind = rp.PopEnum<LaunchParameterKind>();
1287 1292
1288 LOG_DEBUG(Service_AM, "called, kind={:08X}", static_cast<u8>(kind)); 1293 LOG_DEBUG(Service_AM, "called, kind={:08X}", kind);
1289 1294
1290 if (kind == LaunchParameterKind::ApplicationSpecific && !launch_popped_application_specific) { 1295 if (kind == LaunchParameterKind::ApplicationSpecific && !launch_popped_application_specific) {
1291 const auto backend = BCAT::CreateBackendFromSettings(system, [this](u64 tid) { 1296 const auto backend = BCAT::CreateBackendFromSettings(system, [this](u64 tid) {
@@ -1299,7 +1304,7 @@ void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) {
1299 if (data.has_value()) { 1304 if (data.has_value()) {
1300 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 1305 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
1301 rb.Push(RESULT_SUCCESS); 1306 rb.Push(RESULT_SUCCESS);
1302 rb.PushIpcInterface<IStorage>(std::move(*data)); 1307 rb.PushIpcInterface<IStorage>(system, std::move(*data));
1303 launch_popped_application_specific = true; 1308 launch_popped_application_specific = true;
1304 return; 1309 return;
1305 } 1310 }
@@ -1322,7 +1327,7 @@ void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) {
1322 std::vector<u8> buffer(sizeof(LaunchParameterAccountPreselectedUser)); 1327 std::vector<u8> buffer(sizeof(LaunchParameterAccountPreselectedUser));
1323 std::memcpy(buffer.data(), &params, buffer.size()); 1328 std::memcpy(buffer.data(), &params, buffer.size());
1324 1329
1325 rb.PushIpcInterface<IStorage>(std::move(buffer)); 1330 rb.PushIpcInterface<IStorage>(system, std::move(buffer));
1326 launch_popped_account_preselect = true; 1331 launch_popped_account_preselect = true;
1327 return; 1332 return;
1328 } 1333 }
@@ -1379,13 +1384,16 @@ void IApplicationFunctions::GetDisplayVersion(Kernel::HLERequestContext& ctx) {
1379 const auto res = [this] { 1384 const auto res = [this] {
1380 const auto title_id = system.CurrentProcess()->GetTitleID(); 1385 const auto title_id = system.CurrentProcess()->GetTitleID();
1381 1386
1382 FileSys::PatchManager pm{title_id}; 1387 const FileSys::PatchManager pm{title_id, system.GetFileSystemController(),
1388 system.GetContentProvider()};
1383 auto res = pm.GetControlMetadata(); 1389 auto res = pm.GetControlMetadata();
1384 if (res.first != nullptr) { 1390 if (res.first != nullptr) {
1385 return res; 1391 return res;
1386 } 1392 }
1387 1393
1388 FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(title_id)}; 1394 const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(title_id),
1395 system.GetFileSystemController(),
1396 system.GetContentProvider()};
1389 return pm_update.GetControlMetadata(); 1397 return pm_update.GetControlMetadata();
1390 }(); 1398 }();
1391 1399
@@ -1413,13 +1421,16 @@ void IApplicationFunctions::GetDesiredLanguage(Kernel::HLERequestContext& ctx) {
1413 const auto res = [this] { 1421 const auto res = [this] {
1414 const auto title_id = system.CurrentProcess()->GetTitleID(); 1422 const auto title_id = system.CurrentProcess()->GetTitleID();
1415 1423
1416 FileSys::PatchManager pm{title_id}; 1424 const FileSys::PatchManager pm{title_id, system.GetFileSystemController(),
1425 system.GetContentProvider()};
1417 auto res = pm.GetControlMetadata(); 1426 auto res = pm.GetControlMetadata();
1418 if (res.first != nullptr) { 1427 if (res.first != nullptr) {
1419 return res; 1428 return res;
1420 } 1429 }
1421 1430
1422 FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(title_id)}; 1431 const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(title_id),
1432 system.GetFileSystemController(),
1433 system.GetContentProvider()};
1423 return pm_update.GetControlMetadata(); 1434 return pm_update.GetControlMetadata();
1424 }(); 1435 }();
1425 1436
@@ -1526,8 +1537,8 @@ void IApplicationFunctions::GetSaveDataSize(Kernel::HLERequestContext& ctx) {
1526 IPC::RequestParser rp{ctx}; 1537 IPC::RequestParser rp{ctx};
1527 const auto [type, user_id] = rp.PopRaw<Parameters>(); 1538 const auto [type, user_id] = rp.PopRaw<Parameters>();
1528 1539
1529 LOG_DEBUG(Service_AM, "called with type={:02X}, user_id={:016X}{:016X}", static_cast<u8>(type), 1540 LOG_DEBUG(Service_AM, "called with type={:02X}, user_id={:016X}{:016X}", type, user_id[1],
1530 user_id[1], user_id[0]); 1541 user_id[0]);
1531 1542
1532 const auto size = system.GetFileSystemController().ReadSaveDataSize( 1543 const auto size = system.GetFileSystemController().ReadSaveDataSize(
1533 type, system.CurrentProcess()->GetTitleID(), user_id); 1544 type, system.CurrentProcess()->GetTitleID(), user_id);
@@ -1554,6 +1565,34 @@ void IApplicationFunctions::QueryApplicationPlayStatisticsByUid(Kernel::HLEReque
1554 rb.Push<u32>(0); 1565 rb.Push<u32>(0);
1555} 1566}
1556 1567
1568void IApplicationFunctions::ExecuteProgram(Kernel::HLERequestContext& ctx) {
1569 LOG_WARNING(Service_AM, "(STUBBED) called");
1570
1571 IPC::RequestParser rp{ctx};
1572 [[maybe_unused]] const auto unk_1 = rp.Pop<u32>();
1573 [[maybe_unused]] const auto unk_2 = rp.Pop<u32>();
1574 const auto program_index = rp.Pop<u64>();
1575
1576 IPC::ResponseBuilder rb{ctx, 2};
1577 rb.Push(RESULT_SUCCESS);
1578
1579 system.ExecuteProgram(program_index);
1580}
1581
1582void IApplicationFunctions::ClearUserChannel(Kernel::HLERequestContext& ctx) {
1583 LOG_WARNING(Service_AM, "(STUBBED) called");
1584
1585 IPC::ResponseBuilder rb{ctx, 2};
1586 rb.Push(RESULT_SUCCESS);
1587}
1588
1589void IApplicationFunctions::UnpopToUserChannel(Kernel::HLERequestContext& ctx) {
1590 LOG_WARNING(Service_AM, "(STUBBED) called");
1591
1592 IPC::ResponseBuilder rb{ctx, 2};
1593 rb.Push(RESULT_SUCCESS);
1594}
1595
1557void IApplicationFunctions::GetPreviousProgramIndex(Kernel::HLERequestContext& ctx) { 1596void IApplicationFunctions::GetPreviousProgramIndex(Kernel::HLERequestContext& ctx) {
1558 LOG_WARNING(Service_AM, "(STUBBED) called"); 1597 LOG_WARNING(Service_AM, "(STUBBED) called");
1559 1598
@@ -1578,22 +1617,22 @@ void IApplicationFunctions::GetFriendInvitationStorageChannelEvent(Kernel::HLERe
1578 rb.PushCopyObjects(friend_invitation_storage_channel_event.readable); 1617 rb.PushCopyObjects(friend_invitation_storage_channel_event.readable);
1579} 1618}
1580 1619
1581void InstallInterfaces(SM::ServiceManager& service_manager, 1620void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nvflinger,
1582 std::shared_ptr<NVFlinger::NVFlinger> nvflinger, Core::System& system) { 1621 Core::System& system) {
1583 auto message_queue = std::make_shared<AppletMessageQueue>(system.Kernel()); 1622 auto message_queue = std::make_shared<AppletMessageQueue>(system.Kernel());
1584 // Needed on game boot 1623 // Needed on game boot
1585 message_queue->PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged); 1624 message_queue->PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged);
1586 1625
1587 std::make_shared<AppletAE>(nvflinger, message_queue, system)->InstallAsService(service_manager); 1626 std::make_shared<AppletAE>(nvflinger, message_queue, system)->InstallAsService(service_manager);
1588 std::make_shared<AppletOE>(nvflinger, message_queue, system)->InstallAsService(service_manager); 1627 std::make_shared<AppletOE>(nvflinger, message_queue, system)->InstallAsService(service_manager);
1589 std::make_shared<IdleSys>()->InstallAsService(service_manager); 1628 std::make_shared<IdleSys>(system)->InstallAsService(service_manager);
1590 std::make_shared<OMM>()->InstallAsService(service_manager); 1629 std::make_shared<OMM>(system)->InstallAsService(service_manager);
1591 std::make_shared<SPSM>()->InstallAsService(service_manager); 1630 std::make_shared<SPSM>(system)->InstallAsService(service_manager);
1592 std::make_shared<TCAP>()->InstallAsService(service_manager); 1631 std::make_shared<TCAP>(system)->InstallAsService(service_manager);
1593} 1632}
1594 1633
1595IHomeMenuFunctions::IHomeMenuFunctions(Kernel::KernelCore& kernel) 1634IHomeMenuFunctions::IHomeMenuFunctions(Core::System& system_)
1596 : ServiceFramework("IHomeMenuFunctions"), kernel(kernel) { 1635 : ServiceFramework{system_, "IHomeMenuFunctions"} {
1597 // clang-format off 1636 // clang-format off
1598 static const FunctionInfo functions[] = { 1637 static const FunctionInfo functions[] = {
1599 {10, &IHomeMenuFunctions::RequestToGetForeground, "RequestToGetForeground"}, 1638 {10, &IHomeMenuFunctions::RequestToGetForeground, "RequestToGetForeground"},
@@ -1612,7 +1651,7 @@ IHomeMenuFunctions::IHomeMenuFunctions(Kernel::KernelCore& kernel)
1612 RegisterHandlers(functions); 1651 RegisterHandlers(functions);
1613 1652
1614 pop_from_general_channel_event = Kernel::WritableEvent::CreateEventPair( 1653 pop_from_general_channel_event = Kernel::WritableEvent::CreateEventPair(
1615 kernel, "IHomeMenuFunctions:PopFromGeneralChannelEvent"); 1654 system.Kernel(), "IHomeMenuFunctions:PopFromGeneralChannelEvent");
1616} 1655}
1617 1656
1618IHomeMenuFunctions::~IHomeMenuFunctions() = default; 1657IHomeMenuFunctions::~IHomeMenuFunctions() = default;
@@ -1632,7 +1671,8 @@ void IHomeMenuFunctions::GetPopFromGeneralChannelEvent(Kernel::HLERequestContext
1632 rb.PushCopyObjects(pop_from_general_channel_event.readable); 1671 rb.PushCopyObjects(pop_from_general_channel_event.readable);
1633} 1672}
1634 1673
1635IGlobalStateController::IGlobalStateController() : ServiceFramework("IGlobalStateController") { 1674IGlobalStateController::IGlobalStateController(Core::System& system_)
1675 : ServiceFramework{system_, "IGlobalStateController"} {
1636 // clang-format off 1676 // clang-format off
1637 static const FunctionInfo functions[] = { 1677 static const FunctionInfo functions[] = {
1638 {0, nullptr, "RequestToEnterSleep"}, 1678 {0, nullptr, "RequestToEnterSleep"},
@@ -1655,7 +1695,8 @@ IGlobalStateController::IGlobalStateController() : ServiceFramework("IGlobalStat
1655 1695
1656IGlobalStateController::~IGlobalStateController() = default; 1696IGlobalStateController::~IGlobalStateController() = default;
1657 1697
1658IApplicationCreator::IApplicationCreator() : ServiceFramework("IApplicationCreator") { 1698IApplicationCreator::IApplicationCreator(Core::System& system_)
1699 : ServiceFramework{system_, "IApplicationCreator"} {
1659 // clang-format off 1700 // clang-format off
1660 static const FunctionInfo functions[] = { 1701 static const FunctionInfo functions[] = {
1661 {0, nullptr, "CreateApplication"}, 1702 {0, nullptr, "CreateApplication"},
@@ -1670,8 +1711,8 @@ IApplicationCreator::IApplicationCreator() : ServiceFramework("IApplicationCreat
1670 1711
1671IApplicationCreator::~IApplicationCreator() = default; 1712IApplicationCreator::~IApplicationCreator() = default;
1672 1713
1673IProcessWindingController::IProcessWindingController() 1714IProcessWindingController::IProcessWindingController(Core::System& system_)
1674 : ServiceFramework("IProcessWindingController") { 1715 : ServiceFramework{system_, "IProcessWindingController"} {
1675 // clang-format off 1716 // clang-format off
1676 static const FunctionInfo functions[] = { 1717 static const FunctionInfo functions[] = {
1677 {0, nullptr, "GetLaunchReason"}, 1718 {0, nullptr, "GetLaunchReason"},
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h
index bcc06affe..f51aca1af 100644
--- a/src/core/hle/service/am/am.h
+++ b/src/core/hle/service/am/am.h
@@ -55,7 +55,7 @@ public:
55 explicit AppletMessageQueue(Kernel::KernelCore& kernel); 55 explicit AppletMessageQueue(Kernel::KernelCore& kernel);
56 ~AppletMessageQueue(); 56 ~AppletMessageQueue();
57 57
58 const std::shared_ptr<Kernel::ReadableEvent>& GetMesssageRecieveEvent() const; 58 const std::shared_ptr<Kernel::ReadableEvent>& GetMessageReceiveEvent() const;
59 const std::shared_ptr<Kernel::ReadableEvent>& GetOperationModeChangedEvent() const; 59 const std::shared_ptr<Kernel::ReadableEvent>& GetOperationModeChangedEvent() const;
60 void PushMessage(AppletMessage msg); 60 void PushMessage(AppletMessage msg);
61 AppletMessage PopMessage(); 61 AppletMessage PopMessage();
@@ -77,13 +77,11 @@ public:
77private: 77private:
78 void GetAppletResourceUserId(Kernel::HLERequestContext& ctx); 78 void GetAppletResourceUserId(Kernel::HLERequestContext& ctx);
79 void AcquireForegroundRights(Kernel::HLERequestContext& ctx); 79 void AcquireForegroundRights(Kernel::HLERequestContext& ctx);
80
81 Core::System& system;
82}; 80};
83 81
84class IAudioController final : public ServiceFramework<IAudioController> { 82class IAudioController final : public ServiceFramework<IAudioController> {
85public: 83public:
86 IAudioController(); 84 explicit IAudioController(Core::System& system_);
87 ~IAudioController() override; 85 ~IAudioController() override;
88 86
89private: 87private:
@@ -109,20 +107,19 @@ private:
109 107
110class IDisplayController final : public ServiceFramework<IDisplayController> { 108class IDisplayController final : public ServiceFramework<IDisplayController> {
111public: 109public:
112 IDisplayController(); 110 explicit IDisplayController(Core::System& system_);
113 ~IDisplayController() override; 111 ~IDisplayController() override;
114}; 112};
115 113
116class IDebugFunctions final : public ServiceFramework<IDebugFunctions> { 114class IDebugFunctions final : public ServiceFramework<IDebugFunctions> {
117public: 115public:
118 IDebugFunctions(); 116 explicit IDebugFunctions(Core::System& system_);
119 ~IDebugFunctions() override; 117 ~IDebugFunctions() override;
120}; 118};
121 119
122class ISelfController final : public ServiceFramework<ISelfController> { 120class ISelfController final : public ServiceFramework<ISelfController> {
123public: 121public:
124 explicit ISelfController(Core::System& system_, 122 explicit ISelfController(Core::System& system_, NVFlinger::NVFlinger& nvflinger_);
125 std::shared_ptr<NVFlinger::NVFlinger> nvflinger_);
126 ~ISelfController() override; 123 ~ISelfController() override;
127 124
128private: 125private:
@@ -155,8 +152,7 @@ private:
155 Disable = 2, 152 Disable = 2,
156 }; 153 };
157 154
158 Core::System& system; 155 NVFlinger::NVFlinger& nvflinger;
159 std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
160 Kernel::EventPair launchable_event; 156 Kernel::EventPair launchable_event;
161 Kernel::EventPair accumulated_suspended_tick_changed_event; 157 Kernel::EventPair accumulated_suspended_tick_changed_event;
162 158
@@ -168,8 +164,8 @@ private:
168 164
169class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> { 165class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> {
170public: 166public:
171 explicit ICommonStateGetter(Core::System& system, 167 explicit ICommonStateGetter(Core::System& system_,
172 std::shared_ptr<AppletMessageQueue> msg_queue); 168 std::shared_ptr<AppletMessageQueue> msg_queue_);
173 ~ICommonStateGetter() override; 169 ~ICommonStateGetter() override;
174 170
175private: 171private:
@@ -197,7 +193,6 @@ private:
197 void GetDefaultDisplayResolution(Kernel::HLERequestContext& ctx); 193 void GetDefaultDisplayResolution(Kernel::HLERequestContext& ctx);
198 void SetCpuBoostMode(Kernel::HLERequestContext& ctx); 194 void SetCpuBoostMode(Kernel::HLERequestContext& ctx);
199 195
200 Core::System& system;
201 std::shared_ptr<AppletMessageQueue> msg_queue; 196 std::shared_ptr<AppletMessageQueue> msg_queue;
202 bool vr_mode_state{}; 197 bool vr_mode_state{};
203}; 198};
@@ -212,7 +207,7 @@ public:
212 207
213class IStorage final : public ServiceFramework<IStorage> { 208class IStorage final : public ServiceFramework<IStorage> {
214public: 209public:
215 explicit IStorage(std::vector<u8>&& buffer); 210 explicit IStorage(Core::System& system_, std::vector<u8>&& buffer);
216 ~IStorage() override; 211 ~IStorage() override;
217 212
218 std::vector<u8>& GetData() { 213 std::vector<u8>& GetData() {
@@ -236,7 +231,7 @@ private:
236 231
237class IStorageAccessor final : public ServiceFramework<IStorageAccessor> { 232class IStorageAccessor final : public ServiceFramework<IStorageAccessor> {
238public: 233public:
239 explicit IStorageAccessor(IStorage& backing); 234 explicit IStorageAccessor(Core::System& system_, IStorage& backing_);
240 ~IStorageAccessor() override; 235 ~IStorageAccessor() override;
241 236
242private: 237private:
@@ -256,8 +251,6 @@ private:
256 void CreateLibraryApplet(Kernel::HLERequestContext& ctx); 251 void CreateLibraryApplet(Kernel::HLERequestContext& ctx);
257 void CreateStorage(Kernel::HLERequestContext& ctx); 252 void CreateStorage(Kernel::HLERequestContext& ctx);
258 void CreateTransferMemoryStorage(Kernel::HLERequestContext& ctx); 253 void CreateTransferMemoryStorage(Kernel::HLERequestContext& ctx);
259
260 Core::System& system;
261}; 254};
262 255
263class IApplicationFunctions final : public ServiceFramework<IApplicationFunctions> { 256class IApplicationFunctions final : public ServiceFramework<IApplicationFunctions> {
@@ -288,6 +281,9 @@ private:
288 void SetApplicationCopyrightVisibility(Kernel::HLERequestContext& ctx); 281 void SetApplicationCopyrightVisibility(Kernel::HLERequestContext& ctx);
289 void QueryApplicationPlayStatistics(Kernel::HLERequestContext& ctx); 282 void QueryApplicationPlayStatistics(Kernel::HLERequestContext& ctx);
290 void QueryApplicationPlayStatisticsByUid(Kernel::HLERequestContext& ctx); 283 void QueryApplicationPlayStatisticsByUid(Kernel::HLERequestContext& ctx);
284 void ExecuteProgram(Kernel::HLERequestContext& ctx);
285 void ClearUserChannel(Kernel::HLERequestContext& ctx);
286 void UnpopToUserChannel(Kernel::HLERequestContext& ctx);
291 void GetPreviousProgramIndex(Kernel::HLERequestContext& ctx); 287 void GetPreviousProgramIndex(Kernel::HLERequestContext& ctx);
292 void GetGpuErrorDetectedSystemEvent(Kernel::HLERequestContext& ctx); 288 void GetGpuErrorDetectedSystemEvent(Kernel::HLERequestContext& ctx);
293 void GetFriendInvitationStorageChannelEvent(Kernel::HLERequestContext& ctx); 289 void GetFriendInvitationStorageChannelEvent(Kernel::HLERequestContext& ctx);
@@ -297,12 +293,11 @@ private:
297 s32 previous_program_index{-1}; 293 s32 previous_program_index{-1};
298 Kernel::EventPair gpu_error_detected_event; 294 Kernel::EventPair gpu_error_detected_event;
299 Kernel::EventPair friend_invitation_storage_channel_event; 295 Kernel::EventPair friend_invitation_storage_channel_event;
300 Core::System& system;
301}; 296};
302 297
303class IHomeMenuFunctions final : public ServiceFramework<IHomeMenuFunctions> { 298class IHomeMenuFunctions final : public ServiceFramework<IHomeMenuFunctions> {
304public: 299public:
305 explicit IHomeMenuFunctions(Kernel::KernelCore& kernel); 300 explicit IHomeMenuFunctions(Core::System& system_);
306 ~IHomeMenuFunctions() override; 301 ~IHomeMenuFunctions() override;
307 302
308private: 303private:
@@ -310,29 +305,28 @@ private:
310 void GetPopFromGeneralChannelEvent(Kernel::HLERequestContext& ctx); 305 void GetPopFromGeneralChannelEvent(Kernel::HLERequestContext& ctx);
311 306
312 Kernel::EventPair pop_from_general_channel_event; 307 Kernel::EventPair pop_from_general_channel_event;
313 Kernel::KernelCore& kernel;
314}; 308};
315 309
316class IGlobalStateController final : public ServiceFramework<IGlobalStateController> { 310class IGlobalStateController final : public ServiceFramework<IGlobalStateController> {
317public: 311public:
318 IGlobalStateController(); 312 explicit IGlobalStateController(Core::System& system_);
319 ~IGlobalStateController() override; 313 ~IGlobalStateController() override;
320}; 314};
321 315
322class IApplicationCreator final : public ServiceFramework<IApplicationCreator> { 316class IApplicationCreator final : public ServiceFramework<IApplicationCreator> {
323public: 317public:
324 IApplicationCreator(); 318 explicit IApplicationCreator(Core::System& system_);
325 ~IApplicationCreator() override; 319 ~IApplicationCreator() override;
326}; 320};
327 321
328class IProcessWindingController final : public ServiceFramework<IProcessWindingController> { 322class IProcessWindingController final : public ServiceFramework<IProcessWindingController> {
329public: 323public:
330 IProcessWindingController(); 324 explicit IProcessWindingController(Core::System& system_);
331 ~IProcessWindingController() override; 325 ~IProcessWindingController() override;
332}; 326};
333 327
334/// Registers all AM services with the specified service manager. 328/// Registers all AM services with the specified service manager.
335void InstallInterfaces(SM::ServiceManager& service_manager, 329void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nvflinger,
336 std::shared_ptr<NVFlinger::NVFlinger> nvflinger, Core::System& system); 330 Core::System& system);
337 331
338} // namespace Service::AM 332} // namespace Service::AM
diff --git a/src/core/hle/service/am/applet_ae.cpp b/src/core/hle/service/am/applet_ae.cpp
index 9df286d17..5421e0da0 100644
--- a/src/core/hle/service/am/applet_ae.cpp
+++ b/src/core/hle/service/am/applet_ae.cpp
@@ -3,8 +3,8 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/logging/log.h" 5#include "common/logging/log.h"
6#include "core/core.h"
6#include "core/hle/ipc_helpers.h" 7#include "core/hle/ipc_helpers.h"
7#include "core/hle/kernel/process.h"
8#include "core/hle/service/am/am.h" 8#include "core/hle/service/am/am.h"
9#include "core/hle/service/am/applet_ae.h" 9#include "core/hle/service/am/applet_ae.h"
10#include "core/hle/service/nvflinger/nvflinger.h" 10#include "core/hle/service/nvflinger/nvflinger.h"
@@ -13,11 +13,11 @@ namespace Service::AM {
13 13
14class ILibraryAppletProxy final : public ServiceFramework<ILibraryAppletProxy> { 14class ILibraryAppletProxy final : public ServiceFramework<ILibraryAppletProxy> {
15public: 15public:
16 explicit ILibraryAppletProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, 16 explicit ILibraryAppletProxy(NVFlinger::NVFlinger& nvflinger_,
17 std::shared_ptr<AppletMessageQueue> msg_queue, 17 std::shared_ptr<AppletMessageQueue> msg_queue_,
18 Core::System& system) 18 Core::System& system_)
19 : ServiceFramework("ILibraryAppletProxy"), nvflinger(std::move(nvflinger)), 19 : ServiceFramework{system_, "ILibraryAppletProxy"}, nvflinger{nvflinger_},
20 msg_queue(std::move(msg_queue)), system(system) { 20 msg_queue{std::move(msg_queue_)} {
21 // clang-format off 21 // clang-format off
22 static const FunctionInfo functions[] = { 22 static const FunctionInfo functions[] = {
23 {0, &ILibraryAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"}, 23 {0, &ILibraryAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"},
@@ -66,7 +66,7 @@ private:
66 66
67 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 67 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
68 rb.Push(RESULT_SUCCESS); 68 rb.Push(RESULT_SUCCESS);
69 rb.PushIpcInterface<IAudioController>(); 69 rb.PushIpcInterface<IAudioController>(system);
70 } 70 }
71 71
72 void GetDisplayController(Kernel::HLERequestContext& ctx) { 72 void GetDisplayController(Kernel::HLERequestContext& ctx) {
@@ -74,7 +74,7 @@ private:
74 74
75 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 75 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
76 rb.Push(RESULT_SUCCESS); 76 rb.Push(RESULT_SUCCESS);
77 rb.PushIpcInterface<IDisplayController>(); 77 rb.PushIpcInterface<IDisplayController>(system);
78 } 78 }
79 79
80 void GetProcessWindingController(Kernel::HLERequestContext& ctx) { 80 void GetProcessWindingController(Kernel::HLERequestContext& ctx) {
@@ -82,7 +82,7 @@ private:
82 82
83 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 83 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
84 rb.Push(RESULT_SUCCESS); 84 rb.Push(RESULT_SUCCESS);
85 rb.PushIpcInterface<IProcessWindingController>(); 85 rb.PushIpcInterface<IProcessWindingController>(system);
86 } 86 }
87 87
88 void GetDebugFunctions(Kernel::HLERequestContext& ctx) { 88 void GetDebugFunctions(Kernel::HLERequestContext& ctx) {
@@ -90,7 +90,7 @@ private:
90 90
91 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 91 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
92 rb.Push(RESULT_SUCCESS); 92 rb.Push(RESULT_SUCCESS);
93 rb.PushIpcInterface<IDebugFunctions>(); 93 rb.PushIpcInterface<IDebugFunctions>(system);
94 } 94 }
95 95
96 void GetLibraryAppletCreator(Kernel::HLERequestContext& ctx) { 96 void GetLibraryAppletCreator(Kernel::HLERequestContext& ctx) {
@@ -109,17 +109,17 @@ private:
109 rb.PushIpcInterface<IApplicationFunctions>(system); 109 rb.PushIpcInterface<IApplicationFunctions>(system);
110 } 110 }
111 111
112 std::shared_ptr<NVFlinger::NVFlinger> nvflinger; 112 NVFlinger::NVFlinger& nvflinger;
113 std::shared_ptr<AppletMessageQueue> msg_queue; 113 std::shared_ptr<AppletMessageQueue> msg_queue;
114 Core::System& system;
115}; 114};
116 115
117class ISystemAppletProxy final : public ServiceFramework<ISystemAppletProxy> { 116class ISystemAppletProxy final : public ServiceFramework<ISystemAppletProxy> {
118public: 117public:
119 explicit ISystemAppletProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, 118 explicit ISystemAppletProxy(NVFlinger::NVFlinger& nvflinger_,
120 std::shared_ptr<AppletMessageQueue> msg_queue, Core::System& system) 119 std::shared_ptr<AppletMessageQueue> msg_queue_,
121 : ServiceFramework("ISystemAppletProxy"), nvflinger(std::move(nvflinger)), 120 Core::System& system_)
122 msg_queue(std::move(msg_queue)), system(system) { 121 : ServiceFramework{system_, "ISystemAppletProxy"}, nvflinger{nvflinger_},
122 msg_queue{std::move(msg_queue_)} {
123 // clang-format off 123 // clang-format off
124 static const FunctionInfo functions[] = { 124 static const FunctionInfo functions[] = {
125 {0, &ISystemAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"}, 125 {0, &ISystemAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"},
@@ -170,7 +170,7 @@ private:
170 170
171 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 171 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
172 rb.Push(RESULT_SUCCESS); 172 rb.Push(RESULT_SUCCESS);
173 rb.PushIpcInterface<IAudioController>(); 173 rb.PushIpcInterface<IAudioController>(system);
174 } 174 }
175 175
176 void GetDisplayController(Kernel::HLERequestContext& ctx) { 176 void GetDisplayController(Kernel::HLERequestContext& ctx) {
@@ -178,7 +178,7 @@ private:
178 178
179 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 179 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
180 rb.Push(RESULT_SUCCESS); 180 rb.Push(RESULT_SUCCESS);
181 rb.PushIpcInterface<IDisplayController>(); 181 rb.PushIpcInterface<IDisplayController>(system);
182 } 182 }
183 183
184 void GetDebugFunctions(Kernel::HLERequestContext& ctx) { 184 void GetDebugFunctions(Kernel::HLERequestContext& ctx) {
@@ -186,7 +186,7 @@ private:
186 186
187 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 187 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
188 rb.Push(RESULT_SUCCESS); 188 rb.Push(RESULT_SUCCESS);
189 rb.PushIpcInterface<IDebugFunctions>(); 189 rb.PushIpcInterface<IDebugFunctions>(system);
190 } 190 }
191 191
192 void GetLibraryAppletCreator(Kernel::HLERequestContext& ctx) { 192 void GetLibraryAppletCreator(Kernel::HLERequestContext& ctx) {
@@ -202,7 +202,7 @@ private:
202 202
203 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 203 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
204 rb.Push(RESULT_SUCCESS); 204 rb.Push(RESULT_SUCCESS);
205 rb.PushIpcInterface<IHomeMenuFunctions>(system.Kernel()); 205 rb.PushIpcInterface<IHomeMenuFunctions>(system);
206 } 206 }
207 207
208 void GetGlobalStateController(Kernel::HLERequestContext& ctx) { 208 void GetGlobalStateController(Kernel::HLERequestContext& ctx) {
@@ -210,7 +210,7 @@ private:
210 210
211 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 211 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
212 rb.Push(RESULT_SUCCESS); 212 rb.Push(RESULT_SUCCESS);
213 rb.PushIpcInterface<IGlobalStateController>(); 213 rb.PushIpcInterface<IGlobalStateController>(system);
214 } 214 }
215 215
216 void GetApplicationCreator(Kernel::HLERequestContext& ctx) { 216 void GetApplicationCreator(Kernel::HLERequestContext& ctx) {
@@ -218,11 +218,11 @@ private:
218 218
219 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 219 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
220 rb.Push(RESULT_SUCCESS); 220 rb.Push(RESULT_SUCCESS);
221 rb.PushIpcInterface<IApplicationCreator>(); 221 rb.PushIpcInterface<IApplicationCreator>(system);
222 } 222 }
223 std::shared_ptr<NVFlinger::NVFlinger> nvflinger; 223
224 NVFlinger::NVFlinger& nvflinger;
224 std::shared_ptr<AppletMessageQueue> msg_queue; 225 std::shared_ptr<AppletMessageQueue> msg_queue;
225 Core::System& system;
226}; 226};
227 227
228void AppletAE::OpenSystemAppletProxy(Kernel::HLERequestContext& ctx) { 228void AppletAE::OpenSystemAppletProxy(Kernel::HLERequestContext& ctx) {
@@ -249,10 +249,10 @@ void AppletAE::OpenLibraryAppletProxyOld(Kernel::HLERequestContext& ctx) {
249 rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger, msg_queue, system); 249 rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger, msg_queue, system);
250} 250}
251 251
252AppletAE::AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, 252AppletAE::AppletAE(NVFlinger::NVFlinger& nvflinger_, std::shared_ptr<AppletMessageQueue> msg_queue_,
253 std::shared_ptr<AppletMessageQueue> msg_queue, Core::System& system) 253 Core::System& system_)
254 : ServiceFramework("appletAE"), nvflinger(std::move(nvflinger)), 254 : ServiceFramework{system_, "appletAE"}, nvflinger{nvflinger_}, msg_queue{
255 msg_queue(std::move(msg_queue)), system(system) { 255 std::move(msg_queue_)} {
256 // clang-format off 256 // clang-format off
257 static const FunctionInfo functions[] = { 257 static const FunctionInfo functions[] = {
258 {100, &AppletAE::OpenSystemAppletProxy, "OpenSystemAppletProxy"}, 258 {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 2e3e45915..adb207349 100644
--- a/src/core/hle/service/am/applet_ae.h
+++ b/src/core/hle/service/am/applet_ae.h
@@ -23,8 +23,8 @@ class AppletMessageQueue;
23 23
24class AppletAE final : public ServiceFramework<AppletAE> { 24class AppletAE final : public ServiceFramework<AppletAE> {
25public: 25public:
26 explicit AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, 26 explicit AppletAE(NVFlinger::NVFlinger& nvflinger_,
27 std::shared_ptr<AppletMessageQueue> msg_queue, Core::System& system); 27 std::shared_ptr<AppletMessageQueue> msg_queue_, Core::System& system_);
28 ~AppletAE() override; 28 ~AppletAE() override;
29 29
30 const std::shared_ptr<AppletMessageQueue>& GetMessageQueue() const; 30 const std::shared_ptr<AppletMessageQueue>& GetMessageQueue() const;
@@ -34,9 +34,8 @@ private:
34 void OpenLibraryAppletProxy(Kernel::HLERequestContext& ctx); 34 void OpenLibraryAppletProxy(Kernel::HLERequestContext& ctx);
35 void OpenLibraryAppletProxyOld(Kernel::HLERequestContext& ctx); 35 void OpenLibraryAppletProxyOld(Kernel::HLERequestContext& ctx);
36 36
37 std::shared_ptr<NVFlinger::NVFlinger> nvflinger; 37 NVFlinger::NVFlinger& nvflinger;
38 std::shared_ptr<AppletMessageQueue> msg_queue; 38 std::shared_ptr<AppletMessageQueue> msg_queue;
39 Core::System& system;
40}; 39};
41 40
42} // namespace AM 41} // namespace AM
diff --git a/src/core/hle/service/am/applet_oe.cpp b/src/core/hle/service/am/applet_oe.cpp
index a2ffaa440..f9eba8f52 100644
--- a/src/core/hle/service/am/applet_oe.cpp
+++ b/src/core/hle/service/am/applet_oe.cpp
@@ -12,10 +12,11 @@ namespace Service::AM {
12 12
13class IApplicationProxy final : public ServiceFramework<IApplicationProxy> { 13class IApplicationProxy final : public ServiceFramework<IApplicationProxy> {
14public: 14public:
15 explicit IApplicationProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, 15 explicit IApplicationProxy(NVFlinger::NVFlinger& nvflinger_,
16 std::shared_ptr<AppletMessageQueue> msg_queue, Core::System& system) 16 std::shared_ptr<AppletMessageQueue> msg_queue_,
17 : ServiceFramework("IApplicationProxy"), nvflinger(std::move(nvflinger)), 17 Core::System& system_)
18 msg_queue(std::move(msg_queue)), system(system) { 18 : ServiceFramework{system_, "IApplicationProxy"}, nvflinger{nvflinger_},
19 msg_queue{std::move(msg_queue_)} {
19 // clang-format off 20 // clang-format off
20 static const FunctionInfo functions[] = { 21 static const FunctionInfo functions[] = {
21 {0, &IApplicationProxy::GetCommonStateGetter, "GetCommonStateGetter"}, 22 {0, &IApplicationProxy::GetCommonStateGetter, "GetCommonStateGetter"},
@@ -39,7 +40,7 @@ private:
39 40
40 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 41 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
41 rb.Push(RESULT_SUCCESS); 42 rb.Push(RESULT_SUCCESS);
42 rb.PushIpcInterface<IAudioController>(); 43 rb.PushIpcInterface<IAudioController>(system);
43 } 44 }
44 45
45 void GetDisplayController(Kernel::HLERequestContext& ctx) { 46 void GetDisplayController(Kernel::HLERequestContext& ctx) {
@@ -47,7 +48,7 @@ private:
47 48
48 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 49 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
49 rb.Push(RESULT_SUCCESS); 50 rb.Push(RESULT_SUCCESS);
50 rb.PushIpcInterface<IDisplayController>(); 51 rb.PushIpcInterface<IDisplayController>(system);
51 } 52 }
52 53
53 void GetDebugFunctions(Kernel::HLERequestContext& ctx) { 54 void GetDebugFunctions(Kernel::HLERequestContext& ctx) {
@@ -55,7 +56,7 @@ private:
55 56
56 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 57 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
57 rb.Push(RESULT_SUCCESS); 58 rb.Push(RESULT_SUCCESS);
58 rb.PushIpcInterface<IDebugFunctions>(); 59 rb.PushIpcInterface<IDebugFunctions>(system);
59 } 60 }
60 61
61 void GetWindowController(Kernel::HLERequestContext& ctx) { 62 void GetWindowController(Kernel::HLERequestContext& ctx) {
@@ -98,9 +99,8 @@ private:
98 rb.PushIpcInterface<IApplicationFunctions>(system); 99 rb.PushIpcInterface<IApplicationFunctions>(system);
99 } 100 }
100 101
101 std::shared_ptr<NVFlinger::NVFlinger> nvflinger; 102 NVFlinger::NVFlinger& nvflinger;
102 std::shared_ptr<AppletMessageQueue> msg_queue; 103 std::shared_ptr<AppletMessageQueue> msg_queue;
103 Core::System& system;
104}; 104};
105 105
106void AppletOE::OpenApplicationProxy(Kernel::HLERequestContext& ctx) { 106void AppletOE::OpenApplicationProxy(Kernel::HLERequestContext& ctx) {
@@ -111,10 +111,10 @@ void AppletOE::OpenApplicationProxy(Kernel::HLERequestContext& ctx) {
111 rb.PushIpcInterface<IApplicationProxy>(nvflinger, msg_queue, system); 111 rb.PushIpcInterface<IApplicationProxy>(nvflinger, msg_queue, system);
112} 112}
113 113
114AppletOE::AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, 114AppletOE::AppletOE(NVFlinger::NVFlinger& nvflinger_, std::shared_ptr<AppletMessageQueue> msg_queue_,
115 std::shared_ptr<AppletMessageQueue> msg_queue, Core::System& system) 115 Core::System& system_)
116 : ServiceFramework("appletOE"), nvflinger(std::move(nvflinger)), 116 : ServiceFramework{system_, "appletOE"}, nvflinger{nvflinger_}, msg_queue{
117 msg_queue(std::move(msg_queue)), system(system) { 117 std::move(msg_queue_)} {
118 static const FunctionInfo functions[] = { 118 static const FunctionInfo functions[] = {
119 {0, &AppletOE::OpenApplicationProxy, "OpenApplicationProxy"}, 119 {0, &AppletOE::OpenApplicationProxy, "OpenApplicationProxy"},
120 }; 120 };
diff --git a/src/core/hle/service/am/applet_oe.h b/src/core/hle/service/am/applet_oe.h
index 758da792d..6c1aa255a 100644
--- a/src/core/hle/service/am/applet_oe.h
+++ b/src/core/hle/service/am/applet_oe.h
@@ -23,8 +23,8 @@ class AppletMessageQueue;
23 23
24class AppletOE final : public ServiceFramework<AppletOE> { 24class AppletOE final : public ServiceFramework<AppletOE> {
25public: 25public:
26 explicit AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, 26 explicit AppletOE(NVFlinger::NVFlinger& nvflinger_,
27 std::shared_ptr<AppletMessageQueue> msg_queue, Core::System& system); 27 std::shared_ptr<AppletMessageQueue> msg_queue_, Core::System& system_);
28 ~AppletOE() override; 28 ~AppletOE() override;
29 29
30 const std::shared_ptr<AppletMessageQueue>& GetMessageQueue() const; 30 const std::shared_ptr<AppletMessageQueue>& GetMessageQueue() const;
@@ -32,9 +32,8 @@ public:
32private: 32private:
33 void OpenApplicationProxy(Kernel::HLERequestContext& ctx); 33 void OpenApplicationProxy(Kernel::HLERequestContext& ctx);
34 34
35 std::shared_ptr<NVFlinger::NVFlinger> nvflinger; 35 NVFlinger::NVFlinger& nvflinger;
36 std::shared_ptr<AppletMessageQueue> msg_queue; 36 std::shared_ptr<AppletMessageQueue> msg_queue;
37 Core::System& system;
38}; 37};
39 38
40} // namespace AM 39} // namespace AM
diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp
index 4e0800f9a..08676c3fc 100644
--- a/src/core/hle/service/am/applets/applets.cpp
+++ b/src/core/hle/service/am/applets/applets.cpp
@@ -142,14 +142,14 @@ void Applet::Initialize() {
142 142
143AppletFrontendSet::AppletFrontendSet() = default; 143AppletFrontendSet::AppletFrontendSet() = default;
144 144
145AppletFrontendSet::AppletFrontendSet(ControllerApplet controller, ECommerceApplet e_commerce, 145AppletFrontendSet::AppletFrontendSet(ControllerApplet controller_applet, ErrorApplet error_applet,
146 ErrorApplet error, ParentalControlsApplet parental_controls, 146 ParentalControlsApplet parental_controls_applet,
147 PhotoViewer photo_viewer, ProfileSelect profile_select, 147 PhotoViewer photo_viewer_, ProfileSelect profile_select_,
148 SoftwareKeyboard software_keyboard, WebBrowser web_browser) 148 SoftwareKeyboard software_keyboard_, WebBrowser web_browser_)
149 : controller{std::move(controller)}, e_commerce{std::move(e_commerce)}, error{std::move(error)}, 149 : controller{std::move(controller_applet)}, error{std::move(error_applet)},
150 parental_controls{std::move(parental_controls)}, photo_viewer{std::move(photo_viewer)}, 150 parental_controls{std::move(parental_controls_applet)},
151 profile_select{std::move(profile_select)}, software_keyboard{std::move(software_keyboard)}, 151 photo_viewer{std::move(photo_viewer_)}, profile_select{std::move(profile_select_)},
152 web_browser{std::move(web_browser)} {} 152 software_keyboard{std::move(software_keyboard_)}, web_browser{std::move(web_browser_)} {}
153 153
154AppletFrontendSet::~AppletFrontendSet() = default; 154AppletFrontendSet::~AppletFrontendSet() = default;
155 155
@@ -170,10 +170,6 @@ void AppletManager::SetAppletFrontendSet(AppletFrontendSet set) {
170 frontend.controller = std::move(set.controller); 170 frontend.controller = std::move(set.controller);
171 } 171 }
172 172
173 if (set.e_commerce != nullptr) {
174 frontend.e_commerce = std::move(set.e_commerce);
175 }
176
177 if (set.error != nullptr) { 173 if (set.error != nullptr) {
178 frontend.error = std::move(set.error); 174 frontend.error = std::move(set.error);
179 } 175 }
@@ -206,11 +202,8 @@ void AppletManager::SetDefaultAppletFrontendSet() {
206 202
207void AppletManager::SetDefaultAppletsIfMissing() { 203void AppletManager::SetDefaultAppletsIfMissing() {
208 if (frontend.controller == nullptr) { 204 if (frontend.controller == nullptr) {
209 frontend.controller = std::make_unique<Core::Frontend::DefaultControllerApplet>(); 205 frontend.controller =
210 } 206 std::make_unique<Core::Frontend::DefaultControllerApplet>(system.ServiceManager());
211
212 if (frontend.e_commerce == nullptr) {
213 frontend.e_commerce = std::make_unique<Core::Frontend::DefaultECommerceApplet>();
214 } 207 }
215 208
216 if (frontend.error == nullptr) { 209 if (frontend.error == nullptr) {
@@ -256,13 +249,14 @@ std::shared_ptr<Applet> AppletManager::GetApplet(AppletId id) const {
256 return std::make_shared<ProfileSelect>(system, *frontend.profile_select); 249 return std::make_shared<ProfileSelect>(system, *frontend.profile_select);
257 case AppletId::SoftwareKeyboard: 250 case AppletId::SoftwareKeyboard:
258 return std::make_shared<SoftwareKeyboard>(system, *frontend.software_keyboard); 251 return std::make_shared<SoftwareKeyboard>(system, *frontend.software_keyboard);
252 case AppletId::Web:
253 case AppletId::Shop:
254 case AppletId::OfflineWeb:
255 case AppletId::LoginShare:
256 case AppletId::WebAuth:
257 return std::make_shared<WebBrowser>(system, *frontend.web_browser);
259 case AppletId::PhotoViewer: 258 case AppletId::PhotoViewer:
260 return std::make_shared<PhotoViewer>(system, *frontend.photo_viewer); 259 return std::make_shared<PhotoViewer>(system, *frontend.photo_viewer);
261 case AppletId::LibAppletShop:
262 return std::make_shared<WebBrowser>(system, *frontend.web_browser,
263 frontend.e_commerce.get());
264 case AppletId::LibAppletOff:
265 return std::make_shared<WebBrowser>(system, *frontend.web_browser);
266 default: 260 default:
267 UNIMPLEMENTED_MSG( 261 UNIMPLEMENTED_MSG(
268 "No backend implementation exists for applet_id={:02X}! Falling back to stub applet.", 262 "No backend implementation exists for applet_id={:02X}! Falling back to stub applet.",
diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h
index a1f4cf897..4fd792c05 100644
--- a/src/core/hle/service/am/applets/applets.h
+++ b/src/core/hle/service/am/applets/applets.h
@@ -50,13 +50,13 @@ enum class AppletId : u32 {
50 ProfileSelect = 0x10, 50 ProfileSelect = 0x10,
51 SoftwareKeyboard = 0x11, 51 SoftwareKeyboard = 0x11,
52 MiiEdit = 0x12, 52 MiiEdit = 0x12,
53 LibAppletWeb = 0x13, 53 Web = 0x13,
54 LibAppletShop = 0x14, 54 Shop = 0x14,
55 PhotoViewer = 0x15, 55 PhotoViewer = 0x15,
56 Settings = 0x16, 56 Settings = 0x16,
57 LibAppletOff = 0x17, 57 OfflineWeb = 0x17,
58 LibAppletWhitelisted = 0x18, 58 LoginShare = 0x18,
59 LibAppletAuth = 0x19, 59 WebAuth = 0x19,
60 MyPage = 0x1A, 60 MyPage = 0x1A,
61}; 61};
62 62
@@ -157,7 +157,6 @@ protected:
157 157
158struct AppletFrontendSet { 158struct AppletFrontendSet {
159 using ControllerApplet = std::unique_ptr<Core::Frontend::ControllerApplet>; 159 using ControllerApplet = std::unique_ptr<Core::Frontend::ControllerApplet>;
160 using ECommerceApplet = std::unique_ptr<Core::Frontend::ECommerceApplet>;
161 using ErrorApplet = std::unique_ptr<Core::Frontend::ErrorApplet>; 160 using ErrorApplet = std::unique_ptr<Core::Frontend::ErrorApplet>;
162 using ParentalControlsApplet = std::unique_ptr<Core::Frontend::ParentalControlsApplet>; 161 using ParentalControlsApplet = std::unique_ptr<Core::Frontend::ParentalControlsApplet>;
163 using PhotoViewer = std::unique_ptr<Core::Frontend::PhotoViewerApplet>; 162 using PhotoViewer = std::unique_ptr<Core::Frontend::PhotoViewerApplet>;
@@ -166,10 +165,10 @@ struct AppletFrontendSet {
166 using WebBrowser = std::unique_ptr<Core::Frontend::WebBrowserApplet>; 165 using WebBrowser = std::unique_ptr<Core::Frontend::WebBrowserApplet>;
167 166
168 AppletFrontendSet(); 167 AppletFrontendSet();
169 AppletFrontendSet(ControllerApplet controller, ECommerceApplet e_commerce, ErrorApplet error, 168 AppletFrontendSet(ControllerApplet controller_applet, ErrorApplet error_applet,
170 ParentalControlsApplet parental_controls, PhotoViewer photo_viewer, 169 ParentalControlsApplet parental_controls_applet, PhotoViewer photo_viewer_,
171 ProfileSelect profile_select, SoftwareKeyboard software_keyboard, 170 ProfileSelect profile_select_, SoftwareKeyboard software_keyboard_,
172 WebBrowser web_browser); 171 WebBrowser web_browser_);
173 ~AppletFrontendSet(); 172 ~AppletFrontendSet();
174 173
175 AppletFrontendSet(const AppletFrontendSet&) = delete; 174 AppletFrontendSet(const AppletFrontendSet&) = delete;
@@ -179,7 +178,6 @@ struct AppletFrontendSet {
179 AppletFrontendSet& operator=(AppletFrontendSet&&) noexcept; 178 AppletFrontendSet& operator=(AppletFrontendSet&&) noexcept;
180 179
181 ControllerApplet controller; 180 ControllerApplet controller;
182 ECommerceApplet e_commerce;
183 ErrorApplet error; 181 ErrorApplet error;
184 ParentalControlsApplet parental_controls; 182 ParentalControlsApplet parental_controls;
185 PhotoViewer photo_viewer; 183 PhotoViewer photo_viewer;
diff --git a/src/core/hle/service/am/applets/controller.cpp b/src/core/hle/service/am/applets/controller.cpp
index 2151da783..7edfca64e 100644
--- a/src/core/hle/service/am/applets/controller.cpp
+++ b/src/core/hle/service/am/applets/controller.cpp
@@ -25,18 +25,18 @@ namespace Service::AM::Applets {
25static Core::Frontend::ControllerParameters ConvertToFrontendParameters( 25static Core::Frontend::ControllerParameters ConvertToFrontendParameters(
26 ControllerSupportArgPrivate private_arg, ControllerSupportArgHeader header, bool enable_text, 26 ControllerSupportArgPrivate private_arg, ControllerSupportArgHeader header, bool enable_text,
27 std::vector<IdentificationColor> identification_colors, std::vector<ExplainText> text) { 27 std::vector<IdentificationColor> identification_colors, std::vector<ExplainText> text) {
28 HID::Controller_NPad::NPadType npad_style_set; 28 HID::Controller_NPad::NpadStyleSet npad_style_set;
29 npad_style_set.raw = private_arg.style_set; 29 npad_style_set.raw = private_arg.style_set;
30 30
31 return { 31 return {
32 .min_players = std::max(s8(1), header.player_count_min), 32 .min_players = std::max(s8{1}, header.player_count_min),
33 .max_players = header.player_count_max, 33 .max_players = header.player_count_max,
34 .keep_controllers_connected = header.enable_take_over_connection, 34 .keep_controllers_connected = header.enable_take_over_connection,
35 .enable_single_mode = header.enable_single_mode, 35 .enable_single_mode = header.enable_single_mode,
36 .enable_border_color = header.enable_identification_color, 36 .enable_border_color = header.enable_identification_color,
37 .border_colors = identification_colors, 37 .border_colors = std::move(identification_colors),
38 .enable_explain_text = enable_text, 38 .enable_explain_text = enable_text,
39 .explain_text = text, 39 .explain_text = std::move(text),
40 .allow_pro_controller = npad_style_set.pro_controller == 1, 40 .allow_pro_controller = npad_style_set.pro_controller == 1,
41 .allow_handheld = npad_style_set.handheld == 1, 41 .allow_handheld = npad_style_set.handheld == 1,
42 .allow_dual_joycons = npad_style_set.joycon_dual == 1, 42 .allow_dual_joycons = npad_style_set.joycon_dual == 1,
@@ -46,7 +46,7 @@ static Core::Frontend::ControllerParameters ConvertToFrontendParameters(
46} 46}
47 47
48Controller::Controller(Core::System& system_, const Core::Frontend::ControllerApplet& frontend_) 48Controller::Controller(Core::System& system_, const Core::Frontend::ControllerApplet& frontend_)
49 : Applet{system_.Kernel()}, frontend(frontend_) {} 49 : Applet{system_.Kernel()}, frontend{frontend_}, system{system_} {}
50 50
51Controller::~Controller() = default; 51Controller::~Controller() = default;
52 52
@@ -62,7 +62,7 @@ void Controller::Initialize() {
62 common_args.play_startup_sound, common_args.size, common_args.system_tick, 62 common_args.play_startup_sound, common_args.size, common_args.system_tick,
63 common_args.theme_color); 63 common_args.theme_color);
64 64
65 library_applet_version = LibraryAppletVersion{common_args.library_version}; 65 controller_applet_version = ControllerAppletVersion{common_args.library_version};
66 66
67 const auto private_arg_storage = broker.PopNormalDataToApplet(); 67 const auto private_arg_storage = broker.PopNormalDataToApplet();
68 ASSERT(private_arg_storage != nullptr); 68 ASSERT(private_arg_storage != nullptr);
@@ -70,39 +70,78 @@ void Controller::Initialize() {
70 const auto& private_arg = private_arg_storage->GetData(); 70 const auto& private_arg = private_arg_storage->GetData();
71 ASSERT(private_arg.size() == sizeof(ControllerSupportArgPrivate)); 71 ASSERT(private_arg.size() == sizeof(ControllerSupportArgPrivate));
72 72
73 std::memcpy(&controller_private_arg, private_arg.data(), sizeof(ControllerSupportArgPrivate)); 73 std::memcpy(&controller_private_arg, private_arg.data(), private_arg.size());
74 ASSERT_MSG(controller_private_arg.arg_private_size == sizeof(ControllerSupportArgPrivate), 74 ASSERT_MSG(controller_private_arg.arg_private_size == sizeof(ControllerSupportArgPrivate),
75 "Unknown ControllerSupportArgPrivate revision={} with size={}", 75 "Unknown ControllerSupportArgPrivate revision={} with size={}",
76 library_applet_version, controller_private_arg.arg_private_size); 76 controller_applet_version, controller_private_arg.arg_private_size);
77
78 // Some games such as Cave Story+ set invalid values for the ControllerSupportMode.
79 // Defer to arg_size to set the ControllerSupportMode.
80 if (controller_private_arg.mode >= ControllerSupportMode::MaxControllerSupportMode) {
81 switch (controller_private_arg.arg_size) {
82 case sizeof(ControllerSupportArgOld):
83 case sizeof(ControllerSupportArgNew):
84 controller_private_arg.mode = ControllerSupportMode::ShowControllerSupport;
85 break;
86 case sizeof(ControllerUpdateFirmwareArg):
87 controller_private_arg.mode = ControllerSupportMode::ShowControllerFirmwareUpdate;
88 break;
89 default:
90 UNIMPLEMENTED_MSG("Unknown ControllerPrivateArg mode={} with arg_size={}",
91 controller_private_arg.mode, controller_private_arg.arg_size);
92 controller_private_arg.mode = ControllerSupportMode::ShowControllerSupport;
93 break;
94 }
95 }
96
97 // Some games such as Cave Story+ set invalid values for the ControllerSupportCaller.
98 // This is always 0 (Application) except with ShowControllerFirmwareUpdateForSystem.
99 if (controller_private_arg.caller >= ControllerSupportCaller::MaxControllerSupportCaller) {
100 if (controller_private_arg.flag_1 &&
101 controller_private_arg.mode == ControllerSupportMode::ShowControllerFirmwareUpdate) {
102 controller_private_arg.caller = ControllerSupportCaller::System;
103 } else {
104 controller_private_arg.caller = ControllerSupportCaller::Application;
105 }
106 }
77 107
78 switch (controller_private_arg.mode) { 108 switch (controller_private_arg.mode) {
79 case ControllerSupportMode::ShowControllerSupport: { 109 case ControllerSupportMode::ShowControllerSupport:
110 case ControllerSupportMode::ShowControllerStrapGuide: {
80 const auto user_arg_storage = broker.PopNormalDataToApplet(); 111 const auto user_arg_storage = broker.PopNormalDataToApplet();
81 ASSERT(user_arg_storage != nullptr); 112 ASSERT(user_arg_storage != nullptr);
82 113
83 const auto& user_arg = user_arg_storage->GetData(); 114 const auto& user_arg = user_arg_storage->GetData();
84 switch (library_applet_version) { 115 switch (controller_applet_version) {
85 case LibraryAppletVersion::Version3: 116 case ControllerAppletVersion::Version3:
86 case LibraryAppletVersion::Version4: 117 case ControllerAppletVersion::Version4:
87 case LibraryAppletVersion::Version5: 118 case ControllerAppletVersion::Version5:
88 ASSERT(user_arg.size() == sizeof(ControllerSupportArgOld)); 119 ASSERT(user_arg.size() == sizeof(ControllerSupportArgOld));
89 std::memcpy(&controller_user_arg_old, user_arg.data(), sizeof(ControllerSupportArgOld)); 120 std::memcpy(&controller_user_arg_old, user_arg.data(), user_arg.size());
90 break; 121 break;
91 case LibraryAppletVersion::Version7: 122 case ControllerAppletVersion::Version7:
92 ASSERT(user_arg.size() == sizeof(ControllerSupportArgNew)); 123 ASSERT(user_arg.size() == sizeof(ControllerSupportArgNew));
93 std::memcpy(&controller_user_arg_new, user_arg.data(), sizeof(ControllerSupportArgNew)); 124 std::memcpy(&controller_user_arg_new, user_arg.data(), user_arg.size());
94 break; 125 break;
95 default: 126 default:
96 UNIMPLEMENTED_MSG("Unknown ControllerSupportArg revision={} with size={}", 127 UNIMPLEMENTED_MSG("Unknown ControllerSupportArg revision={} with size={}",
97 library_applet_version, controller_private_arg.arg_size); 128 controller_applet_version, controller_private_arg.arg_size);
98 ASSERT(user_arg.size() >= sizeof(ControllerSupportArgNew)); 129 ASSERT(user_arg.size() >= sizeof(ControllerSupportArgNew));
99 std::memcpy(&controller_user_arg_new, user_arg.data(), sizeof(ControllerSupportArgNew)); 130 std::memcpy(&controller_user_arg_new, user_arg.data(), sizeof(ControllerSupportArgNew));
100 break; 131 break;
101 } 132 }
102 break; 133 break;
103 } 134 }
104 case ControllerSupportMode::ShowControllerStrapGuide: 135 case ControllerSupportMode::ShowControllerFirmwareUpdate: {
105 case ControllerSupportMode::ShowControllerFirmwareUpdate: 136 const auto update_arg_storage = broker.PopNormalDataToApplet();
137 ASSERT(update_arg_storage != nullptr);
138
139 const auto& update_arg = update_arg_storage->GetData();
140 ASSERT(update_arg.size() == sizeof(ControllerUpdateFirmwareArg));
141
142 std::memcpy(&controller_update_arg, update_arg.data(), update_arg.size());
143 break;
144 }
106 default: { 145 default: {
107 UNIMPLEMENTED_MSG("Unimplemented ControllerSupportMode={}", controller_private_arg.mode); 146 UNIMPLEMENTED_MSG("Unimplemented ControllerSupportMode={}", controller_private_arg.mode);
108 break; 147 break;
@@ -126,10 +165,10 @@ void Controller::Execute() {
126 switch (controller_private_arg.mode) { 165 switch (controller_private_arg.mode) {
127 case ControllerSupportMode::ShowControllerSupport: { 166 case ControllerSupportMode::ShowControllerSupport: {
128 const auto parameters = [this] { 167 const auto parameters = [this] {
129 switch (library_applet_version) { 168 switch (controller_applet_version) {
130 case LibraryAppletVersion::Version3: 169 case ControllerAppletVersion::Version3:
131 case LibraryAppletVersion::Version4: 170 case ControllerAppletVersion::Version4:
132 case LibraryAppletVersion::Version5: 171 case ControllerAppletVersion::Version5:
133 return ConvertToFrontendParameters( 172 return ConvertToFrontendParameters(
134 controller_private_arg, controller_user_arg_old.header, 173 controller_private_arg, controller_user_arg_old.header,
135 controller_user_arg_old.enable_explain_text, 174 controller_user_arg_old.enable_explain_text,
@@ -138,7 +177,7 @@ void Controller::Execute() {
138 controller_user_arg_old.identification_colors.end()), 177 controller_user_arg_old.identification_colors.end()),
139 std::vector<ExplainText>(controller_user_arg_old.explain_text.begin(), 178 std::vector<ExplainText>(controller_user_arg_old.explain_text.begin(),
140 controller_user_arg_old.explain_text.end())); 179 controller_user_arg_old.explain_text.end()));
141 case LibraryAppletVersion::Version7: 180 case ControllerAppletVersion::Version7:
142 default: 181 default:
143 return ConvertToFrontendParameters( 182 return ConvertToFrontendParameters(
144 controller_private_arg, controller_user_arg_new.header, 183 controller_private_arg, controller_user_arg_new.header,
@@ -170,6 +209,9 @@ void Controller::Execute() {
170 } 209 }
171 case ControllerSupportMode::ShowControllerStrapGuide: 210 case ControllerSupportMode::ShowControllerStrapGuide:
172 case ControllerSupportMode::ShowControllerFirmwareUpdate: 211 case ControllerSupportMode::ShowControllerFirmwareUpdate:
212 UNIMPLEMENTED_MSG("ControllerSupportMode={} is not implemented",
213 controller_private_arg.mode);
214 [[fallthrough]];
173 default: { 215 default: {
174 ConfigurationComplete(); 216 ConfigurationComplete();
175 break; 217 break;
@@ -180,20 +222,19 @@ void Controller::Execute() {
180void Controller::ConfigurationComplete() { 222void Controller::ConfigurationComplete() {
181 ControllerSupportResultInfo result_info{}; 223 ControllerSupportResultInfo result_info{};
182 224
183 const auto& players = Settings::values.players; 225 const auto& players = Settings::values.players.GetValue();
184 226
185 // If enable_single_mode is enabled, player_count is 1 regardless of any other parameters. 227 // If enable_single_mode is enabled, player_count is 1 regardless of any other parameters.
186 // Otherwise, only count connected players from P1-P8. 228 // Otherwise, only count connected players from P1-P8.
187 result_info.player_count = 229 result_info.player_count =
188 is_single_mode ? 1 230 is_single_mode
189 : static_cast<s8>(std::count_if( 231 ? 1
190 players.begin(), players.end() - 2, 232 : static_cast<s8>(std::count_if(players.begin(), players.end() - 2,
191 [](Settings::PlayerInput player) { return player.connected; })); 233 [](const auto& player) { return player.connected; }));
192 234
193 result_info.selected_id = HID::Controller_NPad::IndexToNPad( 235 result_info.selected_id = HID::Controller_NPad::IndexToNPad(std::distance(
194 std::distance(players.begin(), 236 players.begin(), std::find_if(players.begin(), players.end(),
195 std::find_if(players.begin(), players.end(), 237 [](const auto& player) { return player.connected; })));
196 [](Settings::PlayerInput player) { return player.connected; })));
197 238
198 result_info.result = 0; 239 result_info.result = 0;
199 240
@@ -203,7 +244,7 @@ void Controller::ConfigurationComplete() {
203 complete = true; 244 complete = true;
204 out_data = std::vector<u8>(sizeof(ControllerSupportResultInfo)); 245 out_data = std::vector<u8>(sizeof(ControllerSupportResultInfo));
205 std::memcpy(out_data.data(), &result_info, out_data.size()); 246 std::memcpy(out_data.data(), &result_info, out_data.size());
206 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::move(out_data))); 247 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data)));
207 broker.SignalStateChanged(); 248 broker.SignalStateChanged();
208} 249}
209 250
diff --git a/src/core/hle/service/am/applets/controller.h b/src/core/hle/service/am/applets/controller.h
index f7bb3fba9..d4c9da7b1 100644
--- a/src/core/hle/service/am/applets/controller.h
+++ b/src/core/hle/service/am/applets/controller.h
@@ -21,7 +21,7 @@ namespace Service::AM::Applets {
21using IdentificationColor = std::array<u8, 4>; 21using IdentificationColor = std::array<u8, 4>;
22using ExplainText = std::array<char, 0x81>; 22using ExplainText = std::array<char, 0x81>;
23 23
24enum class LibraryAppletVersion : u32_le { 24enum class ControllerAppletVersion : u32_le {
25 Version3 = 0x3, // 1.0.0 - 2.3.0 25 Version3 = 0x3, // 1.0.0 - 2.3.0
26 Version4 = 0x4, // 3.0.0 - 5.1.0 26 Version4 = 0x4, // 3.0.0 - 5.1.0
27 Version5 = 0x5, // 6.0.0 - 7.0.1 27 Version5 = 0x5, // 6.0.0 - 7.0.1
@@ -29,14 +29,18 @@ enum class LibraryAppletVersion : u32_le {
29}; 29};
30 30
31enum class ControllerSupportMode : u8 { 31enum class ControllerSupportMode : u8 {
32 ShowControllerSupport = 0, 32 ShowControllerSupport,
33 ShowControllerStrapGuide = 1, 33 ShowControllerStrapGuide,
34 ShowControllerFirmwareUpdate = 2, 34 ShowControllerFirmwareUpdate,
35
36 MaxControllerSupportMode,
35}; 37};
36 38
37enum class ControllerSupportCaller : u8 { 39enum class ControllerSupportCaller : u8 {
38 Application = 0, 40 Application,
39 System = 1, 41 System,
42
43 MaxControllerSupportCaller,
40}; 44};
41 45
42struct ControllerSupportArgPrivate { 46struct ControllerSupportArgPrivate {
@@ -84,6 +88,13 @@ struct ControllerSupportArgNew {
84static_assert(sizeof(ControllerSupportArgNew) == 0x430, 88static_assert(sizeof(ControllerSupportArgNew) == 0x430,
85 "ControllerSupportArgNew has incorrect size."); 89 "ControllerSupportArgNew has incorrect size.");
86 90
91struct ControllerUpdateFirmwareArg {
92 bool enable_force_update{};
93 INSERT_PADDING_BYTES(3);
94};
95static_assert(sizeof(ControllerUpdateFirmwareArg) == 0x4,
96 "ControllerUpdateFirmwareArg has incorrect size.");
97
87struct ControllerSupportResultInfo { 98struct ControllerSupportResultInfo {
88 s8 player_count{}; 99 s8 player_count{};
89 INSERT_PADDING_BYTES(3); 100 INSERT_PADDING_BYTES(3);
@@ -109,11 +120,13 @@ public:
109 120
110private: 121private:
111 const Core::Frontend::ControllerApplet& frontend; 122 const Core::Frontend::ControllerApplet& frontend;
123 Core::System& system;
112 124
113 LibraryAppletVersion library_applet_version; 125 ControllerAppletVersion controller_applet_version;
114 ControllerSupportArgPrivate controller_private_arg; 126 ControllerSupportArgPrivate controller_private_arg;
115 ControllerSupportArgOld controller_user_arg_old; 127 ControllerSupportArgOld controller_user_arg_old;
116 ControllerSupportArgNew controller_user_arg_new; 128 ControllerSupportArgNew controller_user_arg_new;
129 ControllerUpdateFirmwareArg controller_update_arg;
117 bool complete{false}; 130 bool complete{false};
118 ResultCode status{RESULT_SUCCESS}; 131 ResultCode status{RESULT_SUCCESS};
119 bool is_single_mode{false}; 132 bool is_single_mode{false};
diff --git a/src/core/hle/service/am/applets/error.cpp b/src/core/hle/service/am/applets/error.cpp
index f12fd7f89..d85505082 100644
--- a/src/core/hle/service/am/applets/error.cpp
+++ b/src/core/hle/service/am/applets/error.cpp
@@ -87,7 +87,7 @@ ResultCode Decode64BitError(u64 error) {
87} // Anonymous namespace 87} // Anonymous namespace
88 88
89Error::Error(Core::System& system_, const Core::Frontend::ErrorApplet& frontend_) 89Error::Error(Core::System& system_, const Core::Frontend::ErrorApplet& frontend_)
90 : Applet{system_.Kernel()}, frontend(frontend_), system{system_} {} 90 : Applet{system_.Kernel()}, frontend{frontend_}, system{system_} {}
91 91
92Error::~Error() = default; 92Error::~Error() = default;
93 93
@@ -125,7 +125,7 @@ void Error::Initialize() {
125 error_code = Decode64BitError(args->error_record.error_code_64); 125 error_code = Decode64BitError(args->error_record.error_code_64);
126 break; 126 break;
127 default: 127 default:
128 UNIMPLEMENTED_MSG("Unimplemented LibAppletError mode={:02X}!", static_cast<u8>(mode)); 128 UNIMPLEMENTED_MSG("Unimplemented LibAppletError mode={:02X}!", mode);
129 } 129 }
130} 130}
131 131
@@ -179,14 +179,14 @@ void Error::Execute() {
179 error_code, std::chrono::seconds{args->error_record.posix_time}, callback); 179 error_code, std::chrono::seconds{args->error_record.posix_time}, callback);
180 break; 180 break;
181 default: 181 default:
182 UNIMPLEMENTED_MSG("Unimplemented LibAppletError mode={:02X}!", static_cast<u8>(mode)); 182 UNIMPLEMENTED_MSG("Unimplemented LibAppletError mode={:02X}!", mode);
183 DisplayCompleted(); 183 DisplayCompleted();
184 } 184 }
185} 185}
186 186
187void Error::DisplayCompleted() { 187void Error::DisplayCompleted() {
188 complete = true; 188 complete = true;
189 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::vector<u8>{})); 189 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::vector<u8>{}));
190 broker.SignalStateChanged(); 190 broker.SignalStateChanged();
191} 191}
192 192
diff --git a/src/core/hle/service/am/applets/general_backend.cpp b/src/core/hle/service/am/applets/general_backend.cpp
index 104501ac5..4d1df5cbe 100644
--- a/src/core/hle/service/am/applets/general_backend.cpp
+++ b/src/core/hle/service/am/applets/general_backend.cpp
@@ -38,7 +38,7 @@ static void LogCurrentStorage(AppletDataBroker& broker, std::string_view prefix)
38} 38}
39 39
40Auth::Auth(Core::System& system_, Core::Frontend::ParentalControlsApplet& frontend_) 40Auth::Auth(Core::System& system_, Core::Frontend::ParentalControlsApplet& frontend_)
41 : Applet{system_.Kernel()}, frontend(frontend_) {} 41 : Applet{system_.Kernel()}, frontend{frontend_}, system{system_} {}
42 42
43Auth::~Auth() = default; 43Auth::~Auth() = default;
44 44
@@ -90,7 +90,7 @@ void Auth::Execute() {
90 const auto unimplemented_log = [this] { 90 const auto unimplemented_log = [this] {
91 UNIMPLEMENTED_MSG("Unimplemented Auth applet type for type={:08X}, arg0={:02X}, " 91 UNIMPLEMENTED_MSG("Unimplemented Auth applet type for type={:08X}, arg0={:02X}, "
92 "arg1={:02X}, arg2={:02X}", 92 "arg1={:02X}, arg2={:02X}",
93 static_cast<u32>(type), arg0, arg1, arg2); 93 type, arg0, arg1, arg2);
94 }; 94 };
95 95
96 switch (type) { 96 switch (type) {
@@ -135,8 +135,8 @@ void Auth::Execute() {
135 } 135 }
136} 136}
137 137
138void Auth::AuthFinished(bool successful) { 138void Auth::AuthFinished(bool is_successful) {
139 this->successful = successful; 139 successful = is_successful;
140 140
141 struct Return { 141 struct Return {
142 ResultCode result_code; 142 ResultCode result_code;
@@ -148,12 +148,12 @@ void Auth::AuthFinished(bool successful) {
148 std::vector<u8> out(sizeof(Return)); 148 std::vector<u8> out(sizeof(Return));
149 std::memcpy(out.data(), &return_, sizeof(Return)); 149 std::memcpy(out.data(), &return_, sizeof(Return));
150 150
151 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::move(out))); 151 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out)));
152 broker.SignalStateChanged(); 152 broker.SignalStateChanged();
153} 153}
154 154
155PhotoViewer::PhotoViewer(Core::System& system_, const Core::Frontend::PhotoViewerApplet& frontend_) 155PhotoViewer::PhotoViewer(Core::System& system_, const Core::Frontend::PhotoViewerApplet& frontend_)
156 : Applet{system_.Kernel()}, frontend(frontend_), system{system_} {} 156 : Applet{system_.Kernel()}, frontend{frontend_}, system{system_} {}
157 157
158PhotoViewer::~PhotoViewer() = default; 158PhotoViewer::~PhotoViewer() = default;
159 159
@@ -193,17 +193,17 @@ void PhotoViewer::Execute() {
193 frontend.ShowAllPhotos(callback); 193 frontend.ShowAllPhotos(callback);
194 break; 194 break;
195 default: 195 default:
196 UNIMPLEMENTED_MSG("Unimplemented PhotoViewer applet mode={:02X}!", static_cast<u8>(mode)); 196 UNIMPLEMENTED_MSG("Unimplemented PhotoViewer applet mode={:02X}!", mode);
197 } 197 }
198} 198}
199 199
200void PhotoViewer::ViewFinished() { 200void PhotoViewer::ViewFinished() {
201 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::vector<u8>{})); 201 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::vector<u8>{}));
202 broker.SignalStateChanged(); 202 broker.SignalStateChanged();
203} 203}
204 204
205StubApplet::StubApplet(Core::System& system_, AppletId id_) 205StubApplet::StubApplet(Core::System& system_, AppletId id_)
206 : Applet{system_.Kernel()}, id(id_), system{system_} {} 206 : Applet{system_.Kernel()}, id{id_}, system{system_} {}
207 207
208StubApplet::~StubApplet() = default; 208StubApplet::~StubApplet() = default;
209 209
@@ -234,8 +234,9 @@ void StubApplet::ExecuteInteractive() {
234 LOG_WARNING(Service_AM, "called (STUBBED)"); 234 LOG_WARNING(Service_AM, "called (STUBBED)");
235 LogCurrentStorage(broker, "ExecuteInteractive"); 235 LogCurrentStorage(broker, "ExecuteInteractive");
236 236
237 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::vector<u8>(0x1000))); 237 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::vector<u8>(0x1000)));
238 broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(std::vector<u8>(0x1000))); 238 broker.PushInteractiveDataFromApplet(
239 std::make_shared<IStorage>(system, std::vector<u8>(0x1000)));
239 broker.SignalStateChanged(); 240 broker.SignalStateChanged();
240} 241}
241 242
@@ -243,8 +244,9 @@ void StubApplet::Execute() {
243 LOG_WARNING(Service_AM, "called (STUBBED)"); 244 LOG_WARNING(Service_AM, "called (STUBBED)");
244 LogCurrentStorage(broker, "Execute"); 245 LogCurrentStorage(broker, "Execute");
245 246
246 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::vector<u8>(0x1000))); 247 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::vector<u8>(0x1000)));
247 broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(std::vector<u8>(0x1000))); 248 broker.PushInteractiveDataFromApplet(
249 std::make_shared<IStorage>(system, std::vector<u8>(0x1000)));
248 broker.SignalStateChanged(); 250 broker.SignalStateChanged();
249} 251}
250 252
diff --git a/src/core/hle/service/am/applets/general_backend.h b/src/core/hle/service/am/applets/general_backend.h
index cfa2df369..ba76ae3d3 100644
--- a/src/core/hle/service/am/applets/general_backend.h
+++ b/src/core/hle/service/am/applets/general_backend.h
@@ -29,10 +29,11 @@ public:
29 void ExecuteInteractive() override; 29 void ExecuteInteractive() override;
30 void Execute() override; 30 void Execute() override;
31 31
32 void AuthFinished(bool successful = true); 32 void AuthFinished(bool is_successful = true);
33 33
34private: 34private:
35 Core::Frontend::ParentalControlsApplet& frontend; 35 Core::Frontend::ParentalControlsApplet& frontend;
36 Core::System& system;
36 bool complete = false; 37 bool complete = false;
37 bool successful = false; 38 bool successful = false;
38 39
diff --git a/src/core/hle/service/am/applets/profile_select.cpp b/src/core/hle/service/am/applets/profile_select.cpp
index 70cc23552..77fba16c7 100644
--- a/src/core/hle/service/am/applets/profile_select.cpp
+++ b/src/core/hle/service/am/applets/profile_select.cpp
@@ -17,7 +17,7 @@ constexpr ResultCode ERR_USER_CANCELLED_SELECTION{ErrorModule::Account, 1};
17 17
18ProfileSelect::ProfileSelect(Core::System& system_, 18ProfileSelect::ProfileSelect(Core::System& system_,
19 const Core::Frontend::ProfileSelectApplet& frontend_) 19 const Core::Frontend::ProfileSelectApplet& frontend_)
20 : Applet{system_.Kernel()}, frontend(frontend_) {} 20 : Applet{system_.Kernel()}, frontend{frontend_}, system{system_} {}
21 21
22ProfileSelect::~ProfileSelect() = default; 22ProfileSelect::~ProfileSelect() = default;
23 23
@@ -50,7 +50,7 @@ void ProfileSelect::ExecuteInteractive() {
50 50
51void ProfileSelect::Execute() { 51void ProfileSelect::Execute() {
52 if (complete) { 52 if (complete) {
53 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::move(final_data))); 53 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(final_data)));
54 return; 54 return;
55 } 55 }
56 56
@@ -71,7 +71,7 @@ void ProfileSelect::SelectionComplete(std::optional<Common::UUID> uuid) {
71 71
72 final_data = std::vector<u8>(sizeof(UserSelectionOutput)); 72 final_data = std::vector<u8>(sizeof(UserSelectionOutput));
73 std::memcpy(final_data.data(), &output, final_data.size()); 73 std::memcpy(final_data.data(), &output, final_data.size());
74 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::move(final_data))); 74 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(final_data)));
75 broker.SignalStateChanged(); 75 broker.SignalStateChanged();
76} 76}
77 77
diff --git a/src/core/hle/service/am/applets/profile_select.h b/src/core/hle/service/am/applets/profile_select.h
index 16364ead7..648d33a24 100644
--- a/src/core/hle/service/am/applets/profile_select.h
+++ b/src/core/hle/service/am/applets/profile_select.h
@@ -53,6 +53,7 @@ private:
53 bool complete = false; 53 bool complete = false;
54 ResultCode status = RESULT_SUCCESS; 54 ResultCode status = RESULT_SUCCESS;
55 std::vector<u8> final_data; 55 std::vector<u8> final_data;
56 Core::System& system;
56}; 57};
57 58
58} // namespace Service::AM::Applets 59} // namespace Service::AM::Applets
diff --git a/src/core/hle/service/am/applets/software_keyboard.cpp b/src/core/hle/service/am/applets/software_keyboard.cpp
index bdeb0737a..3022438b1 100644
--- a/src/core/hle/service/am/applets/software_keyboard.cpp
+++ b/src/core/hle/service/am/applets/software_keyboard.cpp
@@ -53,7 +53,7 @@ static Core::Frontend::SoftwareKeyboardParameters ConvertToFrontendParameters(
53 53
54SoftwareKeyboard::SoftwareKeyboard(Core::System& system_, 54SoftwareKeyboard::SoftwareKeyboard(Core::System& system_,
55 const Core::Frontend::SoftwareKeyboardApplet& frontend_) 55 const Core::Frontend::SoftwareKeyboardApplet& frontend_)
56 : Applet{system_.Kernel()}, frontend(frontend_) {} 56 : Applet{system_.Kernel()}, frontend{frontend_}, system{system_} {}
57 57
58SoftwareKeyboard::~SoftwareKeyboard() = default; 58SoftwareKeyboard::~SoftwareKeyboard() = default;
59 59
@@ -122,7 +122,7 @@ void SoftwareKeyboard::ExecuteInteractive() {
122 122
123 switch (request) { 123 switch (request) {
124 case Request::Calc: { 124 case Request::Calc: {
125 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::vector<u8>{1})); 125 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::vector<u8>{1}));
126 broker.SignalStateChanged(); 126 broker.SignalStateChanged();
127 break; 127 break;
128 } 128 }
@@ -135,7 +135,7 @@ void SoftwareKeyboard::ExecuteInteractive() {
135 135
136void SoftwareKeyboard::Execute() { 136void SoftwareKeyboard::Execute() {
137 if (complete) { 137 if (complete) {
138 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::move(final_data))); 138 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(final_data)));
139 broker.SignalStateChanged(); 139 broker.SignalStateChanged();
140 return; 140 return;
141 } 141 }
@@ -179,15 +179,17 @@ void SoftwareKeyboard::WriteText(std::optional<std::u16string> text) {
179 final_data = output_main; 179 final_data = output_main;
180 180
181 if (complete) { 181 if (complete) {
182 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::move(output_main))); 182 broker.PushNormalDataFromApplet(
183 std::make_shared<IStorage>(system, std::move(output_main)));
183 broker.SignalStateChanged(); 184 broker.SignalStateChanged();
184 } else { 185 } else {
185 broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(std::move(output_sub))); 186 broker.PushInteractiveDataFromApplet(
187 std::make_shared<IStorage>(system, std::move(output_sub)));
186 } 188 }
187 } else { 189 } else {
188 output_main[0] = 1; 190 output_main[0] = 1;
189 complete = true; 191 complete = true;
190 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::move(output_main))); 192 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(output_main)));
191 broker.SignalStateChanged(); 193 broker.SignalStateChanged();
192 } 194 }
193} 195}
diff --git a/src/core/hle/service/am/applets/software_keyboard.h b/src/core/hle/service/am/applets/software_keyboard.h
index 5a3824b5a..1d260fef8 100644
--- a/src/core/hle/service/am/applets/software_keyboard.h
+++ b/src/core/hle/service/am/applets/software_keyboard.h
@@ -80,6 +80,7 @@ private:
80 bool complete = false; 80 bool complete = false;
81 bool is_inline = false; 81 bool is_inline = false;
82 std::vector<u8> final_data; 82 std::vector<u8> final_data;
83 Core::System& system;
83}; 84};
84 85
85} // namespace Service::AM::Applets 86} // namespace Service::AM::Applets
diff --git a/src/core/hle/service/am/applets/web_browser.cpp b/src/core/hle/service/am/applets/web_browser.cpp
index efe595c4f..2ab420789 100644
--- a/src/core/hle/service/am/applets/web_browser.cpp
+++ b/src/core/hle/service/am/applets/web_browser.cpp
@@ -1,558 +1,478 @@
1// Copyright 2018 yuzu emulator team 1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <array>
6#include <cstring>
7#include <vector>
8
9#include "common/assert.h" 5#include "common/assert.h"
10#include "common/common_funcs.h"
11#include "common/common_paths.h" 6#include "common/common_paths.h"
12#include "common/file_util.h" 7#include "common/file_util.h"
13#include "common/hex_util.h"
14#include "common/logging/log.h" 8#include "common/logging/log.h"
15#include "common/string_util.h" 9#include "common/string_util.h"
16#include "core/core.h" 10#include "core/core.h"
17#include "core/file_sys/content_archive.h" 11#include "core/file_sys/content_archive.h"
18#include "core/file_sys/mode.h" 12#include "core/file_sys/mode.h"
19#include "core/file_sys/nca_metadata.h" 13#include "core/file_sys/nca_metadata.h"
14#include "core/file_sys/patch_manager.h"
20#include "core/file_sys/registered_cache.h" 15#include "core/file_sys/registered_cache.h"
21#include "core/file_sys/romfs.h" 16#include "core/file_sys/romfs.h"
22#include "core/file_sys/system_archive/system_archive.h" 17#include "core/file_sys/system_archive/system_archive.h"
23#include "core/file_sys/vfs_types.h" 18#include "core/file_sys/vfs_vector.h"
24#include "core/frontend/applets/general_frontend.h"
25#include "core/frontend/applets/web_browser.h" 19#include "core/frontend/applets/web_browser.h"
26#include "core/hle/kernel/process.h" 20#include "core/hle/kernel/process.h"
21#include "core/hle/result.h"
22#include "core/hle/service/am/am.h"
27#include "core/hle/service/am/applets/web_browser.h" 23#include "core/hle/service/am/applets/web_browser.h"
28#include "core/hle/service/filesystem/filesystem.h" 24#include "core/hle/service/filesystem/filesystem.h"
29#include "core/loader/loader.h" 25#include "core/hle/service/ns/pl_u.h"
30 26
31namespace Service::AM::Applets { 27namespace Service::AM::Applets {
32 28
33enum class WebArgTLVType : u16 {
34 InitialURL = 0x1,
35 ShopArgumentsURL = 0x2, ///< TODO(DarkLordZach): This is not the official name.
36 CallbackURL = 0x3,
37 CallbackableURL = 0x4,
38 ApplicationID = 0x5,
39 DocumentPath = 0x6,
40 DocumentKind = 0x7,
41 SystemDataID = 0x8,
42 ShareStartPage = 0x9,
43 Whitelist = 0xA,
44 News = 0xB,
45 UserID = 0xE,
46 AlbumEntry0 = 0xF,
47 ScreenShotEnabled = 0x10,
48 EcClientCertEnabled = 0x11,
49 Unk12 = 0x12,
50 PlayReportEnabled = 0x13,
51 Unk14 = 0x14,
52 Unk15 = 0x15,
53 BootDisplayKind = 0x17,
54 BackgroundKind = 0x18,
55 FooterEnabled = 0x19,
56 PointerEnabled = 0x1A,
57 LeftStickMode = 0x1B,
58 KeyRepeatFrame1 = 0x1C,
59 KeyRepeatFrame2 = 0x1D,
60 BootAsMediaPlayerInv = 0x1E,
61 DisplayUrlKind = 0x1F,
62 BootAsMediaPlayer = 0x21,
63 ShopJumpEnabled = 0x22,
64 MediaAutoPlayEnabled = 0x23,
65 LobbyParameter = 0x24,
66 ApplicationAlbumEntry = 0x26,
67 JsExtensionEnabled = 0x27,
68 AdditionalCommentText = 0x28,
69 TouchEnabledOnContents = 0x29,
70 UserAgentAdditionalString = 0x2A,
71 AdditionalMediaData0 = 0x2B,
72 MediaPlayerAutoCloseEnabled = 0x2C,
73 PageCacheEnabled = 0x2D,
74 WebAudioEnabled = 0x2E,
75 Unk2F = 0x2F,
76 YouTubeVideoWhitelist = 0x31,
77 FooterFixedKind = 0x32,
78 PageFadeEnabled = 0x33,
79 MediaCreatorApplicationRatingAge = 0x34,
80 BootLoadingIconEnabled = 0x35,
81 PageScrollIndicationEnabled = 0x36,
82 MediaPlayerSpeedControlEnabled = 0x37,
83 AlbumEntry1 = 0x38,
84 AlbumEntry2 = 0x39,
85 AlbumEntry3 = 0x3A,
86 AdditionalMediaData1 = 0x3B,
87 AdditionalMediaData2 = 0x3C,
88 AdditionalMediaData3 = 0x3D,
89 BootFooterButton = 0x3E,
90 OverrideWebAudioVolume = 0x3F,
91 OverrideMediaAudioVolume = 0x40,
92 BootMode = 0x41,
93 WebSessionEnabled = 0x42,
94};
95
96enum class ShimKind : u32 {
97 Shop = 1,
98 Login = 2,
99 Offline = 3,
100 Share = 4,
101 Web = 5,
102 Wifi = 6,
103 Lobby = 7,
104};
105
106enum class ShopWebTarget {
107 ApplicationInfo,
108 AddOnContentList,
109 SubscriptionList,
110 ConsumableItemList,
111 Home,
112 Settings,
113};
114
115namespace { 29namespace {
116 30
117constexpr std::size_t SHIM_KIND_COUNT = 0x8; 31template <typename T>
118 32void ParseRawValue(T& value, const std::vector<u8>& data) {
119struct WebArgHeader { 33 static_assert(std::is_trivially_copyable_v<T>,
120 u16 count; 34 "It's undefined behavior to use memcpy with non-trivially copyable objects");
121 INSERT_PADDING_BYTES(2); 35 std::memcpy(&value, data.data(), data.size());
122 ShimKind kind; 36}
123};
124static_assert(sizeof(WebArgHeader) == 0x8, "WebArgHeader has incorrect size.");
125
126struct WebArgTLV {
127 WebArgTLVType type;
128 u16 size;
129 u32 offset;
130};
131static_assert(sizeof(WebArgTLV) == 0x8, "WebArgTLV has incorrect size.");
132
133struct WebCommonReturnValue {
134 u32 result_code;
135 INSERT_PADDING_BYTES(0x4);
136 std::array<char, 0x1000> last_url;
137 u64 last_url_size;
138};
139static_assert(sizeof(WebCommonReturnValue) == 0x1010, "WebCommonReturnValue has incorrect size.");
140
141struct WebWifiPageArg {
142 INSERT_PADDING_BYTES(4);
143 std::array<char, 0x100> connection_test_url;
144 std::array<char, 0x400> initial_url;
145 std::array<u8, 0x10> nifm_network_uuid;
146 u32 nifm_requirement;
147};
148static_assert(sizeof(WebWifiPageArg) == 0x518, "WebWifiPageArg has incorrect size.");
149
150struct WebWifiReturnValue {
151 INSERT_PADDING_BYTES(4);
152 u32 result;
153};
154static_assert(sizeof(WebWifiReturnValue) == 0x8, "WebWifiReturnValue has incorrect size.");
155
156enum class OfflineWebSource : u32 {
157 OfflineHtmlPage = 0x1,
158 ApplicationLegalInformation = 0x2,
159 SystemDataPage = 0x3,
160};
161
162std::map<WebArgTLVType, std::vector<u8>> GetWebArguments(const std::vector<u8>& arg) {
163 if (arg.size() < sizeof(WebArgHeader))
164 return {};
165
166 WebArgHeader header{};
167 std::memcpy(&header, arg.data(), sizeof(WebArgHeader));
168
169 std::map<WebArgTLVType, std::vector<u8>> out;
170 u64 offset = sizeof(WebArgHeader);
171 for (std::size_t i = 0; i < header.count; ++i) {
172 if (arg.size() < (offset + sizeof(WebArgTLV)))
173 return out;
174 37
175 WebArgTLV tlv{}; 38template <typename T>
176 std::memcpy(&tlv, arg.data() + offset, sizeof(WebArgTLV)); 39T ParseRawValue(const std::vector<u8>& data) {
177 offset += sizeof(WebArgTLV); 40 T value;
41 ParseRawValue(value, data);
42 return value;
43}
178 44
179 offset += tlv.offset; 45std::string ParseStringValue(const std::vector<u8>& data) {
180 if (arg.size() < (offset + tlv.size)) 46 return Common::StringFromFixedZeroTerminatedBuffer(reinterpret_cast<const char*>(data.data()),
181 return out; 47 data.size());
48}
182 49
183 std::vector<u8> data(tlv.size); 50std::string GetMainURL(const std::string& url) {
184 std::memcpy(data.data(), arg.data() + offset, tlv.size); 51 const auto index = url.find('?');
185 offset += tlv.size;
186 52
187 out.insert_or_assign(tlv.type, data); 53 if (index == std::string::npos) {
54 return url;
188 } 55 }
189 56
190 return out; 57 return url.substr(0, index);
191} 58}
192 59
193FileSys::VirtualFile GetApplicationRomFS(const Core::System& system, u64 title_id, 60WebArgInputTLVMap ReadWebArgs(const std::vector<u8>& web_arg, WebArgHeader& web_arg_header) {
194 FileSys::ContentRecordType type) { 61 std::memcpy(&web_arg_header, web_arg.data(), sizeof(WebArgHeader));
195 const auto& installed{system.GetContentProvider()};
196 const auto res = installed.GetEntry(title_id, type);
197 62
198 if (res != nullptr) { 63 if (web_arg.size() == sizeof(WebArgHeader)) {
199 return res->GetRomFS(); 64 return {};
200 } 65 }
201 66
202 if (type == FileSys::ContentRecordType::Data) { 67 WebArgInputTLVMap input_tlv_map;
203 return FileSys::SystemArchive::SynthesizeSystemArchive(title_id); 68
69 u64 current_offset = sizeof(WebArgHeader);
70
71 for (std::size_t i = 0; i < web_arg_header.total_tlv_entries; ++i) {
72 if (web_arg.size() < current_offset + sizeof(WebArgInputTLV)) {
73 return input_tlv_map;
74 }
75
76 WebArgInputTLV input_tlv;
77 std::memcpy(&input_tlv, web_arg.data() + current_offset, sizeof(WebArgInputTLV));
78
79 current_offset += sizeof(WebArgInputTLV);
80
81 if (web_arg.size() < current_offset + input_tlv.arg_data_size) {
82 return input_tlv_map;
83 }
84
85 std::vector<u8> data(input_tlv.arg_data_size);
86 std::memcpy(data.data(), web_arg.data() + current_offset, input_tlv.arg_data_size);
87
88 current_offset += input_tlv.arg_data_size;
89
90 input_tlv_map.insert_or_assign(input_tlv.input_tlv_type, std::move(data));
204 } 91 }
205 92
206 return nullptr; 93 return input_tlv_map;
207} 94}
208 95
209} // Anonymous namespace 96FileSys::VirtualFile GetOfflineRomFS(Core::System& system, u64 title_id,
97 FileSys::ContentRecordType nca_type) {
98 if (nca_type == FileSys::ContentRecordType::Data) {
99 const auto nca =
100 system.GetFileSystemController().GetSystemNANDContents()->GetEntry(title_id, nca_type);
101
102 if (nca == nullptr) {
103 LOG_ERROR(Service_AM,
104 "NCA of type={} with title_id={:016X} is not found in the System NAND!",
105 nca_type, title_id);
106 return FileSys::SystemArchive::SynthesizeSystemArchive(title_id);
107 }
210 108
211WebBrowser::WebBrowser(Core::System& system_, Core::Frontend::WebBrowserApplet& frontend_, 109 return nca->GetRomFS();
212 Core::Frontend::ECommerceApplet* frontend_e_commerce_) 110 } else {
213 : Applet{system_.Kernel()}, frontend(frontend_), 111 const auto nca = system.GetContentProvider().GetEntry(title_id, nca_type);
214 frontend_e_commerce(frontend_e_commerce_), system{system_} {}
215 112
216WebBrowser::~WebBrowser() = default; 113 if (nca == nullptr) {
114 LOG_ERROR(Service_AM,
115 "NCA of type={} with title_id={:016X} is not found in the ContentProvider!",
116 nca_type, title_id);
117 return nullptr;
118 }
217 119
218void WebBrowser::Initialize() { 120 const FileSys::PatchManager pm{title_id, system.GetFileSystemController(),
219 Applet::Initialize(); 121 system.GetContentProvider()};
220 122
221 complete = false; 123 return pm.PatchRomFS(nca->GetRomFS(), nca->GetBaseIVFCOffset(), nca_type);
222 temporary_dir.clear(); 124 }
223 filename.clear(); 125}
224 status = RESULT_SUCCESS;
225 126
226 const auto web_arg_storage = broker.PopNormalDataToApplet(); 127void ExtractSharedFonts(Core::System& system) {
227 ASSERT(web_arg_storage != nullptr); 128 static constexpr std::array<const char*, 7> DECRYPTED_SHARED_FONTS{
228 const auto& web_arg = web_arg_storage->GetData(); 129 "FontStandard.ttf",
130 "FontChineseSimplified.ttf",
131 "FontExtendedChineseSimplified.ttf",
132 "FontChineseTraditional.ttf",
133 "FontKorean.ttf",
134 "FontNintendoExtended.ttf",
135 "FontNintendoExtended2.ttf",
136 };
229 137
230 ASSERT(web_arg.size() >= 0x8); 138 for (std::size_t i = 0; i < NS::SHARED_FONTS.size(); ++i) {
231 std::memcpy(&kind, web_arg.data() + 0x4, sizeof(ShimKind)); 139 const auto fonts_dir = Common::FS::SanitizePath(
140 fmt::format("{}/fonts", Common::FS::GetUserPath(Common::FS::UserPath::CacheDir)),
141 Common::FS::DirectorySeparator::PlatformDefault);
232 142
233 args = GetWebArguments(web_arg); 143 const auto font_file_path =
144 Common::FS::SanitizePath(fmt::format("{}/{}", fonts_dir, DECRYPTED_SHARED_FONTS[i]),
145 Common::FS::DirectorySeparator::PlatformDefault);
234 146
235 InitializeInternal(); 147 if (Common::FS::Exists(font_file_path)) {
236} 148 continue;
149 }
237 150
238bool WebBrowser::TransactionComplete() const { 151 const auto font = NS::SHARED_FONTS[i];
239 return complete; 152 const auto font_title_id = static_cast<u64>(font.first);
240}
241 153
242ResultCode WebBrowser::GetStatus() const { 154 const auto nca = system.GetFileSystemController().GetSystemNANDContents()->GetEntry(
243 return status; 155 font_title_id, FileSys::ContentRecordType::Data);
244}
245 156
246void WebBrowser::ExecuteInteractive() { 157 FileSys::VirtualFile romfs;
247 UNIMPLEMENTED_MSG("Unexpected interactive data recieved!");
248}
249 158
250void WebBrowser::Execute() { 159 if (!nca) {
251 if (complete) { 160 romfs = FileSys::SystemArchive::SynthesizeSystemArchive(font_title_id);
252 return; 161 } else {
253 } 162 romfs = nca->GetRomFS();
163 }
254 164
255 if (status != RESULT_SUCCESS) { 165 if (!romfs) {
256 complete = true; 166 LOG_ERROR(Service_AM, "SharedFont RomFS with title_id={:016X} cannot be extracted!",
167 font_title_id);
168 continue;
169 }
257 170
258 // This is a workaround in order not to softlock yuzu when an error happens during the 171 const auto extracted_romfs = FileSys::ExtractRomFS(romfs);
259 // webapplet init. In order to avoid an svcBreak, the status is set to RESULT_SUCCESS
260 Finalize();
261 status = RESULT_SUCCESS;
262 172
263 return; 173 if (!extracted_romfs) {
264 } 174 LOG_ERROR(Service_AM, "SharedFont RomFS with title_id={:016X} failed to extract!",
175 font_title_id);
176 continue;
177 }
265 178
266 ExecuteInternal(); 179 const auto font_file = extracted_romfs->GetFile(font.second);
267}
268 180
269void WebBrowser::UnpackRomFS() { 181 if (!font_file) {
270 if (unpacked) 182 LOG_ERROR(Service_AM, "SharedFont RomFS with title_id={:016X} has no font file \"{}\"!",
271 return; 183 font_title_id, font.second);
184 continue;
185 }
272 186
273 ASSERT(offline_romfs != nullptr); 187 std::vector<u32> font_data_u32(font_file->GetSize() / sizeof(u32));
274 const auto dir = 188 font_file->ReadBytes<u32>(font_data_u32.data(), font_file->GetSize());
275 FileSys::ExtractRomFS(offline_romfs, FileSys::RomFSExtractionType::SingleDiscard);
276 const auto& vfs{system.GetFilesystem()};
277 const auto temp_dir = vfs->CreateDirectory(temporary_dir, FileSys::Mode::ReadWrite);
278 FileSys::VfsRawCopyD(dir, temp_dir);
279 189
280 unpacked = true; 190 std::transform(font_data_u32.begin(), font_data_u32.end(), font_data_u32.begin(),
281} 191 Common::swap32);
282 192
283void WebBrowser::Finalize() { 193 std::vector<u8> decrypted_data(font_file->GetSize() - 8);
284 complete = true;
285 194
286 WebCommonReturnValue out{}; 195 NS::DecryptSharedFontToTTF(font_data_u32, decrypted_data);
287 out.result_code = 0;
288 out.last_url_size = 0;
289 196
290 std::vector<u8> data(sizeof(WebCommonReturnValue)); 197 FileSys::VirtualFile decrypted_font = std::make_shared<FileSys::VectorVfsFile>(
291 std::memcpy(data.data(), &out, sizeof(WebCommonReturnValue)); 198 std::move(decrypted_data), DECRYPTED_SHARED_FONTS[i]);
292 199
293 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::move(data))); 200 const auto temp_dir =
294 broker.SignalStateChanged(); 201 system.GetFilesystem()->CreateDirectory(fonts_dir, FileSys::Mode::ReadWrite);
202
203 const auto out_file = temp_dir->CreateFile(DECRYPTED_SHARED_FONTS[i]);
295 204
296 if (!temporary_dir.empty() && Common::FS::IsDirectory(temporary_dir)) { 205 FileSys::VfsRawCopy(decrypted_font, out_file);
297 Common::FS::DeleteDirRecursively(temporary_dir);
298 } 206 }
299} 207}
300 208
301void WebBrowser::InitializeInternal() { 209} // namespace
302 using WebAppletInitializer = void (WebBrowser::*)();
303 210
304 constexpr std::array<WebAppletInitializer, SHIM_KIND_COUNT> functions{ 211WebBrowser::WebBrowser(Core::System& system_, const Core::Frontend::WebBrowserApplet& frontend_)
305 nullptr, &WebBrowser::InitializeShop, 212 : Applet{system_.Kernel()}, frontend(frontend_), system{system_} {}
306 nullptr, &WebBrowser::InitializeOffline,
307 nullptr, nullptr,
308 nullptr, nullptr,
309 };
310 213
311 const auto index = static_cast<u32>(kind); 214WebBrowser::~WebBrowser() = default;
312 215
313 if (index > functions.size() || functions[index] == nullptr) { 216void WebBrowser::Initialize() {
314 LOG_ERROR(Service_AM, "Invalid shim_kind={:08X}", index); 217 Applet::Initialize();
315 return;
316 }
317 218
318 const auto function = functions[index]; 219 LOG_INFO(Service_AM, "Initializing Web Browser Applet.");
319 (this->*function)();
320}
321 220
322void WebBrowser::ExecuteInternal() { 221 LOG_DEBUG(Service_AM,
323 using WebAppletExecutor = void (WebBrowser::*)(); 222 "Initializing Applet with common_args: arg_version={}, lib_version={}, "
223 "play_startup_sound={}, size={}, system_tick={}, theme_color={}",
224 common_args.arguments_version, common_args.library_version,
225 common_args.play_startup_sound, common_args.size, common_args.system_tick,
226 common_args.theme_color);
324 227
325 constexpr std::array<WebAppletExecutor, SHIM_KIND_COUNT> functions{ 228 web_applet_version = WebAppletVersion{common_args.library_version};
326 nullptr, &WebBrowser::ExecuteShop,
327 nullptr, &WebBrowser::ExecuteOffline,
328 nullptr, nullptr,
329 nullptr, nullptr,
330 };
331 229
332 const auto index = static_cast<u32>(kind); 230 const auto web_arg_storage = broker.PopNormalDataToApplet();
231 ASSERT(web_arg_storage != nullptr);
333 232
334 if (index > functions.size() || functions[index] == nullptr) { 233 const auto& web_arg = web_arg_storage->GetData();
335 LOG_ERROR(Service_AM, "Invalid shim_kind={:08X}", index); 234 ASSERT_OR_EXECUTE(web_arg.size() >= sizeof(WebArgHeader), { return; });
336 return;
337 }
338 235
339 const auto function = functions[index]; 236 web_arg_input_tlv_map = ReadWebArgs(web_arg, web_arg_header);
340 (this->*function)();
341}
342 237
343void WebBrowser::InitializeShop() { 238 LOG_DEBUG(Service_AM, "WebArgHeader: total_tlv_entries={}, shim_kind={}",
344 if (frontend_e_commerce == nullptr) { 239 web_arg_header.total_tlv_entries, web_arg_header.shim_kind);
345 LOG_ERROR(Service_AM, "Missing ECommerce Applet frontend!");
346 status = RESULT_UNKNOWN;
347 return;
348 }
349 240
350 const auto user_id_data = args.find(WebArgTLVType::UserID); 241 ExtractSharedFonts(system);
351 242
352 user_id = std::nullopt; 243 switch (web_arg_header.shim_kind) {
353 if (user_id_data != args.end()) { 244 case ShimKind::Shop:
354 user_id = u128{}; 245 InitializeShop();
355 std::memcpy(user_id->data(), user_id_data->second.data(), sizeof(u128)); 246 break;
247 case ShimKind::Login:
248 InitializeLogin();
249 break;
250 case ShimKind::Offline:
251 InitializeOffline();
252 break;
253 case ShimKind::Share:
254 InitializeShare();
255 break;
256 case ShimKind::Web:
257 InitializeWeb();
258 break;
259 case ShimKind::Wifi:
260 InitializeWifi();
261 break;
262 case ShimKind::Lobby:
263 InitializeLobby();
264 break;
265 default:
266 UNREACHABLE_MSG("Invalid ShimKind={}", web_arg_header.shim_kind);
267 break;
356 } 268 }
269}
357 270
358 const auto url = args.find(WebArgTLVType::ShopArgumentsURL); 271bool WebBrowser::TransactionComplete() const {
272 return complete;
273}
359 274
360 if (url == args.end()) { 275ResultCode WebBrowser::GetStatus() const {
361 LOG_ERROR(Service_AM, "Missing EShop Arguments URL for initialization!"); 276 return status;
362 status = RESULT_UNKNOWN; 277}
363 return;
364 }
365 278
366 std::vector<std::string> split_query; 279void WebBrowser::ExecuteInteractive() {
367 Common::SplitString(Common::StringFromFixedZeroTerminatedBuffer( 280 UNIMPLEMENTED_MSG("WebSession is not implemented");
368 reinterpret_cast<const char*>(url->second.data()), url->second.size()), 281}
369 '?', split_query);
370
371 // 2 -> Main URL '?' Query Parameters
372 // Less is missing info, More is malformed
373 if (split_query.size() != 2) {
374 LOG_ERROR(Service_AM, "EShop Arguments has more than one question mark, malformed");
375 status = RESULT_UNKNOWN;
376 return;
377 }
378 282
379 std::vector<std::string> queries; 283void WebBrowser::Execute() {
380 Common::SplitString(split_query[1], '&', queries); 284 switch (web_arg_header.shim_kind) {
285 case ShimKind::Shop:
286 ExecuteShop();
287 break;
288 case ShimKind::Login:
289 ExecuteLogin();
290 break;
291 case ShimKind::Offline:
292 ExecuteOffline();
293 break;
294 case ShimKind::Share:
295 ExecuteShare();
296 break;
297 case ShimKind::Web:
298 ExecuteWeb();
299 break;
300 case ShimKind::Wifi:
301 ExecuteWifi();
302 break;
303 case ShimKind::Lobby:
304 ExecuteLobby();
305 break;
306 default:
307 UNREACHABLE_MSG("Invalid ShimKind={}", web_arg_header.shim_kind);
308 WebBrowserExit(WebExitReason::EndButtonPressed);
309 break;
310 }
311}
381 312
382 const auto split_single_query = 313void WebBrowser::ExtractOfflineRomFS() {
383 [](const std::string& in) -> std::pair<std::string, std::string> { 314 LOG_DEBUG(Service_AM, "Extracting RomFS to {}", offline_cache_dir);
384 const auto index = in.find('=');
385 if (index == std::string::npos || index == in.size() - 1) {
386 return {in, ""};
387 }
388 315
389 return {in.substr(0, index), in.substr(index + 1)}; 316 const auto extracted_romfs_dir =
390 }; 317 FileSys::ExtractRomFS(offline_romfs, FileSys::RomFSExtractionType::SingleDiscard);
391 318
392 std::transform(queries.begin(), queries.end(), 319 const auto temp_dir =
393 std::inserter(shop_query, std::next(shop_query.begin())), split_single_query); 320 system.GetFilesystem()->CreateDirectory(offline_cache_dir, FileSys::Mode::ReadWrite);
394 321
395 const auto scene = shop_query.find("scene"); 322 FileSys::VfsRawCopyD(extracted_romfs_dir, temp_dir);
323}
396 324
397 if (scene == shop_query.end()) { 325void WebBrowser::WebBrowserExit(WebExitReason exit_reason, std::string last_url) {
398 LOG_ERROR(Service_AM, "No scene parameter was passed via shop query!"); 326 if ((web_arg_header.shim_kind == ShimKind::Share &&
399 status = RESULT_UNKNOWN; 327 web_applet_version >= WebAppletVersion::Version196608) ||
400 return; 328 (web_arg_header.shim_kind == ShimKind::Web &&
329 web_applet_version >= WebAppletVersion::Version524288)) {
330 // TODO: Push Output TLVs instead of a WebCommonReturnValue
401 } 331 }
402 332
403 const std::map<std::string, ShopWebTarget, std::less<>> target_map{ 333 WebCommonReturnValue web_common_return_value;
404 {"product_detail", ShopWebTarget::ApplicationInfo},
405 {"aocs", ShopWebTarget::AddOnContentList},
406 {"subscriptions", ShopWebTarget::SubscriptionList},
407 {"consumption", ShopWebTarget::ConsumableItemList},
408 {"settings", ShopWebTarget::Settings},
409 {"top", ShopWebTarget::Home},
410 };
411 334
412 const auto target = target_map.find(scene->second); 335 web_common_return_value.exit_reason = exit_reason;
413 if (target == target_map.end()) { 336 std::memcpy(&web_common_return_value.last_url, last_url.data(), last_url.size());
414 LOG_ERROR(Service_AM, "Scene for shop query is invalid! (scene={})", scene->second); 337 web_common_return_value.last_url_size = last_url.size();
415 status = RESULT_UNKNOWN;
416 return;
417 }
418 338
419 shop_web_target = target->second; 339 LOG_DEBUG(Service_AM, "WebCommonReturnValue: exit_reason={}, last_url={}, last_url_size={}",
340 exit_reason, last_url, last_url.size());
420 341
421 const auto title_id_data = shop_query.find("dst_app_id"); 342 complete = true;
422 if (title_id_data != shop_query.end()) { 343 std::vector<u8> out_data(sizeof(WebCommonReturnValue));
423 title_id = std::stoull(title_id_data->second, nullptr, 0x10); 344 std::memcpy(out_data.data(), &web_common_return_value, out_data.size());
424 } 345 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data)));
346 broker.SignalStateChanged();
347}
425 348
426 const auto mode_data = shop_query.find("mode"); 349bool WebBrowser::InputTLVExistsInMap(WebArgInputTLVType input_tlv_type) const {
427 if (mode_data != shop_query.end()) { 350 return web_arg_input_tlv_map.find(input_tlv_type) != web_arg_input_tlv_map.end();
428 shop_full_display = mode_data->second == "full";
429 }
430} 351}
431 352
432void WebBrowser::InitializeOffline() { 353std::optional<std::vector<u8>> WebBrowser::GetInputTLVData(WebArgInputTLVType input_tlv_type) {
433 if (args.find(WebArgTLVType::DocumentPath) == args.end() || 354 const auto map_it = web_arg_input_tlv_map.find(input_tlv_type);
434 args.find(WebArgTLVType::DocumentKind) == args.end() || 355
435 args.find(WebArgTLVType::ApplicationID) == args.end()) { 356 if (map_it == web_arg_input_tlv_map.end()) {
436 status = RESULT_UNKNOWN; 357 return std::nullopt;
437 LOG_ERROR(Service_AM, "Missing necessary parameters for initialization!");
438 } 358 }
439 359
440 const auto url_data = args[WebArgTLVType::DocumentPath]; 360 return map_it->second;
441 filename = Common::StringFromFixedZeroTerminatedBuffer( 361}
442 reinterpret_cast<const char*>(url_data.data()), url_data.size());
443 362
444 OfflineWebSource source; 363void WebBrowser::InitializeShop() {}
445 ASSERT(args[WebArgTLVType::DocumentKind].size() >= 4);
446 std::memcpy(&source, args[WebArgTLVType::DocumentKind].data(), sizeof(OfflineWebSource));
447 364
448 constexpr std::array<const char*, 3> WEB_SOURCE_NAMES{ 365void WebBrowser::InitializeLogin() {}
449 "manual", 366
450 "legal", 367void WebBrowser::InitializeOffline() {
451 "system", 368 const auto document_path =
452 }; 369 ParseStringValue(GetInputTLVData(WebArgInputTLVType::DocumentPath).value());
370
371 const auto document_kind =
372 ParseRawValue<DocumentKind>(GetInputTLVData(WebArgInputTLVType::DocumentKind).value());
373
374 std::string additional_paths;
453 375
454 temporary_dir = 376 switch (document_kind) {
455 Common::FS::SanitizePath(Common::FS::GetUserPath(Common::FS::UserPath::CacheDir) + 377 case DocumentKind::OfflineHtmlPage:
456 "web_applet_" + WEB_SOURCE_NAMES[static_cast<u32>(source) - 1], 378 default:
457 Common::FS::DirectorySeparator::PlatformDefault); 379 title_id = system.CurrentProcess()->GetTitleID();
458 Common::FS::DeleteDirRecursively(temporary_dir); 380 nca_type = FileSys::ContentRecordType::HtmlDocument;
459 381 additional_paths = "html-document";
460 u64 title_id = 0; // 0 corresponds to current process
461 ASSERT(args[WebArgTLVType::ApplicationID].size() >= 0x8);
462 std::memcpy(&title_id, args[WebArgTLVType::ApplicationID].data(), sizeof(u64));
463 FileSys::ContentRecordType type = FileSys::ContentRecordType::Data;
464
465 switch (source) {
466 case OfflineWebSource::OfflineHtmlPage:
467 // While there is an AppID TLV field, in official SW this is always ignored.
468 title_id = 0;
469 type = FileSys::ContentRecordType::HtmlDocument;
470 break; 382 break;
471 case OfflineWebSource::ApplicationLegalInformation: 383 case DocumentKind::ApplicationLegalInformation:
472 type = FileSys::ContentRecordType::LegalInformation; 384 title_id = ParseRawValue<u64>(GetInputTLVData(WebArgInputTLVType::ApplicationID).value());
385 nca_type = FileSys::ContentRecordType::LegalInformation;
473 break; 386 break;
474 case OfflineWebSource::SystemDataPage: 387 case DocumentKind::SystemDataPage:
475 type = FileSys::ContentRecordType::Data; 388 title_id = ParseRawValue<u64>(GetInputTLVData(WebArgInputTLVType::SystemDataID).value());
389 nca_type = FileSys::ContentRecordType::Data;
476 break; 390 break;
477 } 391 }
478 392
479 if (title_id == 0) { 393 static constexpr std::array<const char*, 3> RESOURCE_TYPES{
480 title_id = system.CurrentProcess()->GetTitleID(); 394 "manual",
481 } 395 "legal_information",
396 "system_data",
397 };
482 398
483 offline_romfs = GetApplicationRomFS(system, title_id, type); 399 offline_cache_dir = Common::FS::SanitizePath(
484 if (offline_romfs == nullptr) { 400 fmt::format("{}/offline_web_applet_{}/{:016X}",
485 status = RESULT_UNKNOWN; 401 Common::FS::GetUserPath(Common::FS::UserPath::CacheDir),
486 LOG_ERROR(Service_AM, "Failed to find offline data for request!"); 402 RESOURCE_TYPES[static_cast<u32>(document_kind) - 1], title_id),
487 } 403 Common::FS::DirectorySeparator::PlatformDefault);
488 404
489 std::string path_additional_directory; 405 offline_document = Common::FS::SanitizePath(
490 if (source == OfflineWebSource::OfflineHtmlPage) { 406 fmt::format("{}/{}/{}", offline_cache_dir, additional_paths, document_path),
491 path_additional_directory = std::string(DIR_SEP).append("html-document"); 407 Common::FS::DirectorySeparator::PlatformDefault);
492 } 408}
409
410void WebBrowser::InitializeShare() {}
493 411
494 filename = 412void WebBrowser::InitializeWeb() {
495 Common::FS::SanitizePath(temporary_dir + path_additional_directory + DIR_SEP + filename, 413 external_url = ParseStringValue(GetInputTLVData(WebArgInputTLVType::InitialURL).value());
496 Common::FS::DirectorySeparator::PlatformDefault);
497} 414}
498 415
416void WebBrowser::InitializeWifi() {}
417
418void WebBrowser::InitializeLobby() {}
419
499void WebBrowser::ExecuteShop() { 420void WebBrowser::ExecuteShop() {
500 const auto callback = [this]() { Finalize(); }; 421 LOG_WARNING(Service_AM, "(STUBBED) called, Shop Applet is not implemented");
422 WebBrowserExit(WebExitReason::EndButtonPressed);
423}
501 424
502 const auto check_optional_parameter = [this](const auto& p) { 425void WebBrowser::ExecuteLogin() {
503 if (!p.has_value()) { 426 LOG_WARNING(Service_AM, "(STUBBED) called, Login Applet is not implemented");
504 LOG_ERROR(Service_AM, "Missing one or more necessary parameters for execution!"); 427 WebBrowserExit(WebExitReason::EndButtonPressed);
505 status = RESULT_UNKNOWN; 428}
506 return false;
507 }
508 429
509 return true; 430void WebBrowser::ExecuteOffline() {
510 }; 431 const auto main_url = Common::FS::SanitizePath(GetMainURL(offline_document),
432 Common::FS::DirectorySeparator::PlatformDefault);
511 433
512 switch (shop_web_target) { 434 if (!Common::FS::Exists(main_url)) {
513 case ShopWebTarget::ApplicationInfo: 435 offline_romfs = GetOfflineRomFS(system, title_id, nca_type);
514 if (!check_optional_parameter(title_id)) 436
515 return; 437 if (offline_romfs == nullptr) {
516 frontend_e_commerce->ShowApplicationInformation(callback, *title_id, user_id, 438 LOG_ERROR(Service_AM,
517 shop_full_display, shop_extra_parameter); 439 "RomFS with title_id={:016X} and nca_type={} cannot be extracted!", title_id,
518 break; 440 nca_type);
519 case ShopWebTarget::AddOnContentList: 441 WebBrowserExit(WebExitReason::WindowClosed);
520 if (!check_optional_parameter(title_id))
521 return;
522 frontend_e_commerce->ShowAddOnContentList(callback, *title_id, user_id, shop_full_display);
523 break;
524 case ShopWebTarget::ConsumableItemList:
525 if (!check_optional_parameter(title_id))
526 return;
527 frontend_e_commerce->ShowConsumableItemList(callback, *title_id, user_id);
528 break;
529 case ShopWebTarget::Home:
530 if (!check_optional_parameter(user_id))
531 return;
532 if (!check_optional_parameter(shop_full_display))
533 return;
534 frontend_e_commerce->ShowShopHome(callback, *user_id, *shop_full_display);
535 break;
536 case ShopWebTarget::Settings:
537 if (!check_optional_parameter(user_id))
538 return;
539 if (!check_optional_parameter(shop_full_display))
540 return;
541 frontend_e_commerce->ShowSettings(callback, *user_id, *shop_full_display);
542 break;
543 case ShopWebTarget::SubscriptionList:
544 if (!check_optional_parameter(title_id))
545 return; 442 return;
546 frontend_e_commerce->ShowSubscriptionList(callback, *title_id, user_id); 443 }
547 break;
548 default:
549 UNREACHABLE();
550 } 444 }
445
446 LOG_INFO(Service_AM, "Opening offline document at {}", offline_document);
447
448 frontend.OpenLocalWebPage(
449 offline_document, [this] { ExtractOfflineRomFS(); },
450 [this](WebExitReason exit_reason, std::string last_url) {
451 WebBrowserExit(exit_reason, last_url);
452 });
551} 453}
552 454
553void WebBrowser::ExecuteOffline() { 455void WebBrowser::ExecuteShare() {
554 frontend.OpenPageLocal( 456 LOG_WARNING(Service_AM, "(STUBBED) called, Share Applet is not implemented");
555 filename, [this] { UnpackRomFS(); }, [this] { Finalize(); }); 457 WebBrowserExit(WebExitReason::EndButtonPressed);
458}
459
460void WebBrowser::ExecuteWeb() {
461 LOG_INFO(Service_AM, "Opening external URL at {}", external_url);
462
463 frontend.OpenExternalWebPage(external_url,
464 [this](WebExitReason exit_reason, std::string last_url) {
465 WebBrowserExit(exit_reason, last_url);
466 });
556} 467}
557 468
469void WebBrowser::ExecuteWifi() {
470 LOG_WARNING(Service_AM, "(STUBBED) called, Wifi Applet is not implemented");
471 WebBrowserExit(WebExitReason::EndButtonPressed);
472}
473
474void WebBrowser::ExecuteLobby() {
475 LOG_WARNING(Service_AM, "(STUBBED) called, Lobby Applet is not implemented");
476 WebBrowserExit(WebExitReason::EndButtonPressed);
477}
558} // namespace Service::AM::Applets 478} // namespace Service::AM::Applets
diff --git a/src/core/hle/service/am/applets/web_browser.h b/src/core/hle/service/am/applets/web_browser.h
index 8d4027411..04c274754 100644
--- a/src/core/hle/service/am/applets/web_browser.h
+++ b/src/core/hle/service/am/applets/web_browser.h
@@ -1,28 +1,31 @@
1// Copyright 2018 yuzu emulator team 1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
6 6
7#include <map> 7#include <optional>
8
9#include "common/common_funcs.h"
10#include "common/common_types.h"
8#include "core/file_sys/vfs_types.h" 11#include "core/file_sys/vfs_types.h"
9#include "core/hle/service/am/am.h" 12#include "core/hle/result.h"
10#include "core/hle/service/am/applets/applets.h" 13#include "core/hle/service/am/applets/applets.h"
14#include "core/hle/service/am/applets/web_types.h"
11 15
12namespace Core { 16namespace Core {
13class System; 17class System;
14} 18}
15 19
16namespace Service::AM::Applets { 20namespace FileSys {
21enum class ContentRecordType : u8;
22}
17 23
18enum class ShimKind : u32; 24namespace Service::AM::Applets {
19enum class ShopWebTarget;
20enum class WebArgTLVType : u16;
21 25
22class WebBrowser final : public Applet { 26class WebBrowser final : public Applet {
23public: 27public:
24 WebBrowser(Core::System& system_, Core::Frontend::WebBrowserApplet& frontend_, 28 WebBrowser(Core::System& system_, const Core::Frontend::WebBrowserApplet& frontend_);
25 Core::Frontend::ECommerceApplet* frontend_e_commerce_ = nullptr);
26 29
27 ~WebBrowser() override; 30 ~WebBrowser() override;
28 31
@@ -33,49 +36,50 @@ public:
33 void ExecuteInteractive() override; 36 void ExecuteInteractive() override;
34 void Execute() override; 37 void Execute() override;
35 38
36 // Callback to be fired when the frontend needs the manual RomFS unpacked to temporary 39 void ExtractOfflineRomFS();
37 // directory. This is a blocking call and may take a while as some manuals can be up to 100MB in
38 // size. Attempting to access files at filename before invocation is likely to not work.
39 void UnpackRomFS();
40 40
41 // Callback to be fired when the frontend is finished browsing. This will delete the temporary 41 void WebBrowserExit(WebExitReason exit_reason, std::string last_url = "");
42 // manual RomFS extracted files, so ensure this is only called at actual finalization.
43 void Finalize();
44 42
45private: 43private:
46 void InitializeInternal(); 44 bool InputTLVExistsInMap(WebArgInputTLVType input_tlv_type) const;
47 void ExecuteInternal();
48 45
49 // Specific initializers for the types of web applets 46 std::optional<std::vector<u8>> GetInputTLVData(WebArgInputTLVType input_tlv_type);
47
48 // Initializers for the various types of browser applets
50 void InitializeShop(); 49 void InitializeShop();
50 void InitializeLogin();
51 void InitializeOffline(); 51 void InitializeOffline();
52 void InitializeShare();
53 void InitializeWeb();
54 void InitializeWifi();
55 void InitializeLobby();
52 56
53 // Specific executors for the types of web applets 57 // Executors for the various types of browser applets
54 void ExecuteShop(); 58 void ExecuteShop();
59 void ExecuteLogin();
55 void ExecuteOffline(); 60 void ExecuteOffline();
61 void ExecuteShare();
62 void ExecuteWeb();
63 void ExecuteWifi();
64 void ExecuteLobby();
56 65
57 Core::Frontend::WebBrowserApplet& frontend; 66 const Core::Frontend::WebBrowserApplet& frontend;
58
59 // Extra frontends for specialized functions
60 Core::Frontend::ECommerceApplet* frontend_e_commerce;
61 67
62 bool complete = false; 68 bool complete{false};
63 bool unpacked = false; 69 ResultCode status{RESULT_SUCCESS};
64 ResultCode status = RESULT_SUCCESS;
65 70
66 ShimKind kind; 71 WebAppletVersion web_applet_version;
67 std::map<WebArgTLVType, std::vector<u8>> args; 72 WebExitReason web_exit_reason;
73 WebArgHeader web_arg_header;
74 WebArgInputTLVMap web_arg_input_tlv_map;
68 75
76 u64 title_id;
77 FileSys::ContentRecordType nca_type;
78 std::string offline_cache_dir;
79 std::string offline_document;
69 FileSys::VirtualFile offline_romfs; 80 FileSys::VirtualFile offline_romfs;
70 std::string temporary_dir; 81
71 std::string filename; 82 std::string external_url;
72
73 ShopWebTarget shop_web_target;
74 std::map<std::string, std::string, std::less<>> shop_query;
75 std::optional<u64> title_id = 0;
76 std::optional<u128> user_id;
77 std::optional<bool> shop_full_display;
78 std::string shop_extra_parameter;
79 83
80 Core::System& system; 84 Core::System& system;
81}; 85};
diff --git a/src/core/hle/service/am/applets/web_types.h b/src/core/hle/service/am/applets/web_types.h
new file mode 100644
index 000000000..419c2bf79
--- /dev/null
+++ b/src/core/hle/service/am/applets/web_types.h
@@ -0,0 +1,178 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <array>
8#include <unordered_map>
9#include <vector>
10
11#include "common/common_funcs.h"
12#include "common/common_types.h"
13#include "common/swap.h"
14
15namespace Service::AM::Applets {
16
17enum class WebAppletVersion : u32_le {
18 Version0 = 0x0, // Only used by WifiWebAuthApplet
19 Version131072 = 0x20000, // 1.0.0 - 2.3.0
20 Version196608 = 0x30000, // 3.0.0 - 4.1.0
21 Version327680 = 0x50000, // 5.0.0 - 5.1.0
22 Version393216 = 0x60000, // 6.0.0 - 7.0.1
23 Version524288 = 0x80000, // 8.0.0+
24};
25
26enum class ShimKind : u32 {
27 Shop = 1,
28 Login = 2,
29 Offline = 3,
30 Share = 4,
31 Web = 5,
32 Wifi = 6,
33 Lobby = 7,
34};
35
36enum class WebExitReason : u32 {
37 EndButtonPressed = 0,
38 BackButtonPressed = 1,
39 ExitRequested = 2,
40 CallbackURL = 3,
41 WindowClosed = 4,
42 ErrorDialog = 7,
43};
44
45enum class WebArgInputTLVType : u16 {
46 InitialURL = 0x1,
47 CallbackURL = 0x3,
48 CallbackableURL = 0x4,
49 ApplicationID = 0x5,
50 DocumentPath = 0x6,
51 DocumentKind = 0x7,
52 SystemDataID = 0x8,
53 ShareStartPage = 0x9,
54 Whitelist = 0xA,
55 News = 0xB,
56 UserID = 0xE,
57 AlbumEntry0 = 0xF,
58 ScreenShotEnabled = 0x10,
59 EcClientCertEnabled = 0x11,
60 PlayReportEnabled = 0x13,
61 BootDisplayKind = 0x17,
62 BackgroundKind = 0x18,
63 FooterEnabled = 0x19,
64 PointerEnabled = 0x1A,
65 LeftStickMode = 0x1B,
66 KeyRepeatFrame1 = 0x1C,
67 KeyRepeatFrame2 = 0x1D,
68 BootAsMediaPlayerInverted = 0x1E,
69 DisplayURLKind = 0x1F,
70 BootAsMediaPlayer = 0x21,
71 ShopJumpEnabled = 0x22,
72 MediaAutoPlayEnabled = 0x23,
73 LobbyParameter = 0x24,
74 ApplicationAlbumEntry = 0x26,
75 JsExtensionEnabled = 0x27,
76 AdditionalCommentText = 0x28,
77 TouchEnabledOnContents = 0x29,
78 UserAgentAdditionalString = 0x2A,
79 AdditionalMediaData0 = 0x2B,
80 MediaPlayerAutoCloseEnabled = 0x2C,
81 PageCacheEnabled = 0x2D,
82 WebAudioEnabled = 0x2E,
83 YouTubeVideoWhitelist = 0x31,
84 FooterFixedKind = 0x32,
85 PageFadeEnabled = 0x33,
86 MediaCreatorApplicationRatingAge = 0x34,
87 BootLoadingIconEnabled = 0x35,
88 PageScrollIndicatorEnabled = 0x36,
89 MediaPlayerSpeedControlEnabled = 0x37,
90 AlbumEntry1 = 0x38,
91 AlbumEntry2 = 0x39,
92 AlbumEntry3 = 0x3A,
93 AdditionalMediaData1 = 0x3B,
94 AdditionalMediaData2 = 0x3C,
95 AdditionalMediaData3 = 0x3D,
96 BootFooterButton = 0x3E,
97 OverrideWebAudioVolume = 0x3F,
98 OverrideMediaAudioVolume = 0x40,
99 BootMode = 0x41,
100 WebSessionEnabled = 0x42,
101 MediaPlayerOfflineEnabled = 0x43,
102};
103
104enum class WebArgOutputTLVType : u16 {
105 ShareExitReason = 0x1,
106 LastURL = 0x2,
107 LastURLSize = 0x3,
108 SharePostResult = 0x4,
109 PostServiceName = 0x5,
110 PostServiceNameSize = 0x6,
111 PostID = 0x7,
112 PostIDSize = 0x8,
113 MediaPlayerAutoClosedByCompletion = 0x9,
114};
115
116enum class DocumentKind : u32 {
117 OfflineHtmlPage = 1,
118 ApplicationLegalInformation = 2,
119 SystemDataPage = 3,
120};
121
122enum class ShareStartPage : u32 {
123 Default,
124 Settings,
125};
126
127enum class BootDisplayKind : u32 {
128 Default,
129 White,
130 Black,
131};
132
133enum class BackgroundKind : u32 {
134 Default,
135};
136
137enum class LeftStickMode : u32 {
138 Pointer,
139 Cursor,
140};
141
142enum class WebSessionBootMode : u32 {
143 AllForeground,
144 AllForegroundInitiallyHidden,
145};
146
147struct WebArgHeader {
148 u16 total_tlv_entries{};
149 INSERT_PADDING_BYTES(2);
150 ShimKind shim_kind{};
151};
152static_assert(sizeof(WebArgHeader) == 0x8, "WebArgHeader has incorrect size.");
153
154struct WebArgInputTLV {
155 WebArgInputTLVType input_tlv_type{};
156 u16 arg_data_size{};
157 INSERT_PADDING_WORDS(1);
158};
159static_assert(sizeof(WebArgInputTLV) == 0x8, "WebArgInputTLV has incorrect size.");
160
161struct WebArgOutputTLV {
162 WebArgOutputTLVType output_tlv_type{};
163 u16 arg_data_size{};
164 INSERT_PADDING_WORDS(1);
165};
166static_assert(sizeof(WebArgOutputTLV) == 0x8, "WebArgOutputTLV has incorrect size.");
167
168struct WebCommonReturnValue {
169 WebExitReason exit_reason{};
170 INSERT_PADDING_WORDS(1);
171 std::array<char, 0x1000> last_url{};
172 u64 last_url_size{};
173};
174static_assert(sizeof(WebCommonReturnValue) == 0x1010, "WebCommonReturnValue has incorrect size.");
175
176using WebArgInputTLVMap = std::unordered_map<WebArgInputTLVType, std::vector<u8>>;
177
178} // namespace Service::AM::Applets
diff --git a/src/core/hle/service/am/idle.cpp b/src/core/hle/service/am/idle.cpp
index d256d57c8..6196773d5 100644
--- a/src/core/hle/service/am/idle.cpp
+++ b/src/core/hle/service/am/idle.cpp
@@ -6,7 +6,7 @@
6 6
7namespace Service::AM { 7namespace Service::AM {
8 8
9IdleSys::IdleSys() : ServiceFramework{"idle:sys"} { 9IdleSys::IdleSys(Core::System& system_) : ServiceFramework{system_, "idle:sys"} {
10 // clang-format off 10 // clang-format off
11 static const FunctionInfo functions[] = { 11 static const FunctionInfo functions[] = {
12 {0, nullptr, "GetAutoPowerDownEvent"}, 12 {0, nullptr, "GetAutoPowerDownEvent"},
diff --git a/src/core/hle/service/am/idle.h b/src/core/hle/service/am/idle.h
index c44e856b1..e290c30b1 100644
--- a/src/core/hle/service/am/idle.h
+++ b/src/core/hle/service/am/idle.h
@@ -6,11 +6,15 @@
6 6
7#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
8 8
9namespace Core {
10class System;
11}
12
9namespace Service::AM { 13namespace Service::AM {
10 14
11class IdleSys final : public ServiceFramework<IdleSys> { 15class IdleSys final : public ServiceFramework<IdleSys> {
12public: 16public:
13 explicit IdleSys(); 17 explicit IdleSys(Core::System& system_);
14 ~IdleSys() override; 18 ~IdleSys() override;
15}; 19};
16 20
diff --git a/src/core/hle/service/am/omm.cpp b/src/core/hle/service/am/omm.cpp
index 37389ccda..55de67e1d 100644
--- a/src/core/hle/service/am/omm.cpp
+++ b/src/core/hle/service/am/omm.cpp
@@ -6,7 +6,7 @@
6 6
7namespace Service::AM { 7namespace Service::AM {
8 8
9OMM::OMM() : ServiceFramework{"omm"} { 9OMM::OMM(Core::System& system_) : ServiceFramework{system_, "omm"} {
10 // clang-format off 10 // clang-format off
11 static const FunctionInfo functions[] = { 11 static const FunctionInfo functions[] = {
12 {0, nullptr, "GetOperationMode"}, 12 {0, nullptr, "GetOperationMode"},
diff --git a/src/core/hle/service/am/omm.h b/src/core/hle/service/am/omm.h
index 59dc91b72..3766150fe 100644
--- a/src/core/hle/service/am/omm.h
+++ b/src/core/hle/service/am/omm.h
@@ -6,11 +6,15 @@
6 6
7#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
8 8
9namespace Core {
10class System;
11}
12
9namespace Service::AM { 13namespace Service::AM {
10 14
11class OMM final : public ServiceFramework<OMM> { 15class OMM final : public ServiceFramework<OMM> {
12public: 16public:
13 explicit OMM(); 17 explicit OMM(Core::System& system_);
14 ~OMM() override; 18 ~OMM() override;
15}; 19};
16 20
diff --git a/src/core/hle/service/am/spsm.cpp b/src/core/hle/service/am/spsm.cpp
index f27729ce7..95218d9ee 100644
--- a/src/core/hle/service/am/spsm.cpp
+++ b/src/core/hle/service/am/spsm.cpp
@@ -6,7 +6,7 @@
6 6
7namespace Service::AM { 7namespace Service::AM {
8 8
9SPSM::SPSM() : ServiceFramework{"spsm"} { 9SPSM::SPSM(Core::System& system_) : ServiceFramework{system_, "spsm"} {
10 // clang-format off 10 // clang-format off
11 static const FunctionInfo functions[] = { 11 static const FunctionInfo functions[] = {
12 {0, nullptr, "GetState"}, 12 {0, nullptr, "GetState"},
diff --git a/src/core/hle/service/am/spsm.h b/src/core/hle/service/am/spsm.h
index 3a0b979fa..04bbf9e68 100644
--- a/src/core/hle/service/am/spsm.h
+++ b/src/core/hle/service/am/spsm.h
@@ -6,11 +6,15 @@
6 6
7#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
8 8
9namespace Core {
10class System;
11}
12
9namespace Service::AM { 13namespace Service::AM {
10 14
11class SPSM final : public ServiceFramework<SPSM> { 15class SPSM final : public ServiceFramework<SPSM> {
12public: 16public:
13 explicit SPSM(); 17 explicit SPSM(Core::System& system_);
14 ~SPSM() override; 18 ~SPSM() override;
15}; 19};
16 20
diff --git a/src/core/hle/service/am/tcap.cpp b/src/core/hle/service/am/tcap.cpp
index a75cbdda8..4d0971c03 100644
--- a/src/core/hle/service/am/tcap.cpp
+++ b/src/core/hle/service/am/tcap.cpp
@@ -6,7 +6,7 @@
6 6
7namespace Service::AM { 7namespace Service::AM {
8 8
9TCAP::TCAP() : ServiceFramework{"tcap"} { 9TCAP::TCAP(Core::System& system_) : ServiceFramework{system_, "tcap"} {
10 // clang-format off 10 // clang-format off
11 static const FunctionInfo functions[] = { 11 static const FunctionInfo functions[] = {
12 {0, nullptr, "GetContinuousHighSkinTemperatureEvent"}, 12 {0, nullptr, "GetContinuousHighSkinTemperatureEvent"},
diff --git a/src/core/hle/service/am/tcap.h b/src/core/hle/service/am/tcap.h
index 2021b55d1..e9578f16e 100644
--- a/src/core/hle/service/am/tcap.h
+++ b/src/core/hle/service/am/tcap.h
@@ -6,11 +6,15 @@
6 6
7#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
8 8
9namespace Core {
10class System;
11}
12
9namespace Service::AM { 13namespace Service::AM {
10 14
11class TCAP final : public ServiceFramework<TCAP> { 15class TCAP final : public ServiceFramework<TCAP> {
12public: 16public:
13 explicit TCAP(); 17 explicit TCAP(Core::System& system_);
14 ~TCAP() override; 18 ~TCAP() override;
15}; 19};
16 20
diff --git a/src/core/hle/service/aoc/aoc_u.cpp b/src/core/hle/service/aoc/aoc_u.cpp
index 8e79f707b..23e28565b 100644
--- a/src/core/hle/service/aoc/aoc_u.cpp
+++ b/src/core/hle/service/aoc/aoc_u.cpp
@@ -6,6 +6,8 @@
6#include <numeric> 6#include <numeric>
7#include <vector> 7#include <vector>
8#include "common/logging/log.h" 8#include "common/logging/log.h"
9#include "core/core.h"
10#include "core/file_sys/common_funcs.h"
9#include "core/file_sys/content_archive.h" 11#include "core/file_sys/content_archive.h"
10#include "core/file_sys/control_metadata.h" 12#include "core/file_sys/control_metadata.h"
11#include "core/file_sys/nca_metadata.h" 13#include "core/file_sys/nca_metadata.h"
@@ -22,11 +24,8 @@
22 24
23namespace Service::AOC { 25namespace Service::AOC {
24 26
25constexpr u64 DLC_BASE_TITLE_ID_MASK = 0xFFFFFFFFFFFFE000;
26constexpr u64 DLC_BASE_TO_AOC_ID = 0x1000;
27
28static bool CheckAOCTitleIDMatchesBase(u64 title_id, u64 base) { 27static bool CheckAOCTitleIDMatchesBase(u64 title_id, u64 base) {
29 return (title_id & DLC_BASE_TITLE_ID_MASK) == base; 28 return FileSys::GetBaseTitleID(title_id) == base;
30} 29}
31 30
32static std::vector<u64> AccumulateAOCTitleIDs(Core::System& system) { 31static std::vector<u64> AccumulateAOCTitleIDs(Core::System& system) {
@@ -47,8 +46,64 @@ static std::vector<u64> AccumulateAOCTitleIDs(Core::System& system) {
47 return add_on_content; 46 return add_on_content;
48} 47}
49 48
50AOC_U::AOC_U(Core::System& system) 49class IPurchaseEventManager final : public ServiceFramework<IPurchaseEventManager> {
51 : ServiceFramework("aoc:u"), add_on_content(AccumulateAOCTitleIDs(system)), system(system) { 50public:
51 explicit IPurchaseEventManager(Core::System& system_)
52 : ServiceFramework{system_, "IPurchaseEventManager"} {
53 // clang-format off
54 static const FunctionInfo functions[] = {
55 {0, &IPurchaseEventManager::SetDefaultDeliveryTarget, "SetDefaultDeliveryTarget"},
56 {1, &IPurchaseEventManager::SetDeliveryTarget, "SetDeliveryTarget"},
57 {2, &IPurchaseEventManager::GetPurchasedEventReadableHandle, "GetPurchasedEventReadableHandle"},
58 {3, nullptr, "PopPurchasedProductInfo"},
59 {4, nullptr, "PopPurchasedProductInfoWithUid"},
60 };
61 // clang-format on
62
63 RegisterHandlers(functions);
64
65 purchased_event = Kernel::WritableEvent::CreateEventPair(
66 system.Kernel(), "IPurchaseEventManager:PurchasedEvent");
67 }
68
69private:
70 void SetDefaultDeliveryTarget(Kernel::HLERequestContext& ctx) {
71 IPC::RequestParser rp{ctx};
72
73 const auto unknown_1 = rp.Pop<u64>();
74 [[maybe_unused]] const auto unknown_2 = ctx.ReadBuffer();
75
76 LOG_WARNING(Service_AOC, "(STUBBED) called, unknown_1={}", unknown_1);
77
78 IPC::ResponseBuilder rb{ctx, 2};
79 rb.Push(RESULT_SUCCESS);
80 }
81
82 void SetDeliveryTarget(Kernel::HLERequestContext& ctx) {
83 IPC::RequestParser rp{ctx};
84
85 const auto unknown_1 = rp.Pop<u64>();
86 [[maybe_unused]] const auto unknown_2 = ctx.ReadBuffer();
87
88 LOG_WARNING(Service_AOC, "(STUBBED) called, unknown_1={}", unknown_1);
89
90 IPC::ResponseBuilder rb{ctx, 2};
91 rb.Push(RESULT_SUCCESS);
92 }
93
94 void GetPurchasedEventReadableHandle(Kernel::HLERequestContext& ctx) {
95 LOG_WARNING(Service_AOC, "called");
96
97 IPC::ResponseBuilder rb{ctx, 2, 1};
98 rb.Push(RESULT_SUCCESS);
99 rb.PushCopyObjects(purchased_event.readable);
100 }
101
102 Kernel::EventPair purchased_event;
103};
104
105AOC_U::AOC_U(Core::System& system_)
106 : ServiceFramework{system_, "aoc:u"}, add_on_content{AccumulateAOCTitleIDs(system)} {
52 // clang-format off 107 // clang-format off
53 static const FunctionInfo functions[] = { 108 static const FunctionInfo functions[] = {
54 {0, nullptr, "CountAddOnContentByApplicationId"}, 109 {0, nullptr, "CountAddOnContentByApplicationId"},
@@ -61,8 +116,8 @@ AOC_U::AOC_U(Core::System& system)
61 {7, &AOC_U::PrepareAddOnContent, "PrepareAddOnContent"}, 116 {7, &AOC_U::PrepareAddOnContent, "PrepareAddOnContent"},
62 {8, &AOC_U::GetAddOnContentListChangedEvent, "GetAddOnContentListChangedEvent"}, 117 {8, &AOC_U::GetAddOnContentListChangedEvent, "GetAddOnContentListChangedEvent"},
63 {9, nullptr, "GetAddOnContentLostErrorCode"}, 118 {9, nullptr, "GetAddOnContentLostErrorCode"},
64 {100, nullptr, "CreateEcPurchasedEventManager"}, 119 {100, &AOC_U::CreateEcPurchasedEventManager, "CreateEcPurchasedEventManager"},
65 {101, nullptr, "CreatePermanentEcPurchasedEventManager"}, 120 {101, &AOC_U::CreatePermanentEcPurchasedEventManager, "CreatePermanentEcPurchasedEventManager"},
66 }; 121 };
67 // clang-format on 122 // clang-format on
68 123
@@ -122,11 +177,11 @@ void AOC_U::ListAddOnContent(Kernel::HLERequestContext& ctx) {
122 const auto& disabled = Settings::values.disabled_addons[current]; 177 const auto& disabled = Settings::values.disabled_addons[current];
123 if (std::find(disabled.begin(), disabled.end(), "DLC") == disabled.end()) { 178 if (std::find(disabled.begin(), disabled.end(), "DLC") == disabled.end()) {
124 for (u64 content_id : add_on_content) { 179 for (u64 content_id : add_on_content) {
125 if ((content_id & DLC_BASE_TITLE_ID_MASK) != current) { 180 if (FileSys::GetBaseTitleID(content_id) != current) {
126 continue; 181 continue;
127 } 182 }
128 183
129 out.push_back(static_cast<u32>(content_id & 0x7FF)); 184 out.push_back(static_cast<u32>(FileSys::GetAOCID(content_id)));
130 } 185 }
131 } 186 }
132 187
@@ -163,11 +218,12 @@ void AOC_U::GetAddOnContentBaseId(Kernel::HLERequestContext& ctx) {
163 rb.Push(RESULT_SUCCESS); 218 rb.Push(RESULT_SUCCESS);
164 219
165 const auto title_id = system.CurrentProcess()->GetTitleID(); 220 const auto title_id = system.CurrentProcess()->GetTitleID();
166 FileSys::PatchManager pm{title_id}; 221 const FileSys::PatchManager pm{title_id, system.GetFileSystemController(),
222 system.GetContentProvider()};
167 223
168 const auto res = pm.GetControlMetadata(); 224 const auto res = pm.GetControlMetadata();
169 if (res.first == nullptr) { 225 if (res.first == nullptr) {
170 rb.Push(title_id + DLC_BASE_TO_AOC_ID); 226 rb.Push(FileSys::GetAOCBaseTitleID(title_id));
171 return; 227 return;
172 } 228 }
173 229
@@ -199,6 +255,22 @@ void AOC_U::GetAddOnContentListChangedEvent(Kernel::HLERequestContext& ctx) {
199 rb.PushCopyObjects(aoc_change_event.readable); 255 rb.PushCopyObjects(aoc_change_event.readable);
200} 256}
201 257
258void AOC_U::CreateEcPurchasedEventManager(Kernel::HLERequestContext& ctx) {
259 LOG_WARNING(Service_AOC, "(STUBBED) called");
260
261 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
262 rb.Push(RESULT_SUCCESS);
263 rb.PushIpcInterface<IPurchaseEventManager>(system);
264}
265
266void AOC_U::CreatePermanentEcPurchasedEventManager(Kernel::HLERequestContext& ctx) {
267 LOG_WARNING(Service_AOC, "(STUBBED) called");
268
269 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
270 rb.Push(RESULT_SUCCESS);
271 rb.PushIpcInterface<IPurchaseEventManager>(system);
272}
273
202void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { 274void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
203 std::make_shared<AOC_U>(system)->InstallAsService(service_manager); 275 std::make_shared<AOC_U>(system)->InstallAsService(service_manager);
204} 276}
diff --git a/src/core/hle/service/aoc/aoc_u.h b/src/core/hle/service/aoc/aoc_u.h
index 848b2f416..26ee51be0 100644
--- a/src/core/hle/service/aoc/aoc_u.h
+++ b/src/core/hle/service/aoc/aoc_u.h
@@ -6,6 +6,10 @@
6 6
7#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
8 8
9namespace Core {
10class System;
11}
12
9namespace Kernel { 13namespace Kernel {
10class WritableEvent; 14class WritableEvent;
11} 15}
@@ -23,10 +27,11 @@ private:
23 void GetAddOnContentBaseId(Kernel::HLERequestContext& ctx); 27 void GetAddOnContentBaseId(Kernel::HLERequestContext& ctx);
24 void PrepareAddOnContent(Kernel::HLERequestContext& ctx); 28 void PrepareAddOnContent(Kernel::HLERequestContext& ctx);
25 void GetAddOnContentListChangedEvent(Kernel::HLERequestContext& ctx); 29 void GetAddOnContentListChangedEvent(Kernel::HLERequestContext& ctx);
30 void CreateEcPurchasedEventManager(Kernel::HLERequestContext& ctx);
31 void CreatePermanentEcPurchasedEventManager(Kernel::HLERequestContext& ctx);
26 32
27 std::vector<u64> add_on_content; 33 std::vector<u64> add_on_content;
28 Kernel::EventPair aoc_change_event; 34 Kernel::EventPair aoc_change_event;
29 Core::System& system;
30}; 35};
31 36
32/// Registers all AOC services with the specified service manager. 37/// Registers all AOC services with the specified service manager.
diff --git a/src/core/hle/service/apm/apm.cpp b/src/core/hle/service/apm/apm.cpp
index 85bbf5988..97d6619dd 100644
--- a/src/core/hle/service/apm/apm.cpp
+++ b/src/core/hle/service/apm/apm.cpp
@@ -2,6 +2,7 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "core/core.h"
5#include "core/hle/ipc_helpers.h" 6#include "core/hle/ipc_helpers.h"
6#include "core/hle/service/apm/apm.h" 7#include "core/hle/service/apm/apm.h"
7#include "core/hle/service/apm/interface.h" 8#include "core/hle/service/apm/interface.h"
@@ -13,13 +14,14 @@ Module::~Module() = default;
13 14
14void InstallInterfaces(Core::System& system) { 15void InstallInterfaces(Core::System& system) {
15 auto module_ = std::make_shared<Module>(); 16 auto module_ = std::make_shared<Module>();
16 std::make_shared<APM>(module_, system.GetAPMController(), "apm") 17 std::make_shared<APM>(system, module_, system.GetAPMController(), "apm")
17 ->InstallAsService(system.ServiceManager()); 18 ->InstallAsService(system.ServiceManager());
18 std::make_shared<APM>(module_, system.GetAPMController(), "apm:p") 19 std::make_shared<APM>(system, module_, system.GetAPMController(), "apm:p")
19 ->InstallAsService(system.ServiceManager()); 20 ->InstallAsService(system.ServiceManager());
20 std::make_shared<APM>(module_, system.GetAPMController(), "apm:am") 21 std::make_shared<APM>(system, module_, system.GetAPMController(), "apm:am")
22 ->InstallAsService(system.ServiceManager());
23 std::make_shared<APM_Sys>(system, system.GetAPMController())
21 ->InstallAsService(system.ServiceManager()); 24 ->InstallAsService(system.ServiceManager());
22 std::make_shared<APM_Sys>(system.GetAPMController())->InstallAsService(system.ServiceManager());
23} 25}
24 26
25} // namespace Service::APM 27} // namespace Service::APM
diff --git a/src/core/hle/service/apm/apm.h b/src/core/hle/service/apm/apm.h
index cf4c2bb11..691fe6c16 100644
--- a/src/core/hle/service/apm/apm.h
+++ b/src/core/hle/service/apm/apm.h
@@ -4,7 +4,9 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "core/hle/service/service.h" 7namespace Core {
8class System;
9}
8 10
9namespace Service::APM { 11namespace Service::APM {
10 12
diff --git a/src/core/hle/service/apm/controller.cpp b/src/core/hle/service/apm/controller.cpp
index 25a886238..03636642b 100644
--- a/src/core/hle/service/apm/controller.cpp
+++ b/src/core/hle/service/apm/controller.cpp
@@ -48,8 +48,7 @@ void Controller::SetPerformanceConfiguration(PerformanceMode mode,
48 [config](const auto& entry) { return entry.first == config; }); 48 [config](const auto& entry) { return entry.first == config; });
49 49
50 if (iter == config_to_speed.cend()) { 50 if (iter == config_to_speed.cend()) {
51 LOG_ERROR(Service_APM, "Invalid performance configuration value provided: {}", 51 LOG_ERROR(Service_APM, "Invalid performance configuration value provided: {}", config);
52 static_cast<u32>(config));
53 return; 52 return;
54 } 53 }
55 54
@@ -69,7 +68,8 @@ void Controller::SetFromCpuBoostMode(CpuBoostMode mode) {
69} 68}
70 69
71PerformanceMode Controller::GetCurrentPerformanceMode() const { 70PerformanceMode Controller::GetCurrentPerformanceMode() const {
72 return Settings::values.use_docked_mode ? PerformanceMode::Docked : PerformanceMode::Handheld; 71 return Settings::values.use_docked_mode.GetValue() ? PerformanceMode::Docked
72 : PerformanceMode::Handheld;
73} 73}
74 74
75PerformanceConfiguration Controller::GetCurrentPerformanceConfiguration(PerformanceMode mode) { 75PerformanceConfiguration Controller::GetCurrentPerformanceConfiguration(PerformanceMode mode) {
diff --git a/src/core/hle/service/apm/interface.cpp b/src/core/hle/service/apm/interface.cpp
index 06f0f8edd..0bff97a37 100644
--- a/src/core/hle/service/apm/interface.cpp
+++ b/src/core/hle/service/apm/interface.cpp
@@ -12,7 +12,8 @@ namespace Service::APM {
12 12
13class ISession final : public ServiceFramework<ISession> { 13class ISession final : public ServiceFramework<ISession> {
14public: 14public:
15 ISession(Controller& controller) : ServiceFramework("ISession"), controller(controller) { 15 explicit ISession(Core::System& system_, Controller& controller_)
16 : ServiceFramework{system_, "ISession"}, controller{controller_} {
16 static const FunctionInfo functions[] = { 17 static const FunctionInfo functions[] = {
17 {0, &ISession::SetPerformanceConfiguration, "SetPerformanceConfiguration"}, 18 {0, &ISession::SetPerformanceConfiguration, "SetPerformanceConfiguration"},
18 {1, &ISession::GetPerformanceConfiguration, "GetPerformanceConfiguration"}, 19 {1, &ISession::GetPerformanceConfiguration, "GetPerformanceConfiguration"},
@@ -27,8 +28,7 @@ private:
27 28
28 const auto mode = rp.PopEnum<PerformanceMode>(); 29 const auto mode = rp.PopEnum<PerformanceMode>();
29 const auto config = rp.PopEnum<PerformanceConfiguration>(); 30 const auto config = rp.PopEnum<PerformanceConfiguration>();
30 LOG_DEBUG(Service_APM, "called mode={} config={}", static_cast<u32>(mode), 31 LOG_DEBUG(Service_APM, "called mode={} config={}", mode, config);
31 static_cast<u32>(config));
32 32
33 controller.SetPerformanceConfiguration(mode, config); 33 controller.SetPerformanceConfiguration(mode, config);
34 34
@@ -40,7 +40,7 @@ private:
40 IPC::RequestParser rp{ctx}; 40 IPC::RequestParser rp{ctx};
41 41
42 const auto mode = rp.PopEnum<PerformanceMode>(); 42 const auto mode = rp.PopEnum<PerformanceMode>();
43 LOG_DEBUG(Service_APM, "called mode={}", static_cast<u32>(mode)); 43 LOG_DEBUG(Service_APM, "called mode={}", mode);
44 44
45 IPC::ResponseBuilder rb{ctx, 3}; 45 IPC::ResponseBuilder rb{ctx, 3};
46 rb.Push(RESULT_SUCCESS); 46 rb.Push(RESULT_SUCCESS);
@@ -50,12 +50,13 @@ private:
50 Controller& controller; 50 Controller& controller;
51}; 51};
52 52
53APM::APM(std::shared_ptr<Module> apm, Controller& controller, const char* name) 53APM::APM(Core::System& system_, std::shared_ptr<Module> apm_, Controller& controller_,
54 : ServiceFramework(name), apm(std::move(apm)), controller(controller) { 54 const char* name)
55 : ServiceFramework{system_, name}, apm(std::move(apm_)), controller{controller_} {
55 static const FunctionInfo functions[] = { 56 static const FunctionInfo functions[] = {
56 {0, &APM::OpenSession, "OpenSession"}, 57 {0, &APM::OpenSession, "OpenSession"},
57 {1, &APM::GetPerformanceMode, "GetPerformanceMode"}, 58 {1, &APM::GetPerformanceMode, "GetPerformanceMode"},
58 {6, nullptr, "IsCpuOverclockEnabled"}, 59 {6, &APM::IsCpuOverclockEnabled, "IsCpuOverclockEnabled"},
59 }; 60 };
60 RegisterHandlers(functions); 61 RegisterHandlers(functions);
61} 62}
@@ -67,7 +68,7 @@ void APM::OpenSession(Kernel::HLERequestContext& ctx) {
67 68
68 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 69 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
69 rb.Push(RESULT_SUCCESS); 70 rb.Push(RESULT_SUCCESS);
70 rb.PushIpcInterface<ISession>(controller); 71 rb.PushIpcInterface<ISession>(system, controller);
71} 72}
72 73
73void APM::GetPerformanceMode(Kernel::HLERequestContext& ctx) { 74void APM::GetPerformanceMode(Kernel::HLERequestContext& ctx) {
@@ -77,7 +78,16 @@ void APM::GetPerformanceMode(Kernel::HLERequestContext& ctx) {
77 rb.PushEnum(controller.GetCurrentPerformanceMode()); 78 rb.PushEnum(controller.GetCurrentPerformanceMode());
78} 79}
79 80
80APM_Sys::APM_Sys(Controller& controller) : ServiceFramework{"apm:sys"}, controller(controller) { 81void APM::IsCpuOverclockEnabled(Kernel::HLERequestContext& ctx) {
82 LOG_WARNING(Service_APM, "(STUBBED) called");
83
84 IPC::ResponseBuilder rb{ctx, 3};
85 rb.Push(RESULT_SUCCESS);
86 rb.Push(false);
87}
88
89APM_Sys::APM_Sys(Core::System& system_, Controller& controller_)
90 : ServiceFramework{system_, "apm:sys"}, controller{controller_} {
81 // clang-format off 91 // clang-format off
82 static const FunctionInfo functions[] = { 92 static const FunctionInfo functions[] = {
83 {0, nullptr, "RequestPerformanceMode"}, 93 {0, nullptr, "RequestPerformanceMode"},
@@ -101,14 +111,14 @@ void APM_Sys::GetPerformanceEvent(Kernel::HLERequestContext& ctx) {
101 111
102 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 112 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
103 rb.Push(RESULT_SUCCESS); 113 rb.Push(RESULT_SUCCESS);
104 rb.PushIpcInterface<ISession>(controller); 114 rb.PushIpcInterface<ISession>(system, controller);
105} 115}
106 116
107void APM_Sys::SetCpuBoostMode(Kernel::HLERequestContext& ctx) { 117void APM_Sys::SetCpuBoostMode(Kernel::HLERequestContext& ctx) {
108 IPC::RequestParser rp{ctx}; 118 IPC::RequestParser rp{ctx};
109 const auto mode = rp.PopEnum<CpuBoostMode>(); 119 const auto mode = rp.PopEnum<CpuBoostMode>();
110 120
111 LOG_DEBUG(Service_APM, "called, mode={:08X}", static_cast<u32>(mode)); 121 LOG_DEBUG(Service_APM, "called, mode={:08X}", mode);
112 122
113 controller.SetFromCpuBoostMode(mode); 123 controller.SetFromCpuBoostMode(mode);
114 124
diff --git a/src/core/hle/service/apm/interface.h b/src/core/hle/service/apm/interface.h
index de1b89437..063ad5308 100644
--- a/src/core/hle/service/apm/interface.h
+++ b/src/core/hle/service/apm/interface.h
@@ -13,12 +13,14 @@ class Module;
13 13
14class APM final : public ServiceFramework<APM> { 14class APM final : public ServiceFramework<APM> {
15public: 15public:
16 explicit APM(std::shared_ptr<Module> apm, Controller& controller, const char* name); 16 explicit APM(Core::System& system_, std::shared_ptr<Module> apm_, Controller& controller_,
17 const char* name);
17 ~APM() override; 18 ~APM() override;
18 19
19private: 20private:
20 void OpenSession(Kernel::HLERequestContext& ctx); 21 void OpenSession(Kernel::HLERequestContext& ctx);
21 void GetPerformanceMode(Kernel::HLERequestContext& ctx); 22 void GetPerformanceMode(Kernel::HLERequestContext& ctx);
23 void IsCpuOverclockEnabled(Kernel::HLERequestContext& ctx);
22 24
23 std::shared_ptr<Module> apm; 25 std::shared_ptr<Module> apm;
24 Controller& controller; 26 Controller& controller;
@@ -26,7 +28,7 @@ private:
26 28
27class APM_Sys final : public ServiceFramework<APM_Sys> { 29class APM_Sys final : public ServiceFramework<APM_Sys> {
28public: 30public:
29 explicit APM_Sys(Controller& controller); 31 explicit APM_Sys(Core::System& system_, Controller& controller);
30 ~APM_Sys() override; 32 ~APM_Sys() override;
31 33
32 void SetCpuBoostMode(Kernel::HLERequestContext& ctx); 34 void SetCpuBoostMode(Kernel::HLERequestContext& ctx);
diff --git a/src/core/hle/service/audio/audctl.cpp b/src/core/hle/service/audio/audctl.cpp
index 6ddb547fb..84890be72 100644
--- a/src/core/hle/service/audio/audctl.cpp
+++ b/src/core/hle/service/audio/audctl.cpp
@@ -8,7 +8,7 @@
8 8
9namespace Service::Audio { 9namespace Service::Audio {
10 10
11AudCtl::AudCtl() : ServiceFramework{"audctl"} { 11AudCtl::AudCtl(Core::System& system_) : ServiceFramework{system_, "audctl"} {
12 // clang-format off 12 // clang-format off
13 static const FunctionInfo functions[] = { 13 static const FunctionInfo functions[] = {
14 {0, nullptr, "GetTargetVolume"}, 14 {0, nullptr, "GetTargetVolume"},
diff --git a/src/core/hle/service/audio/audctl.h b/src/core/hle/service/audio/audctl.h
index c7fafc02e..15f6c77a0 100644
--- a/src/core/hle/service/audio/audctl.h
+++ b/src/core/hle/service/audio/audctl.h
@@ -6,11 +6,15 @@
6 6
7#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
8 8
9namespace Core {
10class System;
11}
12
9namespace Service::Audio { 13namespace Service::Audio {
10 14
11class AudCtl final : public ServiceFramework<AudCtl> { 15class AudCtl final : public ServiceFramework<AudCtl> {
12public: 16public:
13 explicit AudCtl(); 17 explicit AudCtl(Core::System& system_);
14 ~AudCtl() override; 18 ~AudCtl() override;
15 19
16private: 20private:
diff --git a/src/core/hle/service/audio/auddbg.cpp b/src/core/hle/service/audio/auddbg.cpp
index 8fff3e4b4..6264e4bda 100644
--- a/src/core/hle/service/audio/auddbg.cpp
+++ b/src/core/hle/service/audio/auddbg.cpp
@@ -6,7 +6,7 @@
6 6
7namespace Service::Audio { 7namespace Service::Audio {
8 8
9AudDbg::AudDbg(const char* name) : ServiceFramework{name} { 9AudDbg::AudDbg(Core::System& system_, const char* name) : ServiceFramework{system_, name} {
10 // clang-format off 10 // clang-format off
11 static const FunctionInfo functions[] = { 11 static const FunctionInfo functions[] = {
12 {0, nullptr, "RequestSuspendForDebug"}, 12 {0, nullptr, "RequestSuspendForDebug"},
diff --git a/src/core/hle/service/audio/auddbg.h b/src/core/hle/service/audio/auddbg.h
index 6689f4759..d1653eedd 100644
--- a/src/core/hle/service/audio/auddbg.h
+++ b/src/core/hle/service/audio/auddbg.h
@@ -6,11 +6,15 @@
6 6
7#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
8 8
9namespace Core {
10class System;
11}
12
9namespace Service::Audio { 13namespace Service::Audio {
10 14
11class AudDbg final : public ServiceFramework<AudDbg> { 15class AudDbg final : public ServiceFramework<AudDbg> {
12public: 16public:
13 explicit AudDbg(const char* name); 17 explicit AudDbg(Core::System& system_, const char* name);
14 ~AudDbg() override; 18 ~AudDbg() override;
15}; 19};
16 20
diff --git a/src/core/hle/service/audio/audin_a.cpp b/src/core/hle/service/audio/audin_a.cpp
index ddd12f35e..79c3aa920 100644
--- a/src/core/hle/service/audio/audin_a.cpp
+++ b/src/core/hle/service/audio/audin_a.cpp
@@ -6,7 +6,7 @@
6 6
7namespace Service::Audio { 7namespace Service::Audio {
8 8
9AudInA::AudInA() : ServiceFramework{"audin:a"} { 9AudInA::AudInA(Core::System& system_) : ServiceFramework{system_, "audin:a"} {
10 // clang-format off 10 // clang-format off
11 static const FunctionInfo functions[] = { 11 static const FunctionInfo functions[] = {
12 {0, nullptr, "RequestSuspendAudioIns"}, 12 {0, nullptr, "RequestSuspendAudioIns"},
diff --git a/src/core/hle/service/audio/audin_a.h b/src/core/hle/service/audio/audin_a.h
index e7623bc29..15120a4b6 100644
--- a/src/core/hle/service/audio/audin_a.h
+++ b/src/core/hle/service/audio/audin_a.h
@@ -6,11 +6,15 @@
6 6
7#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
8 8
9namespace Core {
10class System;
11}
12
9namespace Service::Audio { 13namespace Service::Audio {
10 14
11class AudInA final : public ServiceFramework<AudInA> { 15class AudInA final : public ServiceFramework<AudInA> {
12public: 16public:
13 explicit AudInA(); 17 explicit AudInA(Core::System& system_);
14 ~AudInA() override; 18 ~AudInA() override;
15}; 19};
16 20
diff --git a/src/core/hle/service/audio/audin_u.cpp b/src/core/hle/service/audio/audin_u.cpp
index 3e2299426..26a6deddf 100644
--- a/src/core/hle/service/audio/audin_u.cpp
+++ b/src/core/hle/service/audio/audin_u.cpp
@@ -11,7 +11,7 @@ namespace Service::Audio {
11 11
12class IAudioIn final : public ServiceFramework<IAudioIn> { 12class IAudioIn final : public ServiceFramework<IAudioIn> {
13public: 13public:
14 IAudioIn() : ServiceFramework("IAudioIn") { 14 explicit IAudioIn(Core::System& system_) : ServiceFramework{system_, "IAudioIn"} {
15 // clang-format off 15 // clang-format off
16 static const FunctionInfo functions[] = { 16 static const FunctionInfo functions[] = {
17 {0, nullptr, "GetAudioInState"}, 17 {0, nullptr, "GetAudioInState"},
@@ -36,7 +36,7 @@ public:
36 } 36 }
37}; 37};
38 38
39AudInU::AudInU() : ServiceFramework("audin:u") { 39AudInU::AudInU(Core::System& system_) : ServiceFramework{system_, "audin:u"} {
40 // clang-format off 40 // clang-format off
41 static const FunctionInfo functions[] = { 41 static const FunctionInfo functions[] = {
42 {0, &AudInU::ListAudioIns, "ListAudioIns"}, 42 {0, &AudInU::ListAudioIns, "ListAudioIns"},
@@ -96,7 +96,7 @@ void AudInU::OpenInOutImpl(Kernel::HLERequestContext& ctx) {
96 IPC::ResponseBuilder rb{ctx, 6, 0, 1}; 96 IPC::ResponseBuilder rb{ctx, 6, 0, 1};
97 rb.Push(RESULT_SUCCESS); 97 rb.Push(RESULT_SUCCESS);
98 rb.PushRaw<AudInOutParams>(params); 98 rb.PushRaw<AudInOutParams>(params);
99 rb.PushIpcInterface<IAudioIn>(); 99 rb.PushIpcInterface<IAudioIn>(system);
100} 100}
101 101
102void AudInU::OpenAudioIn(Kernel::HLERequestContext& ctx) { 102void AudInU::OpenAudioIn(Kernel::HLERequestContext& ctx) {
diff --git a/src/core/hle/service/audio/audin_u.h b/src/core/hle/service/audio/audin_u.h
index a599f4a64..0d75ae5ac 100644
--- a/src/core/hle/service/audio/audin_u.h
+++ b/src/core/hle/service/audio/audin_u.h
@@ -6,6 +6,10 @@
6 6
7#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
8 8
9namespace Core {
10class System;
11}
12
9namespace Kernel { 13namespace Kernel {
10class HLERequestContext; 14class HLERequestContext;
11} 15}
@@ -14,7 +18,7 @@ namespace Service::Audio {
14 18
15class AudInU final : public ServiceFramework<AudInU> { 19class AudInU final : public ServiceFramework<AudInU> {
16public: 20public:
17 explicit AudInU(); 21 explicit AudInU(Core::System& system_);
18 ~AudInU() override; 22 ~AudInU() override;
19 23
20private: 24private:
diff --git a/src/core/hle/service/audio/audio.cpp b/src/core/hle/service/audio/audio.cpp
index 1781bec83..b3f24f9bb 100644
--- a/src/core/hle/service/audio/audio.cpp
+++ b/src/core/hle/service/audio/audio.cpp
@@ -20,22 +20,22 @@
20namespace Service::Audio { 20namespace Service::Audio {
21 21
22void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { 22void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
23 std::make_shared<AudCtl>()->InstallAsService(service_manager); 23 std::make_shared<AudCtl>(system)->InstallAsService(service_manager);
24 std::make_shared<AudOutA>()->InstallAsService(service_manager); 24 std::make_shared<AudOutA>(system)->InstallAsService(service_manager);
25 std::make_shared<AudOutU>(system)->InstallAsService(service_manager); 25 std::make_shared<AudOutU>(system)->InstallAsService(service_manager);
26 std::make_shared<AudInA>()->InstallAsService(service_manager); 26 std::make_shared<AudInA>(system)->InstallAsService(service_manager);
27 std::make_shared<AudInU>()->InstallAsService(service_manager); 27 std::make_shared<AudInU>(system)->InstallAsService(service_manager);
28 std::make_shared<AudRecA>()->InstallAsService(service_manager); 28 std::make_shared<AudRecA>(system)->InstallAsService(service_manager);
29 std::make_shared<AudRecU>()->InstallAsService(service_manager); 29 std::make_shared<AudRecU>(system)->InstallAsService(service_manager);
30 std::make_shared<AudRenA>()->InstallAsService(service_manager); 30 std::make_shared<AudRenA>(system)->InstallAsService(service_manager);
31 std::make_shared<AudRenU>(system)->InstallAsService(service_manager); 31 std::make_shared<AudRenU>(system)->InstallAsService(service_manager);
32 std::make_shared<CodecCtl>()->InstallAsService(service_manager); 32 std::make_shared<CodecCtl>(system)->InstallAsService(service_manager);
33 std::make_shared<HwOpus>()->InstallAsService(service_manager); 33 std::make_shared<HwOpus>(system)->InstallAsService(service_manager);
34 34
35 std::make_shared<AudDbg>("audin:d")->InstallAsService(service_manager); 35 std::make_shared<AudDbg>(system, "audin:d")->InstallAsService(service_manager);
36 std::make_shared<AudDbg>("audout:d")->InstallAsService(service_manager); 36 std::make_shared<AudDbg>(system, "audout:d")->InstallAsService(service_manager);
37 std::make_shared<AudDbg>("audrec:d")->InstallAsService(service_manager); 37 std::make_shared<AudDbg>(system, "audrec:d")->InstallAsService(service_manager);
38 std::make_shared<AudDbg>("audren:d")->InstallAsService(service_manager); 38 std::make_shared<AudDbg>(system, "audren:d")->InstallAsService(service_manager);
39} 39}
40 40
41} // namespace Service::Audio 41} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audout_a.cpp b/src/core/hle/service/audio/audout_a.cpp
index 85febbca3..19825fd5d 100644
--- a/src/core/hle/service/audio/audout_a.cpp
+++ b/src/core/hle/service/audio/audout_a.cpp
@@ -6,7 +6,7 @@
6 6
7namespace Service::Audio { 7namespace Service::Audio {
8 8
9AudOutA::AudOutA() : ServiceFramework{"audout:a"} { 9AudOutA::AudOutA(Core::System& system_) : ServiceFramework{system_, "audout:a"} {
10 // clang-format off 10 // clang-format off
11 static const FunctionInfo functions[] = { 11 static const FunctionInfo functions[] = {
12 {0, nullptr, "RequestSuspendAudioOuts"}, 12 {0, nullptr, "RequestSuspendAudioOuts"},
diff --git a/src/core/hle/service/audio/audout_a.h b/src/core/hle/service/audio/audout_a.h
index d65b66e8e..2043dfb77 100644
--- a/src/core/hle/service/audio/audout_a.h
+++ b/src/core/hle/service/audio/audout_a.h
@@ -6,11 +6,15 @@
6 6
7#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
8 8
9namespace Core {
10class System;
11}
12
9namespace Service::Audio { 13namespace Service::Audio {
10 14
11class AudOutA final : public ServiceFramework<AudOutA> { 15class AudOutA final : public ServiceFramework<AudOutA> {
12public: 16public:
13 explicit AudOutA(); 17 explicit AudOutA(Core::System& system_);
14 ~AudOutA() override; 18 ~AudOutA() override;
15}; 19};
16 20
diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp
index 9b4910e53..0cd797109 100644
--- a/src/core/hle/service/audio/audout_u.cpp
+++ b/src/core/hle/service/audio/audout_u.cpp
@@ -40,11 +40,11 @@ enum class AudioState : u32 {
40 40
41class IAudioOut final : public ServiceFramework<IAudioOut> { 41class IAudioOut final : public ServiceFramework<IAudioOut> {
42public: 42public:
43 IAudioOut(Core::System& system, AudoutParams audio_params, AudioCore::AudioOut& audio_core, 43 IAudioOut(Core::System& system_, AudoutParams audio_params_, AudioCore::AudioOut& audio_core_,
44 std::string&& device_name, std::string&& unique_name) 44 std::string&& device_name_, std::string&& unique_name)
45 : ServiceFramework("IAudioOut"), audio_core(audio_core), 45 : ServiceFramework{system_, "IAudioOut"}, audio_core{audio_core_},
46 device_name(std::move(device_name)), 46 device_name{std::move(device_name_)}, audio_params{audio_params_}, main_memory{
47 audio_params(audio_params), main_memory{system.Memory()} { 47 system.Memory()} {
48 // clang-format off 48 // clang-format off
49 static const FunctionInfo functions[] = { 49 static const FunctionInfo functions[] = {
50 {0, &IAudioOut::GetAudioOutState, "GetAudioOutState"}, 50 {0, &IAudioOut::GetAudioOutState, "GetAudioOutState"},
@@ -70,8 +70,10 @@ public:
70 Kernel::WritableEvent::CreateEventPair(system.Kernel(), "IAudioOutBufferReleased"); 70 Kernel::WritableEvent::CreateEventPair(system.Kernel(), "IAudioOutBufferReleased");
71 71
72 stream = audio_core.OpenStream(system.CoreTiming(), audio_params.sample_rate, 72 stream = audio_core.OpenStream(system.CoreTiming(), audio_params.sample_rate,
73 audio_params.channel_count, std::move(unique_name), 73 audio_params.channel_count, std::move(unique_name), [this] {
74 [this] { buffer_event.writable->Signal(); }); 74 const auto guard = LockService();
75 buffer_event.writable->Signal();
76 });
75 } 77 }
76 78
77private: 79private:
@@ -213,7 +215,7 @@ private:
213 Core::Memory::Memory& main_memory; 215 Core::Memory::Memory& main_memory;
214}; 216};
215 217
216AudOutU::AudOutU(Core::System& system_) : ServiceFramework("audout:u"), system{system_} { 218AudOutU::AudOutU(Core::System& system_) : ServiceFramework{system_, "audout:u"} {
217 // clang-format off 219 // clang-format off
218 static const FunctionInfo functions[] = { 220 static const FunctionInfo functions[] = {
219 {0, &AudOutU::ListAudioOutsImpl, "ListAudioOuts"}, 221 {0, &AudOutU::ListAudioOutsImpl, "ListAudioOuts"},
diff --git a/src/core/hle/service/audio/audout_u.h b/src/core/hle/service/audio/audout_u.h
index c9f532ccd..f7ae2f2bf 100644
--- a/src/core/hle/service/audio/audout_u.h
+++ b/src/core/hle/service/audio/audout_u.h
@@ -34,8 +34,6 @@ private:
34 34
35 std::vector<std::shared_ptr<IAudioOut>> audio_out_interfaces; 35 std::vector<std::shared_ptr<IAudioOut>> audio_out_interfaces;
36 std::unique_ptr<AudioCore::AudioOut> audio_core; 36 std::unique_ptr<AudioCore::AudioOut> audio_core;
37
38 Core::System& system;
39}; 37};
40 38
41} // namespace Service::Audio 39} // namespace Service::Audio
diff --git a/src/core/hle/service/audio/audrec_a.cpp b/src/core/hle/service/audio/audrec_a.cpp
index ce1bfb48d..c5ab7cad4 100644
--- a/src/core/hle/service/audio/audrec_a.cpp
+++ b/src/core/hle/service/audio/audrec_a.cpp
@@ -6,7 +6,7 @@
6 6
7namespace Service::Audio { 7namespace Service::Audio {
8 8
9AudRecA::AudRecA() : ServiceFramework{"audrec:a"} { 9AudRecA::AudRecA(Core::System& system_) : ServiceFramework{system_, "audrec:a"} {
10 // clang-format off 10 // clang-format off
11 static const FunctionInfo functions[] = { 11 static const FunctionInfo functions[] = {
12 {0, nullptr, "RequestSuspendFinalOutputRecorders"}, 12 {0, nullptr, "RequestSuspendFinalOutputRecorders"},
diff --git a/src/core/hle/service/audio/audrec_a.h b/src/core/hle/service/audio/audrec_a.h
index 384d24c69..2cce90b1d 100644
--- a/src/core/hle/service/audio/audrec_a.h
+++ b/src/core/hle/service/audio/audrec_a.h
@@ -6,11 +6,15 @@
6 6
7#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
8 8
9namespace Core {
10class System;
11}
12
9namespace Service::Audio { 13namespace Service::Audio {
10 14
11class AudRecA final : public ServiceFramework<AudRecA> { 15class AudRecA final : public ServiceFramework<AudRecA> {
12public: 16public:
13 explicit AudRecA(); 17 explicit AudRecA(Core::System& system_);
14 ~AudRecA() override; 18 ~AudRecA() override;
15}; 19};
16 20
diff --git a/src/core/hle/service/audio/audrec_u.cpp b/src/core/hle/service/audio/audrec_u.cpp
index 1a5aed9ed..eb5c63c62 100644
--- a/src/core/hle/service/audio/audrec_u.cpp
+++ b/src/core/hle/service/audio/audrec_u.cpp
@@ -8,7 +8,8 @@ namespace Service::Audio {
8 8
9class IFinalOutputRecorder final : public ServiceFramework<IFinalOutputRecorder> { 9class IFinalOutputRecorder final : public ServiceFramework<IFinalOutputRecorder> {
10public: 10public:
11 IFinalOutputRecorder() : ServiceFramework("IFinalOutputRecorder") { 11 explicit IFinalOutputRecorder(Core::System& system_)
12 : ServiceFramework{system_, "IFinalOutputRecorder"} {
12 // clang-format off 13 // clang-format off
13 static const FunctionInfo functions[] = { 14 static const FunctionInfo functions[] = {
14 {0, nullptr, "GetFinalOutputRecorderState"}, 15 {0, nullptr, "GetFinalOutputRecorderState"},
@@ -29,7 +30,7 @@ public:
29 } 30 }
30}; 31};
31 32
32AudRecU::AudRecU() : ServiceFramework("audrec:u") { 33AudRecU::AudRecU(Core::System& system_) : ServiceFramework{system_, "audrec:u"} {
33 static const FunctionInfo functions[] = { 34 static const FunctionInfo functions[] = {
34 {0, nullptr, "OpenFinalOutputRecorder"}, 35 {0, nullptr, "OpenFinalOutputRecorder"},
35 }; 36 };
diff --git a/src/core/hle/service/audio/audrec_u.h b/src/core/hle/service/audio/audrec_u.h
index ca3d638e8..f79d49e5c 100644
--- a/src/core/hle/service/audio/audrec_u.h
+++ b/src/core/hle/service/audio/audrec_u.h
@@ -6,15 +6,15 @@
6 6
7#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
8 8
9namespace Kernel { 9namespace Core {
10class HLERequestContext; 10class System;
11} 11}
12 12
13namespace Service::Audio { 13namespace Service::Audio {
14 14
15class AudRecU final : public ServiceFramework<AudRecU> { 15class AudRecU final : public ServiceFramework<AudRecU> {
16public: 16public:
17 explicit AudRecU(); 17 explicit AudRecU(Core::System& system_);
18 ~AudRecU() override; 18 ~AudRecU() override;
19}; 19};
20 20
diff --git a/src/core/hle/service/audio/audren_a.cpp b/src/core/hle/service/audio/audren_a.cpp
index edb66d985..5e9f866f0 100644
--- a/src/core/hle/service/audio/audren_a.cpp
+++ b/src/core/hle/service/audio/audren_a.cpp
@@ -6,7 +6,7 @@
6 6
7namespace Service::Audio { 7namespace Service::Audio {
8 8
9AudRenA::AudRenA() : ServiceFramework{"audren:a"} { 9AudRenA::AudRenA(Core::System& system_) : ServiceFramework{system_, "audren:a"} {
10 // clang-format off 10 // clang-format off
11 static const FunctionInfo functions[] = { 11 static const FunctionInfo functions[] = {
12 {0, nullptr, "RequestSuspendAudioRenderers"}, 12 {0, nullptr, "RequestSuspendAudioRenderers"},
diff --git a/src/core/hle/service/audio/audren_a.h b/src/core/hle/service/audio/audren_a.h
index 81fef0ffe..5d0a626ad 100644
--- a/src/core/hle/service/audio/audren_a.h
+++ b/src/core/hle/service/audio/audren_a.h
@@ -6,11 +6,15 @@
6 6
7#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
8 8
9namespace Core {
10class System;
11}
12
9namespace Service::Audio { 13namespace Service::Audio {
10 14
11class AudRenA final : public ServiceFramework<AudRenA> { 15class AudRenA final : public ServiceFramework<AudRenA> {
12public: 16public:
13 explicit AudRenA(); 17 explicit AudRenA(Core::System& system_);
14 ~AudRenA() override; 18 ~AudRenA() override;
15}; 19};
16 20
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp
index a2d3ded7b..c5c22d053 100644
--- a/src/core/hle/service/audio/audren_u.cpp
+++ b/src/core/hle/service/audio/audren_u.cpp
@@ -28,7 +28,7 @@ class IAudioRenderer final : public ServiceFramework<IAudioRenderer> {
28public: 28public:
29 explicit IAudioRenderer(Core::System& system, AudioCommon::AudioRendererParameter audren_params, 29 explicit IAudioRenderer(Core::System& system, AudioCommon::AudioRendererParameter audren_params,
30 const std::size_t instance_number) 30 const std::size_t instance_number)
31 : ServiceFramework("IAudioRenderer") { 31 : ServiceFramework{system, "IAudioRenderer"} {
32 // clang-format off 32 // clang-format off
33 static const FunctionInfo functions[] = { 33 static const FunctionInfo functions[] = {
34 {0, &IAudioRenderer::GetSampleRate, "GetSampleRate"}, 34 {0, &IAudioRenderer::GetSampleRate, "GetSampleRate"},
@@ -49,16 +49,16 @@ public:
49 49
50 system_event = 50 system_event =
51 Kernel::WritableEvent::CreateEventPair(system.Kernel(), "IAudioRenderer:SystemEvent"); 51 Kernel::WritableEvent::CreateEventPair(system.Kernel(), "IAudioRenderer:SystemEvent");
52 renderer = std::make_unique<AudioCore::AudioRenderer>(system.CoreTiming(), system.Memory(), 52 renderer = std::make_unique<AudioCore::AudioRenderer>(
53 audren_params, system_event.writable, 53 system.CoreTiming(), system.Memory(), audren_params,
54 instance_number); 54 [this]() {
55 const auto guard = LockService();
56 system_event.writable->Signal();
57 },
58 instance_number);
55 } 59 }
56 60
57private: 61private:
58 void UpdateAudioCallback() {
59 system_event.writable->Signal();
60 }
61
62 void GetSampleRate(Kernel::HLERequestContext& ctx) { 62 void GetSampleRate(Kernel::HLERequestContext& ctx) {
63 LOG_DEBUG(Service_Audio, "called"); 63 LOG_DEBUG(Service_Audio, "called");
64 64
@@ -167,8 +167,8 @@ private:
167 167
168class IAudioDevice final : public ServiceFramework<IAudioDevice> { 168class IAudioDevice final : public ServiceFramework<IAudioDevice> {
169public: 169public:
170 explicit IAudioDevice(Core::System& system, u32_le revision_num) 170 explicit IAudioDevice(Core::System& system_, u32_le revision_num)
171 : ServiceFramework("IAudioDevice"), revision{revision_num} { 171 : ServiceFramework{system_, "IAudioDevice"}, revision{revision_num} {
172 static const FunctionInfo functions[] = { 172 static const FunctionInfo functions[] = {
173 {0, &IAudioDevice::ListAudioDeviceName, "ListAudioDeviceName"}, 173 {0, &IAudioDevice::ListAudioDeviceName, "ListAudioDeviceName"},
174 {1, &IAudioDevice::SetAudioDeviceOutputVolume, "SetAudioDeviceOutputVolume"}, 174 {1, &IAudioDevice::SetAudioDeviceOutputVolume, "SetAudioDeviceOutputVolume"},
@@ -325,7 +325,7 @@ private:
325 325
326}; // namespace Audio 326}; // namespace Audio
327 327
328AudRenU::AudRenU(Core::System& system_) : ServiceFramework("audren:u"), system{system_} { 328AudRenU::AudRenU(Core::System& system_) : ServiceFramework{system_, "audren:u"} {
329 // clang-format off 329 // clang-format off
330 static const FunctionInfo functions[] = { 330 static const FunctionInfo functions[] = {
331 {0, &AudRenU::OpenAudioRenderer, "OpenAudioRenderer"}, 331 {0, &AudRenU::OpenAudioRenderer, "OpenAudioRenderer"},
diff --git a/src/core/hle/service/audio/audren_u.h b/src/core/hle/service/audio/audren_u.h
index 4e0ccc792..d693dc406 100644
--- a/src/core/hle/service/audio/audren_u.h
+++ b/src/core/hle/service/audio/audren_u.h
@@ -31,7 +31,6 @@ private:
31 void OpenAudioRendererImpl(Kernel::HLERequestContext& ctx); 31 void OpenAudioRendererImpl(Kernel::HLERequestContext& ctx);
32 32
33 std::size_t audren_instance_count = 0; 33 std::size_t audren_instance_count = 0;
34 Core::System& system;
35}; 34};
36 35
37// Describes a particular audio feature that may be supported in a particular revision. 36// Describes a particular audio feature that may be supported in a particular revision.
diff --git a/src/core/hle/service/audio/codecctl.cpp b/src/core/hle/service/audio/codecctl.cpp
index c6864146d..94afec1b6 100644
--- a/src/core/hle/service/audio/codecctl.cpp
+++ b/src/core/hle/service/audio/codecctl.cpp
@@ -2,14 +2,11 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/logging/log.h"
6#include "core/hle/ipc_helpers.h"
7#include "core/hle/kernel/hle_ipc.h"
8#include "core/hle/service/audio/codecctl.h" 5#include "core/hle/service/audio/codecctl.h"
9 6
10namespace Service::Audio { 7namespace Service::Audio {
11 8
12CodecCtl::CodecCtl() : ServiceFramework("codecctl") { 9CodecCtl::CodecCtl(Core::System& system_) : ServiceFramework{system_, "codecctl"} {
13 static const FunctionInfo functions[] = { 10 static const FunctionInfo functions[] = {
14 {0, nullptr, "InitializeCodecController"}, 11 {0, nullptr, "InitializeCodecController"},
15 {1, nullptr, "FinalizeCodecController"}, 12 {1, nullptr, "FinalizeCodecController"},
diff --git a/src/core/hle/service/audio/codecctl.h b/src/core/hle/service/audio/codecctl.h
index 2fe75b6e2..58e53259e 100644
--- a/src/core/hle/service/audio/codecctl.h
+++ b/src/core/hle/service/audio/codecctl.h
@@ -6,15 +6,15 @@
6 6
7#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
8 8
9namespace Kernel { 9namespace Core {
10class HLERequestContext; 10class System;
11} 11}
12 12
13namespace Service::Audio { 13namespace Service::Audio {
14 14
15class CodecCtl final : public ServiceFramework<CodecCtl> { 15class CodecCtl final : public ServiceFramework<CodecCtl> {
16public: 16public:
17 explicit CodecCtl(); 17 explicit CodecCtl(Core::System& system_);
18 ~CodecCtl() override; 18 ~CodecCtl() override;
19}; 19};
20 20
diff --git a/src/core/hle/service/audio/hwopus.cpp b/src/core/hle/service/audio/hwopus.cpp
index f1d81602c..ea3414fd2 100644
--- a/src/core/hle/service/audio/hwopus.cpp
+++ b/src/core/hle/service/audio/hwopus.cpp
@@ -160,8 +160,9 @@ private:
160 160
161class IHardwareOpusDecoderManager final : public ServiceFramework<IHardwareOpusDecoderManager> { 161class IHardwareOpusDecoderManager final : public ServiceFramework<IHardwareOpusDecoderManager> {
162public: 162public:
163 explicit IHardwareOpusDecoderManager(OpusDecoderState decoder_state) 163 explicit IHardwareOpusDecoderManager(Core::System& system_, OpusDecoderState decoder_state)
164 : ServiceFramework("IHardwareOpusDecoderManager"), decoder_state{std::move(decoder_state)} { 164 : ServiceFramework{system_, "IHardwareOpusDecoderManager"}, decoder_state{
165 std::move(decoder_state)} {
165 // clang-format off 166 // clang-format off
166 static const FunctionInfo functions[] = { 167 static const FunctionInfo functions[] = {
167 {0, &IHardwareOpusDecoderManager::DecodeInterleavedOld, "DecodeInterleavedOld"}, 168 {0, &IHardwareOpusDecoderManager::DecodeInterleavedOld, "DecodeInterleavedOld"},
@@ -287,10 +288,10 @@ void HwOpus::OpenOpusDecoder(Kernel::HLERequestContext& ctx) {
287 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 288 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
288 rb.Push(RESULT_SUCCESS); 289 rb.Push(RESULT_SUCCESS);
289 rb.PushIpcInterface<IHardwareOpusDecoderManager>( 290 rb.PushIpcInterface<IHardwareOpusDecoderManager>(
290 OpusDecoderState{std::move(decoder), sample_rate, channel_count}); 291 system, OpusDecoderState{std::move(decoder), sample_rate, channel_count});
291} 292}
292 293
293HwOpus::HwOpus() : ServiceFramework("hwopus") { 294HwOpus::HwOpus(Core::System& system_) : ServiceFramework{system_, "hwopus"} {
294 static const FunctionInfo functions[] = { 295 static const FunctionInfo functions[] = {
295 {0, &HwOpus::OpenOpusDecoder, "OpenOpusDecoder"}, 296 {0, &HwOpus::OpenOpusDecoder, "OpenOpusDecoder"},
296 {1, &HwOpus::GetWorkBufferSize, "GetWorkBufferSize"}, 297 {1, &HwOpus::GetWorkBufferSize, "GetWorkBufferSize"},
diff --git a/src/core/hle/service/audio/hwopus.h b/src/core/hle/service/audio/hwopus.h
index 602ede8ba..4f921f18e 100644
--- a/src/core/hle/service/audio/hwopus.h
+++ b/src/core/hle/service/audio/hwopus.h
@@ -6,11 +6,15 @@
6 6
7#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
8 8
9namespace Core {
10class System;
11}
12
9namespace Service::Audio { 13namespace Service::Audio {
10 14
11class HwOpus final : public ServiceFramework<HwOpus> { 15class HwOpus final : public ServiceFramework<HwOpus> {
12public: 16public:
13 explicit HwOpus(); 17 explicit HwOpus(Core::System& system_);
14 ~HwOpus() override; 18 ~HwOpus() override;
15 19
16private: 20private:
diff --git a/src/core/hle/service/bcat/backend/backend.cpp b/src/core/hle/service/bcat/backend/backend.cpp
index def3410cc..174388445 100644
--- a/src/core/hle/service/bcat/backend/backend.cpp
+++ b/src/core/hle/service/bcat/backend/backend.cpp
@@ -84,7 +84,7 @@ void ProgressServiceBackend::FinishDownload(ResultCode result) {
84 84
85void ProgressServiceBackend::SignalUpdate() const { 85void ProgressServiceBackend::SignalUpdate() const {
86 if (need_hle_lock) { 86 if (need_hle_lock) {
87 std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock); 87 std::lock_guard lock(HLE::g_hle_lock);
88 event.writable->Signal(); 88 event.writable->Signal();
89 } else { 89 } else {
90 event.writable->Signal(); 90 event.writable->Signal();
diff --git a/src/core/hle/service/bcat/backend/boxcat.cpp b/src/core/hle/service/bcat/backend/boxcat.cpp
index ca021a99f..e43f3f47f 100644
--- a/src/core/hle/service/bcat/backend/boxcat.cpp
+++ b/src/core/hle/service/bcat/backend/boxcat.cpp
@@ -196,7 +196,9 @@ private:
196 const std::string& content_type_name) { 196 const std::string& content_type_name) {
197 if (client == nullptr) { 197 if (client == nullptr) {
198 client = std::make_unique<httplib::SSLClient>(BOXCAT_HOSTNAME, PORT); 198 client = std::make_unique<httplib::SSLClient>(BOXCAT_HOSTNAME, PORT);
199 client->set_timeout_sec(timeout_seconds); 199 client->set_connection_timeout(timeout_seconds);
200 client->set_read_timeout(timeout_seconds);
201 client->set_write_timeout(timeout_seconds);
200 } 202 }
201 203
202 httplib::Headers headers{ 204 httplib::Headers headers{
@@ -255,7 +257,7 @@ private:
255 return out; 257 return out;
256 } 258 }
257 259
258 std::unique_ptr<httplib::Client> client; 260 std::unique_ptr<httplib::SSLClient> client;
259 std::string path; 261 std::string path;
260 u64 title_id; 262 u64 title_id;
261 u64 build_id; 263 u64 build_id;
@@ -443,13 +445,25 @@ std::optional<std::vector<u8>> Boxcat::GetLaunchParameter(TitleIDVersion title)
443Boxcat::StatusResult Boxcat::GetStatus(std::optional<std::string>& global, 445Boxcat::StatusResult Boxcat::GetStatus(std::optional<std::string>& global,
444 std::map<std::string, EventStatus>& games) { 446 std::map<std::string, EventStatus>& games) {
445 httplib::SSLClient client{BOXCAT_HOSTNAME, static_cast<int>(PORT)}; 447 httplib::SSLClient client{BOXCAT_HOSTNAME, static_cast<int>(PORT)};
446 client.set_timeout_sec(static_cast<int>(TIMEOUT_SECONDS)); 448 client.set_connection_timeout(static_cast<int>(TIMEOUT_SECONDS));
449 client.set_read_timeout(static_cast<int>(TIMEOUT_SECONDS));
450 client.set_write_timeout(static_cast<int>(TIMEOUT_SECONDS));
447 451
448 httplib::Headers headers{ 452 httplib::Headers headers{
449 {std::string("Game-Assets-API-Version"), std::string(BOXCAT_API_VERSION)}, 453 {std::string("Game-Assets-API-Version"), std::string(BOXCAT_API_VERSION)},
450 {std::string("Boxcat-Client-Type"), std::string(BOXCAT_CLIENT_TYPE)}, 454 {std::string("Boxcat-Client-Type"), std::string(BOXCAT_CLIENT_TYPE)},
451 }; 455 };
452 456
457 if (!client.is_valid()) {
458 LOG_ERROR(Service_BCAT, "Client is invalid, going offline!");
459 return StatusResult::Offline;
460 }
461
462 if (!client.is_socket_open()) {
463 LOG_ERROR(Service_BCAT, "Failed to open socket, going offline!");
464 return StatusResult::Offline;
465 }
466
453 const auto response = client.Get(BOXCAT_PATHNAME_EVENTS, headers); 467 const auto response = client.Get(BOXCAT_PATHNAME_EVENTS, headers);
454 if (response == nullptr) 468 if (response == nullptr)
455 return StatusResult::Offline; 469 return StatusResult::Offline;
@@ -469,7 +483,7 @@ Boxcat::StatusResult Boxcat::GetStatus(std::optional<std::string>& global,
469 global = json["global"].get<std::string>(); 483 global = json["global"].get<std::string>();
470 484
471 if (json["games"].is_array()) { 485 if (json["games"].is_array()) {
472 for (const auto object : json["games"]) { 486 for (const auto& object : json["games"]) {
473 if (object.is_object() && object.find("name") != object.end()) { 487 if (object.is_object() && object.find("name") != object.end()) {
474 EventStatus detail{}; 488 EventStatus detail{};
475 if (object["header"].is_string()) { 489 if (object["header"].is_string()) {
diff --git a/src/core/hle/service/bcat/module.cpp b/src/core/hle/service/bcat/module.cpp
index db0e06ca1..b8696a395 100644
--- a/src/core/hle/service/bcat/module.cpp
+++ b/src/core/hle/service/bcat/module.cpp
@@ -8,6 +8,7 @@
8#include "common/hex_util.h" 8#include "common/hex_util.h"
9#include "common/logging/log.h" 9#include "common/logging/log.h"
10#include "common/string_util.h" 10#include "common/string_util.h"
11#include "core/core.h"
11#include "core/file_sys/vfs.h" 12#include "core/file_sys/vfs.h"
12#include "core/hle/ipc_helpers.h" 13#include "core/hle/ipc_helpers.h"
13#include "core/hle/kernel/process.h" 14#include "core/hle/kernel/process.h"
@@ -87,9 +88,11 @@ struct DeliveryCacheDirectoryEntry {
87 88
88class IDeliveryCacheProgressService final : public ServiceFramework<IDeliveryCacheProgressService> { 89class IDeliveryCacheProgressService final : public ServiceFramework<IDeliveryCacheProgressService> {
89public: 90public:
90 IDeliveryCacheProgressService(std::shared_ptr<Kernel::ReadableEvent> event, 91 explicit IDeliveryCacheProgressService(Core::System& system_,
91 const DeliveryCacheProgressImpl& impl) 92 std::shared_ptr<Kernel::ReadableEvent> event_,
92 : ServiceFramework{"IDeliveryCacheProgressService"}, event(std::move(event)), impl(impl) { 93 const DeliveryCacheProgressImpl& impl_)
94 : ServiceFramework{system_, "IDeliveryCacheProgressService"}, event{std::move(event_)},
95 impl{impl_} {
93 // clang-format off 96 // clang-format off
94 static const FunctionInfo functions[] = { 97 static const FunctionInfo functions[] = {
95 {0, &IDeliveryCacheProgressService::GetEvent, "GetEvent"}, 98 {0, &IDeliveryCacheProgressService::GetEvent, "GetEvent"},
@@ -125,7 +128,7 @@ private:
125class IBcatService final : public ServiceFramework<IBcatService> { 128class IBcatService final : public ServiceFramework<IBcatService> {
126public: 129public:
127 explicit IBcatService(Core::System& system_, Backend& backend_) 130 explicit IBcatService(Core::System& system_, Backend& backend_)
128 : ServiceFramework("IBcatService"), system{system_}, backend{backend_}, 131 : ServiceFramework{system_, "IBcatService"}, backend{backend_},
129 progress{{ 132 progress{{
130 ProgressServiceBackend{system_.Kernel(), "Normal"}, 133 ProgressServiceBackend{system_.Kernel(), "Normal"},
131 ProgressServiceBackend{system_.Kernel(), "Directory"}, 134 ProgressServiceBackend{system_.Kernel(), "Directory"},
@@ -170,7 +173,7 @@ private:
170 173
171 std::shared_ptr<IDeliveryCacheProgressService> CreateProgressService(SyncType type) { 174 std::shared_ptr<IDeliveryCacheProgressService> CreateProgressService(SyncType type) {
172 auto& backend{progress.at(static_cast<std::size_t>(type))}; 175 auto& backend{progress.at(static_cast<std::size_t>(type))};
173 return std::make_shared<IDeliveryCacheProgressService>(backend.GetEvent(), 176 return std::make_shared<IDeliveryCacheProgressService>(system, backend.GetEvent(),
174 backend.GetImpl()); 177 backend.GetImpl());
175 } 178 }
176 179
@@ -260,7 +263,6 @@ private:
260 rb.Push(RESULT_SUCCESS); 263 rb.Push(RESULT_SUCCESS);
261 } 264 }
262 265
263 Core::System& system;
264 Backend& backend; 266 Backend& backend;
265 267
266 std::array<ProgressServiceBackend, static_cast<std::size_t>(SyncType::Count)> progress; 268 std::array<ProgressServiceBackend, static_cast<std::size_t>(SyncType::Count)> progress;
@@ -276,8 +278,8 @@ void Module::Interface::CreateBcatService(Kernel::HLERequestContext& ctx) {
276 278
277class IDeliveryCacheFileService final : public ServiceFramework<IDeliveryCacheFileService> { 279class IDeliveryCacheFileService final : public ServiceFramework<IDeliveryCacheFileService> {
278public: 280public:
279 IDeliveryCacheFileService(FileSys::VirtualDir root_) 281 explicit IDeliveryCacheFileService(Core::System& system_, FileSys::VirtualDir root_)
280 : ServiceFramework{"IDeliveryCacheFileService"}, root(std::move(root_)) { 282 : ServiceFramework{system_, "IDeliveryCacheFileService"}, root(std::move(root_)) {
281 // clang-format off 283 // clang-format off
282 static const FunctionInfo functions[] = { 284 static const FunctionInfo functions[] = {
283 {0, &IDeliveryCacheFileService::Open, "Open"}, 285 {0, &IDeliveryCacheFileService::Open, "Open"},
@@ -393,8 +395,8 @@ private:
393class IDeliveryCacheDirectoryService final 395class IDeliveryCacheDirectoryService final
394 : public ServiceFramework<IDeliveryCacheDirectoryService> { 396 : public ServiceFramework<IDeliveryCacheDirectoryService> {
395public: 397public:
396 IDeliveryCacheDirectoryService(FileSys::VirtualDir root_) 398 explicit IDeliveryCacheDirectoryService(Core::System& system_, FileSys::VirtualDir root_)
397 : ServiceFramework{"IDeliveryCacheDirectoryService"}, root(std::move(root_)) { 399 : ServiceFramework{system_, "IDeliveryCacheDirectoryService"}, root(std::move(root_)) {
398 // clang-format off 400 // clang-format off
399 static const FunctionInfo functions[] = { 401 static const FunctionInfo functions[] = {
400 {0, &IDeliveryCacheDirectoryService::Open, "Open"}, 402 {0, &IDeliveryCacheDirectoryService::Open, "Open"},
@@ -491,8 +493,8 @@ private:
491 493
492class IDeliveryCacheStorageService final : public ServiceFramework<IDeliveryCacheStorageService> { 494class IDeliveryCacheStorageService final : public ServiceFramework<IDeliveryCacheStorageService> {
493public: 495public:
494 IDeliveryCacheStorageService(FileSys::VirtualDir root_) 496 explicit IDeliveryCacheStorageService(Core::System& system_, FileSys::VirtualDir root_)
495 : ServiceFramework{"IDeliveryCacheStorageService"}, root(std::move(root_)) { 497 : ServiceFramework{system_, "IDeliveryCacheStorageService"}, root(std::move(root_)) {
496 // clang-format off 498 // clang-format off
497 static const FunctionInfo functions[] = { 499 static const FunctionInfo functions[] = {
498 {0, &IDeliveryCacheStorageService::CreateFileService, "CreateFileService"}, 500 {0, &IDeliveryCacheStorageService::CreateFileService, "CreateFileService"},
@@ -517,7 +519,7 @@ private:
517 519
518 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 520 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
519 rb.Push(RESULT_SUCCESS); 521 rb.Push(RESULT_SUCCESS);
520 rb.PushIpcInterface<IDeliveryCacheFileService>(root); 522 rb.PushIpcInterface<IDeliveryCacheFileService>(system, root);
521 } 523 }
522 524
523 void CreateDirectoryService(Kernel::HLERequestContext& ctx) { 525 void CreateDirectoryService(Kernel::HLERequestContext& ctx) {
@@ -525,7 +527,7 @@ private:
525 527
526 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 528 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
527 rb.Push(RESULT_SUCCESS); 529 rb.Push(RESULT_SUCCESS);
528 rb.PushIpcInterface<IDeliveryCacheDirectoryService>(root); 530 rb.PushIpcInterface<IDeliveryCacheDirectoryService>(system, root);
529 } 531 }
530 532
531 void EnumerateDeliveryCacheDirectory(Kernel::HLERequestContext& ctx) { 533 void EnumerateDeliveryCacheDirectory(Kernel::HLERequestContext& ctx) {
@@ -550,10 +552,10 @@ private:
550void Module::Interface::CreateDeliveryCacheStorageService(Kernel::HLERequestContext& ctx) { 552void Module::Interface::CreateDeliveryCacheStorageService(Kernel::HLERequestContext& ctx) {
551 LOG_DEBUG(Service_BCAT, "called"); 553 LOG_DEBUG(Service_BCAT, "called");
552 554
555 const auto title_id = system.CurrentProcess()->GetTitleID();
553 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 556 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
554 rb.Push(RESULT_SUCCESS); 557 rb.Push(RESULT_SUCCESS);
555 rb.PushIpcInterface<IDeliveryCacheStorageService>( 558 rb.PushIpcInterface<IDeliveryCacheStorageService>(system, fsc.GetBCATDirectory(title_id));
556 fsc.GetBCATDirectory(system.CurrentProcess()->GetTitleID()));
557} 559}
558 560
559void Module::Interface::CreateDeliveryCacheStorageServiceWithApplicationId( 561void Module::Interface::CreateDeliveryCacheStorageServiceWithApplicationId(
@@ -565,7 +567,7 @@ void Module::Interface::CreateDeliveryCacheStorageServiceWithApplicationId(
565 567
566 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 568 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
567 rb.Push(RESULT_SUCCESS); 569 rb.Push(RESULT_SUCCESS);
568 rb.PushIpcInterface<IDeliveryCacheStorageService>(fsc.GetBCATDirectory(title_id)); 570 rb.PushIpcInterface<IDeliveryCacheStorageService>(system, fsc.GetBCATDirectory(title_id));
569} 571}
570 572
571std::unique_ptr<Backend> CreateBackendFromSettings([[maybe_unused]] Core::System& system, 573std::unique_ptr<Backend> CreateBackendFromSettings([[maybe_unused]] Core::System& system,
@@ -581,10 +583,9 @@ std::unique_ptr<Backend> CreateBackendFromSettings([[maybe_unused]] Core::System
581 583
582Module::Interface::Interface(Core::System& system_, std::shared_ptr<Module> module_, 584Module::Interface::Interface(Core::System& system_, std::shared_ptr<Module> module_,
583 FileSystem::FileSystemController& fsc_, const char* name) 585 FileSystem::FileSystemController& fsc_, const char* name)
584 : ServiceFramework(name), fsc{fsc_}, module{std::move(module_)}, 586 : ServiceFramework{system_, name}, fsc{fsc_}, module{std::move(module_)},
585 backend{CreateBackendFromSettings(system_, 587 backend{CreateBackendFromSettings(system_,
586 [&fsc_](u64 tid) { return fsc_.GetBCATDirectory(tid); })}, 588 [&fsc_](u64 tid) { return fsc_.GetBCATDirectory(tid); })} {}
587 system{system_} {}
588 589
589Module::Interface::~Interface() = default; 590Module::Interface::~Interface() = default;
590 591
diff --git a/src/core/hle/service/bcat/module.h b/src/core/hle/service/bcat/module.h
index e4ba23ba0..738731c06 100644
--- a/src/core/hle/service/bcat/module.h
+++ b/src/core/hle/service/bcat/module.h
@@ -37,9 +37,6 @@ public:
37 37
38 std::shared_ptr<Module> module; 38 std::shared_ptr<Module> module;
39 std::unique_ptr<Backend> backend; 39 std::unique_ptr<Backend> backend;
40
41 private:
42 Core::System& system;
43 }; 40 };
44}; 41};
45 42
diff --git a/src/core/hle/service/bpc/bpc.cpp b/src/core/hle/service/bpc/bpc.cpp
index fac6b2f9c..e4630320e 100644
--- a/src/core/hle/service/bpc/bpc.cpp
+++ b/src/core/hle/service/bpc/bpc.cpp
@@ -12,7 +12,7 @@ namespace Service::BPC {
12 12
13class BPC final : public ServiceFramework<BPC> { 13class BPC final : public ServiceFramework<BPC> {
14public: 14public:
15 explicit BPC() : ServiceFramework{"bpc"} { 15 explicit BPC(Core::System& system_) : ServiceFramework{system_, "bpc"} {
16 // clang-format off 16 // clang-format off
17 static const FunctionInfo functions[] = { 17 static const FunctionInfo functions[] = {
18 {0, nullptr, "ShutdownSystem"}, 18 {0, nullptr, "ShutdownSystem"},
@@ -40,7 +40,7 @@ public:
40 40
41class BPC_R final : public ServiceFramework<BPC_R> { 41class BPC_R final : public ServiceFramework<BPC_R> {
42public: 42public:
43 explicit BPC_R() : ServiceFramework{"bpc:r"} { 43 explicit BPC_R(Core::System& system_) : ServiceFramework{system_, "bpc:r"} {
44 // clang-format off 44 // clang-format off
45 static const FunctionInfo functions[] = { 45 static const FunctionInfo functions[] = {
46 {0, nullptr, "GetRtcTime"}, 46 {0, nullptr, "GetRtcTime"},
@@ -55,9 +55,9 @@ public:
55 } 55 }
56}; 56};
57 57
58void InstallInterfaces(SM::ServiceManager& sm) { 58void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
59 std::make_shared<BPC>()->InstallAsService(sm); 59 std::make_shared<BPC>(system)->InstallAsService(sm);
60 std::make_shared<BPC_R>()->InstallAsService(sm); 60 std::make_shared<BPC_R>(system)->InstallAsService(sm);
61} 61}
62 62
63} // namespace Service::BPC 63} // namespace Service::BPC
diff --git a/src/core/hle/service/bpc/bpc.h b/src/core/hle/service/bpc/bpc.h
index eaa37be8d..6ec25aa9b 100644
--- a/src/core/hle/service/bpc/bpc.h
+++ b/src/core/hle/service/bpc/bpc.h
@@ -4,12 +4,16 @@
4 4
5#pragma once 5#pragma once
6 6
7namespace Core {
8class System;
9}
10
7namespace Service::SM { 11namespace Service::SM {
8class ServiceManager; 12class ServiceManager;
9} 13}
10 14
11namespace Service::BPC { 15namespace Service::BPC {
12 16
13void InstallInterfaces(SM::ServiceManager& sm); 17void InstallInterfaces(SM::ServiceManager& sm, Core::System& system);
14 18
15} // namespace Service::BPC 19} // namespace Service::BPC
diff --git a/src/core/hle/service/btdrv/btdrv.cpp b/src/core/hle/service/btdrv/btdrv.cpp
index f311afa2f..2de86f1f1 100644
--- a/src/core/hle/service/btdrv/btdrv.cpp
+++ b/src/core/hle/service/btdrv/btdrv.cpp
@@ -3,6 +3,7 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/logging/log.h" 5#include "common/logging/log.h"
6#include "core/core.h"
6#include "core/hle/ipc_helpers.h" 7#include "core/hle/ipc_helpers.h"
7#include "core/hle/kernel/hle_ipc.h" 8#include "core/hle/kernel/hle_ipc.h"
8#include "core/hle/kernel/kernel.h" 9#include "core/hle/kernel/kernel.h"
@@ -16,7 +17,7 @@ namespace Service::BtDrv {
16 17
17class Bt final : public ServiceFramework<Bt> { 18class Bt final : public ServiceFramework<Bt> {
18public: 19public:
19 explicit Bt(Core::System& system) : ServiceFramework{"bt"} { 20 explicit Bt(Core::System& system_) : ServiceFramework{system_, "bt"} {
20 // clang-format off 21 // clang-format off
21 static const FunctionInfo functions[] = { 22 static const FunctionInfo functions[] = {
22 {0, nullptr, "LeClientReadCharacteristic"}, 23 {0, nullptr, "LeClientReadCharacteristic"},
@@ -51,7 +52,7 @@ private:
51 52
52class BtDrv final : public ServiceFramework<BtDrv> { 53class BtDrv final : public ServiceFramework<BtDrv> {
53public: 54public:
54 explicit BtDrv() : ServiceFramework{"btdrv"} { 55 explicit BtDrv(Core::System& system_) : ServiceFramework{system_, "btdrv"} {
55 // clang-format off 56 // clang-format off
56 static const FunctionInfo functions[] = { 57 static const FunctionInfo functions[] = {
57 {0, nullptr, "InitializeBluetoothDriver"}, 58 {0, nullptr, "InitializeBluetoothDriver"},
@@ -165,7 +166,7 @@ public:
165}; 166};
166 167
167void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) { 168void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
168 std::make_shared<BtDrv>()->InstallAsService(sm); 169 std::make_shared<BtDrv>(system)->InstallAsService(sm);
169 std::make_shared<Bt>(system)->InstallAsService(sm); 170 std::make_shared<Bt>(system)->InstallAsService(sm);
170} 171}
171 172
diff --git a/src/core/hle/service/btm/btm.cpp b/src/core/hle/service/btm/btm.cpp
index 0d251c6d0..38b55300e 100644
--- a/src/core/hle/service/btm/btm.cpp
+++ b/src/core/hle/service/btm/btm.cpp
@@ -5,6 +5,7 @@
5#include <memory> 5#include <memory>
6 6
7#include "common/logging/log.h" 7#include "common/logging/log.h"
8#include "core/core.h"
8#include "core/hle/ipc_helpers.h" 9#include "core/hle/ipc_helpers.h"
9#include "core/hle/kernel/hle_ipc.h" 10#include "core/hle/kernel/hle_ipc.h"
10#include "core/hle/kernel/kernel.h" 11#include "core/hle/kernel/kernel.h"
@@ -17,7 +18,7 @@ namespace Service::BTM {
17 18
18class IBtmUserCore final : public ServiceFramework<IBtmUserCore> { 19class IBtmUserCore final : public ServiceFramework<IBtmUserCore> {
19public: 20public:
20 explicit IBtmUserCore(Core::System& system) : ServiceFramework{"IBtmUserCore"} { 21 explicit IBtmUserCore(Core::System& system_) : ServiceFramework{system_, "IBtmUserCore"} {
21 // clang-format off 22 // clang-format off
22 static const FunctionInfo functions[] = { 23 static const FunctionInfo functions[] = {
23 {0, &IBtmUserCore::AcquireBleScanEvent, "AcquireBleScanEvent"}, 24 {0, &IBtmUserCore::AcquireBleScanEvent, "AcquireBleScanEvent"},
@@ -106,7 +107,7 @@ private:
106 107
107class BTM_USR final : public ServiceFramework<BTM_USR> { 108class BTM_USR final : public ServiceFramework<BTM_USR> {
108public: 109public:
109 explicit BTM_USR(Core::System& system) : ServiceFramework{"btm:u"}, system(system) { 110 explicit BTM_USR(Core::System& system_) : ServiceFramework{system_, "btm:u"} {
110 // clang-format off 111 // clang-format off
111 static const FunctionInfo functions[] = { 112 static const FunctionInfo functions[] = {
112 {0, &BTM_USR::GetCore, "GetCore"}, 113 {0, &BTM_USR::GetCore, "GetCore"},
@@ -123,13 +124,11 @@ private:
123 rb.Push(RESULT_SUCCESS); 124 rb.Push(RESULT_SUCCESS);
124 rb.PushIpcInterface<IBtmUserCore>(system); 125 rb.PushIpcInterface<IBtmUserCore>(system);
125 } 126 }
126
127 Core::System& system;
128}; 127};
129 128
130class BTM final : public ServiceFramework<BTM> { 129class BTM final : public ServiceFramework<BTM> {
131public: 130public:
132 explicit BTM() : ServiceFramework{"btm"} { 131 explicit BTM(Core::System& system_) : ServiceFramework{system_, "btm"} {
133 // clang-format off 132 // clang-format off
134 static const FunctionInfo functions[] = { 133 static const FunctionInfo functions[] = {
135 {0, nullptr, "GetState"}, 134 {0, nullptr, "GetState"},
@@ -206,7 +205,7 @@ public:
206 205
207class BTM_DBG final : public ServiceFramework<BTM_DBG> { 206class BTM_DBG final : public ServiceFramework<BTM_DBG> {
208public: 207public:
209 explicit BTM_DBG() : ServiceFramework{"btm:dbg"} { 208 explicit BTM_DBG(Core::System& system_) : ServiceFramework{system_, "btm:dbg"} {
210 // clang-format off 209 // clang-format off
211 static const FunctionInfo functions[] = { 210 static const FunctionInfo functions[] = {
212 {0, nullptr, "AcquireDiscoveryEvent"}, 211 {0, nullptr, "AcquireDiscoveryEvent"},
@@ -231,7 +230,7 @@ public:
231 230
232class IBtmSystemCore final : public ServiceFramework<IBtmSystemCore> { 231class IBtmSystemCore final : public ServiceFramework<IBtmSystemCore> {
233public: 232public:
234 explicit IBtmSystemCore() : ServiceFramework{"IBtmSystemCore"} { 233 explicit IBtmSystemCore(Core::System& system_) : ServiceFramework{system_, "IBtmSystemCore"} {
235 // clang-format off 234 // clang-format off
236 static const FunctionInfo functions[] = { 235 static const FunctionInfo functions[] = {
237 {0, nullptr, "StartGamepadPairing"}, 236 {0, nullptr, "StartGamepadPairing"},
@@ -253,7 +252,7 @@ public:
253 252
254class BTM_SYS final : public ServiceFramework<BTM_SYS> { 253class BTM_SYS final : public ServiceFramework<BTM_SYS> {
255public: 254public:
256 explicit BTM_SYS() : ServiceFramework{"btm:sys"} { 255 explicit BTM_SYS(Core::System& system_) : ServiceFramework{system_, "btm:sys"} {
257 // clang-format off 256 // clang-format off
258 static const FunctionInfo functions[] = { 257 static const FunctionInfo functions[] = {
259 {0, &BTM_SYS::GetCore, "GetCore"}, 258 {0, &BTM_SYS::GetCore, "GetCore"},
@@ -269,14 +268,14 @@ private:
269 268
270 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 269 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
271 rb.Push(RESULT_SUCCESS); 270 rb.Push(RESULT_SUCCESS);
272 rb.PushIpcInterface<IBtmSystemCore>(); 271 rb.PushIpcInterface<IBtmSystemCore>(system);
273 } 272 }
274}; 273};
275 274
276void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) { 275void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
277 std::make_shared<BTM>()->InstallAsService(sm); 276 std::make_shared<BTM>(system)->InstallAsService(sm);
278 std::make_shared<BTM_DBG>()->InstallAsService(sm); 277 std::make_shared<BTM_DBG>(system)->InstallAsService(sm);
279 std::make_shared<BTM_SYS>()->InstallAsService(sm); 278 std::make_shared<BTM_SYS>(system)->InstallAsService(sm);
280 std::make_shared<BTM_USR>(system)->InstallAsService(sm); 279 std::make_shared<BTM_USR>(system)->InstallAsService(sm);
281} 280}
282 281
diff --git a/src/core/hle/service/caps/caps.cpp b/src/core/hle/service/caps/caps.cpp
index ba5749b84..5b7fe8e9b 100644
--- a/src/core/hle/service/caps/caps.cpp
+++ b/src/core/hle/service/caps/caps.cpp
@@ -13,13 +13,13 @@
13 13
14namespace Service::Capture { 14namespace Service::Capture {
15 15
16void InstallInterfaces(SM::ServiceManager& sm) { 16void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
17 std::make_shared<CAPS_A>()->InstallAsService(sm); 17 std::make_shared<CAPS_A>(system)->InstallAsService(sm);
18 std::make_shared<CAPS_C>()->InstallAsService(sm); 18 std::make_shared<CAPS_C>(system)->InstallAsService(sm);
19 std::make_shared<CAPS_U>()->InstallAsService(sm); 19 std::make_shared<CAPS_U>(system)->InstallAsService(sm);
20 std::make_shared<CAPS_SC>()->InstallAsService(sm); 20 std::make_shared<CAPS_SC>(system)->InstallAsService(sm);
21 std::make_shared<CAPS_SS>()->InstallAsService(sm); 21 std::make_shared<CAPS_SS>(system)->InstallAsService(sm);
22 std::make_shared<CAPS_SU>()->InstallAsService(sm); 22 std::make_shared<CAPS_SU>(system)->InstallAsService(sm);
23} 23}
24 24
25} // namespace Service::Capture 25} // namespace Service::Capture
diff --git a/src/core/hle/service/caps/caps.h b/src/core/hle/service/caps/caps.h
index b8c67b6e2..3c4290c88 100644
--- a/src/core/hle/service/caps/caps.h
+++ b/src/core/hle/service/caps/caps.h
@@ -6,6 +6,10 @@
6 6
7#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
8 8
9namespace Core {
10class System;
11}
12
9namespace Service::SM { 13namespace Service::SM {
10class ServiceManager; 14class ServiceManager;
11} 15}
@@ -87,6 +91,6 @@ static_assert(sizeof(ApplicationAlbumFileEntry) == 0x30,
87 "ApplicationAlbumFileEntry has incorrect size."); 91 "ApplicationAlbumFileEntry has incorrect size.");
88 92
89/// Registers all Capture services with the specified service manager. 93/// Registers all Capture services with the specified service manager.
90void InstallInterfaces(SM::ServiceManager& sm); 94void InstallInterfaces(SM::ServiceManager& sm, Core::System& system);
91 95
92} // namespace Service::Capture 96} // namespace Service::Capture
diff --git a/src/core/hle/service/caps/caps_a.cpp b/src/core/hle/service/caps/caps_a.cpp
index a0a3b2ae3..1fe4f0e14 100644
--- a/src/core/hle/service/caps/caps_a.cpp
+++ b/src/core/hle/service/caps/caps_a.cpp
@@ -8,7 +8,8 @@ namespace Service::Capture {
8 8
9class IAlbumAccessorSession final : public ServiceFramework<IAlbumAccessorSession> { 9class IAlbumAccessorSession final : public ServiceFramework<IAlbumAccessorSession> {
10public: 10public:
11 explicit IAlbumAccessorSession() : ServiceFramework{"IAlbumAccessorSession"} { 11 explicit IAlbumAccessorSession(Core::System& system_)
12 : ServiceFramework{system_, "IAlbumAccessorSession"} {
12 // clang-format off 13 // clang-format off
13 static const FunctionInfo functions[] = { 14 static const FunctionInfo functions[] = {
14 {2001, nullptr, "OpenAlbumMovieReadStream"}, 15 {2001, nullptr, "OpenAlbumMovieReadStream"},
@@ -26,7 +27,7 @@ public:
26 } 27 }
27}; 28};
28 29
29CAPS_A::CAPS_A() : ServiceFramework("caps:a") { 30CAPS_A::CAPS_A(Core::System& system_) : ServiceFramework{system_, "caps:a"} {
30 // clang-format off 31 // clang-format off
31 static const FunctionInfo functions[] = { 32 static const FunctionInfo functions[] = {
32 {0, nullptr, "GetAlbumFileCount"}, 33 {0, nullptr, "GetAlbumFileCount"},
diff --git a/src/core/hle/service/caps/caps_a.h b/src/core/hle/service/caps/caps_a.h
index cb93aad5b..389cc6dbe 100644
--- a/src/core/hle/service/caps/caps_a.h
+++ b/src/core/hle/service/caps/caps_a.h
@@ -6,6 +6,10 @@
6 6
7#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
8 8
9namespace Core {
10class System;
11}
12
9namespace Kernel { 13namespace Kernel {
10class HLERequestContext; 14class HLERequestContext;
11} 15}
@@ -14,7 +18,7 @@ namespace Service::Capture {
14 18
15class CAPS_A final : public ServiceFramework<CAPS_A> { 19class CAPS_A final : public ServiceFramework<CAPS_A> {
16public: 20public:
17 explicit CAPS_A(); 21 explicit CAPS_A(Core::System& system_);
18 ~CAPS_A() override; 22 ~CAPS_A() override;
19}; 23};
20 24
diff --git a/src/core/hle/service/caps/caps_c.cpp b/src/core/hle/service/caps/caps_c.cpp
index ab17a187e..45c1c9d30 100644
--- a/src/core/hle/service/caps/caps_c.cpp
+++ b/src/core/hle/service/caps/caps_c.cpp
@@ -2,13 +2,16 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/logging/log.h"
6#include "core/hle/ipc_helpers.h"
5#include "core/hle/service/caps/caps_c.h" 7#include "core/hle/service/caps/caps_c.h"
6 8
7namespace Service::Capture { 9namespace Service::Capture {
8 10
9class IAlbumControlSession final : public ServiceFramework<IAlbumControlSession> { 11class IAlbumControlSession final : public ServiceFramework<IAlbumControlSession> {
10public: 12public:
11 explicit IAlbumControlSession() : ServiceFramework{"IAlbumControlSession"} { 13 explicit IAlbumControlSession(Core::System& system_)
14 : ServiceFramework{system_, "IAlbumControlSession"} {
12 // clang-format off 15 // clang-format off
13 static const FunctionInfo functions[] = { 16 static const FunctionInfo functions[] = {
14 {2001, nullptr, "OpenAlbumMovieReadStream"}, 17 {2001, nullptr, "OpenAlbumMovieReadStream"},
@@ -42,12 +45,12 @@ public:
42 } 45 }
43}; 46};
44 47
45CAPS_C::CAPS_C() : ServiceFramework("caps:c") { 48CAPS_C::CAPS_C(Core::System& system_) : ServiceFramework{system_, "caps:c"} {
46 // clang-format off 49 // clang-format off
47 static const FunctionInfo functions[] = { 50 static const FunctionInfo functions[] = {
48 {1, nullptr, "CaptureRawImage"}, 51 {1, nullptr, "CaptureRawImage"},
49 {2, nullptr, "CaptureRawImageWithTimeout"}, 52 {2, nullptr, "CaptureRawImageWithTimeout"},
50 {33, nullptr, "Unknown33"}, 53 {33, &CAPS_C::SetShimLibraryVersion, "SetShimLibraryVersion"},
51 {1001, nullptr, "RequestTakingScreenShot"}, 54 {1001, nullptr, "RequestTakingScreenShot"},
52 {1002, nullptr, "RequestTakingScreenShotWithTimeout"}, 55 {1002, nullptr, "RequestTakingScreenShotWithTimeout"},
53 {1011, nullptr, "NotifyTakingScreenShotRefused"}, 56 {1011, nullptr, "NotifyTakingScreenShotRefused"},
@@ -72,4 +75,16 @@ CAPS_C::CAPS_C() : ServiceFramework("caps:c") {
72 75
73CAPS_C::~CAPS_C() = default; 76CAPS_C::~CAPS_C() = default;
74 77
78void CAPS_C::SetShimLibraryVersion(Kernel::HLERequestContext& ctx) {
79 IPC::RequestParser rp{ctx};
80 const auto library_version{rp.Pop<u64>()};
81 const auto applet_resource_user_id{rp.Pop<u64>()};
82
83 LOG_WARNING(Service_Capture, "(STUBBED) called. library_version={}, applet_resource_user_id={}",
84 library_version, applet_resource_user_id);
85
86 IPC::ResponseBuilder rb{ctx, 2};
87 rb.Push(RESULT_SUCCESS);
88}
89
75} // namespace Service::Capture 90} // namespace Service::Capture
diff --git a/src/core/hle/service/caps/caps_c.h b/src/core/hle/service/caps/caps_c.h
index a9d028689..c6d1dfdce 100644
--- a/src/core/hle/service/caps/caps_c.h
+++ b/src/core/hle/service/caps/caps_c.h
@@ -6,6 +6,10 @@
6 6
7#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
8 8
9namespace Core {
10class System;
11}
12
9namespace Kernel { 13namespace Kernel {
10class HLERequestContext; 14class HLERequestContext;
11} 15}
@@ -14,8 +18,11 @@ namespace Service::Capture {
14 18
15class CAPS_C final : public ServiceFramework<CAPS_C> { 19class CAPS_C final : public ServiceFramework<CAPS_C> {
16public: 20public:
17 explicit CAPS_C(); 21 explicit CAPS_C(Core::System& system_);
18 ~CAPS_C() override; 22 ~CAPS_C() override;
23
24private:
25 void SetShimLibraryVersion(Kernel::HLERequestContext& ctx);
19}; 26};
20 27
21} // namespace Service::Capture 28} // namespace Service::Capture
diff --git a/src/core/hle/service/caps/caps_sc.cpp b/src/core/hle/service/caps/caps_sc.cpp
index 822ee96c8..d91e18e80 100644
--- a/src/core/hle/service/caps/caps_sc.cpp
+++ b/src/core/hle/service/caps/caps_sc.cpp
@@ -6,7 +6,7 @@
6 6
7namespace Service::Capture { 7namespace Service::Capture {
8 8
9CAPS_SC::CAPS_SC() : ServiceFramework("caps:sc") { 9CAPS_SC::CAPS_SC(Core::System& system_) : ServiceFramework{system_, "caps:sc"} {
10 // clang-format off 10 // clang-format off
11 static const FunctionInfo functions[] = { 11 static const FunctionInfo functions[] = {
12 {1, nullptr, "CaptureRawImage"}, 12 {1, nullptr, "CaptureRawImage"},
diff --git a/src/core/hle/service/caps/caps_sc.h b/src/core/hle/service/caps/caps_sc.h
index ac3e929ca..e79a33ee5 100644
--- a/src/core/hle/service/caps/caps_sc.h
+++ b/src/core/hle/service/caps/caps_sc.h
@@ -6,15 +6,15 @@
6 6
7#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
8 8
9namespace Kernel { 9namespace Core {
10class HLERequestContext; 10class System;
11} 11}
12 12
13namespace Service::Capture { 13namespace Service::Capture {
14 14
15class CAPS_SC final : public ServiceFramework<CAPS_SC> { 15class CAPS_SC final : public ServiceFramework<CAPS_SC> {
16public: 16public:
17 explicit CAPS_SC(); 17 explicit CAPS_SC(Core::System& system_);
18 ~CAPS_SC() override; 18 ~CAPS_SC() override;
19}; 19};
20 20
diff --git a/src/core/hle/service/caps/caps_ss.cpp b/src/core/hle/service/caps/caps_ss.cpp
index 24dc716e7..2b5314691 100644
--- a/src/core/hle/service/caps/caps_ss.cpp
+++ b/src/core/hle/service/caps/caps_ss.cpp
@@ -6,7 +6,7 @@
6 6
7namespace Service::Capture { 7namespace Service::Capture {
8 8
9CAPS_SS::CAPS_SS() : ServiceFramework("caps:ss") { 9CAPS_SS::CAPS_SS(Core::System& system_) : ServiceFramework{system_, "caps:ss"} {
10 // clang-format off 10 // clang-format off
11 static const FunctionInfo functions[] = { 11 static const FunctionInfo functions[] = {
12 {201, nullptr, "SaveScreenShot"}, 12 {201, nullptr, "SaveScreenShot"},
diff --git a/src/core/hle/service/caps/caps_ss.h b/src/core/hle/service/caps/caps_ss.h
index 450686e4f..1816f7885 100644
--- a/src/core/hle/service/caps/caps_ss.h
+++ b/src/core/hle/service/caps/caps_ss.h
@@ -6,15 +6,15 @@
6 6
7#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
8 8
9namespace Kernel { 9namespace Core {
10class HLERequestContext; 10class System;
11} 11}
12 12
13namespace Service::Capture { 13namespace Service::Capture {
14 14
15class CAPS_SS final : public ServiceFramework<CAPS_SS> { 15class CAPS_SS final : public ServiceFramework<CAPS_SS> {
16public: 16public:
17 explicit CAPS_SS(); 17 explicit CAPS_SS(Core::System& system_);
18 ~CAPS_SS() override; 18 ~CAPS_SS() override;
19}; 19};
20 20
diff --git a/src/core/hle/service/caps/caps_su.cpp b/src/core/hle/service/caps/caps_su.cpp
index fffb2ecf9..eae39eb7b 100644
--- a/src/core/hle/service/caps/caps_su.cpp
+++ b/src/core/hle/service/caps/caps_su.cpp
@@ -8,7 +8,7 @@
8 8
9namespace Service::Capture { 9namespace Service::Capture {
10 10
11CAPS_SU::CAPS_SU() : ServiceFramework("caps:su") { 11CAPS_SU::CAPS_SU(Core::System& system_) : ServiceFramework{system_, "caps:su"} {
12 // clang-format off 12 // clang-format off
13 static const FunctionInfo functions[] = { 13 static const FunctionInfo functions[] = {
14 {32, &CAPS_SU::SetShimLibraryVersion, "SetShimLibraryVersion"}, 14 {32, &CAPS_SU::SetShimLibraryVersion, "SetShimLibraryVersion"},
@@ -25,7 +25,12 @@ CAPS_SU::CAPS_SU() : ServiceFramework("caps:su") {
25CAPS_SU::~CAPS_SU() = default; 25CAPS_SU::~CAPS_SU() = default;
26 26
27void CAPS_SU::SetShimLibraryVersion(Kernel::HLERequestContext& ctx) { 27void CAPS_SU::SetShimLibraryVersion(Kernel::HLERequestContext& ctx) {
28 LOG_WARNING(Service_Capture, "(STUBBED) called"); 28 IPC::RequestParser rp{ctx};
29 const auto library_version{rp.Pop<u64>()};
30 const auto applet_resource_user_id{rp.Pop<u64>()};
31
32 LOG_WARNING(Service_Capture, "(STUBBED) called. library_version={}, applet_resource_user_id={}",
33 library_version, applet_resource_user_id);
29 34
30 IPC::ResponseBuilder rb{ctx, 2}; 35 IPC::ResponseBuilder rb{ctx, 2};
31 rb.Push(RESULT_SUCCESS); 36 rb.Push(RESULT_SUCCESS);
diff --git a/src/core/hle/service/caps/caps_su.h b/src/core/hle/service/caps/caps_su.h
index 62c9603a9..b366fdb13 100644
--- a/src/core/hle/service/caps/caps_su.h
+++ b/src/core/hle/service/caps/caps_su.h
@@ -6,6 +6,10 @@
6 6
7#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
8 8
9namespace Core {
10class System;
11}
12
9namespace Kernel { 13namespace Kernel {
10class HLERequestContext; 14class HLERequestContext;
11} 15}
@@ -14,7 +18,7 @@ namespace Service::Capture {
14 18
15class CAPS_SU final : public ServiceFramework<CAPS_SU> { 19class CAPS_SU final : public ServiceFramework<CAPS_SU> {
16public: 20public:
17 explicit CAPS_SU(); 21 explicit CAPS_SU(Core::System& system_);
18 ~CAPS_SU() override; 22 ~CAPS_SU() override;
19 23
20private: 24private:
diff --git a/src/core/hle/service/caps/caps_u.cpp b/src/core/hle/service/caps/caps_u.cpp
index f36d8de2d..842316a2e 100644
--- a/src/core/hle/service/caps/caps_u.cpp
+++ b/src/core/hle/service/caps/caps_u.cpp
@@ -12,8 +12,8 @@ namespace Service::Capture {
12class IAlbumAccessorApplicationSession final 12class IAlbumAccessorApplicationSession final
13 : public ServiceFramework<IAlbumAccessorApplicationSession> { 13 : public ServiceFramework<IAlbumAccessorApplicationSession> {
14public: 14public:
15 explicit IAlbumAccessorApplicationSession() 15 explicit IAlbumAccessorApplicationSession(Core::System& system_)
16 : ServiceFramework{"IAlbumAccessorApplicationSession"} { 16 : ServiceFramework{system_, "IAlbumAccessorApplicationSession"} {
17 // clang-format off 17 // clang-format off
18 static const FunctionInfo functions[] = { 18 static const FunctionInfo functions[] = {
19 {2001, nullptr, "OpenAlbumMovieReadStream"}, 19 {2001, nullptr, "OpenAlbumMovieReadStream"},
@@ -28,11 +28,10 @@ public:
28 } 28 }
29}; 29};
30 30
31CAPS_U::CAPS_U() : ServiceFramework("caps:u") { 31CAPS_U::CAPS_U(Core::System& system_) : ServiceFramework{system_, "caps:u"} {
32 // clang-format off 32 // clang-format off
33 static const FunctionInfo functions[] = { 33 static const FunctionInfo functions[] = {
34 {31, nullptr, "GetShimLibraryVersion"}, 34 {32, &CAPS_U::SetShimLibraryVersion, "SetShimLibraryVersion"},
35 {32, nullptr, "SetShimLibraryVersion"},
36 {102, &CAPS_U::GetAlbumContentsFileListForApplication, "GetAlbumContentsFileListForApplication"}, 35 {102, &CAPS_U::GetAlbumContentsFileListForApplication, "GetAlbumContentsFileListForApplication"},
37 {103, nullptr, "DeleteAlbumContentsFileForApplication"}, 36 {103, nullptr, "DeleteAlbumContentsFileForApplication"},
38 {104, nullptr, "GetAlbumContentsFileSizeForApplication"}, 37 {104, nullptr, "GetAlbumContentsFileSizeForApplication"},
@@ -42,7 +41,7 @@ CAPS_U::CAPS_U() : ServiceFramework("caps:u") {
42 {130, nullptr, "PrecheckToCreateContentsForApplication"}, 41 {130, nullptr, "PrecheckToCreateContentsForApplication"},
43 {140, nullptr, "GetAlbumFileList1AafeAruidDeprecated"}, 42 {140, nullptr, "GetAlbumFileList1AafeAruidDeprecated"},
44 {141, nullptr, "GetAlbumFileList2AafeUidAruidDeprecated"}, 43 {141, nullptr, "GetAlbumFileList2AafeUidAruidDeprecated"},
45 {142, nullptr, "GetAlbumFileList3AaeAruid"}, 44 {142, &CAPS_U::GetAlbumFileList3AaeAruid, "GetAlbumFileList3AaeAruid"},
46 {143, nullptr, "GetAlbumFileList4AaeUidAruid"}, 45 {143, nullptr, "GetAlbumFileList4AaeUidAruid"},
47 {60002, nullptr, "OpenAccessorSessionForApplication"}, 46 {60002, nullptr, "OpenAccessorSessionForApplication"},
48 }; 47 };
@@ -53,6 +52,18 @@ CAPS_U::CAPS_U() : ServiceFramework("caps:u") {
53 52
54CAPS_U::~CAPS_U() = default; 53CAPS_U::~CAPS_U() = default;
55 54
55void CAPS_U::SetShimLibraryVersion(Kernel::HLERequestContext& ctx) {
56 IPC::RequestParser rp{ctx};
57 const auto library_version{rp.Pop<u64>()};
58 const auto applet_resource_user_id{rp.Pop<u64>()};
59
60 LOG_WARNING(Service_Capture, "(STUBBED) called. library_version={}, applet_resource_user_id={}",
61 library_version, applet_resource_user_id);
62
63 IPC::ResponseBuilder rb{ctx, 2};
64 rb.Push(RESULT_SUCCESS);
65}
66
56void CAPS_U::GetAlbumContentsFileListForApplication(Kernel::HLERequestContext& ctx) { 67void CAPS_U::GetAlbumContentsFileListForApplication(Kernel::HLERequestContext& ctx) {
57 // Takes a type-0x6 output buffer containing an array of ApplicationAlbumFileEntry, a PID, an 68 // Takes a type-0x6 output buffer containing an array of ApplicationAlbumFileEntry, a PID, an
58 // u8 ContentType, two s64s, and an u64 AppletResourceUserId. Returns an output u64 for total 69 // u8 ContentType, two s64s, and an u64 AppletResourceUserId. Returns an output u64 for total
@@ -66,17 +77,24 @@ void CAPS_U::GetAlbumContentsFileListForApplication(Kernel::HLERequestContext& c
66 77
67 // TODO: Update this when we implement the album. 78 // TODO: Update this when we implement the album.
68 // Currently we do not have a method of accessing album entries, set this to 0 for now. 79 // Currently we do not have a method of accessing album entries, set this to 0 for now.
69 constexpr s32 total_entries{0}; 80 constexpr u32 total_entries_1{};
81 constexpr u32 total_entries_2{};
70 82
71 LOG_WARNING(Service_Capture, 83 LOG_WARNING(
72 "(STUBBED) called. pid={}, content_type={}, start_posix_time={}, " 84 Service_Capture,
73 "end_posix_time={}, applet_resource_user_id={}, total_entries={}", 85 "(STUBBED) called. pid={}, content_type={}, start_posix_time={}, "
74 pid, content_type, start_posix_time, end_posix_time, applet_resource_user_id, 86 "end_posix_time={}, applet_resource_user_id={}, total_entries_1={}, total_entries_2={}",
75 total_entries); 87 pid, content_type, start_posix_time, end_posix_time, applet_resource_user_id,
88 total_entries_1, total_entries_2);
76 89
77 IPC::ResponseBuilder rb{ctx, 3}; 90 IPC::ResponseBuilder rb{ctx, 4};
78 rb.Push(RESULT_SUCCESS); 91 rb.Push(RESULT_SUCCESS);
79 rb.Push(total_entries); 92 rb.Push(total_entries_1);
93 rb.Push(total_entries_2);
94}
95
96void CAPS_U::GetAlbumFileList3AaeAruid(Kernel::HLERequestContext& ctx) {
97 GetAlbumContentsFileListForApplication(ctx);
80} 98}
81 99
82} // namespace Service::Capture 100} // namespace Service::Capture
diff --git a/src/core/hle/service/caps/caps_u.h b/src/core/hle/service/caps/caps_u.h
index 689364de4..e7e0d8775 100644
--- a/src/core/hle/service/caps/caps_u.h
+++ b/src/core/hle/service/caps/caps_u.h
@@ -6,6 +6,10 @@
6 6
7#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
8 8
9namespace Core {
10class System;
11}
12
9namespace Kernel { 13namespace Kernel {
10class HLERequestContext; 14class HLERequestContext;
11} 15}
@@ -14,11 +18,13 @@ namespace Service::Capture {
14 18
15class CAPS_U final : public ServiceFramework<CAPS_U> { 19class CAPS_U final : public ServiceFramework<CAPS_U> {
16public: 20public:
17 explicit CAPS_U(); 21 explicit CAPS_U(Core::System& system_);
18 ~CAPS_U() override; 22 ~CAPS_U() override;
19 23
20private: 24private:
25 void SetShimLibraryVersion(Kernel::HLERequestContext& ctx);
21 void GetAlbumContentsFileListForApplication(Kernel::HLERequestContext& ctx); 26 void GetAlbumContentsFileListForApplication(Kernel::HLERequestContext& ctx);
27 void GetAlbumFileList3AaeAruid(Kernel::HLERequestContext& ctx);
22}; 28};
23 29
24} // namespace Service::Capture 30} // namespace Service::Capture
diff --git a/src/core/hle/service/erpt/erpt.cpp b/src/core/hle/service/erpt/erpt.cpp
index 4ec8c3093..4924c61c3 100644
--- a/src/core/hle/service/erpt/erpt.cpp
+++ b/src/core/hle/service/erpt/erpt.cpp
@@ -12,7 +12,7 @@ namespace Service::ERPT {
12 12
13class ErrorReportContext final : public ServiceFramework<ErrorReportContext> { 13class ErrorReportContext final : public ServiceFramework<ErrorReportContext> {
14public: 14public:
15 explicit ErrorReportContext() : ServiceFramework{"erpt:c"} { 15 explicit ErrorReportContext(Core::System& system_) : ServiceFramework{system_, "erpt:c"} {
16 // clang-format off 16 // clang-format off
17 static const FunctionInfo functions[] = { 17 static const FunctionInfo functions[] = {
18 {0, nullptr, "SubmitContext"}, 18 {0, nullptr, "SubmitContext"},
@@ -35,7 +35,7 @@ public:
35 35
36class ErrorReportSession final : public ServiceFramework<ErrorReportSession> { 36class ErrorReportSession final : public ServiceFramework<ErrorReportSession> {
37public: 37public:
38 explicit ErrorReportSession() : ServiceFramework{"erpt:r"} { 38 explicit ErrorReportSession(Core::System& system_) : ServiceFramework{system_, "erpt:r"} {
39 // clang-format off 39 // clang-format off
40 static const FunctionInfo functions[] = { 40 static const FunctionInfo functions[] = {
41 {0, nullptr, "OpenReport"}, 41 {0, nullptr, "OpenReport"},
@@ -48,9 +48,9 @@ public:
48 } 48 }
49}; 49};
50 50
51void InstallInterfaces(SM::ServiceManager& sm) { 51void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
52 std::make_shared<ErrorReportContext>()->InstallAsService(sm); 52 std::make_shared<ErrorReportContext>(system)->InstallAsService(sm);
53 std::make_shared<ErrorReportSession>()->InstallAsService(sm); 53 std::make_shared<ErrorReportSession>(system)->InstallAsService(sm);
54} 54}
55 55
56} // namespace Service::ERPT 56} // namespace Service::ERPT
diff --git a/src/core/hle/service/erpt/erpt.h b/src/core/hle/service/erpt/erpt.h
index de439ab6d..8cd5c081f 100644
--- a/src/core/hle/service/erpt/erpt.h
+++ b/src/core/hle/service/erpt/erpt.h
@@ -4,6 +4,10 @@
4 4
5#pragma once 5#pragma once
6 6
7namespace Core {
8class System;
9}
10
7namespace Service::SM { 11namespace Service::SM {
8class ServiceManager; 12class ServiceManager;
9} 13}
@@ -11,6 +15,6 @@ class ServiceManager;
11namespace Service::ERPT { 15namespace Service::ERPT {
12 16
13/// Registers all ERPT services with the specified service manager. 17/// Registers all ERPT services with the specified service manager.
14void InstallInterfaces(SM::ServiceManager& sm); 18void InstallInterfaces(SM::ServiceManager& sm, Core::System& system);
15 19
16} // namespace Service::ERPT 20} // namespace Service::ERPT
diff --git a/src/core/hle/service/es/es.cpp b/src/core/hle/service/es/es.cpp
index c2737a365..26d1e3306 100644
--- a/src/core/hle/service/es/es.cpp
+++ b/src/core/hle/service/es/es.cpp
@@ -14,7 +14,7 @@ constexpr ResultCode ERROR_INVALID_RIGHTS_ID{ErrorModule::ETicket, 3};
14 14
15class ETicket final : public ServiceFramework<ETicket> { 15class ETicket final : public ServiceFramework<ETicket> {
16public: 16public:
17 explicit ETicket() : ServiceFramework{"es"} { 17 explicit ETicket(Core::System& system_) : ServiceFramework{system_, "es"} {
18 // clang-format off 18 // clang-format off
19 static const FunctionInfo functions[] = { 19 static const FunctionInfo functions[] = {
20 {1, &ETicket::ImportTicket, "ImportTicket"}, 20 {1, &ETicket::ImportTicket, "ImportTicket"},
@@ -305,8 +305,8 @@ private:
305 Core::Crypto::KeyManager& keys = Core::Crypto::KeyManager::Instance(); 305 Core::Crypto::KeyManager& keys = Core::Crypto::KeyManager::Instance();
306}; 306};
307 307
308void InstallInterfaces(SM::ServiceManager& service_manager) { 308void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
309 std::make_shared<ETicket>()->InstallAsService(service_manager); 309 std::make_shared<ETicket>(system)->InstallAsService(service_manager);
310} 310}
311 311
312} // namespace Service::ES 312} // namespace Service::ES
diff --git a/src/core/hle/service/es/es.h b/src/core/hle/service/es/es.h
index afe70465b..2a7b27d12 100644
--- a/src/core/hle/service/es/es.h
+++ b/src/core/hle/service/es/es.h
@@ -4,6 +4,10 @@
4 4
5#pragma once 5#pragma once
6 6
7namespace Core {
8class System;
9}
10
7namespace Service::SM { 11namespace Service::SM {
8class ServiceManager; 12class ServiceManager;
9} 13}
@@ -11,6 +15,6 @@ class ServiceManager;
11namespace Service::ES { 15namespace Service::ES {
12 16
13/// Registers all ES services with the specified service manager. 17/// Registers all ES services with the specified service manager.
14void InstallInterfaces(SM::ServiceManager& service_manager); 18void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system);
15 19
16} // namespace Service::ES 20} // namespace Service::ES
diff --git a/src/core/hle/service/eupld/eupld.cpp b/src/core/hle/service/eupld/eupld.cpp
index 0d6d244f4..2d650b1b7 100644
--- a/src/core/hle/service/eupld/eupld.cpp
+++ b/src/core/hle/service/eupld/eupld.cpp
@@ -12,7 +12,7 @@ namespace Service::EUPLD {
12 12
13class ErrorUploadContext final : public ServiceFramework<ErrorUploadContext> { 13class ErrorUploadContext final : public ServiceFramework<ErrorUploadContext> {
14public: 14public:
15 explicit ErrorUploadContext() : ServiceFramework{"eupld:c"} { 15 explicit ErrorUploadContext(Core::System& system_) : ServiceFramework{system_, "eupld:c"} {
16 // clang-format off 16 // clang-format off
17 static const FunctionInfo functions[] = { 17 static const FunctionInfo functions[] = {
18 {0, nullptr, "SetUrl"}, 18 {0, nullptr, "SetUrl"},
@@ -29,7 +29,7 @@ public:
29 29
30class ErrorUploadRequest final : public ServiceFramework<ErrorUploadRequest> { 30class ErrorUploadRequest final : public ServiceFramework<ErrorUploadRequest> {
31public: 31public:
32 explicit ErrorUploadRequest() : ServiceFramework{"eupld:r"} { 32 explicit ErrorUploadRequest(Core::System& system_) : ServiceFramework{system_, "eupld:r"} {
33 // clang-format off 33 // clang-format off
34 static const FunctionInfo functions[] = { 34 static const FunctionInfo functions[] = {
35 {0, nullptr, "Initialize"}, 35 {0, nullptr, "Initialize"},
@@ -45,9 +45,9 @@ public:
45 } 45 }
46}; 46};
47 47
48void InstallInterfaces(SM::ServiceManager& sm) { 48void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
49 std::make_shared<ErrorUploadContext>()->InstallAsService(sm); 49 std::make_shared<ErrorUploadContext>(system)->InstallAsService(sm);
50 std::make_shared<ErrorUploadRequest>()->InstallAsService(sm); 50 std::make_shared<ErrorUploadRequest>(system)->InstallAsService(sm);
51} 51}
52 52
53} // namespace Service::EUPLD 53} // namespace Service::EUPLD
diff --git a/src/core/hle/service/eupld/eupld.h b/src/core/hle/service/eupld/eupld.h
index 6eef2c15f..539993a9d 100644
--- a/src/core/hle/service/eupld/eupld.h
+++ b/src/core/hle/service/eupld/eupld.h
@@ -4,6 +4,10 @@
4 4
5#pragma once 5#pragma once
6 6
7namespace Core {
8class System;
9}
10
7namespace Service::SM { 11namespace Service::SM {
8class ServiceManager; 12class ServiceManager;
9} 13}
@@ -11,6 +15,6 @@ class ServiceManager;
11namespace Service::EUPLD { 15namespace Service::EUPLD {
12 16
13/// Registers all EUPLD services with the specified service manager. 17/// Registers all EUPLD services with the specified service manager.
14void InstallInterfaces(SM::ServiceManager& sm); 18void InstallInterfaces(SM::ServiceManager& sm, Core::System& system);
15 19
16} // namespace Service::EUPLD 20} // namespace Service::EUPLD
diff --git a/src/core/hle/service/fatal/fatal.cpp b/src/core/hle/service/fatal/fatal.cpp
index 2546d7595..13147472e 100644
--- a/src/core/hle/service/fatal/fatal.cpp
+++ b/src/core/hle/service/fatal/fatal.cpp
@@ -20,8 +20,9 @@
20 20
21namespace Service::Fatal { 21namespace Service::Fatal {
22 22
23Module::Interface::Interface(std::shared_ptr<Module> module, Core::System& system, const char* name) 23Module::Interface::Interface(std::shared_ptr<Module> module_, Core::System& system_,
24 : ServiceFramework(name), module(std::move(module)), system(system) {} 24 const char* name)
25 : ServiceFramework{system_, name}, module{std::move(module_)} {}
25 26
26Module::Interface::~Interface() = default; 27Module::Interface::~Interface() = default;
27 28
@@ -110,8 +111,9 @@ static void GenerateErrorReport(Core::System& system, ResultCode error_code,
110 111
111static void ThrowFatalError(Core::System& system, ResultCode error_code, FatalType fatal_type, 112static void ThrowFatalError(Core::System& system, ResultCode error_code, FatalType fatal_type,
112 const FatalInfo& info) { 113 const FatalInfo& info) {
113 LOG_ERROR(Service_Fatal, "Threw fatal error type {} with error code 0x{:X}", 114 LOG_ERROR(Service_Fatal, "Threw fatal error type {} with error code 0x{:X}", fatal_type,
114 static_cast<u32>(fatal_type), error_code.raw); 115 error_code.raw);
116
115 switch (fatal_type) { 117 switch (fatal_type) {
116 case FatalType::ErrorReportAndScreen: 118 case FatalType::ErrorReportAndScreen:
117 GenerateErrorReport(system, error_code, info); 119 GenerateErrorReport(system, error_code, info);
diff --git a/src/core/hle/service/fatal/fatal.h b/src/core/hle/service/fatal/fatal.h
index bd9339dfc..2095bf89f 100644
--- a/src/core/hle/service/fatal/fatal.h
+++ b/src/core/hle/service/fatal/fatal.h
@@ -16,7 +16,8 @@ class Module final {
16public: 16public:
17 class Interface : public ServiceFramework<Interface> { 17 class Interface : public ServiceFramework<Interface> {
18 public: 18 public:
19 explicit Interface(std::shared_ptr<Module> module, Core::System& system, const char* name); 19 explicit Interface(std::shared_ptr<Module> module_, Core::System& system_,
20 const char* name);
20 ~Interface() override; 21 ~Interface() override;
21 22
22 void ThrowFatal(Kernel::HLERequestContext& ctx); 23 void ThrowFatal(Kernel::HLERequestContext& ctx);
@@ -25,7 +26,6 @@ public:
25 26
26 protected: 27 protected:
27 std::shared_ptr<Module> module; 28 std::shared_ptr<Module> module;
28 Core::System& system;
29 }; 29 };
30}; 30};
31 31
diff --git a/src/core/hle/service/fatal/fatal_p.cpp b/src/core/hle/service/fatal/fatal_p.cpp
index 066ccf6b0..8672b85dc 100644
--- a/src/core/hle/service/fatal/fatal_p.cpp
+++ b/src/core/hle/service/fatal/fatal_p.cpp
@@ -6,8 +6,8 @@
6 6
7namespace Service::Fatal { 7namespace Service::Fatal {
8 8
9Fatal_P::Fatal_P(std::shared_ptr<Module> module, Core::System& system) 9Fatal_P::Fatal_P(std::shared_ptr<Module> module_, Core::System& system_)
10 : Module::Interface(std::move(module), system, "fatal:p") {} 10 : Interface(std::move(module_), system_, "fatal:p") {}
11 11
12Fatal_P::~Fatal_P() = default; 12Fatal_P::~Fatal_P() = default;
13 13
diff --git a/src/core/hle/service/fatal/fatal_p.h b/src/core/hle/service/fatal/fatal_p.h
index c6d953cb5..ffa5b7b98 100644
--- a/src/core/hle/service/fatal/fatal_p.h
+++ b/src/core/hle/service/fatal/fatal_p.h
@@ -10,7 +10,7 @@ namespace Service::Fatal {
10 10
11class Fatal_P final : public Module::Interface { 11class Fatal_P final : public Module::Interface {
12public: 12public:
13 explicit Fatal_P(std::shared_ptr<Module> module, Core::System& system); 13 explicit Fatal_P(std::shared_ptr<Module> module_, Core::System& system_);
14 ~Fatal_P() override; 14 ~Fatal_P() override;
15}; 15};
16 16
diff --git a/src/core/hle/service/fatal/fatal_u.cpp b/src/core/hle/service/fatal/fatal_u.cpp
index 8d72ed485..82993938a 100644
--- a/src/core/hle/service/fatal/fatal_u.cpp
+++ b/src/core/hle/service/fatal/fatal_u.cpp
@@ -6,8 +6,8 @@
6 6
7namespace Service::Fatal { 7namespace Service::Fatal {
8 8
9Fatal_U::Fatal_U(std::shared_ptr<Module> module, Core::System& system) 9Fatal_U::Fatal_U(std::shared_ptr<Module> module_, Core::System& system_)
10 : Module::Interface(std::move(module), system, "fatal:u") { 10 : Interface(std::move(module_), system_, "fatal:u") {
11 static const FunctionInfo functions[] = { 11 static const FunctionInfo functions[] = {
12 {0, &Fatal_U::ThrowFatal, "ThrowFatal"}, 12 {0, &Fatal_U::ThrowFatal, "ThrowFatal"},
13 {1, &Fatal_U::ThrowFatalWithPolicy, "ThrowFatalWithPolicy"}, 13 {1, &Fatal_U::ThrowFatalWithPolicy, "ThrowFatalWithPolicy"},
diff --git a/src/core/hle/service/fatal/fatal_u.h b/src/core/hle/service/fatal/fatal_u.h
index 34c5c7f95..0b58c9112 100644
--- a/src/core/hle/service/fatal/fatal_u.h
+++ b/src/core/hle/service/fatal/fatal_u.h
@@ -10,7 +10,7 @@ namespace Service::Fatal {
10 10
11class Fatal_U final : public Module::Interface { 11class Fatal_U final : public Module::Interface {
12public: 12public:
13 explicit Fatal_U(std::shared_ptr<Module> module, Core::System& system); 13 explicit Fatal_U(std::shared_ptr<Module> module_, Core::System& system_);
14 ~Fatal_U() override; 14 ~Fatal_U() override;
15}; 15};
16 16
diff --git a/src/core/hle/service/fgm/fgm.cpp b/src/core/hle/service/fgm/fgm.cpp
index e461274c1..9dc1bc52e 100644
--- a/src/core/hle/service/fgm/fgm.cpp
+++ b/src/core/hle/service/fgm/fgm.cpp
@@ -14,7 +14,7 @@ namespace Service::FGM {
14 14
15class IRequest final : public ServiceFramework<IRequest> { 15class IRequest final : public ServiceFramework<IRequest> {
16public: 16public:
17 explicit IRequest() : ServiceFramework{"IRequest"} { 17 explicit IRequest(Core::System& system_) : ServiceFramework{system_, "IRequest"} {
18 // clang-format off 18 // clang-format off
19 static const FunctionInfo functions[] = { 19 static const FunctionInfo functions[] = {
20 {0, nullptr, "Initialize"}, 20 {0, nullptr, "Initialize"},
@@ -30,7 +30,7 @@ public:
30 30
31class FGM final : public ServiceFramework<FGM> { 31class FGM final : public ServiceFramework<FGM> {
32public: 32public:
33 explicit FGM(const char* name) : ServiceFramework{name} { 33 explicit FGM(Core::System& system_, const char* name) : ServiceFramework{system_, name} {
34 // clang-format off 34 // clang-format off
35 static const FunctionInfo functions[] = { 35 static const FunctionInfo functions[] = {
36 {0, &FGM::Initialize, "Initialize"}, 36 {0, &FGM::Initialize, "Initialize"},
@@ -46,13 +46,13 @@ private:
46 46
47 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 47 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
48 rb.Push(RESULT_SUCCESS); 48 rb.Push(RESULT_SUCCESS);
49 rb.PushIpcInterface<IRequest>(); 49 rb.PushIpcInterface<IRequest>(system);
50 } 50 }
51}; 51};
52 52
53class FGM_DBG final : public ServiceFramework<FGM_DBG> { 53class FGM_DBG final : public ServiceFramework<FGM_DBG> {
54public: 54public:
55 explicit FGM_DBG() : ServiceFramework{"fgm:dbg"} { 55 explicit FGM_DBG(Core::System& system_) : ServiceFramework{system_, "fgm:dbg"} {
56 // clang-format off 56 // clang-format off
57 static const FunctionInfo functions[] = { 57 static const FunctionInfo functions[] = {
58 {0, nullptr, "Initialize"}, 58 {0, nullptr, "Initialize"},
@@ -65,11 +65,11 @@ public:
65 } 65 }
66}; 66};
67 67
68void InstallInterfaces(SM::ServiceManager& sm) { 68void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
69 std::make_shared<FGM>("fgm")->InstallAsService(sm); 69 std::make_shared<FGM>(system, "fgm")->InstallAsService(sm);
70 std::make_shared<FGM>("fgm:0")->InstallAsService(sm); 70 std::make_shared<FGM>(system, "fgm:0")->InstallAsService(sm);
71 std::make_shared<FGM>("fgm:9")->InstallAsService(sm); 71 std::make_shared<FGM>(system, "fgm:9")->InstallAsService(sm);
72 std::make_shared<FGM_DBG>()->InstallAsService(sm); 72 std::make_shared<FGM_DBG>(system)->InstallAsService(sm);
73} 73}
74 74
75} // namespace Service::FGM 75} // namespace Service::FGM
diff --git a/src/core/hle/service/fgm/fgm.h b/src/core/hle/service/fgm/fgm.h
index e59691264..75978f2ed 100644
--- a/src/core/hle/service/fgm/fgm.h
+++ b/src/core/hle/service/fgm/fgm.h
@@ -4,12 +4,16 @@
4 4
5#pragma once 5#pragma once
6 6
7namespace Core {
8class System;
9}
10
7namespace Service::SM { 11namespace Service::SM {
8class ServiceManager; 12class ServiceManager;
9} 13}
10 14
11namespace Service::FGM { 15namespace Service::FGM {
12 16
13void InstallInterfaces(SM::ServiceManager& sm); 17void InstallInterfaces(SM::ServiceManager& sm, Core::System& system);
14 18
15} // namespace Service::FGM 19} // namespace Service::FGM
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp
index 54a5fb84b..b15c737e1 100644
--- a/src/core/hle/service/filesystem/filesystem.cpp
+++ b/src/core/hle/service/filesystem/filesystem.cpp
@@ -79,7 +79,7 @@ ResultCode VfsDirectoryServiceWrapper::DeleteFile(const std::string& path_) cons
79 } 79 }
80 80
81 auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path)); 81 auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path));
82 if (dir->GetFile(Common::FS::GetFilename(path)) == nullptr) { 82 if (dir == nullptr || dir->GetFile(Common::FS::GetFilename(path)) == nullptr) {
83 return FileSys::ERROR_PATH_NOT_FOUND; 83 return FileSys::ERROR_PATH_NOT_FOUND;
84 } 84 }
85 if (!dir->DeleteFile(Common::FS::GetFilename(path))) { 85 if (!dir->DeleteFile(Common::FS::GetFilename(path))) {
@@ -93,8 +93,9 @@ ResultCode VfsDirectoryServiceWrapper::DeleteFile(const std::string& path_) cons
93ResultCode VfsDirectoryServiceWrapper::CreateDirectory(const std::string& path_) const { 93ResultCode VfsDirectoryServiceWrapper::CreateDirectory(const std::string& path_) const {
94 std::string path(Common::FS::SanitizePath(path_)); 94 std::string path(Common::FS::SanitizePath(path_));
95 auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path)); 95 auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path));
96 if (dir == nullptr && Common::FS::GetFilename(Common::FS::GetParentPath(path)).empty()) 96 if (dir == nullptr || Common::FS::GetFilename(Common::FS::GetParentPath(path)).empty()) {
97 dir = backing; 97 dir = backing;
98 }
98 auto new_dir = dir->CreateSubdirectory(Common::FS::GetFilename(path)); 99 auto new_dir = dir->CreateSubdirectory(Common::FS::GetFilename(path));
99 if (new_dir == nullptr) { 100 if (new_dir == nullptr) {
100 // TODO(DarkLordZach): Find a better error code for this 101 // TODO(DarkLordZach): Find a better error code for this
@@ -297,10 +298,35 @@ ResultVal<FileSys::VirtualFile> FileSystemController::OpenRomFSCurrentProcess()
297 return romfs_factory->OpenCurrentProcess(system.CurrentProcess()->GetTitleID()); 298 return romfs_factory->OpenCurrentProcess(system.CurrentProcess()->GetTitleID());
298} 299}
299 300
301ResultVal<FileSys::VirtualFile> FileSystemController::OpenPatchedRomFS(
302 u64 title_id, FileSys::ContentRecordType type) const {
303 LOG_TRACE(Service_FS, "Opening patched RomFS for title_id={:016X}", title_id);
304
305 if (romfs_factory == nullptr) {
306 // TODO: Find a better error code for this
307 return RESULT_UNKNOWN;
308 }
309
310 return romfs_factory->OpenPatchedRomFS(title_id, type);
311}
312
313ResultVal<FileSys::VirtualFile> FileSystemController::OpenPatchedRomFSWithProgramIndex(
314 u64 title_id, u8 program_index, FileSys::ContentRecordType type) const {
315 LOG_TRACE(Service_FS, "Opening patched RomFS for title_id={:016X}, program_index={}", title_id,
316 program_index);
317
318 if (romfs_factory == nullptr) {
319 // TODO: Find a better error code for this
320 return RESULT_UNKNOWN;
321 }
322
323 return romfs_factory->OpenPatchedRomFSWithProgramIndex(title_id, program_index, type);
324}
325
300ResultVal<FileSys::VirtualFile> FileSystemController::OpenRomFS( 326ResultVal<FileSys::VirtualFile> FileSystemController::OpenRomFS(
301 u64 title_id, FileSys::StorageId storage_id, FileSys::ContentRecordType type) const { 327 u64 title_id, FileSys::StorageId storage_id, FileSys::ContentRecordType type) const {
302 LOG_TRACE(Service_FS, "Opening RomFS for title_id={:016X}, storage_id={:02X}, type={:02X}", 328 LOG_TRACE(Service_FS, "Opening RomFS for title_id={:016X}, storage_id={:02X}, type={:02X}",
303 title_id, static_cast<u8>(storage_id), static_cast<u8>(type)); 329 title_id, storage_id, type);
304 330
305 if (romfs_factory == nullptr) { 331 if (romfs_factory == nullptr) {
306 // TODO(bunnei): Find a better error code for this 332 // TODO(bunnei): Find a better error code for this
@@ -312,8 +338,8 @@ ResultVal<FileSys::VirtualFile> FileSystemController::OpenRomFS(
312 338
313ResultVal<FileSys::VirtualDir> FileSystemController::CreateSaveData( 339ResultVal<FileSys::VirtualDir> FileSystemController::CreateSaveData(
314 FileSys::SaveDataSpaceId space, const FileSys::SaveDataAttribute& save_struct) const { 340 FileSys::SaveDataSpaceId space, const FileSys::SaveDataAttribute& save_struct) const {
315 LOG_TRACE(Service_FS, "Creating Save Data for space_id={:01X}, save_struct={}", 341 LOG_TRACE(Service_FS, "Creating Save Data for space_id={:01X}, save_struct={}", space,
316 static_cast<u8>(space), save_struct.DebugInfo()); 342 save_struct.DebugInfo());
317 343
318 if (save_data_factory == nullptr) { 344 if (save_data_factory == nullptr) {
319 return FileSys::ERROR_ENTITY_NOT_FOUND; 345 return FileSys::ERROR_ENTITY_NOT_FOUND;
@@ -324,8 +350,8 @@ ResultVal<FileSys::VirtualDir> FileSystemController::CreateSaveData(
324 350
325ResultVal<FileSys::VirtualDir> FileSystemController::OpenSaveData( 351ResultVal<FileSys::VirtualDir> FileSystemController::OpenSaveData(
326 FileSys::SaveDataSpaceId space, const FileSys::SaveDataAttribute& attribute) const { 352 FileSys::SaveDataSpaceId space, const FileSys::SaveDataAttribute& attribute) const {
327 LOG_TRACE(Service_FS, "Opening Save Data for space_id={:01X}, save_struct={}", 353 LOG_TRACE(Service_FS, "Opening Save Data for space_id={:01X}, save_struct={}", space,
328 static_cast<u8>(space), attribute.DebugInfo()); 354 attribute.DebugInfo());
329 355
330 if (save_data_factory == nullptr) { 356 if (save_data_factory == nullptr) {
331 return FileSys::ERROR_ENTITY_NOT_FOUND; 357 return FileSys::ERROR_ENTITY_NOT_FOUND;
@@ -336,7 +362,7 @@ ResultVal<FileSys::VirtualDir> FileSystemController::OpenSaveData(
336 362
337ResultVal<FileSys::VirtualDir> FileSystemController::OpenSaveDataSpace( 363ResultVal<FileSys::VirtualDir> FileSystemController::OpenSaveDataSpace(
338 FileSys::SaveDataSpaceId space) const { 364 FileSys::SaveDataSpaceId space) const {
339 LOG_TRACE(Service_FS, "Opening Save Data Space for space_id={:01X}", static_cast<u8>(space)); 365 LOG_TRACE(Service_FS, "Opening Save Data Space for space_id={:01X}", space);
340 366
341 if (save_data_factory == nullptr) { 367 if (save_data_factory == nullptr) {
342 return FileSys::ERROR_ENTITY_NOT_FOUND; 368 return FileSys::ERROR_ENTITY_NOT_FOUND;
@@ -357,7 +383,7 @@ ResultVal<FileSys::VirtualDir> FileSystemController::OpenSDMC() const {
357 383
358ResultVal<FileSys::VirtualDir> FileSystemController::OpenBISPartition( 384ResultVal<FileSys::VirtualDir> FileSystemController::OpenBISPartition(
359 FileSys::BisPartitionId id) const { 385 FileSys::BisPartitionId id) const {
360 LOG_TRACE(Service_FS, "Opening BIS Partition with id={:08X}", static_cast<u32>(id)); 386 LOG_TRACE(Service_FS, "Opening BIS Partition with id={:08X}", id);
361 387
362 if (bis_factory == nullptr) { 388 if (bis_factory == nullptr) {
363 return FileSys::ERROR_ENTITY_NOT_FOUND; 389 return FileSys::ERROR_ENTITY_NOT_FOUND;
@@ -373,7 +399,7 @@ ResultVal<FileSys::VirtualDir> FileSystemController::OpenBISPartition(
373 399
374ResultVal<FileSys::VirtualFile> FileSystemController::OpenBISPartitionStorage( 400ResultVal<FileSys::VirtualFile> FileSystemController::OpenBISPartitionStorage(
375 FileSys::BisPartitionId id) const { 401 FileSys::BisPartitionId id) const {
376 LOG_TRACE(Service_FS, "Opening BIS Partition Storage with id={:08X}", static_cast<u32>(id)); 402 LOG_TRACE(Service_FS, "Opening BIS Partition Storage with id={:08X}", id);
377 403
378 if (bis_factory == nullptr) { 404 if (bis_factory == nullptr) {
379 return FileSys::ERROR_ENTITY_NOT_FOUND; 405 return FileSys::ERROR_ENTITY_NOT_FOUND;
@@ -454,7 +480,9 @@ FileSys::SaveDataSize FileSystemController::ReadSaveDataSize(FileSys::SaveDataTy
454 const auto res = system.GetAppLoader().ReadControlData(nacp); 480 const auto res = system.GetAppLoader().ReadControlData(nacp);
455 481
456 if (res != Loader::ResultStatus::Success) { 482 if (res != Loader::ResultStatus::Success) {
457 FileSys::PatchManager pm{system.CurrentProcess()->GetTitleID()}; 483 const FileSys::PatchManager pm{system.CurrentProcess()->GetTitleID(),
484 system.GetFileSystemController(),
485 system.GetContentProvider()};
458 const auto metadata = pm.GetControlMetadata(); 486 const auto metadata = pm.GetControlMetadata();
459 const auto& nacp_unique = metadata.first; 487 const auto& nacp_unique = metadata.first;
460 488
@@ -714,7 +742,8 @@ void FileSystemController::CreateFactories(FileSys::VfsFilesystem& vfs, bool ove
714 } 742 }
715 743
716 if (save_data_factory == nullptr) { 744 if (save_data_factory == nullptr) {
717 save_data_factory = std::make_unique<FileSys::SaveDataFactory>(std::move(nand_directory)); 745 save_data_factory =
746 std::make_unique<FileSys::SaveDataFactory>(system, std::move(nand_directory));
718 } 747 }
719 748
720 if (sdmc_factory == nullptr) { 749 if (sdmc_factory == nullptr) {
@@ -725,10 +754,9 @@ void FileSystemController::CreateFactories(FileSys::VfsFilesystem& vfs, bool ove
725} 754}
726 755
727void InstallInterfaces(Core::System& system) { 756void InstallInterfaces(Core::System& system) {
728 std::make_shared<FSP_LDR>()->InstallAsService(system.ServiceManager()); 757 std::make_shared<FSP_LDR>(system)->InstallAsService(system.ServiceManager());
729 std::make_shared<FSP_PR>()->InstallAsService(system.ServiceManager()); 758 std::make_shared<FSP_PR>(system)->InstallAsService(system.ServiceManager());
730 std::make_shared<FSP_SRV>(system.GetFileSystemController(), system.GetReporter()) 759 std::make_shared<FSP_SRV>(system)->InstallAsService(system.ServiceManager());
731 ->InstallAsService(system.ServiceManager());
732} 760}
733 761
734} // namespace Service::FileSystem 762} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h
index 6dbbf0b2b..7102d3f9a 100644
--- a/src/core/hle/service/filesystem/filesystem.h
+++ b/src/core/hle/service/filesystem/filesystem.h
@@ -66,6 +66,10 @@ public:
66 66
67 void SetPackedUpdate(FileSys::VirtualFile update_raw); 67 void SetPackedUpdate(FileSys::VirtualFile update_raw);
68 ResultVal<FileSys::VirtualFile> OpenRomFSCurrentProcess() const; 68 ResultVal<FileSys::VirtualFile> OpenRomFSCurrentProcess() const;
69 ResultVal<FileSys::VirtualFile> OpenPatchedRomFS(u64 title_id,
70 FileSys::ContentRecordType type) const;
71 ResultVal<FileSys::VirtualFile> OpenPatchedRomFSWithProgramIndex(
72 u64 title_id, u8 program_index, FileSys::ContentRecordType type) const;
69 ResultVal<FileSys::VirtualFile> OpenRomFS(u64 title_id, FileSys::StorageId storage_id, 73 ResultVal<FileSys::VirtualFile> OpenRomFS(u64 title_id, FileSys::StorageId storage_id,
70 FileSys::ContentRecordType type) const; 74 FileSys::ContentRecordType type) const;
71 ResultVal<FileSys::VirtualDir> CreateSaveData( 75 ResultVal<FileSys::VirtualDir> CreateSaveData(
diff --git a/src/core/hle/service/filesystem/fsp_ldr.cpp b/src/core/hle/service/filesystem/fsp_ldr.cpp
index fb487d5bc..1f6c17ba5 100644
--- a/src/core/hle/service/filesystem/fsp_ldr.cpp
+++ b/src/core/hle/service/filesystem/fsp_ldr.cpp
@@ -7,7 +7,7 @@
7 7
8namespace Service::FileSystem { 8namespace Service::FileSystem {
9 9
10FSP_LDR::FSP_LDR() : ServiceFramework{"fsp:ldr"} { 10FSP_LDR::FSP_LDR(Core::System& system_) : ServiceFramework{system_, "fsp:ldr"} {
11 // clang-format off 11 // clang-format off
12 static const FunctionInfo functions[] = { 12 static const FunctionInfo functions[] = {
13 {0, nullptr, "OpenCodeFileSystem"}, 13 {0, nullptr, "OpenCodeFileSystem"},
diff --git a/src/core/hle/service/filesystem/fsp_ldr.h b/src/core/hle/service/filesystem/fsp_ldr.h
index 8210b7729..d6432a0e1 100644
--- a/src/core/hle/service/filesystem/fsp_ldr.h
+++ b/src/core/hle/service/filesystem/fsp_ldr.h
@@ -6,11 +6,15 @@
6 6
7#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
8 8
9namespace Core {
10class System;
11}
12
9namespace Service::FileSystem { 13namespace Service::FileSystem {
10 14
11class FSP_LDR final : public ServiceFramework<FSP_LDR> { 15class FSP_LDR final : public ServiceFramework<FSP_LDR> {
12public: 16public:
13 explicit FSP_LDR(); 17 explicit FSP_LDR(Core::System& system_);
14 ~FSP_LDR() override; 18 ~FSP_LDR() override;
15}; 19};
16 20
diff --git a/src/core/hle/service/filesystem/fsp_pr.cpp b/src/core/hle/service/filesystem/fsp_pr.cpp
index 378201610..00e4d1662 100644
--- a/src/core/hle/service/filesystem/fsp_pr.cpp
+++ b/src/core/hle/service/filesystem/fsp_pr.cpp
@@ -7,7 +7,7 @@
7 7
8namespace Service::FileSystem { 8namespace Service::FileSystem {
9 9
10FSP_PR::FSP_PR() : ServiceFramework{"fsp:pr"} { 10FSP_PR::FSP_PR(Core::System& system_) : ServiceFramework{system_, "fsp:pr"} {
11 // clang-format off 11 // clang-format off
12 static const FunctionInfo functions[] = { 12 static const FunctionInfo functions[] = {
13 {0, nullptr, "RegisterProgram"}, 13 {0, nullptr, "RegisterProgram"},
diff --git a/src/core/hle/service/filesystem/fsp_pr.h b/src/core/hle/service/filesystem/fsp_pr.h
index 556ae5ce9..9e622518c 100644
--- a/src/core/hle/service/filesystem/fsp_pr.h
+++ b/src/core/hle/service/filesystem/fsp_pr.h
@@ -6,11 +6,15 @@
6 6
7#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
8 8
9namespace Core {
10class System;
11}
12
9namespace Service::FileSystem { 13namespace Service::FileSystem {
10 14
11class FSP_PR final : public ServiceFramework<FSP_PR> { 15class FSP_PR final : public ServiceFramework<FSP_PR> {
12public: 16public:
13 explicit FSP_PR(); 17 explicit FSP_PR(Core::System& system_);
14 ~FSP_PR() override; 18 ~FSP_PR() override;
15}; 19};
16 20
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp
index 649128be4..9cc260515 100644
--- a/src/core/hle/service/filesystem/fsp_srv.cpp
+++ b/src/core/hle/service/filesystem/fsp_srv.cpp
@@ -14,6 +14,7 @@
14#include "common/hex_util.h" 14#include "common/hex_util.h"
15#include "common/logging/log.h" 15#include "common/logging/log.h"
16#include "common/string_util.h" 16#include "common/string_util.h"
17#include "core/core.h"
17#include "core/file_sys/directory.h" 18#include "core/file_sys/directory.h"
18#include "core/file_sys/errors.h" 19#include "core/file_sys/errors.h"
19#include "core/file_sys/mode.h" 20#include "core/file_sys/mode.h"
@@ -56,8 +57,8 @@ enum class FileSystemType : u8 {
56 57
57class IStorage final : public ServiceFramework<IStorage> { 58class IStorage final : public ServiceFramework<IStorage> {
58public: 59public:
59 explicit IStorage(FileSys::VirtualFile backend_) 60 explicit IStorage(Core::System& system_, FileSys::VirtualFile backend_)
60 : ServiceFramework("IStorage"), backend(std::move(backend_)) { 61 : ServiceFramework{system_, "IStorage"}, backend(std::move(backend_)) {
61 static const FunctionInfo functions[] = { 62 static const FunctionInfo functions[] = {
62 {0, &IStorage::Read, "Read"}, 63 {0, &IStorage::Read, "Read"},
63 {1, nullptr, "Write"}, 64 {1, nullptr, "Write"},
@@ -114,8 +115,8 @@ private:
114 115
115class IFile final : public ServiceFramework<IFile> { 116class IFile final : public ServiceFramework<IFile> {
116public: 117public:
117 explicit IFile(FileSys::VirtualFile backend_) 118 explicit IFile(Core::System& system_, FileSys::VirtualFile backend_)
118 : ServiceFramework("IFile"), backend(std::move(backend_)) { 119 : ServiceFramework{system_, "IFile"}, backend(std::move(backend_)) {
119 static const FunctionInfo functions[] = { 120 static const FunctionInfo functions[] = {
120 {0, &IFile::Read, "Read"}, {1, &IFile::Write, "Write"}, 121 {0, &IFile::Read, "Read"}, {1, &IFile::Write, "Write"},
121 {2, &IFile::Flush, "Flush"}, {3, &IFile::SetSize, "SetSize"}, 122 {2, &IFile::Flush, "Flush"}, {3, &IFile::SetSize, "SetSize"},
@@ -246,8 +247,8 @@ static void BuildEntryIndex(std::vector<FileSys::Entry>& entries, const std::vec
246 247
247class IDirectory final : public ServiceFramework<IDirectory> { 248class IDirectory final : public ServiceFramework<IDirectory> {
248public: 249public:
249 explicit IDirectory(FileSys::VirtualDir backend_) 250 explicit IDirectory(Core::System& system_, FileSys::VirtualDir backend_)
250 : ServiceFramework("IDirectory"), backend(std::move(backend_)) { 251 : ServiceFramework{system_, "IDirectory"}, backend(std::move(backend_)) {
251 static const FunctionInfo functions[] = { 252 static const FunctionInfo functions[] = {
252 {0, &IDirectory::Read, "Read"}, 253 {0, &IDirectory::Read, "Read"},
253 {1, &IDirectory::GetEntryCount, "GetEntryCount"}, 254 {1, &IDirectory::GetEntryCount, "GetEntryCount"},
@@ -302,8 +303,9 @@ private:
302 303
303class IFileSystem final : public ServiceFramework<IFileSystem> { 304class IFileSystem final : public ServiceFramework<IFileSystem> {
304public: 305public:
305 explicit IFileSystem(FileSys::VirtualDir backend, SizeGetter size) 306 explicit IFileSystem(Core::System& system_, FileSys::VirtualDir backend_, SizeGetter size_)
306 : ServiceFramework("IFileSystem"), backend(std::move(backend)), size(std::move(size)) { 307 : ServiceFramework{system_, "IFileSystem"}, backend{std::move(backend_)}, size{std::move(
308 size_)} {
307 static const FunctionInfo functions[] = { 309 static const FunctionInfo functions[] = {
308 {0, &IFileSystem::CreateFile, "CreateFile"}, 310 {0, &IFileSystem::CreateFile, "CreateFile"},
309 {1, &IFileSystem::DeleteFile, "DeleteFile"}, 311 {1, &IFileSystem::DeleteFile, "DeleteFile"},
@@ -411,7 +413,7 @@ public:
411 413
412 const auto mode = static_cast<FileSys::Mode>(rp.Pop<u32>()); 414 const auto mode = static_cast<FileSys::Mode>(rp.Pop<u32>());
413 415
414 LOG_DEBUG(Service_FS, "called. file={}, mode={}", name, static_cast<u32>(mode)); 416 LOG_DEBUG(Service_FS, "called. file={}, mode={}", name, mode);
415 417
416 auto result = backend.OpenFile(name, mode); 418 auto result = backend.OpenFile(name, mode);
417 if (result.Failed()) { 419 if (result.Failed()) {
@@ -420,7 +422,7 @@ public:
420 return; 422 return;
421 } 423 }
422 424
423 auto file = std::make_shared<IFile>(result.Unwrap()); 425 auto file = std::make_shared<IFile>(system, result.Unwrap());
424 426
425 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 427 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
426 rb.Push(RESULT_SUCCESS); 428 rb.Push(RESULT_SUCCESS);
@@ -445,7 +447,7 @@ public:
445 return; 447 return;
446 } 448 }
447 449
448 auto directory = std::make_shared<IDirectory>(result.Unwrap()); 450 auto directory = std::make_shared<IDirectory>(system, result.Unwrap());
449 451
450 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 452 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
451 rb.Push(RESULT_SUCCESS); 453 rb.Push(RESULT_SUCCESS);
@@ -500,8 +502,9 @@ private:
500 502
501class ISaveDataInfoReader final : public ServiceFramework<ISaveDataInfoReader> { 503class ISaveDataInfoReader final : public ServiceFramework<ISaveDataInfoReader> {
502public: 504public:
503 explicit ISaveDataInfoReader(FileSys::SaveDataSpaceId space, FileSystemController& fsc) 505 explicit ISaveDataInfoReader(Core::System& system_, FileSys::SaveDataSpaceId space,
504 : ServiceFramework("ISaveDataInfoReader"), fsc(fsc) { 506 FileSystemController& fsc_)
507 : ServiceFramework{system_, "ISaveDataInfoReader"}, fsc{fsc_} {
505 static const FunctionInfo functions[] = { 508 static const FunctionInfo functions[] = {
506 {0, &ISaveDataInfoReader::ReadSaveDataInfo, "ReadSaveDataInfo"}, 509 {0, &ISaveDataInfoReader::ReadSaveDataInfo, "ReadSaveDataInfo"},
507 }; 510 };
@@ -550,8 +553,7 @@ private:
550 const auto save_root = fsc.OpenSaveDataSpace(space); 553 const auto save_root = fsc.OpenSaveDataSpace(space);
551 554
552 if (save_root.Failed() || *save_root == nullptr) { 555 if (save_root.Failed() || *save_root == nullptr) {
553 LOG_ERROR(Service_FS, "The save root for the space_id={:02X} was invalid!", 556 LOG_ERROR(Service_FS, "The save root for the space_id={:02X} was invalid!", space);
554 static_cast<u8>(space));
555 return; 557 return;
556 } 558 }
557 559
@@ -650,8 +652,9 @@ private:
650 u64 next_entry_index = 0; 652 u64 next_entry_index = 0;
651}; 653};
652 654
653FSP_SRV::FSP_SRV(FileSystemController& fsc, const Core::Reporter& reporter) 655FSP_SRV::FSP_SRV(Core::System& system_)
654 : ServiceFramework("fsp-srv"), fsc(fsc), reporter(reporter) { 656 : ServiceFramework{system_, "fsp-srv"}, fsc{system.GetFileSystemController()},
657 content_provider{system.GetContentProvider()}, reporter{system.GetReporter()} {
655 // clang-format off 658 // clang-format off
656 static const FunctionInfo functions[] = { 659 static const FunctionInfo functions[] = {
657 {0, nullptr, "OpenFileSystem"}, 660 {0, nullptr, "OpenFileSystem"},
@@ -714,7 +717,7 @@ FSP_SRV::FSP_SRV(FileSystemController& fsc, const Core::Reporter& reporter)
714 {202, &FSP_SRV::OpenDataStorageByDataId, "OpenDataStorageByDataId"}, 717 {202, &FSP_SRV::OpenDataStorageByDataId, "OpenDataStorageByDataId"},
715 {203, &FSP_SRV::OpenPatchDataStorageByCurrentProcess, "OpenPatchDataStorageByCurrentProcess"}, 718 {203, &FSP_SRV::OpenPatchDataStorageByCurrentProcess, "OpenPatchDataStorageByCurrentProcess"},
716 {204, nullptr, "OpenDataFileSystemByProgramIndex"}, 719 {204, nullptr, "OpenDataFileSystemByProgramIndex"},
717 {205, nullptr, "OpenDataStorageByProgramIndex"}, 720 {205, &FSP_SRV::OpenDataStorageWithProgramIndex, "OpenDataStorageWithProgramIndex"},
718 {400, nullptr, "OpenDeviceOperator"}, 721 {400, nullptr, "OpenDeviceOperator"},
719 {500, nullptr, "OpenSdCardDetectionEventNotifier"}, 722 {500, nullptr, "OpenSdCardDetectionEventNotifier"},
720 {501, nullptr, "OpenGameCardDetectionEventNotifier"}, 723 {501, nullptr, "OpenGameCardDetectionEventNotifier"},
@@ -791,8 +794,7 @@ void FSP_SRV::OpenFileSystemWithPatch(Kernel::HLERequestContext& ctx) {
791 794
792 const auto type = rp.PopRaw<FileSystemType>(); 795 const auto type = rp.PopRaw<FileSystemType>();
793 const auto title_id = rp.PopRaw<u64>(); 796 const auto title_id = rp.PopRaw<u64>();
794 LOG_WARNING(Service_FS, "(STUBBED) called with type={}, title_id={:016X}", 797 LOG_WARNING(Service_FS, "(STUBBED) called with type={}, title_id={:016X}", type, title_id);
795 static_cast<u8>(type), title_id);
796 798
797 IPC::ResponseBuilder rb{ctx, 2, 0, 0}; 799 IPC::ResponseBuilder rb{ctx, 2, 0, 0};
798 rb.Push(RESULT_UNKNOWN); 800 rb.Push(RESULT_UNKNOWN);
@@ -801,8 +803,9 @@ void FSP_SRV::OpenFileSystemWithPatch(Kernel::HLERequestContext& ctx) {
801void FSP_SRV::OpenSdCardFileSystem(Kernel::HLERequestContext& ctx) { 803void FSP_SRV::OpenSdCardFileSystem(Kernel::HLERequestContext& ctx) {
802 LOG_DEBUG(Service_FS, "called"); 804 LOG_DEBUG(Service_FS, "called");
803 805
804 auto filesystem = std::make_shared<IFileSystem>( 806 auto filesystem =
805 fsc.OpenSDMC().Unwrap(), SizeGetter::FromStorageId(fsc, FileSys::StorageId::SdCard)); 807 std::make_shared<IFileSystem>(system, fsc.OpenSDMC().Unwrap(),
808 SizeGetter::FromStorageId(fsc, FileSys::StorageId::SdCard));
806 809
807 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 810 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
808 rb.Push(RESULT_SUCCESS); 811 rb.Push(RESULT_SUCCESS);
@@ -862,8 +865,8 @@ void FSP_SRV::OpenSaveDataFileSystem(Kernel::HLERequestContext& ctx) {
862 UNREACHABLE(); 865 UNREACHABLE();
863 } 866 }
864 867
865 auto filesystem = 868 auto filesystem = std::make_shared<IFileSystem>(system, std::move(dir.Unwrap()),
866 std::make_shared<IFileSystem>(std::move(dir.Unwrap()), SizeGetter::FromStorageId(fsc, id)); 869 SizeGetter::FromStorageId(fsc, id));
867 870
868 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 871 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
869 rb.Push(RESULT_SUCCESS); 872 rb.Push(RESULT_SUCCESS);
@@ -878,11 +881,12 @@ void FSP_SRV::OpenReadOnlySaveDataFileSystem(Kernel::HLERequestContext& ctx) {
878void FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId(Kernel::HLERequestContext& ctx) { 881void FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId(Kernel::HLERequestContext& ctx) {
879 IPC::RequestParser rp{ctx}; 882 IPC::RequestParser rp{ctx};
880 const auto space = rp.PopRaw<FileSys::SaveDataSpaceId>(); 883 const auto space = rp.PopRaw<FileSys::SaveDataSpaceId>();
881 LOG_INFO(Service_FS, "called, space={}", static_cast<u8>(space)); 884 LOG_INFO(Service_FS, "called, space={}", space);
882 885
883 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 886 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
884 rb.Push(RESULT_SUCCESS); 887 rb.Push(RESULT_SUCCESS);
885 rb.PushIpcInterface<ISaveDataInfoReader>(std::make_shared<ISaveDataInfoReader>(space, fsc)); 888 rb.PushIpcInterface<ISaveDataInfoReader>(
889 std::make_shared<ISaveDataInfoReader>(system, space, fsc));
886} 890}
887 891
888void FSP_SRV::WriteSaveDataFileSystemExtraDataBySaveDataAttribute(Kernel::HLERequestContext& ctx) { 892void FSP_SRV::WriteSaveDataFileSystemExtraDataBySaveDataAttribute(Kernel::HLERequestContext& ctx) {
@@ -909,10 +913,10 @@ void FSP_SRV::ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(
909 "(STUBBED) called, flags={}, space_id={}, attribute.title_id={:016X}\n" 913 "(STUBBED) called, flags={}, space_id={}, attribute.title_id={:016X}\n"
910 "attribute.user_id={:016X}{:016X}, attribute.save_id={:016X}\n" 914 "attribute.user_id={:016X}{:016X}, attribute.save_id={:016X}\n"
911 "attribute.type={}, attribute.rank={}, attribute.index={}", 915 "attribute.type={}, attribute.rank={}, attribute.index={}",
912 flags, static_cast<u32>(parameters.space_id), parameters.attribute.title_id, 916 flags, parameters.space_id, parameters.attribute.title_id,
913 parameters.attribute.user_id[1], parameters.attribute.user_id[0], 917 parameters.attribute.user_id[1], parameters.attribute.user_id[0],
914 parameters.attribute.save_id, static_cast<u32>(parameters.attribute.type), 918 parameters.attribute.save_id, parameters.attribute.type, parameters.attribute.rank,
915 static_cast<u32>(parameters.attribute.rank), parameters.attribute.index); 919 parameters.attribute.index);
916 920
917 IPC::ResponseBuilder rb{ctx, 3}; 921 IPC::ResponseBuilder rb{ctx, 3};
918 rb.Push(RESULT_SUCCESS); 922 rb.Push(RESULT_SUCCESS);
@@ -931,7 +935,7 @@ void FSP_SRV::OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) {
931 return; 935 return;
932 } 936 }
933 937
934 auto storage = std::make_shared<IStorage>(std::move(romfs.Unwrap())); 938 auto storage = std::make_shared<IStorage>(system, std::move(romfs.Unwrap()));
935 939
936 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 940 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
937 rb.Push(RESULT_SUCCESS); 941 rb.Push(RESULT_SUCCESS);
@@ -945,7 +949,7 @@ void FSP_SRV::OpenDataStorageByDataId(Kernel::HLERequestContext& ctx) {
945 const auto title_id = rp.PopRaw<u64>(); 949 const auto title_id = rp.PopRaw<u64>();
946 950
947 LOG_DEBUG(Service_FS, "called with storage_id={:02X}, unknown={:08X}, title_id={:016X}", 951 LOG_DEBUG(Service_FS, "called with storage_id={:02X}, unknown={:08X}, title_id={:016X}",
948 static_cast<u8>(storage_id), unknown, title_id); 952 storage_id, unknown, title_id);
949 953
950 auto data = fsc.OpenRomFS(title_id, storage_id, FileSys::ContentRecordType::Data); 954 auto data = fsc.OpenRomFS(title_id, storage_id, FileSys::ContentRecordType::Data);
951 955
@@ -955,23 +959,23 @@ void FSP_SRV::OpenDataStorageByDataId(Kernel::HLERequestContext& ctx) {
955 if (archive != nullptr) { 959 if (archive != nullptr) {
956 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 960 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
957 rb.Push(RESULT_SUCCESS); 961 rb.Push(RESULT_SUCCESS);
958 rb.PushIpcInterface(std::make_shared<IStorage>(archive)); 962 rb.PushIpcInterface(std::make_shared<IStorage>(system, archive));
959 return; 963 return;
960 } 964 }
961 965
962 // TODO(DarkLordZach): Find the right error code to use here 966 // TODO(DarkLordZach): Find the right error code to use here
963 LOG_ERROR(Service_FS, 967 LOG_ERROR(Service_FS,
964 "could not open data storage with title_id={:016X}, storage_id={:02X}", title_id, 968 "could not open data storage with title_id={:016X}, storage_id={:02X}", title_id,
965 static_cast<u8>(storage_id)); 969 storage_id);
966 IPC::ResponseBuilder rb{ctx, 2}; 970 IPC::ResponseBuilder rb{ctx, 2};
967 rb.Push(RESULT_UNKNOWN); 971 rb.Push(RESULT_UNKNOWN);
968 return; 972 return;
969 } 973 }
970 974
971 FileSys::PatchManager pm{title_id}; 975 const FileSys::PatchManager pm{title_id, fsc, content_provider};
972 976
973 auto storage = std::make_shared<IStorage>( 977 auto storage = std::make_shared<IStorage>(
974 pm.PatchRomFS(std::move(data.Unwrap()), 0, FileSys::ContentRecordType::Data)); 978 system, pm.PatchRomFS(std::move(data.Unwrap()), 0, FileSys::ContentRecordType::Data));
975 979
976 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 980 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
977 rb.Push(RESULT_SUCCESS); 981 rb.Push(RESULT_SUCCESS);
@@ -981,21 +985,46 @@ void FSP_SRV::OpenDataStorageByDataId(Kernel::HLERequestContext& ctx) {
981void FSP_SRV::OpenPatchDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) { 985void FSP_SRV::OpenPatchDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) {
982 IPC::RequestParser rp{ctx}; 986 IPC::RequestParser rp{ctx};
983 987
984 auto storage_id = rp.PopRaw<FileSys::StorageId>(); 988 const auto storage_id = rp.PopRaw<FileSys::StorageId>();
985 auto title_id = rp.PopRaw<u64>(); 989 const auto title_id = rp.PopRaw<u64>();
986 990
987 LOG_DEBUG(Service_FS, "called with storage_id={:02X}, title_id={:016X}", 991 LOG_DEBUG(Service_FS, "called with storage_id={:02X}, title_id={:016X}", storage_id, title_id);
988 static_cast<u8>(storage_id), title_id);
989 992
990 IPC::ResponseBuilder rb{ctx, 2}; 993 IPC::ResponseBuilder rb{ctx, 2};
991 rb.Push(FileSys::ERROR_ENTITY_NOT_FOUND); 994 rb.Push(FileSys::ERROR_ENTITY_NOT_FOUND);
992} 995}
993 996
997void FSP_SRV::OpenDataStorageWithProgramIndex(Kernel::HLERequestContext& ctx) {
998 IPC::RequestParser rp{ctx};
999
1000 const auto program_index = rp.PopRaw<u8>();
1001
1002 LOG_DEBUG(Service_FS, "called, program_index={}", program_index);
1003
1004 auto romfs = fsc.OpenPatchedRomFSWithProgramIndex(
1005 system.CurrentProcess()->GetTitleID(), program_index, FileSys::ContentRecordType::Program);
1006
1007 if (romfs.Failed()) {
1008 // TODO: Find the right error code to use here
1009 LOG_ERROR(Service_FS, "could not open storage with program_index={}", program_index);
1010
1011 IPC::ResponseBuilder rb{ctx, 2};
1012 rb.Push(RESULT_UNKNOWN);
1013 return;
1014 }
1015
1016 auto storage = std::make_shared<IStorage>(system, std::move(romfs.Unwrap()));
1017
1018 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
1019 rb.Push(RESULT_SUCCESS);
1020 rb.PushIpcInterface<IStorage>(std::move(storage));
1021}
1022
994void FSP_SRV::SetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) { 1023void FSP_SRV::SetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) {
995 IPC::RequestParser rp{ctx}; 1024 IPC::RequestParser rp{ctx};
996 log_mode = rp.PopEnum<LogMode>(); 1025 log_mode = rp.PopEnum<LogMode>();
997 1026
998 LOG_DEBUG(Service_FS, "called, log_mode={:08X}", static_cast<u32>(log_mode)); 1027 LOG_DEBUG(Service_FS, "called, log_mode={:08X}", log_mode);
999 1028
1000 IPC::ResponseBuilder rb{ctx, 2}; 1029 IPC::ResponseBuilder rb{ctx, 2};
1001 rb.Push(RESULT_SUCCESS); 1030 rb.Push(RESULT_SUCCESS);
@@ -1033,7 +1062,8 @@ void FSP_SRV::GetAccessLogVersionInfo(Kernel::HLERequestContext& ctx) {
1033 1062
1034class IMultiCommitManager final : public ServiceFramework<IMultiCommitManager> { 1063class IMultiCommitManager final : public ServiceFramework<IMultiCommitManager> {
1035public: 1064public:
1036 explicit IMultiCommitManager() : ServiceFramework("IMultiCommitManager") { 1065 explicit IMultiCommitManager(Core::System& system_)
1066 : ServiceFramework{system_, "IMultiCommitManager"} {
1037 static const FunctionInfo functions[] = { 1067 static const FunctionInfo functions[] = {
1038 {1, &IMultiCommitManager::Add, "Add"}, 1068 {1, &IMultiCommitManager::Add, "Add"},
1039 {2, &IMultiCommitManager::Commit, "Commit"}, 1069 {2, &IMultiCommitManager::Commit, "Commit"},
@@ -1064,7 +1094,7 @@ void FSP_SRV::OpenMultiCommitManager(Kernel::HLERequestContext& ctx) {
1064 1094
1065 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 1095 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
1066 rb.Push(RESULT_SUCCESS); 1096 rb.Push(RESULT_SUCCESS);
1067 rb.PushIpcInterface<IMultiCommitManager>(std::make_shared<IMultiCommitManager>()); 1097 rb.PushIpcInterface<IMultiCommitManager>(std::make_shared<IMultiCommitManager>(system));
1068} 1098}
1069 1099
1070} // namespace Service::FileSystem 1100} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp_srv.h b/src/core/hle/service/filesystem/fsp_srv.h
index 4964e874e..8ed933279 100644
--- a/src/core/hle/service/filesystem/fsp_srv.h
+++ b/src/core/hle/service/filesystem/fsp_srv.h
@@ -12,8 +12,9 @@ class Reporter;
12} 12}
13 13
14namespace FileSys { 14namespace FileSys {
15class ContentProvider;
15class FileSystemBackend; 16class FileSystemBackend;
16} 17} // namespace FileSys
17 18
18namespace Service::FileSystem { 19namespace Service::FileSystem {
19 20
@@ -32,7 +33,7 @@ enum class LogMode : u32 {
32 33
33class FSP_SRV final : public ServiceFramework<FSP_SRV> { 34class FSP_SRV final : public ServiceFramework<FSP_SRV> {
34public: 35public:
35 explicit FSP_SRV(FileSystemController& fsc, const Core::Reporter& reporter); 36 explicit FSP_SRV(Core::System& system_);
36 ~FSP_SRV() override; 37 ~FSP_SRV() override;
37 38
38private: 39private:
@@ -48,6 +49,7 @@ private:
48 void OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx); 49 void OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx);
49 void OpenDataStorageByDataId(Kernel::HLERequestContext& ctx); 50 void OpenDataStorageByDataId(Kernel::HLERequestContext& ctx);
50 void OpenPatchDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx); 51 void OpenPatchDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx);
52 void OpenDataStorageWithProgramIndex(Kernel::HLERequestContext& ctx);
51 void SetGlobalAccessLogMode(Kernel::HLERequestContext& ctx); 53 void SetGlobalAccessLogMode(Kernel::HLERequestContext& ctx);
52 void GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx); 54 void GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx);
53 void OutputAccessLogToSdCard(Kernel::HLERequestContext& ctx); 55 void OutputAccessLogToSdCard(Kernel::HLERequestContext& ctx);
@@ -55,6 +57,7 @@ private:
55 void OpenMultiCommitManager(Kernel::HLERequestContext& ctx); 57 void OpenMultiCommitManager(Kernel::HLERequestContext& ctx);
56 58
57 FileSystemController& fsc; 59 FileSystemController& fsc;
60 const FileSys::ContentProvider& content_provider;
58 61
59 FileSys::VirtualFile romfs; 62 FileSys::VirtualFile romfs;
60 u64 current_process_id = 0; 63 u64 current_process_id = 0;
diff --git a/src/core/hle/service/friend/friend.cpp b/src/core/hle/service/friend/friend.cpp
index b7adaffc7..c5b053c31 100644
--- a/src/core/hle/service/friend/friend.cpp
+++ b/src/core/hle/service/friend/friend.cpp
@@ -5,6 +5,7 @@
5#include <queue> 5#include <queue>
6#include "common/logging/log.h" 6#include "common/logging/log.h"
7#include "common/uuid.h" 7#include "common/uuid.h"
8#include "core/core.h"
8#include "core/hle/ipc_helpers.h" 9#include "core/hle/ipc_helpers.h"
9#include "core/hle/kernel/readable_event.h" 10#include "core/hle/kernel/readable_event.h"
10#include "core/hle/kernel/writable_event.h" 11#include "core/hle/kernel/writable_event.h"
@@ -16,7 +17,7 @@ namespace Service::Friend {
16 17
17class IFriendService final : public ServiceFramework<IFriendService> { 18class IFriendService final : public ServiceFramework<IFriendService> {
18public: 19public:
19 IFriendService() : ServiceFramework("IFriendService") { 20 explicit IFriendService(Core::System& system_) : ServiceFramework{system_, "IFriendService"} {
20 // clang-format off 21 // clang-format off
21 static const FunctionInfo functions[] = { 22 static const FunctionInfo functions[] = {
22 {0, nullptr, "GetCompletionEvent"}, 23 {0, nullptr, "GetCompletionEvent"},
@@ -170,8 +171,8 @@ private:
170 171
171class INotificationService final : public ServiceFramework<INotificationService> { 172class INotificationService final : public ServiceFramework<INotificationService> {
172public: 173public:
173 INotificationService(Common::UUID uuid, Core::System& system) 174 explicit INotificationService(Common::UUID uuid_, Core::System& system_)
174 : ServiceFramework("INotificationService"), uuid(uuid) { 175 : ServiceFramework{system_, "INotificationService"}, uuid{uuid_} {
175 // clang-format off 176 // clang-format off
176 static const FunctionInfo functions[] = { 177 static const FunctionInfo functions[] = {
177 {0, &INotificationService::GetEvent, "GetEvent"}, 178 {0, &INotificationService::GetEvent, "GetEvent"},
@@ -228,8 +229,7 @@ private:
228 break; 229 break;
229 default: 230 default:
230 // HOS seems not have an error case for an unknown notification 231 // HOS seems not have an error case for an unknown notification
231 LOG_WARNING(Service_ACC, "Unknown notification {:08X}", 232 LOG_WARNING(Service_ACC, "Unknown notification {:08X}", notification.notification_type);
232 static_cast<u32>(notification.notification_type));
233 break; 233 break;
234 } 234 }
235 235
@@ -266,7 +266,7 @@ private:
266void Module::Interface::CreateFriendService(Kernel::HLERequestContext& ctx) { 266void Module::Interface::CreateFriendService(Kernel::HLERequestContext& ctx) {
267 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 267 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
268 rb.Push(RESULT_SUCCESS); 268 rb.Push(RESULT_SUCCESS);
269 rb.PushIpcInterface<IFriendService>(); 269 rb.PushIpcInterface<IFriendService>(system);
270 LOG_DEBUG(Service_ACC, "called"); 270 LOG_DEBUG(Service_ACC, "called");
271} 271}
272 272
@@ -281,8 +281,9 @@ void Module::Interface::CreateNotificationService(Kernel::HLERequestContext& ctx
281 rb.PushIpcInterface<INotificationService>(uuid, system); 281 rb.PushIpcInterface<INotificationService>(uuid, system);
282} 282}
283 283
284Module::Interface::Interface(std::shared_ptr<Module> module, Core::System& system, const char* name) 284Module::Interface::Interface(std::shared_ptr<Module> module_, Core::System& system_,
285 : ServiceFramework(name), module(std::move(module)), system(system) {} 285 const char* name)
286 : ServiceFramework{system_, name}, module{std::move(module_)} {}
286 287
287Module::Interface::~Interface() = default; 288Module::Interface::~Interface() = default;
288 289
diff --git a/src/core/hle/service/friend/friend.h b/src/core/hle/service/friend/friend.h
index 24f3fc969..8be3321db 100644
--- a/src/core/hle/service/friend/friend.h
+++ b/src/core/hle/service/friend/friend.h
@@ -16,7 +16,8 @@ class Module final {
16public: 16public:
17 class Interface : public ServiceFramework<Interface> { 17 class Interface : public ServiceFramework<Interface> {
18 public: 18 public:
19 explicit Interface(std::shared_ptr<Module> module, Core::System& system, const char* name); 19 explicit Interface(std::shared_ptr<Module> module_, Core::System& system_,
20 const char* name);
20 ~Interface() override; 21 ~Interface() override;
21 22
22 void CreateFriendService(Kernel::HLERequestContext& ctx); 23 void CreateFriendService(Kernel::HLERequestContext& ctx);
@@ -24,7 +25,6 @@ public:
24 25
25 protected: 26 protected:
26 std::shared_ptr<Module> module; 27 std::shared_ptr<Module> module;
27 Core::System& system;
28 }; 28 };
29}; 29};
30 30
diff --git a/src/core/hle/service/friend/interface.cpp b/src/core/hle/service/friend/interface.cpp
index 58155f652..7368ccec2 100644
--- a/src/core/hle/service/friend/interface.cpp
+++ b/src/core/hle/service/friend/interface.cpp
@@ -6,8 +6,8 @@
6 6
7namespace Service::Friend { 7namespace Service::Friend {
8 8
9Friend::Friend(std::shared_ptr<Module> module, Core::System& system, const char* name) 9Friend::Friend(std::shared_ptr<Module> module_, Core::System& system_, const char* name)
10 : Interface(std::move(module), system, name) { 10 : Interface(std::move(module_), system_, name) {
11 static const FunctionInfo functions[] = { 11 static const FunctionInfo functions[] = {
12 {0, &Friend::CreateFriendService, "CreateFriendService"}, 12 {0, &Friend::CreateFriendService, "CreateFriendService"},
13 {1, &Friend::CreateNotificationService, "CreateNotificationService"}, 13 {1, &Friend::CreateNotificationService, "CreateNotificationService"},
diff --git a/src/core/hle/service/friend/interface.h b/src/core/hle/service/friend/interface.h
index 465a35770..43d914b32 100644
--- a/src/core/hle/service/friend/interface.h
+++ b/src/core/hle/service/friend/interface.h
@@ -10,7 +10,7 @@ namespace Service::Friend {
10 10
11class Friend final : public Module::Interface { 11class Friend final : public Module::Interface {
12public: 12public:
13 explicit Friend(std::shared_ptr<Module> module, Core::System& system, const char* name); 13 explicit Friend(std::shared_ptr<Module> module_, Core::System& system_, const char* name);
14 ~Friend() override; 14 ~Friend() override;
15}; 15};
16 16
diff --git a/src/core/hle/service/glue/arp.cpp b/src/core/hle/service/glue/arp.cpp
index b591ce31b..fc77e7286 100644
--- a/src/core/hle/service/glue/arp.cpp
+++ b/src/core/hle/service/glue/arp.cpp
@@ -5,6 +5,7 @@
5#include <memory> 5#include <memory>
6 6
7#include "common/logging/log.h" 7#include "common/logging/log.h"
8#include "core/core.h"
8#include "core/file_sys/control_metadata.h" 9#include "core/file_sys/control_metadata.h"
9#include "core/hle/ipc_helpers.h" 10#include "core/hle/ipc_helpers.h"
10#include "core/hle/kernel/hle_ipc.h" 11#include "core/hle/kernel/hle_ipc.h"
@@ -32,8 +33,8 @@ std::optional<u64> GetTitleIDForProcessID(const Core::System& system, u64 proces
32} 33}
33} // Anonymous namespace 34} // Anonymous namespace
34 35
35ARP_R::ARP_R(const Core::System& system, const ARPManager& manager) 36ARP_R::ARP_R(Core::System& system_, const ARPManager& manager_)
36 : ServiceFramework{"arp:r"}, system(system), manager(manager) { 37 : ServiceFramework{system_, "arp:r"}, manager{manager_} {
37 // clang-format off 38 // clang-format off
38 static const FunctionInfo functions[] = { 39 static const FunctionInfo functions[] = {
39 {0, &ARP_R::GetApplicationLaunchProperty, "GetApplicationLaunchProperty"}, 40 {0, &ARP_R::GetApplicationLaunchProperty, "GetApplicationLaunchProperty"},
@@ -151,8 +152,9 @@ class IRegistrar final : public ServiceFramework<IRegistrar> {
151 152
152public: 153public:
153 explicit IRegistrar( 154 explicit IRegistrar(
155 Core::System& system_,
154 std::function<ResultCode(u64, ApplicationLaunchProperty, std::vector<u8>)> issuer) 156 std::function<ResultCode(u64, ApplicationLaunchProperty, std::vector<u8>)> issuer)
155 : ServiceFramework{"IRegistrar"}, issue_process_id(std::move(issuer)) { 157 : ServiceFramework{system_, "IRegistrar"}, issue_process_id{std::move(issuer)} {
156 // clang-format off 158 // clang-format off
157 static const FunctionInfo functions[] = { 159 static const FunctionInfo functions[] = {
158 {0, &IRegistrar::Issue, "Issue"}, 160 {0, &IRegistrar::Issue, "Issue"},
@@ -236,8 +238,8 @@ private:
236 std::vector<u8> control; 238 std::vector<u8> control;
237}; 239};
238 240
239ARP_W::ARP_W(const Core::System& system, ARPManager& manager) 241ARP_W::ARP_W(Core::System& system_, ARPManager& manager_)
240 : ServiceFramework{"arp:w"}, system(system), manager(manager) { 242 : ServiceFramework{system_, "arp:w"}, manager{manager_} {
241 // clang-format off 243 // clang-format off
242 static const FunctionInfo functions[] = { 244 static const FunctionInfo functions[] = {
243 {0, &ARP_W::AcquireRegistrar, "AcquireRegistrar"}, 245 {0, &ARP_W::AcquireRegistrar, "AcquireRegistrar"},
@@ -254,7 +256,7 @@ void ARP_W::AcquireRegistrar(Kernel::HLERequestContext& ctx) {
254 LOG_DEBUG(Service_ARP, "called"); 256 LOG_DEBUG(Service_ARP, "called");
255 257
256 registrar = std::make_shared<IRegistrar>( 258 registrar = std::make_shared<IRegistrar>(
257 [this](u64 process_id, ApplicationLaunchProperty launch, std::vector<u8> control) { 259 system, [this](u64 process_id, ApplicationLaunchProperty launch, std::vector<u8> control) {
258 const auto res = GetTitleIDForProcessID(system, process_id); 260 const auto res = GetTitleIDForProcessID(system, process_id);
259 if (!res.has_value()) { 261 if (!res.has_value()) {
260 return ERR_NOT_REGISTERED; 262 return ERR_NOT_REGISTERED;
diff --git a/src/core/hle/service/glue/arp.h b/src/core/hle/service/glue/arp.h
index d5f8a7e7a..34b412e26 100644
--- a/src/core/hle/service/glue/arp.h
+++ b/src/core/hle/service/glue/arp.h
@@ -13,7 +13,7 @@ class IRegistrar;
13 13
14class ARP_R final : public ServiceFramework<ARP_R> { 14class ARP_R final : public ServiceFramework<ARP_R> {
15public: 15public:
16 explicit ARP_R(const Core::System& system, const ARPManager& manager); 16 explicit ARP_R(Core::System& system_, const ARPManager& manager_);
17 ~ARP_R() override; 17 ~ARP_R() override;
18 18
19private: 19private:
@@ -22,20 +22,18 @@ private:
22 void GetApplicationControlProperty(Kernel::HLERequestContext& ctx); 22 void GetApplicationControlProperty(Kernel::HLERequestContext& ctx);
23 void GetApplicationControlPropertyWithApplicationId(Kernel::HLERequestContext& ctx); 23 void GetApplicationControlPropertyWithApplicationId(Kernel::HLERequestContext& ctx);
24 24
25 const Core::System& system;
26 const ARPManager& manager; 25 const ARPManager& manager;
27}; 26};
28 27
29class ARP_W final : public ServiceFramework<ARP_W> { 28class ARP_W final : public ServiceFramework<ARP_W> {
30public: 29public:
31 explicit ARP_W(const Core::System& system, ARPManager& manager); 30 explicit ARP_W(Core::System& system_, ARPManager& manager_);
32 ~ARP_W() override; 31 ~ARP_W() override;
33 32
34private: 33private:
35 void AcquireRegistrar(Kernel::HLERequestContext& ctx); 34 void AcquireRegistrar(Kernel::HLERequestContext& ctx);
36 void DeleteProperties(Kernel::HLERequestContext& ctx); 35 void DeleteProperties(Kernel::HLERequestContext& ctx);
37 36
38 const Core::System& system;
39 ARPManager& manager; 37 ARPManager& manager;
40 std::shared_ptr<IRegistrar> registrar; 38 std::shared_ptr<IRegistrar> registrar;
41}; 39};
diff --git a/src/core/hle/service/glue/bgtc.cpp b/src/core/hle/service/glue/bgtc.cpp
index cd89d088f..a478b68e1 100644
--- a/src/core/hle/service/glue/bgtc.cpp
+++ b/src/core/hle/service/glue/bgtc.cpp
@@ -6,7 +6,7 @@
6 6
7namespace Service::Glue { 7namespace Service::Glue {
8 8
9BGTC_T::BGTC_T() : ServiceFramework{"bgtc:t"} { 9BGTC_T::BGTC_T(Core::System& system_) : ServiceFramework{system_, "bgtc:t"} {
10 // clang-format off 10 // clang-format off
11 static const FunctionInfo functions[] = { 11 static const FunctionInfo functions[] = {
12 {1, nullptr, "NotifyTaskStarting"}, 12 {1, nullptr, "NotifyTaskStarting"},
@@ -31,7 +31,7 @@ BGTC_T::BGTC_T() : ServiceFramework{"bgtc:t"} {
31 31
32BGTC_T::~BGTC_T() = default; 32BGTC_T::~BGTC_T() = default;
33 33
34BGTC_SC::BGTC_SC() : ServiceFramework{"bgtc:sc"} { 34BGTC_SC::BGTC_SC(Core::System& system_) : ServiceFramework{system_, "bgtc:sc"} {
35 // clang-format off 35 // clang-format off
36 static const FunctionInfo functions[] = { 36 static const FunctionInfo functions[] = {
37 {1, nullptr, "GetState"}, 37 {1, nullptr, "GetState"},
diff --git a/src/core/hle/service/glue/bgtc.h b/src/core/hle/service/glue/bgtc.h
index 81844f03e..906116ba6 100644
--- a/src/core/hle/service/glue/bgtc.h
+++ b/src/core/hle/service/glue/bgtc.h
@@ -6,17 +6,21 @@
6 6
7#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
8 8
9namespace Core {
10class System;
11}
12
9namespace Service::Glue { 13namespace Service::Glue {
10 14
11class BGTC_T final : public ServiceFramework<BGTC_T> { 15class BGTC_T final : public ServiceFramework<BGTC_T> {
12public: 16public:
13 BGTC_T(); 17 explicit BGTC_T(Core::System& system_);
14 ~BGTC_T() override; 18 ~BGTC_T() override;
15}; 19};
16 20
17class BGTC_SC final : public ServiceFramework<BGTC_SC> { 21class BGTC_SC final : public ServiceFramework<BGTC_SC> {
18public: 22public:
19 BGTC_SC(); 23 explicit BGTC_SC(Core::System& system_);
20 ~BGTC_SC() override; 24 ~BGTC_SC() override;
21}; 25};
22 26
diff --git a/src/core/hle/service/glue/glue.cpp b/src/core/hle/service/glue/glue.cpp
index c728e815c..4eafbe5fa 100644
--- a/src/core/hle/service/glue/glue.cpp
+++ b/src/core/hle/service/glue/glue.cpp
@@ -18,8 +18,8 @@ void InstallInterfaces(Core::System& system) {
18 ->InstallAsService(system.ServiceManager()); 18 ->InstallAsService(system.ServiceManager());
19 19
20 // BackGround Task Controller 20 // BackGround Task Controller
21 std::make_shared<BGTC_T>()->InstallAsService(system.ServiceManager()); 21 std::make_shared<BGTC_T>(system)->InstallAsService(system.ServiceManager());
22 std::make_shared<BGTC_SC>()->InstallAsService(system.ServiceManager()); 22 std::make_shared<BGTC_SC>(system)->InstallAsService(system.ServiceManager());
23} 23}
24 24
25} // namespace Service::Glue 25} // namespace Service::Glue
diff --git a/src/core/hle/service/grc/grc.cpp b/src/core/hle/service/grc/grc.cpp
index 401e0b208..a502ab47f 100644
--- a/src/core/hle/service/grc/grc.cpp
+++ b/src/core/hle/service/grc/grc.cpp
@@ -12,7 +12,7 @@ namespace Service::GRC {
12 12
13class GRC final : public ServiceFramework<GRC> { 13class GRC final : public ServiceFramework<GRC> {
14public: 14public:
15 explicit GRC() : ServiceFramework{"grc:c"} { 15 explicit GRC(Core::System& system) : ServiceFramework{system, "grc:c"} {
16 // clang-format off 16 // clang-format off
17 static const FunctionInfo functions[] = { 17 static const FunctionInfo functions[] = {
18 {1, nullptr, "OpenContinuousRecorder"}, 18 {1, nullptr, "OpenContinuousRecorder"},
@@ -27,8 +27,8 @@ public:
27 } 27 }
28}; 28};
29 29
30void InstallInterfaces(SM::ServiceManager& sm) { 30void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
31 std::make_shared<GRC>()->InstallAsService(sm); 31 std::make_shared<GRC>(system)->InstallAsService(sm);
32} 32}
33 33
34} // namespace Service::GRC 34} // namespace Service::GRC
diff --git a/src/core/hle/service/grc/grc.h b/src/core/hle/service/grc/grc.h
index e0d29e70d..9069fe756 100644
--- a/src/core/hle/service/grc/grc.h
+++ b/src/core/hle/service/grc/grc.h
@@ -4,12 +4,16 @@
4 4
5#pragma once 5#pragma once
6 6
7namespace Core {
8class System;
9}
10
7namespace Service::SM { 11namespace Service::SM {
8class ServiceManager; 12class ServiceManager;
9} 13}
10 14
11namespace Service::GRC { 15namespace Service::GRC {
12 16
13void InstallInterfaces(SM::ServiceManager& sm); 17void InstallInterfaces(SM::ServiceManager& sm, Core::System& system);
14 18
15} // namespace Service::GRC 19} // namespace Service::GRC
diff --git a/src/core/hle/service/hid/controllers/controller_base.h b/src/core/hle/service/hid/controllers/controller_base.h
index 8bc69c372..f47a9e61c 100644
--- a/src/core/hle/service/hid/controllers/controller_base.h
+++ b/src/core/hle/service/hid/controllers/controller_base.h
@@ -31,6 +31,10 @@ public:
31 virtual void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, 31 virtual void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
32 std::size_t size) = 0; 32 std::size_t size) = 0;
33 33
34 // When the controller is requesting a motion update for the shared memory
35 virtual void OnMotionUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
36 std::size_t size) {}
37
34 // Called when input devices should be loaded 38 // Called when input devices should be loaded
35 virtual void OnLoadInputDevices() = 0; 39 virtual void OnLoadInputDevices() = 0;
36 40
diff --git a/src/core/hle/service/hid/controllers/keyboard.cpp b/src/core/hle/service/hid/controllers/keyboard.cpp
index 0b896d5ad..59b694cd4 100644
--- a/src/core/hle/service/hid/controllers/keyboard.cpp
+++ b/src/core/hle/service/hid/controllers/keyboard.cpp
@@ -42,8 +42,8 @@ void Controller_Keyboard::OnUpdate(const Core::Timing::CoreTiming& core_timing,
42 cur_entry.modifier = 0; 42 cur_entry.modifier = 0;
43 if (Settings::values.keyboard_enabled) { 43 if (Settings::values.keyboard_enabled) {
44 for (std::size_t i = 0; i < keyboard_keys.size(); ++i) { 44 for (std::size_t i = 0; i < keyboard_keys.size(); ++i) {
45 cur_entry.key[i / KEYS_PER_BYTE] |= 45 auto& entry = cur_entry.key[i / KEYS_PER_BYTE];
46 (keyboard_keys[i]->GetStatus() << (i % KEYS_PER_BYTE)); 46 entry = static_cast<u8>(entry | (keyboard_keys[i]->GetStatus() << (i % KEYS_PER_BYTE)));
47 } 47 }
48 48
49 for (std::size_t i = 0; i < keyboard_mods.size(); ++i) { 49 for (std::size_t i = 0; i < keyboard_mods.size(); ++i) {
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index 620386cd1..d280e7caf 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -116,8 +116,36 @@ u32 Controller_NPad::IndexToNPad(std::size_t index) {
116 } 116 }
117} 117}
118 118
119bool Controller_NPad::IsNpadIdValid(u32 npad_id) {
120 switch (npad_id) {
121 case 0:
122 case 1:
123 case 2:
124 case 3:
125 case 4:
126 case 5:
127 case 6:
128 case 7:
129 case NPAD_UNKNOWN:
130 case NPAD_HANDHELD:
131 return true;
132 default:
133 LOG_ERROR(Service_HID, "Invalid npad id {}", npad_id);
134 return false;
135 }
136}
137
138bool Controller_NPad::IsDeviceHandleValid(const DeviceHandle& device_handle) {
139 return IsNpadIdValid(device_handle.npad_id) &&
140 device_handle.npad_type < NpadType::MaxNpadType &&
141 device_handle.device_index < DeviceIndex::MaxDeviceIndex;
142}
143
119Controller_NPad::Controller_NPad(Core::System& system) : ControllerBase(system), system(system) {} 144Controller_NPad::Controller_NPad(Core::System& system) : ControllerBase(system), system(system) {}
120Controller_NPad::~Controller_NPad() = default; 145
146Controller_NPad::~Controller_NPad() {
147 OnRelease();
148}
121 149
122void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) { 150void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) {
123 const auto controller_type = connected_controllers[controller_idx].type; 151 const auto controller_type = connected_controllers[controller_idx].type;
@@ -139,7 +167,7 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) {
139 controller.properties.is_vertical.Assign(1); 167 controller.properties.is_vertical.Assign(1);
140 controller.properties.use_plus.Assign(1); 168 controller.properties.use_plus.Assign(1);
141 controller.properties.use_minus.Assign(1); 169 controller.properties.use_minus.Assign(1);
142 controller.pad_assignment = NPadAssignments::Single; 170 controller.pad_assignment = NpadAssignments::Single;
143 break; 171 break;
144 case NPadControllerType::Handheld: 172 case NPadControllerType::Handheld:
145 controller.joy_styles.handheld.Assign(1); 173 controller.joy_styles.handheld.Assign(1);
@@ -147,7 +175,7 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) {
147 controller.properties.is_vertical.Assign(1); 175 controller.properties.is_vertical.Assign(1);
148 controller.properties.use_plus.Assign(1); 176 controller.properties.use_plus.Assign(1);
149 controller.properties.use_minus.Assign(1); 177 controller.properties.use_minus.Assign(1);
150 controller.pad_assignment = NPadAssignments::Dual; 178 controller.pad_assignment = NpadAssignments::Dual;
151 break; 179 break;
152 case NPadControllerType::JoyDual: 180 case NPadControllerType::JoyDual:
153 controller.joy_styles.joycon_dual.Assign(1); 181 controller.joy_styles.joycon_dual.Assign(1);
@@ -156,26 +184,26 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) {
156 controller.properties.is_vertical.Assign(1); 184 controller.properties.is_vertical.Assign(1);
157 controller.properties.use_plus.Assign(1); 185 controller.properties.use_plus.Assign(1);
158 controller.properties.use_minus.Assign(1); 186 controller.properties.use_minus.Assign(1);
159 controller.pad_assignment = NPadAssignments::Dual; 187 controller.pad_assignment = NpadAssignments::Dual;
160 break; 188 break;
161 case NPadControllerType::JoyLeft: 189 case NPadControllerType::JoyLeft:
162 controller.joy_styles.joycon_left.Assign(1); 190 controller.joy_styles.joycon_left.Assign(1);
163 controller.device_type.joycon_left.Assign(1); 191 controller.device_type.joycon_left.Assign(1);
164 controller.properties.is_horizontal.Assign(1); 192 controller.properties.is_horizontal.Assign(1);
165 controller.properties.use_minus.Assign(1); 193 controller.properties.use_minus.Assign(1);
166 controller.pad_assignment = NPadAssignments::Single; 194 controller.pad_assignment = NpadAssignments::Single;
167 break; 195 break;
168 case NPadControllerType::JoyRight: 196 case NPadControllerType::JoyRight:
169 controller.joy_styles.joycon_right.Assign(1); 197 controller.joy_styles.joycon_right.Assign(1);
170 controller.device_type.joycon_right.Assign(1); 198 controller.device_type.joycon_right.Assign(1);
171 controller.properties.is_horizontal.Assign(1); 199 controller.properties.is_horizontal.Assign(1);
172 controller.properties.use_plus.Assign(1); 200 controller.properties.use_plus.Assign(1);
173 controller.pad_assignment = NPadAssignments::Single; 201 controller.pad_assignment = NpadAssignments::Single;
174 break; 202 break;
175 case NPadControllerType::Pokeball: 203 case NPadControllerType::Pokeball:
176 controller.joy_styles.pokeball.Assign(1); 204 controller.joy_styles.pokeball.Assign(1);
177 controller.device_type.pokeball.Assign(1); 205 controller.device_type.pokeball.Assign(1);
178 controller.pad_assignment = NPadAssignments::Single; 206 controller.pad_assignment = NpadAssignments::Single;
179 break; 207 break;
180 } 208 }
181 209
@@ -184,11 +212,14 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) {
184 controller.single_color.button_color = 0; 212 controller.single_color.button_color = 0;
185 213
186 controller.dual_color_error = ColorReadError::ReadOk; 214 controller.dual_color_error = ColorReadError::ReadOk;
187 controller.left_color.body_color = Settings::values.players[controller_idx].body_color_left; 215 controller.left_color.body_color =
188 controller.left_color.button_color = Settings::values.players[controller_idx].button_color_left; 216 Settings::values.players.GetValue()[controller_idx].body_color_left;
189 controller.right_color.body_color = Settings::values.players[controller_idx].body_color_right; 217 controller.left_color.button_color =
218 Settings::values.players.GetValue()[controller_idx].button_color_left;
219 controller.right_color.body_color =
220 Settings::values.players.GetValue()[controller_idx].body_color_right;
190 controller.right_color.button_color = 221 controller.right_color.button_color =
191 Settings::values.players[controller_idx].button_color_right; 222 Settings::values.players.GetValue()[controller_idx].button_color_right;
192 223
193 controller.battery_level[0] = BATTERY_FULL; 224 controller.battery_level[0] = BATTERY_FULL;
194 controller.battery_level[1] = BATTERY_FULL; 225 controller.battery_level[1] = BATTERY_FULL;
@@ -199,7 +230,7 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) {
199 230
200void Controller_NPad::OnInit() { 231void Controller_NPad::OnInit() {
201 auto& kernel = system.Kernel(); 232 auto& kernel = system.Kernel();
202 for (std::size_t i = 0; i < styleset_changed_events.size(); i++) { 233 for (std::size_t i = 0; i < styleset_changed_events.size(); ++i) {
203 styleset_changed_events[i] = Kernel::WritableEvent::CreateEventPair( 234 styleset_changed_events[i] = Kernel::WritableEvent::CreateEventPair(
204 kernel, fmt::format("npad:NpadStyleSetChanged_{}", i)); 235 kernel, fmt::format("npad:NpadStyleSetChanged_{}", i));
205 } 236 }
@@ -208,6 +239,8 @@ void Controller_NPad::OnInit() {
208 return; 239 return;
209 } 240 }
210 241
242 OnLoadInputDevices();
243
211 if (style.raw == 0) { 244 if (style.raw == 0) {
212 // We want to support all controllers 245 // We want to support all controllers
213 style.handheld.Assign(1); 246 style.handheld.Assign(1);
@@ -218,12 +251,27 @@ void Controller_NPad::OnInit() {
218 style.pokeball.Assign(1); 251 style.pokeball.Assign(1);
219 } 252 }
220 253
221 std::transform(Settings::values.players.begin(), Settings::values.players.end(), 254 std::transform(Settings::values.players.GetValue().begin(),
222 connected_controllers.begin(), [](const Settings::PlayerInput& player) { 255 Settings::values.players.GetValue().end(), connected_controllers.begin(),
256 [](const Settings::PlayerInput& player) {
223 return ControllerHolder{MapSettingsTypeToNPad(player.controller_type), 257 return ControllerHolder{MapSettingsTypeToNPad(player.controller_type),
224 player.connected}; 258 player.connected};
225 }); 259 });
226 260
261 // Connect the Player 1 or Handheld controller if none are connected.
262 if (std::none_of(connected_controllers.begin(), connected_controllers.end(),
263 [](const ControllerHolder& controller) { return controller.is_connected; })) {
264 const auto controller =
265 MapSettingsTypeToNPad(Settings::values.players.GetValue()[0].controller_type);
266 if (controller == NPadControllerType::Handheld) {
267 Settings::values.players.GetValue()[HANDHELD_INDEX].connected = true;
268 connected_controllers[HANDHELD_INDEX] = {controller, true};
269 } else {
270 Settings::values.players.GetValue()[0].connected = true;
271 connected_controllers[0] = {controller, true};
272 }
273 }
274
227 // Account for handheld 275 // Account for handheld
228 if (connected_controllers[HANDHELD_INDEX].is_connected) { 276 if (connected_controllers[HANDHELD_INDEX].is_connected) {
229 connected_controllers[HANDHELD_INDEX].type = NPadControllerType::Handheld; 277 connected_controllers[HANDHELD_INDEX].type = NPadControllerType::Handheld;
@@ -242,7 +290,7 @@ void Controller_NPad::OnInit() {
242} 290}
243 291
244void Controller_NPad::OnLoadInputDevices() { 292void Controller_NPad::OnLoadInputDevices() {
245 const auto& players = Settings::values.players; 293 const auto& players = Settings::values.players.GetValue();
246 for (std::size_t i = 0; i < players.size(); ++i) { 294 for (std::size_t i = 0; i < players.size(); ++i) {
247 std::transform(players[i].buttons.begin() + Settings::NativeButton::BUTTON_HID_BEGIN, 295 std::transform(players[i].buttons.begin() + Settings::NativeButton::BUTTON_HID_BEGIN,
248 players[i].buttons.begin() + Settings::NativeButton::BUTTON_HID_END, 296 players[i].buttons.begin() + Settings::NativeButton::BUTTON_HID_END,
@@ -250,17 +298,30 @@ void Controller_NPad::OnLoadInputDevices() {
250 std::transform(players[i].analogs.begin() + Settings::NativeAnalog::STICK_HID_BEGIN, 298 std::transform(players[i].analogs.begin() + Settings::NativeAnalog::STICK_HID_BEGIN,
251 players[i].analogs.begin() + Settings::NativeAnalog::STICK_HID_END, 299 players[i].analogs.begin() + Settings::NativeAnalog::STICK_HID_END,
252 sticks[i].begin(), Input::CreateDevice<Input::AnalogDevice>); 300 sticks[i].begin(), Input::CreateDevice<Input::AnalogDevice>);
301 std::transform(players[i].vibrations.begin() +
302 Settings::NativeVibration::VIBRATION_HID_BEGIN,
303 players[i].vibrations.begin() + Settings::NativeVibration::VIBRATION_HID_END,
304 vibrations[i].begin(), Input::CreateDevice<Input::VibrationDevice>);
253 std::transform(players[i].motions.begin() + Settings::NativeMotion::MOTION_HID_BEGIN, 305 std::transform(players[i].motions.begin() + Settings::NativeMotion::MOTION_HID_BEGIN,
254 players[i].motions.begin() + Settings::NativeMotion::MOTION_HID_END, 306 players[i].motions.begin() + Settings::NativeMotion::MOTION_HID_END,
255 motions[i].begin(), Input::CreateDevice<Input::MotionDevice>); 307 motions[i].begin(), Input::CreateDevice<Input::MotionDevice>);
308 for (std::size_t device_idx = 0; device_idx < vibrations[i].size(); ++device_idx) {
309 InitializeVibrationDeviceAtIndex(i, device_idx);
310 }
256 } 311 }
257} 312}
258 313
259void Controller_NPad::OnRelease() {} 314void Controller_NPad::OnRelease() {
315 for (std::size_t npad_idx = 0; npad_idx < vibrations.size(); ++npad_idx) {
316 for (std::size_t device_idx = 0; device_idx < vibrations[npad_idx].size(); ++device_idx) {
317 VibrateControllerAtIndex(npad_idx, device_idx, {});
318 }
319 }
320}
260 321
261void Controller_NPad::RequestPadStateUpdate(u32 npad_id) { 322void Controller_NPad::RequestPadStateUpdate(u32 npad_id) {
262 const auto controller_idx = NPadIdToIndex(npad_id); 323 const auto controller_idx = NPadIdToIndex(npad_id);
263 [[maybe_unused]] const auto controller_type = connected_controllers[controller_idx].type; 324 const auto controller_type = connected_controllers[controller_idx].type;
264 if (!connected_controllers[controller_idx].is_connected) { 325 if (!connected_controllers[controller_idx].is_connected) {
265 return; 326 return;
266 } 327 }
@@ -269,61 +330,69 @@ void Controller_NPad::RequestPadStateUpdate(u32 npad_id) {
269 auto& rstick_entry = npad_pad_states[controller_idx].r_stick; 330 auto& rstick_entry = npad_pad_states[controller_idx].r_stick;
270 const auto& button_state = buttons[controller_idx]; 331 const auto& button_state = buttons[controller_idx];
271 const auto& analog_state = sticks[controller_idx]; 332 const auto& analog_state = sticks[controller_idx];
272 const auto& motion_state = motions[controller_idx];
273 const auto [stick_l_x_f, stick_l_y_f] = 333 const auto [stick_l_x_f, stick_l_y_f] =
274 analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetStatus(); 334 analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetStatus();
275 const auto [stick_r_x_f, stick_r_y_f] = 335 const auto [stick_r_x_f, stick_r_y_f] =
276 analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]->GetStatus(); 336 analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]->GetStatus();
277 337
278 using namespace Settings::NativeButton; 338 using namespace Settings::NativeButton;
279 pad_state.a.Assign(button_state[A - BUTTON_HID_BEGIN]->GetStatus()); 339 if (controller_type != NPadControllerType::JoyLeft) {
280 pad_state.b.Assign(button_state[B - BUTTON_HID_BEGIN]->GetStatus()); 340 pad_state.a.Assign(button_state[A - BUTTON_HID_BEGIN]->GetStatus());
281 pad_state.x.Assign(button_state[X - BUTTON_HID_BEGIN]->GetStatus()); 341 pad_state.b.Assign(button_state[B - BUTTON_HID_BEGIN]->GetStatus());
282 pad_state.y.Assign(button_state[Y - BUTTON_HID_BEGIN]->GetStatus()); 342 pad_state.x.Assign(button_state[X - BUTTON_HID_BEGIN]->GetStatus());
283 pad_state.l_stick.Assign(button_state[LStick - BUTTON_HID_BEGIN]->GetStatus()); 343 pad_state.y.Assign(button_state[Y - BUTTON_HID_BEGIN]->GetStatus());
284 pad_state.r_stick.Assign(button_state[RStick - BUTTON_HID_BEGIN]->GetStatus()); 344 pad_state.r_stick.Assign(button_state[RStick - BUTTON_HID_BEGIN]->GetStatus());
285 pad_state.l.Assign(button_state[L - BUTTON_HID_BEGIN]->GetStatus()); 345 pad_state.r.Assign(button_state[R - BUTTON_HID_BEGIN]->GetStatus());
286 pad_state.r.Assign(button_state[R - BUTTON_HID_BEGIN]->GetStatus()); 346 pad_state.zr.Assign(button_state[ZR - BUTTON_HID_BEGIN]->GetStatus());
287 pad_state.zl.Assign(button_state[ZL - BUTTON_HID_BEGIN]->GetStatus()); 347 pad_state.plus.Assign(button_state[Plus - BUTTON_HID_BEGIN]->GetStatus());
288 pad_state.zr.Assign(button_state[ZR - BUTTON_HID_BEGIN]->GetStatus()); 348
289 pad_state.plus.Assign(button_state[Plus - BUTTON_HID_BEGIN]->GetStatus()); 349 pad_state.r_stick_right.Assign(
290 pad_state.minus.Assign(button_state[Minus - BUTTON_HID_BEGIN]->GetStatus()); 350 analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]
291 351 ->GetAnalogDirectionStatus(Input::AnalogDirection::RIGHT));
292 pad_state.d_left.Assign(button_state[DLeft - BUTTON_HID_BEGIN]->GetStatus()); 352 pad_state.r_stick_left.Assign(
293 pad_state.d_up.Assign(button_state[DUp - BUTTON_HID_BEGIN]->GetStatus()); 353 analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]
294 pad_state.d_right.Assign(button_state[DRight - BUTTON_HID_BEGIN]->GetStatus()); 354 ->GetAnalogDirectionStatus(Input::AnalogDirection::LEFT));
295 pad_state.d_down.Assign(button_state[DDown - BUTTON_HID_BEGIN]->GetStatus()); 355 pad_state.r_stick_up.Assign(
296 356 analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]
297 pad_state.l_stick_right.Assign( 357 ->GetAnalogDirectionStatus(Input::AnalogDirection::UP));
298 analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetAnalogDirectionStatus( 358 pad_state.r_stick_down.Assign(
299 Input::AnalogDirection::RIGHT)); 359 analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]
300 pad_state.l_stick_left.Assign( 360 ->GetAnalogDirectionStatus(Input::AnalogDirection::DOWN));
301 analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetAnalogDirectionStatus( 361 rstick_entry.x = static_cast<s32>(stick_r_x_f * HID_JOYSTICK_MAX);
302 Input::AnalogDirection::LEFT)); 362 rstick_entry.y = static_cast<s32>(stick_r_y_f * HID_JOYSTICK_MAX);
303 pad_state.l_stick_up.Assign( 363 }
304 analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetAnalogDirectionStatus( 364
305 Input::AnalogDirection::UP)); 365 if (controller_type != NPadControllerType::JoyRight) {
306 pad_state.l_stick_down.Assign( 366 pad_state.d_left.Assign(button_state[DLeft - BUTTON_HID_BEGIN]->GetStatus());
307 analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetAnalogDirectionStatus( 367 pad_state.d_up.Assign(button_state[DUp - BUTTON_HID_BEGIN]->GetStatus());
308 Input::AnalogDirection::DOWN)); 368 pad_state.d_right.Assign(button_state[DRight - BUTTON_HID_BEGIN]->GetStatus());
309 369 pad_state.d_down.Assign(button_state[DDown - BUTTON_HID_BEGIN]->GetStatus());
310 pad_state.r_stick_right.Assign( 370 pad_state.l_stick.Assign(button_state[LStick - BUTTON_HID_BEGIN]->GetStatus());
311 analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)] 371 pad_state.l.Assign(button_state[L - BUTTON_HID_BEGIN]->GetStatus());
312 ->GetAnalogDirectionStatus(Input::AnalogDirection::RIGHT)); 372 pad_state.zl.Assign(button_state[ZL - BUTTON_HID_BEGIN]->GetStatus());
313 pad_state.r_stick_left.Assign(analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)] 373 pad_state.minus.Assign(button_state[Minus - BUTTON_HID_BEGIN]->GetStatus());
314 ->GetAnalogDirectionStatus(Input::AnalogDirection::LEFT)); 374
315 pad_state.r_stick_up.Assign(analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)] 375 pad_state.l_stick_right.Assign(
316 ->GetAnalogDirectionStatus(Input::AnalogDirection::UP)); 376 analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]
317 pad_state.r_stick_down.Assign(analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)] 377 ->GetAnalogDirectionStatus(Input::AnalogDirection::RIGHT));
318 ->GetAnalogDirectionStatus(Input::AnalogDirection::DOWN)); 378 pad_state.l_stick_left.Assign(
319 379 analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]
320 pad_state.left_sl.Assign(button_state[SL - BUTTON_HID_BEGIN]->GetStatus()); 380 ->GetAnalogDirectionStatus(Input::AnalogDirection::LEFT));
321 pad_state.left_sr.Assign(button_state[SR - BUTTON_HID_BEGIN]->GetStatus()); 381 pad_state.l_stick_up.Assign(
322 382 analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]
323 lstick_entry.x = static_cast<s32>(stick_l_x_f * HID_JOYSTICK_MAX); 383 ->GetAnalogDirectionStatus(Input::AnalogDirection::UP));
324 lstick_entry.y = static_cast<s32>(stick_l_y_f * HID_JOYSTICK_MAX); 384 pad_state.l_stick_down.Assign(
325 rstick_entry.x = static_cast<s32>(stick_r_x_f * HID_JOYSTICK_MAX); 385 analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]
326 rstick_entry.y = static_cast<s32>(stick_r_y_f * HID_JOYSTICK_MAX); 386 ->GetAnalogDirectionStatus(Input::AnalogDirection::DOWN));
387 lstick_entry.x = static_cast<s32>(stick_l_x_f * HID_JOYSTICK_MAX);
388 lstick_entry.y = static_cast<s32>(stick_l_y_f * HID_JOYSTICK_MAX);
389 }
390
391 if (controller_type == NPadControllerType::JoyLeft ||
392 controller_type == NPadControllerType::JoyRight) {
393 pad_state.left_sl.Assign(button_state[SL - BUTTON_HID_BEGIN]->GetStatus());
394 pad_state.left_sr.Assign(button_state[SR - BUTTON_HID_BEGIN]->GetStatus());
395 }
327} 396}
328 397
329void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, 398void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
@@ -331,7 +400,7 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
331 if (!IsControllerActivated()) { 400 if (!IsControllerActivated()) {
332 return; 401 return;
333 } 402 }
334 for (std::size_t i = 0; i < shared_memory_entries.size(); i++) { 403 for (std::size_t i = 0; i < shared_memory_entries.size(); ++i) {
335 auto& npad = shared_memory_entries[i]; 404 auto& npad = shared_memory_entries[i];
336 const std::array<NPadGeneric*, 7> controller_npads{&npad.main_controller_states, 405 const std::array<NPadGeneric*, 7> controller_npads{&npad.main_controller_states,
337 &npad.handheld_states, 406 &npad.handheld_states,
@@ -365,6 +434,123 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
365 } 434 }
366 const u32 npad_index = static_cast<u32>(i); 435 const u32 npad_index = static_cast<u32>(i);
367 436
437 RequestPadStateUpdate(npad_index);
438 auto& pad_state = npad_pad_states[npad_index];
439
440 auto& main_controller =
441 npad.main_controller_states.npad[npad.main_controller_states.common.last_entry_index];
442 auto& handheld_entry =
443 npad.handheld_states.npad[npad.handheld_states.common.last_entry_index];
444 auto& dual_entry = npad.dual_states.npad[npad.dual_states.common.last_entry_index];
445 auto& left_entry = npad.left_joy_states.npad[npad.left_joy_states.common.last_entry_index];
446 auto& right_entry =
447 npad.right_joy_states.npad[npad.right_joy_states.common.last_entry_index];
448 auto& pokeball_entry =
449 npad.pokeball_states.npad[npad.pokeball_states.common.last_entry_index];
450 auto& libnx_entry = npad.libnx.npad[npad.libnx.common.last_entry_index];
451
452 libnx_entry.connection_status.raw = 0;
453 libnx_entry.connection_status.IsConnected.Assign(1);
454
455 switch (controller_type) {
456 case NPadControllerType::None:
457 UNREACHABLE();
458 break;
459 case NPadControllerType::ProController:
460 main_controller.connection_status.raw = 0;
461 main_controller.connection_status.IsConnected.Assign(1);
462 main_controller.connection_status.IsWired.Assign(1);
463 main_controller.pad.pad_states.raw = pad_state.pad_states.raw;
464 main_controller.pad.l_stick = pad_state.l_stick;
465 main_controller.pad.r_stick = pad_state.r_stick;
466
467 libnx_entry.connection_status.IsWired.Assign(1);
468 break;
469 case NPadControllerType::Handheld:
470 handheld_entry.connection_status.raw = 0;
471 handheld_entry.connection_status.IsConnected.Assign(1);
472 handheld_entry.connection_status.IsWired.Assign(1);
473 handheld_entry.connection_status.IsLeftJoyConnected.Assign(1);
474 handheld_entry.connection_status.IsRightJoyConnected.Assign(1);
475 handheld_entry.connection_status.IsLeftJoyWired.Assign(1);
476 handheld_entry.connection_status.IsRightJoyWired.Assign(1);
477 handheld_entry.pad.pad_states.raw = pad_state.pad_states.raw;
478 handheld_entry.pad.l_stick = pad_state.l_stick;
479 handheld_entry.pad.r_stick = pad_state.r_stick;
480
481 libnx_entry.connection_status.IsWired.Assign(1);
482 libnx_entry.connection_status.IsLeftJoyConnected.Assign(1);
483 libnx_entry.connection_status.IsRightJoyConnected.Assign(1);
484 libnx_entry.connection_status.IsLeftJoyWired.Assign(1);
485 libnx_entry.connection_status.IsRightJoyWired.Assign(1);
486 break;
487 case NPadControllerType::JoyDual:
488 dual_entry.connection_status.raw = 0;
489 dual_entry.connection_status.IsConnected.Assign(1);
490 dual_entry.connection_status.IsLeftJoyConnected.Assign(1);
491 dual_entry.connection_status.IsRightJoyConnected.Assign(1);
492 dual_entry.pad.pad_states.raw = pad_state.pad_states.raw;
493 dual_entry.pad.l_stick = pad_state.l_stick;
494 dual_entry.pad.r_stick = pad_state.r_stick;
495
496 libnx_entry.connection_status.IsLeftJoyConnected.Assign(1);
497 libnx_entry.connection_status.IsRightJoyConnected.Assign(1);
498 break;
499 case NPadControllerType::JoyLeft:
500 left_entry.connection_status.raw = 0;
501 left_entry.connection_status.IsConnected.Assign(1);
502 left_entry.connection_status.IsLeftJoyConnected.Assign(1);
503 left_entry.pad.pad_states.raw = pad_state.pad_states.raw;
504 left_entry.pad.l_stick = pad_state.l_stick;
505 left_entry.pad.r_stick = pad_state.r_stick;
506
507 libnx_entry.connection_status.IsLeftJoyConnected.Assign(1);
508 break;
509 case NPadControllerType::JoyRight:
510 right_entry.connection_status.raw = 0;
511 right_entry.connection_status.IsConnected.Assign(1);
512 right_entry.connection_status.IsRightJoyConnected.Assign(1);
513 right_entry.pad.pad_states.raw = pad_state.pad_states.raw;
514 right_entry.pad.l_stick = pad_state.l_stick;
515 right_entry.pad.r_stick = pad_state.r_stick;
516
517 libnx_entry.connection_status.IsRightJoyConnected.Assign(1);
518 break;
519 case NPadControllerType::Pokeball:
520 pokeball_entry.connection_status.raw = 0;
521 pokeball_entry.connection_status.IsConnected.Assign(1);
522 pokeball_entry.pad.pad_states.raw = pad_state.pad_states.raw;
523 pokeball_entry.pad.l_stick = pad_state.l_stick;
524 pokeball_entry.pad.r_stick = pad_state.r_stick;
525 break;
526 }
527
528 // LibNX exclusively uses this section, so we always update it since LibNX doesn't activate
529 // any controllers.
530 libnx_entry.pad.pad_states.raw = pad_state.pad_states.raw;
531 libnx_entry.pad.l_stick = pad_state.l_stick;
532 libnx_entry.pad.r_stick = pad_state.r_stick;
533
534 press_state |= static_cast<u32>(pad_state.pad_states.raw);
535 }
536 std::memcpy(data + NPAD_OFFSET, shared_memory_entries.data(),
537 shared_memory_entries.size() * sizeof(NPadEntry));
538}
539
540void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
541 std::size_t data_len) {
542 if (!IsControllerActivated()) {
543 return;
544 }
545 for (std::size_t i = 0; i < shared_memory_entries.size(); ++i) {
546 auto& npad = shared_memory_entries[i];
547
548 const auto& controller_type = connected_controllers[i].type;
549
550 if (controller_type == NPadControllerType::None || !connected_controllers[i].is_connected) {
551 continue;
552 }
553
368 const std::array<SixAxisGeneric*, 6> controller_sixaxes{ 554 const std::array<SixAxisGeneric*, 6> controller_sixaxes{
369 &npad.sixaxis_full, &npad.sixaxis_handheld, &npad.sixaxis_dual_left, 555 &npad.sixaxis_full, &npad.sixaxis_handheld, &npad.sixaxis_dual_left,
370 &npad.sixaxis_dual_right, &npad.sixaxis_left, &npad.sixaxis_right, 556 &npad.sixaxis_dual_right, &npad.sixaxis_left, &npad.sixaxis_right,
@@ -390,7 +576,7 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
390 // Try to read sixaxis sensor states 576 // Try to read sixaxis sensor states
391 std::array<MotionDevice, 2> motion_devices; 577 std::array<MotionDevice, 2> motion_devices;
392 578
393 if (sixaxis_sensors_enabled && Settings::values.motion_enabled) { 579 if (sixaxis_sensors_enabled && Settings::values.motion_enabled.GetValue()) {
394 sixaxis_at_rest = true; 580 sixaxis_at_rest = true;
395 for (std::size_t e = 0; e < motion_devices.size(); ++e) { 581 for (std::size_t e = 0; e < motion_devices.size(); ++e) {
396 const auto& device = motions[i][e]; 582 const auto& device = motions[i][e];
@@ -403,23 +589,6 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
403 } 589 }
404 } 590 }
405 591
406 RequestPadStateUpdate(npad_index);
407 auto& pad_state = npad_pad_states[npad_index];
408
409 auto& main_controller =
410 npad.main_controller_states.npad[npad.main_controller_states.common.last_entry_index];
411 auto& handheld_entry =
412 npad.handheld_states.npad[npad.handheld_states.common.last_entry_index];
413 auto& dual_entry = npad.dual_states.npad[npad.dual_states.common.last_entry_index];
414 auto& left_entry = npad.left_joy_states.npad[npad.left_joy_states.common.last_entry_index];
415 auto& right_entry =
416 npad.right_joy_states.npad[npad.right_joy_states.common.last_entry_index];
417 auto& pokeball_entry =
418 npad.pokeball_states.npad[npad.pokeball_states.common.last_entry_index];
419 auto& libnx_entry = npad.libnx.npad[npad.libnx.common.last_entry_index];
420
421 libnx_entry.connection_status.raw = 0;
422 libnx_entry.connection_status.IsConnected.Assign(1);
423 auto& full_sixaxis_entry = 592 auto& full_sixaxis_entry =
424 npad.sixaxis_full.sixaxis[npad.sixaxis_full.common.last_entry_index]; 593 npad.sixaxis_full.sixaxis[npad.sixaxis_full.common.last_entry_index];
425 auto& handheld_sixaxis_entry = 594 auto& handheld_sixaxis_entry =
@@ -438,15 +607,6 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
438 UNREACHABLE(); 607 UNREACHABLE();
439 break; 608 break;
440 case NPadControllerType::ProController: 609 case NPadControllerType::ProController:
441 main_controller.connection_status.raw = 0;
442 main_controller.connection_status.IsConnected.Assign(1);
443 main_controller.connection_status.IsWired.Assign(1);
444 main_controller.pad.pad_states.raw = pad_state.pad_states.raw;
445 main_controller.pad.l_stick = pad_state.l_stick;
446 main_controller.pad.r_stick = pad_state.r_stick;
447
448 libnx_entry.connection_status.IsWired.Assign(1);
449
450 if (sixaxis_sensors_enabled && motions[i][0]) { 610 if (sixaxis_sensors_enabled && motions[i][0]) {
451 full_sixaxis_entry.accel = motion_devices[0].accel; 611 full_sixaxis_entry.accel = motion_devices[0].accel;
452 full_sixaxis_entry.gyro = motion_devices[0].gyro; 612 full_sixaxis_entry.gyro = motion_devices[0].gyro;
@@ -455,23 +615,6 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
455 } 615 }
456 break; 616 break;
457 case NPadControllerType::Handheld: 617 case NPadControllerType::Handheld:
458 handheld_entry.connection_status.raw = 0;
459 handheld_entry.connection_status.IsConnected.Assign(1);
460 handheld_entry.connection_status.IsWired.Assign(1);
461 handheld_entry.connection_status.IsLeftJoyConnected.Assign(1);
462 handheld_entry.connection_status.IsRightJoyConnected.Assign(1);
463 handheld_entry.connection_status.IsLeftJoyWired.Assign(1);
464 handheld_entry.connection_status.IsRightJoyWired.Assign(1);
465 handheld_entry.pad.pad_states.raw = pad_state.pad_states.raw;
466 handheld_entry.pad.l_stick = pad_state.l_stick;
467 handheld_entry.pad.r_stick = pad_state.r_stick;
468
469 libnx_entry.connection_status.IsWired.Assign(1);
470 libnx_entry.connection_status.IsLeftJoyConnected.Assign(1);
471 libnx_entry.connection_status.IsRightJoyConnected.Assign(1);
472 libnx_entry.connection_status.IsLeftJoyWired.Assign(1);
473 libnx_entry.connection_status.IsRightJoyWired.Assign(1);
474
475 if (sixaxis_sensors_enabled && motions[i][0]) { 618 if (sixaxis_sensors_enabled && motions[i][0]) {
476 handheld_sixaxis_entry.accel = motion_devices[0].accel; 619 handheld_sixaxis_entry.accel = motion_devices[0].accel;
477 handheld_sixaxis_entry.gyro = motion_devices[0].gyro; 620 handheld_sixaxis_entry.gyro = motion_devices[0].gyro;
@@ -480,17 +623,6 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
480 } 623 }
481 break; 624 break;
482 case NPadControllerType::JoyDual: 625 case NPadControllerType::JoyDual:
483 dual_entry.connection_status.raw = 0;
484 dual_entry.connection_status.IsConnected.Assign(1);
485 dual_entry.connection_status.IsLeftJoyConnected.Assign(1);
486 dual_entry.connection_status.IsRightJoyConnected.Assign(1);
487 dual_entry.pad.pad_states.raw = pad_state.pad_states.raw;
488 dual_entry.pad.l_stick = pad_state.l_stick;
489 dual_entry.pad.r_stick = pad_state.r_stick;
490
491 libnx_entry.connection_status.IsLeftJoyConnected.Assign(1);
492 libnx_entry.connection_status.IsRightJoyConnected.Assign(1);
493
494 if (sixaxis_sensors_enabled && motions[i][0]) { 626 if (sixaxis_sensors_enabled && motions[i][0]) {
495 // Set motion for the left joycon 627 // Set motion for the left joycon
496 dual_left_sixaxis_entry.accel = motion_devices[0].accel; 628 dual_left_sixaxis_entry.accel = motion_devices[0].accel;
@@ -507,15 +639,6 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
507 } 639 }
508 break; 640 break;
509 case NPadControllerType::JoyLeft: 641 case NPadControllerType::JoyLeft:
510 left_entry.connection_status.raw = 0;
511 left_entry.connection_status.IsConnected.Assign(1);
512 left_entry.connection_status.IsLeftJoyConnected.Assign(1);
513 left_entry.pad.pad_states.raw = pad_state.pad_states.raw;
514 left_entry.pad.l_stick = pad_state.l_stick;
515 left_entry.pad.r_stick = pad_state.r_stick;
516
517 libnx_entry.connection_status.IsLeftJoyConnected.Assign(1);
518
519 if (sixaxis_sensors_enabled && motions[i][0]) { 642 if (sixaxis_sensors_enabled && motions[i][0]) {
520 left_sixaxis_entry.accel = motion_devices[0].accel; 643 left_sixaxis_entry.accel = motion_devices[0].accel;
521 left_sixaxis_entry.gyro = motion_devices[0].gyro; 644 left_sixaxis_entry.gyro = motion_devices[0].gyro;
@@ -524,15 +647,6 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
524 } 647 }
525 break; 648 break;
526 case NPadControllerType::JoyRight: 649 case NPadControllerType::JoyRight:
527 right_entry.connection_status.raw = 0;
528 right_entry.connection_status.IsConnected.Assign(1);
529 right_entry.connection_status.IsRightJoyConnected.Assign(1);
530 right_entry.pad.pad_states.raw = pad_state.pad_states.raw;
531 right_entry.pad.l_stick = pad_state.l_stick;
532 right_entry.pad.r_stick = pad_state.r_stick;
533
534 libnx_entry.connection_status.IsRightJoyConnected.Assign(1);
535
536 if (sixaxis_sensors_enabled && motions[i][1]) { 650 if (sixaxis_sensors_enabled && motions[i][1]) {
537 right_sixaxis_entry.accel = motion_devices[1].accel; 651 right_sixaxis_entry.accel = motion_devices[1].accel;
538 right_sixaxis_entry.gyro = motion_devices[1].gyro; 652 right_sixaxis_entry.gyro = motion_devices[1].gyro;
@@ -541,35 +655,22 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
541 } 655 }
542 break; 656 break;
543 case NPadControllerType::Pokeball: 657 case NPadControllerType::Pokeball:
544 pokeball_entry.connection_status.raw = 0;
545 pokeball_entry.connection_status.IsConnected.Assign(1);
546 pokeball_entry.pad.pad_states.raw = pad_state.pad_states.raw;
547 pokeball_entry.pad.l_stick = pad_state.l_stick;
548 pokeball_entry.pad.r_stick = pad_state.r_stick;
549 break; 658 break;
550 } 659 }
551
552 // LibNX exclusively uses this section, so we always update it since LibNX doesn't activate
553 // any controllers.
554 libnx_entry.pad.pad_states.raw = pad_state.pad_states.raw;
555 libnx_entry.pad.l_stick = pad_state.l_stick;
556 libnx_entry.pad.r_stick = pad_state.r_stick;
557
558 press_state |= static_cast<u32>(pad_state.pad_states.raw);
559 } 660 }
560 std::memcpy(data + NPAD_OFFSET, shared_memory_entries.data(), 661 std::memcpy(data + NPAD_OFFSET, shared_memory_entries.data(),
561 shared_memory_entries.size() * sizeof(NPadEntry)); 662 shared_memory_entries.size() * sizeof(NPadEntry));
562} 663}
563 664
564void Controller_NPad::SetSupportedStyleSet(NPadType style_set) { 665void Controller_NPad::SetSupportedStyleSet(NpadStyleSet style_set) {
565 style.raw = style_set.raw; 666 style.raw = style_set.raw;
566} 667}
567 668
568Controller_NPad::NPadType Controller_NPad::GetSupportedStyleSet() const { 669Controller_NPad::NpadStyleSet Controller_NPad::GetSupportedStyleSet() const {
569 return style; 670 return style;
570} 671}
571 672
572void Controller_NPad::SetSupportedNPadIdTypes(u8* data, std::size_t length) { 673void Controller_NPad::SetSupportedNpadIdTypes(u8* data, std::size_t length) {
573 ASSERT(length > 0 && (length % sizeof(u32)) == 0); 674 ASSERT(length > 0 && (length % sizeof(u32)) == 0);
574 supported_npad_id_types.clear(); 675 supported_npad_id_types.clear();
575 supported_npad_id_types.resize(length / sizeof(u32)); 676 supported_npad_id_types.resize(length / sizeof(u32));
@@ -581,7 +682,7 @@ void Controller_NPad::GetSupportedNpadIdTypes(u32* data, std::size_t max_length)
581 std::memcpy(data, supported_npad_id_types.data(), supported_npad_id_types.size()); 682 std::memcpy(data, supported_npad_id_types.data(), supported_npad_id_types.size());
582} 683}
583 684
584std::size_t Controller_NPad::GetSupportedNPadIdTypesSize() const { 685std::size_t Controller_NPad::GetSupportedNpadIdTypesSize() const {
585 return supported_npad_id_types.size(); 686 return supported_npad_id_types.size();
586} 687}
587 688
@@ -601,7 +702,15 @@ Controller_NPad::NpadHandheldActivationMode Controller_NPad::GetNpadHandheldActi
601 return handheld_activation_mode; 702 return handheld_activation_mode;
602} 703}
603 704
604void Controller_NPad::SetNpadMode(u32 npad_id, NPadAssignments assignment_mode) { 705void Controller_NPad::SetNpadCommunicationMode(NpadCommunicationMode communication_mode_) {
706 communication_mode = communication_mode_;
707}
708
709Controller_NPad::NpadCommunicationMode Controller_NPad::GetNpadCommunicationMode() const {
710 return communication_mode;
711}
712
713void Controller_NPad::SetNpadMode(u32 npad_id, NpadAssignments assignment_mode) {
605 const std::size_t npad_index = NPadIdToIndex(npad_id); 714 const std::size_t npad_index = NPadIdToIndex(npad_id);
606 ASSERT(npad_index < shared_memory_entries.size()); 715 ASSERT(npad_index < shared_memory_entries.size());
607 if (shared_memory_entries[npad_index].pad_assignment != assignment_mode) { 716 if (shared_memory_entries[npad_index].pad_assignment != assignment_mode) {
@@ -609,24 +718,156 @@ void Controller_NPad::SetNpadMode(u32 npad_id, NPadAssignments assignment_mode)
609 } 718 }
610} 719}
611 720
612void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids, 721bool Controller_NPad::VibrateControllerAtIndex(std::size_t npad_index, std::size_t device_index,
613 const std::vector<Vibration>& vibrations) { 722 const VibrationValue& vibration_value) {
614 LOG_DEBUG(Service_HID, "(STUBBED) called"); 723 if (!connected_controllers[npad_index].is_connected || !vibrations[npad_index][device_index]) {
724 return false;
725 }
615 726
616 if (!Settings::values.vibration_enabled || !can_controllers_vibrate) { 727 const auto& player = Settings::values.players.GetValue()[npad_index];
617 return; 728
729 if (!player.vibration_enabled) {
730 if (latest_vibration_values[npad_index][device_index].amp_low != 0.0f ||
731 latest_vibration_values[npad_index][device_index].amp_high != 0.0f) {
732 // Send an empty vibration to stop any vibrations.
733 vibrations[npad_index][device_index]->SetRumblePlay(0.0f, 160.0f, 0.0f, 320.0f);
734 // Then reset the vibration value to its default value.
735 latest_vibration_values[npad_index][device_index] = {};
736 }
737
738 return false;
618 } 739 }
619 for (std::size_t i = 0; i < controller_ids.size(); i++) { 740
620 std::size_t controller_pos = NPadIdToIndex(static_cast<u32>(i)); 741 if (!Settings::values.enable_accurate_vibrations.GetValue()) {
621 if (connected_controllers[controller_pos].is_connected) { 742 using std::chrono::duration_cast;
622 // TODO(ogniK): Vibrate the physical controller 743 using std::chrono::milliseconds;
744 using std::chrono::steady_clock;
745
746 const auto now = steady_clock::now();
747
748 // Filter out non-zero vibrations that are within 10ms of each other.
749 if ((vibration_value.amp_low != 0.0f || vibration_value.amp_high != 0.0f) &&
750 duration_cast<milliseconds>(now - last_vibration_timepoints[npad_index][device_index]) <
751 milliseconds(10)) {
752 return false;
623 } 753 }
754
755 last_vibration_timepoints[npad_index][device_index] = now;
756 }
757
758 auto& vibration = vibrations[npad_index][device_index];
759 const auto player_vibration_strength = static_cast<f32>(player.vibration_strength);
760 const auto amp_low =
761 std::min(vibration_value.amp_low * player_vibration_strength / 100.0f, 1.0f);
762 const auto amp_high =
763 std::min(vibration_value.amp_high * player_vibration_strength / 100.0f, 1.0f);
764 return vibration->SetRumblePlay(amp_low, vibration_value.freq_low, amp_high,
765 vibration_value.freq_high);
766}
767
768void Controller_NPad::VibrateController(const DeviceHandle& vibration_device_handle,
769 const VibrationValue& vibration_value) {
770 if (!IsDeviceHandleValid(vibration_device_handle)) {
771 return;
772 }
773
774 if (!Settings::values.vibration_enabled.GetValue() && !permit_vibration_session_enabled) {
775 return;
776 }
777
778 const auto npad_index = NPadIdToIndex(vibration_device_handle.npad_id);
779 const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index);
780
781 if (!vibration_devices_mounted[npad_index][device_index] ||
782 !connected_controllers[npad_index].is_connected) {
783 return;
784 }
785
786 if (vibration_device_handle.device_index == DeviceIndex::None) {
787 UNREACHABLE_MSG("DeviceIndex should never be None!");
788 return;
789 }
790
791 // Some games try to send mismatched parameters in the device handle, block these.
792 if ((connected_controllers[npad_index].type == NPadControllerType::JoyLeft &&
793 (vibration_device_handle.npad_type == NpadType::JoyconRight ||
794 vibration_device_handle.device_index == DeviceIndex::Right)) ||
795 (connected_controllers[npad_index].type == NPadControllerType::JoyRight &&
796 (vibration_device_handle.npad_type == NpadType::JoyconLeft ||
797 vibration_device_handle.device_index == DeviceIndex::Left))) {
798 return;
799 }
800
801 // Filter out vibrations with equivalent values to reduce unnecessary state changes.
802 if (vibration_value.amp_low == latest_vibration_values[npad_index][device_index].amp_low &&
803 vibration_value.amp_high == latest_vibration_values[npad_index][device_index].amp_high) {
804 return;
805 }
806
807 if (VibrateControllerAtIndex(npad_index, device_index, vibration_value)) {
808 latest_vibration_values[npad_index][device_index] = vibration_value;
624 } 809 }
625 last_processed_vibration = vibrations.back();
626} 810}
627 811
628Controller_NPad::Vibration Controller_NPad::GetLastVibration() const { 812void Controller_NPad::VibrateControllers(const std::vector<DeviceHandle>& vibration_device_handles,
629 return last_processed_vibration; 813 const std::vector<VibrationValue>& vibration_values) {
814 if (!Settings::values.vibration_enabled.GetValue() && !permit_vibration_session_enabled) {
815 return;
816 }
817
818 ASSERT_OR_EXECUTE_MSG(
819 vibration_device_handles.size() == vibration_values.size(), { return; },
820 "The amount of device handles does not match with the amount of vibration values,"
821 "this is undefined behavior!");
822
823 for (std::size_t i = 0; i < vibration_device_handles.size(); ++i) {
824 VibrateController(vibration_device_handles[i], vibration_values[i]);
825 }
826}
827
828Controller_NPad::VibrationValue Controller_NPad::GetLastVibration(
829 const DeviceHandle& vibration_device_handle) const {
830 if (!IsDeviceHandleValid(vibration_device_handle)) {
831 return {};
832 }
833
834 const auto npad_index = NPadIdToIndex(vibration_device_handle.npad_id);
835 const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index);
836 return latest_vibration_values[npad_index][device_index];
837}
838
839void Controller_NPad::InitializeVibrationDevice(const DeviceHandle& vibration_device_handle) {
840 if (!IsDeviceHandleValid(vibration_device_handle)) {
841 return;
842 }
843
844 const auto npad_index = NPadIdToIndex(vibration_device_handle.npad_id);
845 const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index);
846 InitializeVibrationDeviceAtIndex(npad_index, device_index);
847}
848
849void Controller_NPad::InitializeVibrationDeviceAtIndex(std::size_t npad_index,
850 std::size_t device_index) {
851 if (vibrations[npad_index][device_index]) {
852 vibration_devices_mounted[npad_index][device_index] =
853 vibrations[npad_index][device_index]->GetStatus() == 1;
854 } else {
855 vibration_devices_mounted[npad_index][device_index] = false;
856 }
857}
858
859void Controller_NPad::SetPermitVibrationSession(bool permit_vibration_session) {
860 permit_vibration_session_enabled = permit_vibration_session;
861}
862
863bool Controller_NPad::IsVibrationDeviceMounted(const DeviceHandle& vibration_device_handle) const {
864 if (!IsDeviceHandleValid(vibration_device_handle)) {
865 return false;
866 }
867
868 const auto npad_index = NPadIdToIndex(vibration_device_handle.npad_id);
869 const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index);
870 return vibration_devices_mounted[npad_index][device_index];
630} 871}
631 872
632std::shared_ptr<Kernel::ReadableEvent> Controller_NPad::GetStyleSetChangedEvent(u32 npad_id) const { 873std::shared_ptr<Kernel::ReadableEvent> Controller_NPad::GetStyleSetChangedEvent(u32 npad_id) const {
@@ -645,31 +886,38 @@ void Controller_NPad::AddNewControllerAt(NPadControllerType controller, std::siz
645void Controller_NPad::UpdateControllerAt(NPadControllerType controller, std::size_t npad_index, 886void Controller_NPad::UpdateControllerAt(NPadControllerType controller, std::size_t npad_index,
646 bool connected) { 887 bool connected) {
647 if (!connected) { 888 if (!connected) {
648 DisconnectNPadAtIndex(npad_index); 889 DisconnectNpadAtIndex(npad_index);
649 return; 890 return;
650 } 891 }
651 892
652 if (controller == NPadControllerType::Handheld) { 893 if (controller == NPadControllerType::Handheld) {
653 Settings::values.players[HANDHELD_INDEX].controller_type = 894 Settings::values.players.GetValue()[HANDHELD_INDEX].controller_type =
654 MapNPadToSettingsType(controller); 895 MapNPadToSettingsType(controller);
655 Settings::values.players[HANDHELD_INDEX].connected = true; 896 Settings::values.players.GetValue()[HANDHELD_INDEX].connected = true;
656 connected_controllers[HANDHELD_INDEX] = {controller, true}; 897 connected_controllers[HANDHELD_INDEX] = {controller, true};
657 InitNewlyAddedController(HANDHELD_INDEX); 898 InitNewlyAddedController(HANDHELD_INDEX);
658 return; 899 return;
659 } 900 }
660 901
661 Settings::values.players[npad_index].controller_type = MapNPadToSettingsType(controller); 902 Settings::values.players.GetValue()[npad_index].controller_type =
662 Settings::values.players[npad_index].connected = true; 903 MapNPadToSettingsType(controller);
904 Settings::values.players.GetValue()[npad_index].connected = true;
663 connected_controllers[npad_index] = {controller, true}; 905 connected_controllers[npad_index] = {controller, true};
664 InitNewlyAddedController(npad_index); 906 InitNewlyAddedController(npad_index);
665} 907}
666 908
667void Controller_NPad::DisconnectNPad(u32 npad_id) { 909void Controller_NPad::DisconnectNpad(u32 npad_id) {
668 DisconnectNPadAtIndex(NPadIdToIndex(npad_id)); 910 DisconnectNpadAtIndex(NPadIdToIndex(npad_id));
669} 911}
670 912
671void Controller_NPad::DisconnectNPadAtIndex(std::size_t npad_index) { 913void Controller_NPad::DisconnectNpadAtIndex(std::size_t npad_index) {
672 Settings::values.players[npad_index].connected = false; 914 for (std::size_t device_idx = 0; device_idx < vibrations[npad_index].size(); ++device_idx) {
915 // Send an empty vibration to stop any vibrations.
916 VibrateControllerAtIndex(npad_index, device_idx, {});
917 vibration_devices_mounted[npad_index][device_idx] = false;
918 }
919
920 Settings::values.players.GetValue()[npad_index].connected = false;
673 connected_controllers[npad_index].is_connected = false; 921 connected_controllers[npad_index].is_connected = false;
674 922
675 auto& controller = shared_memory_entries[npad_index]; 923 auto& controller = shared_memory_entries[npad_index];
@@ -707,7 +955,7 @@ void Controller_NPad::MergeSingleJoyAsDualJoy(u32 npad_id_1, u32 npad_id_2) {
707 (connected_controllers[npad_index_2].type == NPadControllerType::JoyLeft && 955 (connected_controllers[npad_index_2].type == NPadControllerType::JoyLeft &&
708 connected_controllers[npad_index_1].type == NPadControllerType::JoyRight)) { 956 connected_controllers[npad_index_1].type == NPadControllerType::JoyRight)) {
709 // Disconnect the joycon at the second id and connect the dual joycon at the first index. 957 // Disconnect the joycon at the second id and connect the dual joycon at the first index.
710 DisconnectNPad(npad_id_2); 958 DisconnectNpad(npad_id_2);
711 AddNewControllerAt(NPadControllerType::JoyDual, npad_index_1); 959 AddNewControllerAt(NPadControllerType::JoyDual, npad_index_1);
712 } 960 }
713} 961}
@@ -770,12 +1018,13 @@ Controller_NPad::LedPattern Controller_NPad::GetLedPattern(u32 npad_id) {
770 } 1018 }
771} 1019}
772 1020
773void Controller_NPad::SetVibrationEnabled(bool can_vibrate) { 1021bool Controller_NPad::IsUnintendedHomeButtonInputProtectionEnabled(u32 npad_id) const {
774 can_controllers_vibrate = can_vibrate; 1022 return unintended_home_button_input_protection[NPadIdToIndex(npad_id)];
775} 1023}
776 1024
777bool Controller_NPad::IsVibrationEnabled() const { 1025void Controller_NPad::SetUnintendedHomeButtonInputProtectionEnabled(bool is_protection_enabled,
778 return can_controllers_vibrate; 1026 u32 npad_id) {
1027 unintended_home_button_input_protection[NPadIdToIndex(npad_id)] = is_protection_enabled;
779} 1028}
780 1029
781void Controller_NPad::ClearAllConnectedControllers() { 1030void Controller_NPad::ClearAllConnectedControllers() {
@@ -809,7 +1058,7 @@ void Controller_NPad::ClearAllControllers() {
809} 1058}
810 1059
811u32 Controller_NPad::GetAndResetPressState() { 1060u32 Controller_NPad::GetAndResetPressState() {
812 return std::exchange(press_state, 0); 1061 return press_state.exchange(0);
813} 1062}
814 1063
815bool Controller_NPad::IsControllerSupported(NPadControllerType controller) const { 1064bool Controller_NPad::IsControllerSupported(NPadControllerType controller) const {
@@ -822,7 +1071,7 @@ bool Controller_NPad::IsControllerSupported(NPadControllerType controller) const
822 return false; 1071 return false;
823 } 1072 }
824 // Handheld should not be supported in docked mode 1073 // Handheld should not be supported in docked mode
825 if (Settings::values.use_docked_mode) { 1074 if (Settings::values.use_docked_mode.GetValue()) {
826 return false; 1075 return false;
827 } 1076 }
828 1077
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index 654d97c3f..e2e826623 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -5,6 +5,7 @@
5#pragma once 5#pragma once
6 6
7#include <array> 7#include <array>
8#include <atomic>
8#include "common/bit_field.h" 9#include "common/bit_field.h"
9#include "common/common_types.h" 10#include "common/common_types.h"
10#include "core/frontend/input.h" 11#include "core/frontend/input.h"
@@ -32,31 +33,39 @@ public:
32 // When the controller is requesting an update for the shared memory 33 // When the controller is requesting an update for the shared memory
33 void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override; 34 void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override;
34 35
36 // When the controller is requesting a motion update for the shared memory
37 void OnMotionUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
38 std::size_t size) override;
39
35 // Called when input devices should be loaded 40 // Called when input devices should be loaded
36 void OnLoadInputDevices() override; 41 void OnLoadInputDevices() override;
37 42
38 struct NPadType { 43 enum class NPadControllerType {
39 union { 44 None,
40 u32_le raw{}; 45 ProController,
41 46 Handheld,
42 BitField<0, 1, u32> pro_controller; 47 JoyDual,
43 BitField<1, 1, u32> handheld; 48 JoyLeft,
44 BitField<2, 1, u32> joycon_dual; 49 JoyRight,
45 BitField<3, 1, u32> joycon_left; 50 Pokeball,
46 BitField<4, 1, u32> joycon_right; 51 };
47 52
48 BitField<6, 1, u32> pokeball; // TODO(ogniK): Confirm when possible 53 enum class NpadType : u8 {
49 }; 54 ProController = 3,
55 Handheld = 4,
56 JoyconDual = 5,
57 JoyconLeft = 6,
58 JoyconRight = 7,
59 Pokeball = 9,
60 MaxNpadType = 10,
50 }; 61 };
51 static_assert(sizeof(NPadType) == 4, "NPadType is an invalid size");
52 62
53 struct Vibration { 63 enum class DeviceIndex : u8 {
54 f32 amp_low; 64 Left = 0,
55 f32 freq_low; 65 Right = 1,
56 f32 amp_high; 66 None = 2,
57 f32 freq_high; 67 MaxDeviceIndex = 3,
58 }; 68 };
59 static_assert(sizeof(Vibration) == 0x10, "Vibration is an invalid size");
60 69
61 enum class GyroscopeZeroDriftMode : u32 { 70 enum class GyroscopeZeroDriftMode : u32 {
62 Loose = 0, 71 Loose = 0,
@@ -69,7 +78,7 @@ public:
69 Horizontal = 1, 78 Horizontal = 1,
70 }; 79 };
71 80
72 enum class NPadAssignments : u32_le { 81 enum class NpadAssignments : u32 {
73 Dual = 0, 82 Dual = 0,
74 Single = 1, 83 Single = 1,
75 }; 84 };
@@ -80,15 +89,43 @@ public:
80 None = 2, 89 None = 2,
81 }; 90 };
82 91
83 enum class NPadControllerType { 92 enum class NpadCommunicationMode : u64 {
84 None, 93 Unknown0 = 0,
85 ProController, 94 Unknown1 = 1,
86 Handheld, 95 Unknown2 = 2,
87 JoyDual, 96 Unknown3 = 3,
88 JoyLeft, 97 };
89 JoyRight, 98
90 Pokeball, 99 struct DeviceHandle {
100 NpadType npad_type{};
101 u8 npad_id{};
102 DeviceIndex device_index{};
103 INSERT_PADDING_BYTES(1);
104 };
105 static_assert(sizeof(DeviceHandle) == 4, "DeviceHandle is an invalid size");
106
107 struct NpadStyleSet {
108 union {
109 u32_le raw{};
110
111 BitField<0, 1, u32> pro_controller;
112 BitField<1, 1, u32> handheld;
113 BitField<2, 1, u32> joycon_dual;
114 BitField<3, 1, u32> joycon_left;
115 BitField<4, 1, u32> joycon_right;
116
117 BitField<6, 1, u32> pokeball; // TODO(ogniK): Confirm when possible
118 };
91 }; 119 };
120 static_assert(sizeof(NpadStyleSet) == 4, "NpadStyleSet is an invalid size");
121
122 struct VibrationValue {
123 f32 amp_low{0.0f};
124 f32 freq_low{160.0f};
125 f32 amp_high{0.0f};
126 f32 freq_high{320.0f};
127 };
128 static_assert(sizeof(VibrationValue) == 0x10, "Vibration is an invalid size");
92 129
93 struct LedPattern { 130 struct LedPattern {
94 explicit LedPattern(u64 light1, u64 light2, u64 light3, u64 light4) { 131 explicit LedPattern(u64 light1, u64 light2, u64 light3, u64 light4) {
@@ -106,12 +143,12 @@ public:
106 }; 143 };
107 }; 144 };
108 145
109 void SetSupportedStyleSet(NPadType style_set); 146 void SetSupportedStyleSet(NpadStyleSet style_set);
110 NPadType GetSupportedStyleSet() const; 147 NpadStyleSet GetSupportedStyleSet() const;
111 148
112 void SetSupportedNPadIdTypes(u8* data, std::size_t length); 149 void SetSupportedNpadIdTypes(u8* data, std::size_t length);
113 void GetSupportedNpadIdTypes(u32* data, std::size_t max_length); 150 void GetSupportedNpadIdTypes(u32* data, std::size_t max_length);
114 std::size_t GetSupportedNPadIdTypesSize() const; 151 std::size_t GetSupportedNpadIdTypesSize() const;
115 152
116 void SetHoldType(NpadHoldType joy_hold_type); 153 void SetHoldType(NpadHoldType joy_hold_type);
117 NpadHoldType GetHoldType() const; 154 NpadHoldType GetHoldType() const;
@@ -119,12 +156,29 @@ public:
119 void SetNpadHandheldActivationMode(NpadHandheldActivationMode activation_mode); 156 void SetNpadHandheldActivationMode(NpadHandheldActivationMode activation_mode);
120 NpadHandheldActivationMode GetNpadHandheldActivationMode() const; 157 NpadHandheldActivationMode GetNpadHandheldActivationMode() const;
121 158
122 void SetNpadMode(u32 npad_id, NPadAssignments assignment_mode); 159 void SetNpadCommunicationMode(NpadCommunicationMode communication_mode_);
160 NpadCommunicationMode GetNpadCommunicationMode() const;
161
162 void SetNpadMode(u32 npad_id, NpadAssignments assignment_mode);
163
164 bool VibrateControllerAtIndex(std::size_t npad_index, std::size_t device_index,
165 const VibrationValue& vibration_value);
166
167 void VibrateController(const DeviceHandle& vibration_device_handle,
168 const VibrationValue& vibration_value);
169
170 void VibrateControllers(const std::vector<DeviceHandle>& vibration_device_handles,
171 const std::vector<VibrationValue>& vibration_values);
172
173 VibrationValue GetLastVibration(const DeviceHandle& vibration_device_handle) const;
174
175 void InitializeVibrationDevice(const DeviceHandle& vibration_device_handle);
176
177 void InitializeVibrationDeviceAtIndex(std::size_t npad_index, std::size_t device_index);
123 178
124 void VibrateController(const std::vector<u32>& controller_ids, 179 void SetPermitVibrationSession(bool permit_vibration_session);
125 const std::vector<Vibration>& vibrations);
126 180
127 Vibration GetLastVibration() const; 181 bool IsVibrationDeviceMounted(const DeviceHandle& vibration_device_handle) const;
128 182
129 std::shared_ptr<Kernel::ReadableEvent> GetStyleSetChangedEvent(u32 npad_id) const; 183 std::shared_ptr<Kernel::ReadableEvent> GetStyleSetChangedEvent(u32 npad_id) const;
130 void SignalStyleSetChangedEvent(u32 npad_id) const; 184 void SignalStyleSetChangedEvent(u32 npad_id) const;
@@ -134,16 +188,16 @@ public:
134 // Adds a new controller at an index with connection status. 188 // Adds a new controller at an index with connection status.
135 void UpdateControllerAt(NPadControllerType controller, std::size_t npad_index, bool connected); 189 void UpdateControllerAt(NPadControllerType controller, std::size_t npad_index, bool connected);
136 190
137 void DisconnectNPad(u32 npad_id); 191 void DisconnectNpad(u32 npad_id);
138 void DisconnectNPadAtIndex(std::size_t index); 192 void DisconnectNpadAtIndex(std::size_t index);
139 193
140 void SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode drift_mode); 194 void SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode drift_mode);
141 GyroscopeZeroDriftMode GetGyroscopeZeroDriftMode() const; 195 GyroscopeZeroDriftMode GetGyroscopeZeroDriftMode() const;
142 bool IsSixAxisSensorAtRest() const; 196 bool IsSixAxisSensorAtRest() const;
143 void SetSixAxisEnabled(bool six_axis_status); 197 void SetSixAxisEnabled(bool six_axis_status);
144 LedPattern GetLedPattern(u32 npad_id); 198 LedPattern GetLedPattern(u32 npad_id);
145 void SetVibrationEnabled(bool can_vibrate); 199 bool IsUnintendedHomeButtonInputProtectionEnabled(u32 npad_id) const;
146 bool IsVibrationEnabled() const; 200 void SetUnintendedHomeButtonInputProtectionEnabled(bool is_protection_enabled, u32 npad_id);
147 void ClearAllConnectedControllers(); 201 void ClearAllConnectedControllers();
148 void DisconnectAllConnectedControllers(); 202 void DisconnectAllConnectedControllers();
149 void ConnectAllDisconnectedControllers(); 203 void ConnectAllDisconnectedControllers();
@@ -162,6 +216,8 @@ public:
162 static Settings::ControllerType MapNPadToSettingsType(Controller_NPad::NPadControllerType type); 216 static Settings::ControllerType MapNPadToSettingsType(Controller_NPad::NPadControllerType type);
163 static std::size_t NPadIdToIndex(u32 npad_id); 217 static std::size_t NPadIdToIndex(u32 npad_id);
164 static u32 IndexToNPad(std::size_t index); 218 static u32 IndexToNPad(std::size_t index);
219 static bool IsNpadIdValid(u32 npad_id);
220 static bool IsDeviceHandleValid(const DeviceHandle& device_handle);
165 221
166private: 222private:
167 struct CommonHeader { 223 struct CommonHeader {
@@ -318,8 +374,8 @@ private:
318 }; 374 };
319 375
320 struct NPadEntry { 376 struct NPadEntry {
321 NPadType joy_styles; 377 NpadStyleSet joy_styles;
322 NPadAssignments pad_assignment; 378 NpadAssignments pad_assignment;
323 379
324 ColorReadError single_color_error; 380 ColorReadError single_color_error;
325 ControllerColor single_color; 381 ControllerColor single_color;
@@ -360,9 +416,9 @@ private:
360 bool IsControllerSupported(NPadControllerType controller) const; 416 bool IsControllerSupported(NPadControllerType controller) const;
361 void RequestPadStateUpdate(u32 npad_id); 417 void RequestPadStateUpdate(u32 npad_id);
362 418
363 u32 press_state{}; 419 std::atomic<u32> press_state{};
364 420
365 NPadType style{}; 421 NpadStyleSet style{};
366 std::array<NPadEntry, 10> shared_memory_entries{}; 422 std::array<NPadEntry, 10> shared_memory_entries{};
367 using ButtonArray = std::array< 423 using ButtonArray = std::array<
368 std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeButton::NUM_BUTTONS_HID>, 424 std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeButton::NUM_BUTTONS_HID>,
@@ -370,21 +426,30 @@ private:
370 using StickArray = std::array< 426 using StickArray = std::array<
371 std::array<std::unique_ptr<Input::AnalogDevice>, Settings::NativeAnalog::NUM_STICKS_HID>, 427 std::array<std::unique_ptr<Input::AnalogDevice>, Settings::NativeAnalog::NUM_STICKS_HID>,
372 10>; 428 10>;
429 using VibrationArray = std::array<std::array<std::unique_ptr<Input::VibrationDevice>,
430 Settings::NativeVibration::NUM_VIBRATIONS_HID>,
431 10>;
373 using MotionArray = std::array< 432 using MotionArray = std::array<
374 std::array<std::unique_ptr<Input::MotionDevice>, Settings::NativeMotion::NUM_MOTION_HID>, 433 std::array<std::unique_ptr<Input::MotionDevice>, Settings::NativeMotion::NUM_MOTIONS_HID>,
375 10>; 434 10>;
376 ButtonArray buttons; 435 ButtonArray buttons;
377 StickArray sticks; 436 StickArray sticks;
437 VibrationArray vibrations;
378 MotionArray motions; 438 MotionArray motions;
379 std::vector<u32> supported_npad_id_types{}; 439 std::vector<u32> supported_npad_id_types{};
380 NpadHoldType hold_type{NpadHoldType::Vertical}; 440 NpadHoldType hold_type{NpadHoldType::Vertical};
381 NpadHandheldActivationMode handheld_activation_mode{NpadHandheldActivationMode::Dual}; 441 NpadHandheldActivationMode handheld_activation_mode{NpadHandheldActivationMode::Dual};
442 // NpadCommunicationMode is unknown, default value is 1
443 NpadCommunicationMode communication_mode{NpadCommunicationMode::Unknown1};
382 // Each controller should have their own styleset changed event 444 // Each controller should have their own styleset changed event
383 std::array<Kernel::EventPair, 10> styleset_changed_events; 445 std::array<Kernel::EventPair, 10> styleset_changed_events;
384 Vibration last_processed_vibration{}; 446 std::array<std::array<std::chrono::steady_clock::time_point, 2>, 10> last_vibration_timepoints;
447 std::array<std::array<VibrationValue, 2>, 10> latest_vibration_values{};
448 bool permit_vibration_session_enabled{false};
449 std::array<std::array<bool, 2>, 10> vibration_devices_mounted{};
385 std::array<ControllerHolder, 10> connected_controllers{}; 450 std::array<ControllerHolder, 10> connected_controllers{};
451 std::array<bool, 10> unintended_home_button_input_protection{};
386 GyroscopeZeroDriftMode gyroscope_zero_drift_mode{GyroscopeZeroDriftMode::Standard}; 452 GyroscopeZeroDriftMode gyroscope_zero_drift_mode{GyroscopeZeroDriftMode::Standard};
387 bool can_controllers_vibrate{true};
388 bool sixaxis_sensors_enabled{true}; 453 bool sixaxis_sensors_enabled{true};
389 bool sixaxis_at_rest{true}; 454 bool sixaxis_at_rest{true};
390 std::array<ControllerPad, 10> npad_pad_states{}; 455 std::array<ControllerPad, 10> npad_pad_states{};
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 395e83b3f..8d95f74e6 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -40,11 +40,12 @@ namespace Service::HID {
40// Updating period for each HID device. 40// Updating period for each HID device.
41// HID is polled every 15ms, this value was derived from 41// HID is polled every 15ms, this value was derived from
42// https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering#joy-con-status-data-packet 42// https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering#joy-con-status-data-packet
43constexpr auto pad_update_ns = std::chrono::nanoseconds{1000 * 1000}; // (1ms, 1000Hz) 43constexpr auto pad_update_ns = std::chrono::nanoseconds{1000 * 1000}; // (1ms, 1000Hz)
44constexpr auto motion_update_ns = std::chrono::nanoseconds{15 * 1000 * 1000}; // (15ms, 66.666Hz)
44constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000; 45constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000;
45 46
46IAppletResource::IAppletResource(Core::System& system) 47IAppletResource::IAppletResource(Core::System& system_)
47 : ServiceFramework("IAppletResource"), system(system) { 48 : ServiceFramework{system_, "IAppletResource"} {
48 static const FunctionInfo functions[] = { 49 static const FunctionInfo functions[] = {
49 {0, &IAppletResource::GetSharedMemoryHandle, "GetSharedMemoryHandle"}, 50 {0, &IAppletResource::GetSharedMemoryHandle, "GetSharedMemoryHandle"},
50 }; 51 };
@@ -77,12 +78,18 @@ IAppletResource::IAppletResource(Core::System& system)
77 pad_update_event = Core::Timing::CreateEvent( 78 pad_update_event = Core::Timing::CreateEvent(
78 "HID::UpdatePadCallback", 79 "HID::UpdatePadCallback",
79 [this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { 80 [this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
81 const auto guard = LockService();
80 UpdateControllers(user_data, ns_late); 82 UpdateControllers(user_data, ns_late);
81 }); 83 });
82 84 motion_update_event = Core::Timing::CreateEvent(
83 // TODO(shinyquagsire23): Other update callbacks? (accel, gyro?) 85 "HID::MotionPadCallback",
86 [this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
87 const auto guard = LockService();
88 UpdateMotion(user_data, ns_late);
89 });
84 90
85 system.CoreTiming().ScheduleEvent(pad_update_ns, pad_update_event); 91 system.CoreTiming().ScheduleEvent(pad_update_ns, pad_update_event);
92 system.CoreTiming().ScheduleEvent(motion_update_ns, motion_update_event);
86 93
87 ReloadInputDevices(); 94 ReloadInputDevices();
88} 95}
@@ -122,22 +129,50 @@ void IAppletResource::UpdateControllers(std::uintptr_t user_data,
122 core_timing.ScheduleEvent(pad_update_ns - ns_late, pad_update_event); 129 core_timing.ScheduleEvent(pad_update_ns - ns_late, pad_update_event);
123} 130}
124 131
132void IAppletResource::UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
133 auto& core_timing = system.CoreTiming();
134
135 for (const auto& controller : controllers) {
136 controller->OnMotionUpdate(core_timing, shared_mem->GetPointer(), SHARED_MEMORY_SIZE);
137 }
138
139 core_timing.ScheduleEvent(motion_update_ns - ns_late, motion_update_event);
140}
141
125class IActiveVibrationDeviceList final : public ServiceFramework<IActiveVibrationDeviceList> { 142class IActiveVibrationDeviceList final : public ServiceFramework<IActiveVibrationDeviceList> {
126public: 143public:
127 IActiveVibrationDeviceList() : ServiceFramework("IActiveVibrationDeviceList") { 144 explicit IActiveVibrationDeviceList(Core::System& system_,
145 std::shared_ptr<IAppletResource> applet_resource_)
146 : ServiceFramework{system_, "IActiveVibrationDeviceList"},
147 applet_resource(applet_resource_) {
148 // clang-format off
128 static const FunctionInfo functions[] = { 149 static const FunctionInfo functions[] = {
129 {0, &IActiveVibrationDeviceList::ActivateVibrationDevice, "ActivateVibrationDevice"}, 150 {0, &IActiveVibrationDeviceList::InitializeVibrationDevice, "InitializeVibrationDevice"},
130 }; 151 };
152 // clang-format on
153
131 RegisterHandlers(functions); 154 RegisterHandlers(functions);
132 } 155 }
133 156
134private: 157private:
135 void ActivateVibrationDevice(Kernel::HLERequestContext& ctx) { 158 void InitializeVibrationDevice(Kernel::HLERequestContext& ctx) {
136 LOG_WARNING(Service_HID, "(STUBBED) called"); 159 IPC::RequestParser rp{ctx};
160 const auto vibration_device_handle{rp.PopRaw<Controller_NPad::DeviceHandle>()};
161
162 if (applet_resource != nullptr) {
163 applet_resource->GetController<Controller_NPad>(HidController::NPad)
164 .InitializeVibrationDevice(vibration_device_handle);
165 }
166
167 LOG_DEBUG(Service_HID, "called, npad_type={}, npad_id={}, device_index={}",
168 vibration_device_handle.npad_type, vibration_device_handle.npad_id,
169 vibration_device_handle.device_index);
137 170
138 IPC::ResponseBuilder rb{ctx, 2}; 171 IPC::ResponseBuilder rb{ctx, 2};
139 rb.Push(RESULT_SUCCESS); 172 rb.Push(RESULT_SUCCESS);
140 } 173 }
174
175 std::shared_ptr<IAppletResource> applet_resource;
141}; 176};
142 177
143std::shared_ptr<IAppletResource> Hid::GetAppletResource() { 178std::shared_ptr<IAppletResource> Hid::GetAppletResource() {
@@ -148,7 +183,7 @@ std::shared_ptr<IAppletResource> Hid::GetAppletResource() {
148 return applet_resource; 183 return applet_resource;
149} 184}
150 185
151Hid::Hid(Core::System& system) : ServiceFramework("hid"), system(system) { 186Hid::Hid(Core::System& system_) : ServiceFramework{system_, "hid"} {
152 // clang-format off 187 // clang-format off
153 static const FunctionInfo functions[] = { 188 static const FunctionInfo functions[] = {
154 {0, &Hid::CreateAppletResource, "CreateAppletResource"}, 189 {0, &Hid::CreateAppletResource, "CreateAppletResource"},
@@ -173,7 +208,7 @@ Hid::Hid(Core::System& system) : ServiceFramework("hid"), system(system) {
173 {66, &Hid::StartSixAxisSensor, "StartSixAxisSensor"}, 208 {66, &Hid::StartSixAxisSensor, "StartSixAxisSensor"},
174 {67, &Hid::StopSixAxisSensor, "StopSixAxisSensor"}, 209 {67, &Hid::StopSixAxisSensor, "StopSixAxisSensor"},
175 {68, nullptr, "IsSixAxisSensorFusionEnabled"}, 210 {68, nullptr, "IsSixAxisSensorFusionEnabled"},
176 {69, nullptr, "EnableSixAxisSensorFusion"}, 211 {69, &Hid::EnableSixAxisSensorFusion, "EnableSixAxisSensorFusion"},
177 {70, nullptr, "SetSixAxisSensorFusionParameters"}, 212 {70, nullptr, "SetSixAxisSensorFusionParameters"},
178 {71, nullptr, "GetSixAxisSensorFusionParameters"}, 213 {71, nullptr, "GetSixAxisSensorFusionParameters"},
179 {72, nullptr, "ResetSixAxisSensorFusionParameters"}, 214 {72, nullptr, "ResetSixAxisSensorFusionParameters"},
@@ -209,8 +244,8 @@ Hid::Hid(Core::System& system) : ServiceFramework("hid"), system(system) {
209 {128, &Hid::SetNpadHandheldActivationMode, "SetNpadHandheldActivationMode"}, 244 {128, &Hid::SetNpadHandheldActivationMode, "SetNpadHandheldActivationMode"},
210 {129, &Hid::GetNpadHandheldActivationMode, "GetNpadHandheldActivationMode"}, 245 {129, &Hid::GetNpadHandheldActivationMode, "GetNpadHandheldActivationMode"},
211 {130, &Hid::SwapNpadAssignment, "SwapNpadAssignment"}, 246 {130, &Hid::SwapNpadAssignment, "SwapNpadAssignment"},
212 {131, nullptr, "IsUnintendedHomeButtonInputProtectionEnabled"}, 247 {131, &Hid::IsUnintendedHomeButtonInputProtectionEnabled, "IsUnintendedHomeButtonInputProtectionEnabled"},
213 {132, nullptr, "EnableUnintendedHomeButtonInputProtection"}, 248 {132, &Hid::EnableUnintendedHomeButtonInputProtection, "EnableUnintendedHomeButtonInputProtection"},
214 {133, nullptr, "SetNpadJoyAssignmentModeSingleWithDestination"}, 249 {133, nullptr, "SetNpadJoyAssignmentModeSingleWithDestination"},
215 {134, nullptr, "SetNpadAnalogStickUseCenterClamp"}, 250 {134, nullptr, "SetNpadAnalogStickUseCenterClamp"},
216 {135, nullptr, "SetNpadCaptureButtonAssignment"}, 251 {135, nullptr, "SetNpadCaptureButtonAssignment"},
@@ -226,7 +261,7 @@ Hid::Hid(Core::System& system) : ServiceFramework("hid"), system(system) {
226 {208, nullptr, "GetActualVibrationGcErmCommand"}, 261 {208, nullptr, "GetActualVibrationGcErmCommand"},
227 {209, &Hid::BeginPermitVibrationSession, "BeginPermitVibrationSession"}, 262 {209, &Hid::BeginPermitVibrationSession, "BeginPermitVibrationSession"},
228 {210, &Hid::EndPermitVibrationSession, "EndPermitVibrationSession"}, 263 {210, &Hid::EndPermitVibrationSession, "EndPermitVibrationSession"},
229 {211, nullptr, "IsVibrationDeviceMounted"}, 264 {211, &Hid::IsVibrationDeviceMounted, "IsVibrationDeviceMounted"},
230 {300, &Hid::ActivateConsoleSixAxisSensor, "ActivateConsoleSixAxisSensor"}, 265 {300, &Hid::ActivateConsoleSixAxisSensor, "ActivateConsoleSixAxisSensor"},
231 {301, &Hid::StartConsoleSixAxisSensor, "StartConsoleSixAxisSensor"}, 266 {301, &Hid::StartConsoleSixAxisSensor, "StartConsoleSixAxisSensor"},
232 {302, &Hid::StopConsoleSixAxisSensor, "StopConsoleSixAxisSensor"}, 267 {302, &Hid::StopConsoleSixAxisSensor, "StopConsoleSixAxisSensor"},
@@ -245,7 +280,7 @@ Hid::Hid(Core::System& system) : ServiceFramework("hid"), system(system) {
245 {404, nullptr, "HasLeftRightBattery"}, 280 {404, nullptr, "HasLeftRightBattery"},
246 {405, nullptr, "GetNpadInterfaceType"}, 281 {405, nullptr, "GetNpadInterfaceType"},
247 {406, nullptr, "GetNpadLeftRightInterfaceType"}, 282 {406, nullptr, "GetNpadLeftRightInterfaceType"},
248 {407, nullptr, "GetNpadOfHighestBatteryLevelForJoyLeft"}, 283 {407, nullptr, "GetNpadOfHighestBatteryLevel"},
249 {408, nullptr, "GetNpadOfHighestBatteryLevelForJoyRight"}, 284 {408, nullptr, "GetNpadOfHighestBatteryLevelForJoyRight"},
250 {500, nullptr, "GetPalmaConnectionHandle"}, 285 {500, nullptr, "GetPalmaConnectionHandle"},
251 {501, nullptr, "InitializePalma"}, 286 {501, nullptr, "InitializePalma"},
@@ -277,8 +312,8 @@ Hid::Hid(Core::System& system) : ServiceFramework("hid"), system(system) {
277 {527, nullptr, "EnablePalmaBoostMode"}, 312 {527, nullptr, "EnablePalmaBoostMode"},
278 {528, nullptr, "GetPalmaBluetoothAddress"}, 313 {528, nullptr, "GetPalmaBluetoothAddress"},
279 {529, nullptr, "SetDisallowedPalmaConnection"}, 314 {529, nullptr, "SetDisallowedPalmaConnection"},
280 {1000, nullptr, "SetNpadCommunicationMode"}, 315 {1000, &Hid::SetNpadCommunicationMode, "SetNpadCommunicationMode"},
281 {1001, nullptr, "GetNpadCommunicationMode"}, 316 {1001, &Hid::GetNpadCommunicationMode, "GetNpadCommunicationMode"},
282 {1002, nullptr, "SetTouchScreenConfiguration"}, 317 {1002, nullptr, "SetTouchScreenConfiguration"},
283 {1003, nullptr, "IsFirmwareUpdateNeededForNotification"}, 318 {1003, nullptr, "IsFirmwareUpdateNeededForNotification"},
284 {2000, nullptr, "ActivateDigitizer"}, 319 {2000, nullptr, "ActivateDigitizer"},
@@ -305,154 +340,195 @@ void Hid::CreateAppletResource(Kernel::HLERequestContext& ctx) {
305 rb.PushIpcInterface<IAppletResource>(applet_resource); 340 rb.PushIpcInterface<IAppletResource>(applet_resource);
306} 341}
307 342
308void Hid::ActivateXpad(Kernel::HLERequestContext& ctx) { 343void Hid::ActivateDebugPad(Kernel::HLERequestContext& ctx) {
309 IPC::RequestParser rp{ctx}; 344 IPC::RequestParser rp{ctx};
310 const auto basic_xpad_id{rp.Pop<u32>()};
311 const auto applet_resource_user_id{rp.Pop<u64>()}; 345 const auto applet_resource_user_id{rp.Pop<u64>()};
312 346
313 LOG_DEBUG(Service_HID, "called, basic_xpad_id={}, applet_resource_user_id={}", basic_xpad_id, 347 applet_resource->ActivateController(HidController::DebugPad);
314 applet_resource_user_id); 348
349 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
315 350
316 applet_resource->ActivateController(HidController::XPad);
317 IPC::ResponseBuilder rb{ctx, 2}; 351 IPC::ResponseBuilder rb{ctx, 2};
318 rb.Push(RESULT_SUCCESS); 352 rb.Push(RESULT_SUCCESS);
319} 353}
320 354
321void Hid::GetXpadIDs(Kernel::HLERequestContext& ctx) { 355void Hid::ActivateTouchScreen(Kernel::HLERequestContext& ctx) {
322 IPC::RequestParser rp{ctx}; 356 IPC::RequestParser rp{ctx};
323 const auto applet_resource_user_id{rp.Pop<u64>()}; 357 const auto applet_resource_user_id{rp.Pop<u64>()};
324 358
325 LOG_DEBUG(Service_HID, "(STUBBED) called, applet_resource_user_id={}", applet_resource_user_id); 359 applet_resource->ActivateController(HidController::Touchscreen);
326
327 IPC::ResponseBuilder rb{ctx, 3};
328 rb.Push(RESULT_SUCCESS);
329 rb.Push(0);
330}
331 360
332void Hid::ActivateSixAxisSensor(Kernel::HLERequestContext& ctx) { 361 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
333 IPC::RequestParser rp{ctx};
334 const auto handle{rp.Pop<u32>()};
335 const auto applet_resource_user_id{rp.Pop<u64>()};
336 applet_resource->GetController<Controller_NPad>(HidController::NPad).SetSixAxisEnabled(true);
337 LOG_DEBUG(Service_HID, "called, handle={}, applet_resource_user_id={}", handle,
338 applet_resource_user_id);
339 362
340 IPC::ResponseBuilder rb{ctx, 2}; 363 IPC::ResponseBuilder rb{ctx, 2};
341 rb.Push(RESULT_SUCCESS); 364 rb.Push(RESULT_SUCCESS);
342} 365}
343 366
344void Hid::DeactivateSixAxisSensor(Kernel::HLERequestContext& ctx) { 367void Hid::ActivateMouse(Kernel::HLERequestContext& ctx) {
345 IPC::RequestParser rp{ctx}; 368 IPC::RequestParser rp{ctx};
346 const auto handle{rp.Pop<u32>()};
347 const auto applet_resource_user_id{rp.Pop<u64>()}; 369 const auto applet_resource_user_id{rp.Pop<u64>()};
348 applet_resource->GetController<Controller_NPad>(HidController::NPad).SetSixAxisEnabled(false);
349 370
350 LOG_DEBUG(Service_HID, "called, handle={}, applet_resource_user_id={}", handle, 371 applet_resource->ActivateController(HidController::Mouse);
351 applet_resource_user_id); 372
373 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
352 374
353 IPC::ResponseBuilder rb{ctx, 2}; 375 IPC::ResponseBuilder rb{ctx, 2};
354 rb.Push(RESULT_SUCCESS); 376 rb.Push(RESULT_SUCCESS);
355} 377}
356 378
357void Hid::ActivateDebugPad(Kernel::HLERequestContext& ctx) { 379void Hid::ActivateKeyboard(Kernel::HLERequestContext& ctx) {
358 IPC::RequestParser rp{ctx}; 380 IPC::RequestParser rp{ctx};
359 const auto applet_resource_user_id{rp.Pop<u64>()}; 381 const auto applet_resource_user_id{rp.Pop<u64>()};
360 382
383 applet_resource->ActivateController(HidController::Keyboard);
384
361 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); 385 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
362 386
363 applet_resource->ActivateController(HidController::DebugPad);
364 IPC::ResponseBuilder rb{ctx, 2}; 387 IPC::ResponseBuilder rb{ctx, 2};
365 rb.Push(RESULT_SUCCESS); 388 rb.Push(RESULT_SUCCESS);
366} 389}
367 390
368void Hid::ActivateTouchScreen(Kernel::HLERequestContext& ctx) { 391void Hid::SendKeyboardLockKeyEvent(Kernel::HLERequestContext& ctx) {
369 IPC::RequestParser rp{ctx}; 392 IPC::RequestParser rp{ctx};
370 const auto applet_resource_user_id{rp.Pop<u64>()}; 393 const auto flags{rp.Pop<u32>()};
371 394
372 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); 395 LOG_WARNING(Service_HID, "(STUBBED) called. flags={}", flags);
373 396
374 applet_resource->ActivateController(HidController::Touchscreen);
375 IPC::ResponseBuilder rb{ctx, 2}; 397 IPC::ResponseBuilder rb{ctx, 2};
376 rb.Push(RESULT_SUCCESS); 398 rb.Push(RESULT_SUCCESS);
377} 399}
378 400
379void Hid::ActivateMouse(Kernel::HLERequestContext& ctx) { 401void Hid::ActivateXpad(Kernel::HLERequestContext& ctx) {
380 IPC::RequestParser rp{ctx}; 402 IPC::RequestParser rp{ctx};
381 const auto applet_resource_user_id{rp.Pop<u64>()}; 403 struct Parameters {
404 u32 basic_xpad_id{};
405 INSERT_PADDING_WORDS(1);
406 u64 applet_resource_user_id{};
407 };
382 408
383 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); 409 const auto parameters{rp.PopRaw<Parameters>()};
410
411 applet_resource->ActivateController(HidController::XPad);
412
413 LOG_DEBUG(Service_HID, "called, basic_xpad_id={}, applet_resource_user_id={}",
414 parameters.basic_xpad_id, parameters.applet_resource_user_id);
384 415
385 applet_resource->ActivateController(HidController::Mouse);
386 IPC::ResponseBuilder rb{ctx, 2}; 416 IPC::ResponseBuilder rb{ctx, 2};
387 rb.Push(RESULT_SUCCESS); 417 rb.Push(RESULT_SUCCESS);
388} 418}
389 419
390void Hid::ActivateKeyboard(Kernel::HLERequestContext& ctx) { 420void Hid::GetXpadIDs(Kernel::HLERequestContext& ctx) {
391 IPC::RequestParser rp{ctx}; 421 IPC::RequestParser rp{ctx};
392 const auto applet_resource_user_id{rp.Pop<u64>()}; 422 const auto applet_resource_user_id{rp.Pop<u64>()};
393 423
394 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); 424 LOG_DEBUG(Service_HID, "(STUBBED) called, applet_resource_user_id={}", applet_resource_user_id);
395 425
396 applet_resource->ActivateController(HidController::Keyboard); 426 IPC::ResponseBuilder rb{ctx, 3};
397 IPC::ResponseBuilder rb{ctx, 2};
398 rb.Push(RESULT_SUCCESS); 427 rb.Push(RESULT_SUCCESS);
428 rb.Push(0);
399} 429}
400 430
401void Hid::SendKeyboardLockKeyEvent(Kernel::HLERequestContext& ctx) { 431void Hid::ActivateSixAxisSensor(Kernel::HLERequestContext& ctx) {
402 IPC::RequestParser rp{ctx}; 432 IPC::RequestParser rp{ctx};
403 const auto flags{rp.Pop<u32>()}; 433 struct Parameters {
404 LOG_WARNING(Service_HID, "(STUBBED) called. flags={}", flags); 434 Controller_NPad::DeviceHandle sixaxis_handle{};
435 INSERT_PADDING_WORDS(1);
436 u64 applet_resource_user_id{};
437 };
438
439 const auto parameters{rp.PopRaw<Parameters>()};
440
441 applet_resource->GetController<Controller_NPad>(HidController::NPad).SetSixAxisEnabled(true);
442
443 LOG_DEBUG(Service_HID,
444 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
445 parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
446 parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
405 447
406 IPC::ResponseBuilder rb{ctx, 2}; 448 IPC::ResponseBuilder rb{ctx, 2};
407 rb.Push(RESULT_SUCCESS); 449 rb.Push(RESULT_SUCCESS);
408} 450}
409 451
410void Hid::ActivateGesture(Kernel::HLERequestContext& ctx) { 452void Hid::DeactivateSixAxisSensor(Kernel::HLERequestContext& ctx) {
411 IPC::RequestParser rp{ctx}; 453 IPC::RequestParser rp{ctx};
412 const auto unknown{rp.Pop<u32>()}; 454 struct Parameters {
413 const auto applet_resource_user_id{rp.Pop<u64>()}; 455 Controller_NPad::DeviceHandle sixaxis_handle{};
456 INSERT_PADDING_WORDS(1);
457 u64 applet_resource_user_id{};
458 };
414 459
415 LOG_DEBUG(Service_HID, "called, unknown={}, applet_resource_user_id={}", unknown, 460 const auto parameters{rp.PopRaw<Parameters>()};
416 applet_resource_user_id); 461
462 applet_resource->GetController<Controller_NPad>(HidController::NPad).SetSixAxisEnabled(false);
463
464 LOG_DEBUG(Service_HID,
465 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
466 parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
467 parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
417 468
418 applet_resource->ActivateController(HidController::Gesture);
419 IPC::ResponseBuilder rb{ctx, 2}; 469 IPC::ResponseBuilder rb{ctx, 2};
420 rb.Push(RESULT_SUCCESS); 470 rb.Push(RESULT_SUCCESS);
421} 471}
422 472
423void Hid::ActivateNpadWithRevision(Kernel::HLERequestContext& ctx) { 473void Hid::StartSixAxisSensor(Kernel::HLERequestContext& ctx) {
424 // Should have no effect with how our npad sets up the data
425 IPC::RequestParser rp{ctx}; 474 IPC::RequestParser rp{ctx};
426 const auto unknown{rp.Pop<u32>()}; 475 struct Parameters {
427 const auto applet_resource_user_id{rp.Pop<u64>()}; 476 Controller_NPad::DeviceHandle sixaxis_handle{};
477 INSERT_PADDING_WORDS(1);
478 u64 applet_resource_user_id{};
479 };
428 480
429 LOG_DEBUG(Service_HID, "called, unknown={}, applet_resource_user_id={}", unknown, 481 const auto parameters{rp.PopRaw<Parameters>()};
430 applet_resource_user_id); 482
483 applet_resource->GetController<Controller_NPad>(HidController::NPad).SetSixAxisEnabled(true);
484
485 LOG_DEBUG(Service_HID,
486 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
487 parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
488 parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
431 489
432 applet_resource->ActivateController(HidController::NPad);
433 IPC::ResponseBuilder rb{ctx, 2}; 490 IPC::ResponseBuilder rb{ctx, 2};
434 rb.Push(RESULT_SUCCESS); 491 rb.Push(RESULT_SUCCESS);
435} 492}
436 493
437void Hid::StartSixAxisSensor(Kernel::HLERequestContext& ctx) { 494void Hid::StopSixAxisSensor(Kernel::HLERequestContext& ctx) {
438 IPC::RequestParser rp{ctx}; 495 IPC::RequestParser rp{ctx};
439 const auto handle{rp.Pop<u32>()}; 496 struct Parameters {
440 const auto applet_resource_user_id{rp.Pop<u64>()}; 497 Controller_NPad::DeviceHandle sixaxis_handle{};
498 INSERT_PADDING_WORDS(1);
499 u64 applet_resource_user_id{};
500 };
441 501
442 LOG_WARNING(Service_HID, "(STUBBED) called, handle={}, applet_resource_user_id={}", handle, 502 const auto parameters{rp.PopRaw<Parameters>()};
443 applet_resource_user_id); 503
504 applet_resource->GetController<Controller_NPad>(HidController::NPad).SetSixAxisEnabled(false);
505
506 LOG_DEBUG(Service_HID,
507 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
508 parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
509 parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
444 510
445 IPC::ResponseBuilder rb{ctx, 2}; 511 IPC::ResponseBuilder rb{ctx, 2};
446 rb.Push(RESULT_SUCCESS); 512 rb.Push(RESULT_SUCCESS);
447} 513}
448 514
449void Hid::StopSixAxisSensor(Kernel::HLERequestContext& ctx) { 515void Hid::EnableSixAxisSensorFusion(Kernel::HLERequestContext& ctx) {
450 IPC::RequestParser rp{ctx}; 516 IPC::RequestParser rp{ctx};
451 const auto handle{rp.Pop<u32>()}; 517 struct Parameters {
452 const auto applet_resource_user_id{rp.Pop<u64>()}; 518 bool enable_sixaxis_sensor_fusion{};
519 INSERT_PADDING_BYTES(3);
520 Controller_NPad::DeviceHandle sixaxis_handle{};
521 u64 applet_resource_user_id{};
522 };
453 523
454 LOG_WARNING(Service_HID, "(STUBBED) called, handle={}, applet_resource_user_id={}", handle, 524 const auto parameters{rp.PopRaw<Parameters>()};
455 applet_resource_user_id); 525
526 LOG_WARNING(Service_HID,
527 "(STUBBED) called, enable_sixaxis_sensor_fusion={}, npad_type={}, npad_id={}, "
528 "device_index={}, applet_resource_user_id={}",
529 parameters.enable_sixaxis_sensor_fusion, parameters.sixaxis_handle.npad_type,
530 parameters.sixaxis_handle.npad_id, parameters.sixaxis_handle.device_index,
531 parameters.applet_resource_user_id);
456 532
457 IPC::ResponseBuilder rb{ctx, 2}; 533 IPC::ResponseBuilder rb{ctx, 2};
458 rb.Push(RESULT_SUCCESS); 534 rb.Push(RESULT_SUCCESS);
@@ -460,14 +536,17 @@ void Hid::StopSixAxisSensor(Kernel::HLERequestContext& ctx) {
460 536
461void Hid::SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { 537void Hid::SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) {
462 IPC::RequestParser rp{ctx}; 538 IPC::RequestParser rp{ctx};
463 const auto handle{rp.Pop<u32>()}; 539 const auto sixaxis_handle{rp.PopRaw<Controller_NPad::DeviceHandle>()};
464 const auto drift_mode{rp.Pop<u32>()}; 540 const auto drift_mode{rp.PopEnum<Controller_NPad::GyroscopeZeroDriftMode>()};
465 const auto applet_resource_user_id{rp.Pop<u64>()}; 541 const auto applet_resource_user_id{rp.Pop<u64>()};
466 542
467 applet_resource->GetController<Controller_NPad>(HidController::NPad) 543 applet_resource->GetController<Controller_NPad>(HidController::NPad)
468 .SetGyroscopeZeroDriftMode(Controller_NPad::GyroscopeZeroDriftMode{drift_mode}); 544 .SetGyroscopeZeroDriftMode(drift_mode);
469 545
470 LOG_DEBUG(Service_HID, "called, handle={}, drift_mode={}, applet_resource_user_id={}", handle, 546 LOG_DEBUG(Service_HID,
547 "called, npad_type={}, npad_id={}, device_index={}, drift_mode={}, "
548 "applet_resource_user_id={}",
549 sixaxis_handle.npad_type, sixaxis_handle.npad_id, sixaxis_handle.device_index,
471 drift_mode, applet_resource_user_id); 550 drift_mode, applet_resource_user_id);
472 551
473 IPC::ResponseBuilder rb{ctx, 2}; 552 IPC::ResponseBuilder rb{ctx, 2};
@@ -476,29 +555,42 @@ void Hid::SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) {
476 555
477void Hid::GetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { 556void Hid::GetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) {
478 IPC::RequestParser rp{ctx}; 557 IPC::RequestParser rp{ctx};
479 const auto handle{rp.Pop<u32>()}; 558 struct Parameters {
480 const auto applet_resource_user_id{rp.Pop<u64>()}; 559 Controller_NPad::DeviceHandle sixaxis_handle{};
560 INSERT_PADDING_WORDS(1);
561 u64 applet_resource_user_id{};
562 };
563
564 const auto parameters{rp.PopRaw<Parameters>()};
481 565
482 LOG_DEBUG(Service_HID, "called, handle={}, applet_resource_user_id={}", handle, 566 LOG_DEBUG(Service_HID,
483 applet_resource_user_id); 567 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
568 parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
569 parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
484 570
485 IPC::ResponseBuilder rb{ctx, 3}; 571 IPC::ResponseBuilder rb{ctx, 3};
486 rb.Push(RESULT_SUCCESS); 572 rb.Push(RESULT_SUCCESS);
487 rb.Push<u32>( 573 rb.PushEnum(applet_resource->GetController<Controller_NPad>(HidController::NPad)
488 static_cast<u32>(applet_resource->GetController<Controller_NPad>(HidController::NPad) 574 .GetGyroscopeZeroDriftMode());
489 .GetGyroscopeZeroDriftMode()));
490} 575}
491 576
492void Hid::ResetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { 577void Hid::ResetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) {
493 IPC::RequestParser rp{ctx}; 578 IPC::RequestParser rp{ctx};
494 const auto handle{rp.Pop<u32>()}; 579 struct Parameters {
495 const auto applet_resource_user_id{rp.Pop<u64>()}; 580 Controller_NPad::DeviceHandle sixaxis_handle{};
581 INSERT_PADDING_WORDS(1);
582 u64 applet_resource_user_id{};
583 };
584
585 const auto parameters{rp.PopRaw<Parameters>()};
496 586
497 applet_resource->GetController<Controller_NPad>(HidController::NPad) 587 applet_resource->GetController<Controller_NPad>(HidController::NPad)
498 .SetGyroscopeZeroDriftMode(Controller_NPad::GyroscopeZeroDriftMode::Standard); 588 .SetGyroscopeZeroDriftMode(Controller_NPad::GyroscopeZeroDriftMode::Standard);
499 589
500 LOG_DEBUG(Service_HID, "called, handle={}, applet_resource_user_id={}", handle, 590 LOG_DEBUG(Service_HID,
501 applet_resource_user_id); 591 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
592 parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
593 parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
502 594
503 IPC::ResponseBuilder rb{ctx, 2}; 595 IPC::ResponseBuilder rb{ctx, 2};
504 rb.Push(RESULT_SUCCESS); 596 rb.Push(RESULT_SUCCESS);
@@ -506,11 +598,18 @@ void Hid::ResetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) {
506 598
507void Hid::IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) { 599void Hid::IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) {
508 IPC::RequestParser rp{ctx}; 600 IPC::RequestParser rp{ctx};
509 const auto handle{rp.Pop<u32>()}; 601 struct Parameters {
510 const auto applet_resource_user_id{rp.Pop<u64>()}; 602 Controller_NPad::DeviceHandle sixaxis_handle{};
603 INSERT_PADDING_WORDS(1);
604 u64 applet_resource_user_id{};
605 };
606
607 const auto parameters{rp.PopRaw<Parameters>()};
511 608
512 LOG_DEBUG(Service_HID, "called, handle={}, applet_resource_user_id={}", handle, 609 LOG_DEBUG(Service_HID,
513 applet_resource_user_id); 610 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
611 parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
612 parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
514 613
515 IPC::ResponseBuilder rb{ctx, 3}; 614 IPC::ResponseBuilder rb{ctx, 3};
516 rb.Push(RESULT_SUCCESS); 615 rb.Push(RESULT_SUCCESS);
@@ -518,15 +617,34 @@ void Hid::IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) {
518 .IsSixAxisSensorAtRest()); 617 .IsSixAxisSensorAtRest());
519} 618}
520 619
620void Hid::ActivateGesture(Kernel::HLERequestContext& ctx) {
621 IPC::RequestParser rp{ctx};
622 struct Parameters {
623 u32 unknown{};
624 INSERT_PADDING_WORDS(1);
625 u64 applet_resource_user_id{};
626 };
627
628 const auto parameters{rp.PopRaw<Parameters>()};
629
630 applet_resource->ActivateController(HidController::Gesture);
631
632 LOG_DEBUG(Service_HID, "called, unknown={}, applet_resource_user_id={}", parameters.unknown,
633 parameters.applet_resource_user_id);
634
635 IPC::ResponseBuilder rb{ctx, 2};
636 rb.Push(RESULT_SUCCESS);
637}
638
521void Hid::SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) { 639void Hid::SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) {
522 IPC::RequestParser rp{ctx}; 640 IPC::RequestParser rp{ctx};
523 const auto supported_styleset{rp.Pop<u32>()}; 641 const auto supported_styleset{rp.Pop<u32>()};
524 642
525 LOG_DEBUG(Service_HID, "called, supported_styleset={}", supported_styleset);
526
527 applet_resource->GetController<Controller_NPad>(HidController::NPad) 643 applet_resource->GetController<Controller_NPad>(HidController::NPad)
528 .SetSupportedStyleSet({supported_styleset}); 644 .SetSupportedStyleSet({supported_styleset});
529 645
646 LOG_DEBUG(Service_HID, "called, supported_styleset={}", supported_styleset);
647
530 IPC::ResponseBuilder rb{ctx, 2}; 648 IPC::ResponseBuilder rb{ctx, 2};
531 rb.Push(RESULT_SUCCESS); 649 rb.Push(RESULT_SUCCESS);
532} 650}
@@ -537,21 +655,22 @@ void Hid::GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) {
537 655
538 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); 656 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
539 657
540 auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
541
542 IPC::ResponseBuilder rb{ctx, 3}; 658 IPC::ResponseBuilder rb{ctx, 3};
543 rb.Push(RESULT_SUCCESS); 659 rb.Push(RESULT_SUCCESS);
544 rb.Push<u32>(controller.GetSupportedStyleSet().raw); 660 rb.Push(applet_resource->GetController<Controller_NPad>(HidController::NPad)
661 .GetSupportedStyleSet()
662 .raw);
545} 663}
546 664
547void Hid::SetSupportedNpadIdType(Kernel::HLERequestContext& ctx) { 665void Hid::SetSupportedNpadIdType(Kernel::HLERequestContext& ctx) {
548 IPC::RequestParser rp{ctx}; 666 IPC::RequestParser rp{ctx};
549 const auto applet_resource_user_id{rp.Pop<u64>()}; 667 const auto applet_resource_user_id{rp.Pop<u64>()};
550 668
669 applet_resource->GetController<Controller_NPad>(HidController::NPad)
670 .SetSupportedNpadIdTypes(ctx.ReadBuffer().data(), ctx.GetReadBufferSize());
671
551 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); 672 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
552 673
553 applet_resource->GetController<Controller_NPad>(HidController::NPad)
554 .SetSupportedNPadIdTypes(ctx.ReadBuffer().data(), ctx.GetReadBufferSize());
555 IPC::ResponseBuilder rb{ctx, 2}; 674 IPC::ResponseBuilder rb{ctx, 2};
556 rb.Push(RESULT_SUCCESS); 675 rb.Push(RESULT_SUCCESS);
557} 676}
@@ -560,48 +679,62 @@ void Hid::ActivateNpad(Kernel::HLERequestContext& ctx) {
560 IPC::RequestParser rp{ctx}; 679 IPC::RequestParser rp{ctx};
561 const auto applet_resource_user_id{rp.Pop<u64>()}; 680 const auto applet_resource_user_id{rp.Pop<u64>()};
562 681
682 applet_resource->ActivateController(HidController::NPad);
683
563 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); 684 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
564 685
565 IPC::ResponseBuilder rb{ctx, 2}; 686 IPC::ResponseBuilder rb{ctx, 2};
566 rb.Push(RESULT_SUCCESS); 687 rb.Push(RESULT_SUCCESS);
567 applet_resource->ActivateController(HidController::NPad);
568} 688}
569 689
570void Hid::DeactivateNpad(Kernel::HLERequestContext& ctx) { 690void Hid::DeactivateNpad(Kernel::HLERequestContext& ctx) {
571 IPC::RequestParser rp{ctx}; 691 IPC::RequestParser rp{ctx};
572 const auto applet_resource_user_id{rp.Pop<u64>()}; 692 const auto applet_resource_user_id{rp.Pop<u64>()};
573 693
694 applet_resource->DeactivateController(HidController::NPad);
695
574 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); 696 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
575 697
576 IPC::ResponseBuilder rb{ctx, 2}; 698 IPC::ResponseBuilder rb{ctx, 2};
577 rb.Push(RESULT_SUCCESS); 699 rb.Push(RESULT_SUCCESS);
578 applet_resource->DeactivateController(HidController::NPad);
579} 700}
580 701
581void Hid::AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) { 702void Hid::AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) {
582 IPC::RequestParser rp{ctx}; 703 IPC::RequestParser rp{ctx};
583 const auto npad_id{rp.Pop<u32>()}; 704 struct Parameters {
584 const auto applet_resource_user_id{rp.Pop<u64>()}; 705 u32 npad_id{};
585 const auto unknown{rp.Pop<u64>()}; 706 INSERT_PADDING_WORDS(1);
707 u64 applet_resource_user_id{};
708 u64 unknown{};
709 };
586 710
587 LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}, unknown={}", npad_id, 711 const auto parameters{rp.PopRaw<Parameters>()};
588 applet_resource_user_id, unknown); 712
713 LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}, unknown={}",
714 parameters.npad_id, parameters.applet_resource_user_id, parameters.unknown);
589 715
590 IPC::ResponseBuilder rb{ctx, 2, 1}; 716 IPC::ResponseBuilder rb{ctx, 2, 1};
591 rb.Push(RESULT_SUCCESS); 717 rb.Push(RESULT_SUCCESS);
592 rb.PushCopyObjects(applet_resource->GetController<Controller_NPad>(HidController::NPad) 718 rb.PushCopyObjects(applet_resource->GetController<Controller_NPad>(HidController::NPad)
593 .GetStyleSetChangedEvent(npad_id)); 719 .GetStyleSetChangedEvent(parameters.npad_id));
594} 720}
595 721
596void Hid::DisconnectNpad(Kernel::HLERequestContext& ctx) { 722void Hid::DisconnectNpad(Kernel::HLERequestContext& ctx) {
597 IPC::RequestParser rp{ctx}; 723 IPC::RequestParser rp{ctx};
598 const auto npad_id{rp.Pop<u32>()}; 724 struct Parameters {
599 const auto applet_resource_user_id{rp.Pop<u64>()}; 725 u32 npad_id{};
726 INSERT_PADDING_WORDS(1);
727 u64 applet_resource_user_id{};
728 };
729
730 const auto parameters{rp.PopRaw<Parameters>()};
731
732 applet_resource->GetController<Controller_NPad>(HidController::NPad)
733 .DisconnectNpad(parameters.npad_id);
600 734
601 LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", npad_id, 735 LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id,
602 applet_resource_user_id); 736 parameters.applet_resource_user_id);
603 737
604 applet_resource->GetController<Controller_NPad>(HidController::NPad).DisconnectNPad(npad_id);
605 IPC::ResponseBuilder rb{ctx, 2}; 738 IPC::ResponseBuilder rb{ctx, 2};
606 rb.Push(RESULT_SUCCESS); 739 rb.Push(RESULT_SUCCESS);
607} 740}
@@ -614,22 +747,41 @@ void Hid::GetPlayerLedPattern(Kernel::HLERequestContext& ctx) {
614 747
615 IPC::ResponseBuilder rb{ctx, 4}; 748 IPC::ResponseBuilder rb{ctx, 4};
616 rb.Push(RESULT_SUCCESS); 749 rb.Push(RESULT_SUCCESS);
617 rb.PushRaw<u64>(applet_resource->GetController<Controller_NPad>(HidController::NPad) 750 rb.Push(applet_resource->GetController<Controller_NPad>(HidController::NPad)
618 .GetLedPattern(npad_id) 751 .GetLedPattern(npad_id)
619 .raw); 752 .raw);
753}
754
755void Hid::ActivateNpadWithRevision(Kernel::HLERequestContext& ctx) {
756 // Should have no effect with how our npad sets up the data
757 IPC::RequestParser rp{ctx};
758 struct Parameters {
759 u32 unknown{};
760 INSERT_PADDING_WORDS(1);
761 u64 applet_resource_user_id{};
762 };
763
764 const auto parameters{rp.PopRaw<Parameters>()};
765
766 applet_resource->ActivateController(HidController::NPad);
767
768 LOG_DEBUG(Service_HID, "called, unknown={}, applet_resource_user_id={}", parameters.unknown,
769 parameters.applet_resource_user_id);
770
771 IPC::ResponseBuilder rb{ctx, 2};
772 rb.Push(RESULT_SUCCESS);
620} 773}
621 774
622void Hid::SetNpadJoyHoldType(Kernel::HLERequestContext& ctx) { 775void Hid::SetNpadJoyHoldType(Kernel::HLERequestContext& ctx) {
623 IPC::RequestParser rp{ctx}; 776 IPC::RequestParser rp{ctx};
624 const auto applet_resource_user_id{rp.Pop<u64>()}; 777 const auto applet_resource_user_id{rp.Pop<u64>()};
625 const auto hold_type{rp.Pop<u64>()}; 778 const auto hold_type{rp.PopEnum<Controller_NPad::NpadHoldType>()};
779
780 applet_resource->GetController<Controller_NPad>(HidController::NPad).SetHoldType(hold_type);
626 781
627 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, hold_type={}", 782 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, hold_type={}",
628 applet_resource_user_id, hold_type); 783 applet_resource_user_id, hold_type);
629 784
630 auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
631 controller.SetHoldType(Controller_NPad::NpadHoldType{hold_type});
632
633 IPC::ResponseBuilder rb{ctx, 2}; 785 IPC::ResponseBuilder rb{ctx, 2};
634 rb.Push(RESULT_SUCCESS); 786 rb.Push(RESULT_SUCCESS);
635} 787}
@@ -640,22 +792,26 @@ void Hid::GetNpadJoyHoldType(Kernel::HLERequestContext& ctx) {
640 792
641 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); 793 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
642 794
643 const auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
644 IPC::ResponseBuilder rb{ctx, 4}; 795 IPC::ResponseBuilder rb{ctx, 4};
645 rb.Push(RESULT_SUCCESS); 796 rb.Push(RESULT_SUCCESS);
646 rb.Push<u64>(static_cast<u64>(controller.GetHoldType())); 797 rb.PushEnum(applet_resource->GetController<Controller_NPad>(HidController::NPad).GetHoldType());
647} 798}
648 799
649void Hid::SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx) { 800void Hid::SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx) {
650 IPC::RequestParser rp{ctx}; 801 IPC::RequestParser rp{ctx};
651 const auto npad_id{rp.Pop<u32>()}; 802 struct Parameters {
652 const auto applet_resource_user_id{rp.Pop<u64>()}; 803 u32 npad_id{};
804 INSERT_PADDING_WORDS(1);
805 u64 applet_resource_user_id{};
806 };
653 807
654 LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}", npad_id, 808 const auto parameters{rp.PopRaw<Parameters>()};
655 applet_resource_user_id); 809
810 applet_resource->GetController<Controller_NPad>(HidController::NPad)
811 .SetNpadMode(parameters.npad_id, Controller_NPad::NpadAssignments::Single);
656 812
657 auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); 813 LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}",
658 controller.SetNpadMode(npad_id, Controller_NPad::NPadAssignments::Single); 814 parameters.npad_id, parameters.applet_resource_user_id);
659 815
660 IPC::ResponseBuilder rb{ctx, 2}; 816 IPC::ResponseBuilder rb{ctx, 2};
661 rb.Push(RESULT_SUCCESS); 817 rb.Push(RESULT_SUCCESS);
@@ -664,16 +820,22 @@ void Hid::SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx
664void Hid::SetNpadJoyAssignmentModeSingle(Kernel::HLERequestContext& ctx) { 820void Hid::SetNpadJoyAssignmentModeSingle(Kernel::HLERequestContext& ctx) {
665 // TODO: Check the differences between this and SetNpadJoyAssignmentModeSingleByDefault 821 // TODO: Check the differences between this and SetNpadJoyAssignmentModeSingleByDefault
666 IPC::RequestParser rp{ctx}; 822 IPC::RequestParser rp{ctx};
667 const auto npad_id{rp.Pop<u32>()}; 823 struct Parameters {
668 const auto applet_resource_user_id{rp.Pop<u64>()}; 824 u32 npad_id{};
669 const auto npad_joy_device_type{rp.Pop<u64>()}; 825 INSERT_PADDING_WORDS(1);
826 u64 applet_resource_user_id{};
827 u64 npad_joy_device_type{};
828 };
829
830 const auto parameters{rp.PopRaw<Parameters>()};
831
832 applet_resource->GetController<Controller_NPad>(HidController::NPad)
833 .SetNpadMode(parameters.npad_id, Controller_NPad::NpadAssignments::Single);
670 834
671 LOG_WARNING(Service_HID, 835 LOG_WARNING(Service_HID,
672 "(STUBBED) called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}", 836 "(STUBBED) called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}",
673 npad_id, applet_resource_user_id, npad_joy_device_type); 837 parameters.npad_id, parameters.applet_resource_user_id,
674 838 parameters.npad_joy_device_type);
675 auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
676 controller.SetNpadMode(npad_id, Controller_NPad::NPadAssignments::Single);
677 839
678 IPC::ResponseBuilder rb{ctx, 2}; 840 IPC::ResponseBuilder rb{ctx, 2};
679 rb.Push(RESULT_SUCCESS); 841 rb.Push(RESULT_SUCCESS);
@@ -681,14 +843,19 @@ void Hid::SetNpadJoyAssignmentModeSingle(Kernel::HLERequestContext& ctx) {
681 843
682void Hid::SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) { 844void Hid::SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) {
683 IPC::RequestParser rp{ctx}; 845 IPC::RequestParser rp{ctx};
684 const auto npad_id{rp.Pop<u32>()}; 846 struct Parameters {
685 const auto applet_resource_user_id{rp.Pop<u64>()}; 847 u32 npad_id{};
848 INSERT_PADDING_WORDS(1);
849 u64 applet_resource_user_id{};
850 };
851
852 const auto parameters{rp.PopRaw<Parameters>()};
686 853
687 LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", npad_id, 854 applet_resource->GetController<Controller_NPad>(HidController::NPad)
688 applet_resource_user_id); 855 .SetNpadMode(parameters.npad_id, Controller_NPad::NpadAssignments::Dual);
689 856
690 auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); 857 LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}",
691 controller.SetNpadMode(npad_id, Controller_NPad::NPadAssignments::Dual); 858 parameters.npad_id, parameters.applet_resource_user_id);
692 859
693 IPC::ResponseBuilder rb{ctx, 2}; 860 IPC::ResponseBuilder rb{ctx, 2};
694 rb.Push(RESULT_SUCCESS); 861 rb.Push(RESULT_SUCCESS);
@@ -700,12 +867,12 @@ void Hid::MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) {
700 const auto npad_id_2{rp.Pop<u32>()}; 867 const auto npad_id_2{rp.Pop<u32>()};
701 const auto applet_resource_user_id{rp.Pop<u64>()}; 868 const auto applet_resource_user_id{rp.Pop<u64>()};
702 869
870 applet_resource->GetController<Controller_NPad>(HidController::NPad)
871 .MergeSingleJoyAsDualJoy(npad_id_1, npad_id_2);
872
703 LOG_DEBUG(Service_HID, "called, npad_id_1={}, npad_id_2={}, applet_resource_user_id={}", 873 LOG_DEBUG(Service_HID, "called, npad_id_1={}, npad_id_2={}, applet_resource_user_id={}",
704 npad_id_1, npad_id_2, applet_resource_user_id); 874 npad_id_1, npad_id_2, applet_resource_user_id);
705 875
706 auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
707 controller.MergeSingleJoyAsDualJoy(npad_id_1, npad_id_2);
708
709 IPC::ResponseBuilder rb{ctx, 2}; 876 IPC::ResponseBuilder rb{ctx, 2};
710 rb.Push(RESULT_SUCCESS); 877 rb.Push(RESULT_SUCCESS);
711} 878}
@@ -714,9 +881,9 @@ void Hid::StartLrAssignmentMode(Kernel::HLERequestContext& ctx) {
714 IPC::RequestParser rp{ctx}; 881 IPC::RequestParser rp{ctx};
715 const auto applet_resource_user_id{rp.Pop<u64>()}; 882 const auto applet_resource_user_id{rp.Pop<u64>()};
716 883
884 applet_resource->GetController<Controller_NPad>(HidController::NPad).StartLRAssignmentMode();
885
717 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); 886 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
718 auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
719 controller.StartLRAssignmentMode();
720 887
721 IPC::ResponseBuilder rb{ctx, 2}; 888 IPC::ResponseBuilder rb{ctx, 2};
722 rb.Push(RESULT_SUCCESS); 889 rb.Push(RESULT_SUCCESS);
@@ -726,9 +893,9 @@ void Hid::StopLrAssignmentMode(Kernel::HLERequestContext& ctx) {
726 IPC::RequestParser rp{ctx}; 893 IPC::RequestParser rp{ctx};
727 const auto applet_resource_user_id{rp.Pop<u64>()}; 894 const auto applet_resource_user_id{rp.Pop<u64>()};
728 895
896 applet_resource->GetController<Controller_NPad>(HidController::NPad).StopLRAssignmentMode();
897
729 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); 898 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
730 auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
731 controller.StopLRAssignmentMode();
732 899
733 IPC::ResponseBuilder rb{ctx, 2}; 900 IPC::ResponseBuilder rb{ctx, 2};
734 rb.Push(RESULT_SUCCESS); 901 rb.Push(RESULT_SUCCESS);
@@ -737,13 +904,13 @@ void Hid::StopLrAssignmentMode(Kernel::HLERequestContext& ctx) {
737void Hid::SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) { 904void Hid::SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) {
738 IPC::RequestParser rp{ctx}; 905 IPC::RequestParser rp{ctx};
739 const auto applet_resource_user_id{rp.Pop<u64>()}; 906 const auto applet_resource_user_id{rp.Pop<u64>()};
740 const auto mode{rp.Pop<u64>()}; 907 const auto activation_mode{rp.PopEnum<Controller_NPad::NpadHandheldActivationMode>()};
741
742 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, mode={}", applet_resource_user_id,
743 mode);
744 908
745 applet_resource->GetController<Controller_NPad>(HidController::NPad) 909 applet_resource->GetController<Controller_NPad>(HidController::NPad)
746 .SetNpadHandheldActivationMode(Controller_NPad::NpadHandheldActivationMode{mode}); 910 .SetNpadHandheldActivationMode(activation_mode);
911
912 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, activation_mode={}",
913 applet_resource_user_id, activation_mode);
747 914
748 IPC::ResponseBuilder rb{ctx, 2}; 915 IPC::ResponseBuilder rb{ctx, 2};
749 rb.Push(RESULT_SUCCESS); 916 rb.Push(RESULT_SUCCESS);
@@ -757,23 +924,24 @@ void Hid::GetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) {
757 924
758 IPC::ResponseBuilder rb{ctx, 4}; 925 IPC::ResponseBuilder rb{ctx, 4};
759 rb.Push(RESULT_SUCCESS); 926 rb.Push(RESULT_SUCCESS);
760 rb.Push<u64>( 927 rb.PushEnum(applet_resource->GetController<Controller_NPad>(HidController::NPad)
761 static_cast<u64>(applet_resource->GetController<Controller_NPad>(HidController::NPad) 928 .GetNpadHandheldActivationMode());
762 .GetNpadHandheldActivationMode()));
763} 929}
764 930
765void Hid::SwapNpadAssignment(Kernel::HLERequestContext& ctx) { 931void Hid::SwapNpadAssignment(Kernel::HLERequestContext& ctx) {
766 IPC::RequestParser rp{ctx}; 932 IPC::RequestParser rp{ctx};
767 const auto npad_1{rp.Pop<u32>()}; 933 const auto npad_id_1{rp.Pop<u32>()};
768 const auto npad_2{rp.Pop<u32>()}; 934 const auto npad_id_2{rp.Pop<u32>()};
769 const auto applet_resource_user_id{rp.Pop<u64>()}; 935 const auto applet_resource_user_id{rp.Pop<u64>()};
770 936
771 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, npad_1={}, npad_2={}", 937 const bool res = applet_resource->GetController<Controller_NPad>(HidController::NPad)
772 applet_resource_user_id, npad_1, npad_2); 938 .SwapNpadAssignment(npad_id_1, npad_id_2);
939
940 LOG_DEBUG(Service_HID, "called, npad_id_1={}, npad_id_2={}, applet_resource_user_id={}",
941 npad_id_1, npad_id_2, applet_resource_user_id);
773 942
774 auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
775 IPC::ResponseBuilder rb{ctx, 2}; 943 IPC::ResponseBuilder rb{ctx, 2};
776 if (controller.SwapNpadAssignment(npad_1, npad_2)) { 944 if (res) {
777 rb.Push(RESULT_SUCCESS); 945 rb.Push(RESULT_SUCCESS);
778 } else { 946 } else {
779 LOG_ERROR(Service_HID, "Npads are not connected!"); 947 LOG_ERROR(Service_HID, "Npads are not connected!");
@@ -781,61 +949,99 @@ void Hid::SwapNpadAssignment(Kernel::HLERequestContext& ctx) {
781 } 949 }
782} 950}
783 951
784void Hid::BeginPermitVibrationSession(Kernel::HLERequestContext& ctx) { 952void Hid::IsUnintendedHomeButtonInputProtectionEnabled(Kernel::HLERequestContext& ctx) {
785 IPC::RequestParser rp{ctx}; 953 IPC::RequestParser rp{ctx};
786 const auto applet_resource_user_id{rp.Pop<u64>()}; 954 struct Parameters {
787 955 u32 npad_id{};
788 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); 956 INSERT_PADDING_WORDS(1);
957 u64 applet_resource_user_id{};
958 };
789 959
790 applet_resource->GetController<Controller_NPad>(HidController::NPad).SetVibrationEnabled(true); 960 const auto parameters{rp.PopRaw<Parameters>()};
791 IPC::ResponseBuilder rb{ctx, 2};
792 rb.Push(RESULT_SUCCESS);
793}
794 961
795void Hid::EndPermitVibrationSession(Kernel::HLERequestContext& ctx) { 962 LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}",
796 LOG_DEBUG(Service_HID, "called"); 963 parameters.npad_id, parameters.applet_resource_user_id);
797 964
798 applet_resource->GetController<Controller_NPad>(HidController::NPad).SetVibrationEnabled(false); 965 IPC::ResponseBuilder rb{ctx, 3};
799 IPC::ResponseBuilder rb{ctx, 2};
800 rb.Push(RESULT_SUCCESS); 966 rb.Push(RESULT_SUCCESS);
967 rb.Push(applet_resource->GetController<Controller_NPad>(HidController::NPad)
968 .IsUnintendedHomeButtonInputProtectionEnabled(parameters.npad_id));
801} 969}
802 970
803void Hid::SendVibrationValue(Kernel::HLERequestContext& ctx) { 971void Hid::EnableUnintendedHomeButtonInputProtection(Kernel::HLERequestContext& ctx) {
804 IPC::RequestParser rp{ctx}; 972 IPC::RequestParser rp{ctx};
805 const auto controller_id{rp.Pop<u32>()}; 973 struct Parameters {
806 const auto vibration_values{rp.PopRaw<Controller_NPad::Vibration>()}; 974 bool unintended_home_button_input_protection{};
807 const auto applet_resource_user_id{rp.Pop<u64>()}; 975 INSERT_PADDING_BYTES(3);
976 u32 npad_id{};
977 u64 applet_resource_user_id{};
978 };
979
980 const auto parameters{rp.PopRaw<Parameters>()};
808 981
809 LOG_DEBUG(Service_HID, "called, controller_id={}, applet_resource_user_id={}", controller_id, 982 applet_resource->GetController<Controller_NPad>(HidController::NPad)
810 applet_resource_user_id); 983 .SetUnintendedHomeButtonInputProtectionEnabled(
984 parameters.unintended_home_button_input_protection, parameters.npad_id);
985
986 LOG_WARNING(Service_HID,
987 "(STUBBED) called, unintended_home_button_input_protection={}, npad_id={},"
988 "applet_resource_user_id={}",
989 parameters.unintended_home_button_input_protection, parameters.npad_id,
990 parameters.applet_resource_user_id);
811 991
812 IPC::ResponseBuilder rb{ctx, 2}; 992 IPC::ResponseBuilder rb{ctx, 2};
813 rb.Push(RESULT_SUCCESS); 993 rb.Push(RESULT_SUCCESS);
814
815 applet_resource->GetController<Controller_NPad>(HidController::NPad)
816 .VibrateController({controller_id}, {vibration_values});
817} 994}
818 995
819void Hid::SendVibrationValues(Kernel::HLERequestContext& ctx) { 996void Hid::GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) {
820 IPC::RequestParser rp{ctx}; 997 IPC::RequestParser rp{ctx};
821 const auto applet_resource_user_id{rp.Pop<u64>()}; 998 const auto vibration_device_handle{rp.PopRaw<Controller_NPad::DeviceHandle>()};
999
1000 VibrationDeviceInfo vibration_device_info;
1001
1002 vibration_device_info.type = VibrationDeviceType::LinearResonantActuator;
1003
1004 switch (vibration_device_handle.device_index) {
1005 case Controller_NPad::DeviceIndex::Left:
1006 vibration_device_info.position = VibrationDevicePosition::Left;
1007 break;
1008 case Controller_NPad::DeviceIndex::Right:
1009 vibration_device_info.position = VibrationDevicePosition::Right;
1010 break;
1011 case Controller_NPad::DeviceIndex::None:
1012 default:
1013 UNREACHABLE_MSG("DeviceIndex should never be None!");
1014 vibration_device_info.position = VibrationDevicePosition::None;
1015 break;
1016 }
822 1017
823 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); 1018 LOG_DEBUG(Service_HID, "called, vibration_device_type={}, vibration_device_position={}",
1019 vibration_device_info.type, vibration_device_info.position);
824 1020
825 const auto controllers = ctx.ReadBuffer(0); 1021 IPC::ResponseBuilder rb{ctx, 4};
826 const auto vibrations = ctx.ReadBuffer(1); 1022 rb.Push(RESULT_SUCCESS);
1023 rb.PushRaw(vibration_device_info);
1024}
827 1025
828 std::vector<u32> controller_list(controllers.size() / sizeof(u32)); 1026void Hid::SendVibrationValue(Kernel::HLERequestContext& ctx) {
829 std::vector<Controller_NPad::Vibration> vibration_list(vibrations.size() / 1027 IPC::RequestParser rp{ctx};
830 sizeof(Controller_NPad::Vibration)); 1028 struct Parameters {
1029 Controller_NPad::DeviceHandle vibration_device_handle{};
1030 Controller_NPad::VibrationValue vibration_value{};
1031 INSERT_PADDING_WORDS(1);
1032 u64 applet_resource_user_id{};
1033 };
831 1034
832 std::memcpy(controller_list.data(), controllers.data(), controllers.size()); 1035 const auto parameters{rp.PopRaw<Parameters>()};
833 std::memcpy(vibration_list.data(), vibrations.data(), vibrations.size());
834 std::transform(controller_list.begin(), controller_list.end(), controller_list.begin(),
835 [](u32 controller_id) { return controller_id - 3; });
836 1036
837 applet_resource->GetController<Controller_NPad>(HidController::NPad) 1037 applet_resource->GetController<Controller_NPad>(HidController::NPad)
838 .VibrateController(controller_list, vibration_list); 1038 .VibrateController(parameters.vibration_device_handle, parameters.vibration_value);
1039
1040 LOG_DEBUG(Service_HID,
1041 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
1042 parameters.vibration_device_handle.npad_type,
1043 parameters.vibration_device_handle.npad_id,
1044 parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id);
839 1045
840 IPC::ResponseBuilder rb{ctx, 2}; 1046 IPC::ResponseBuilder rb{ctx, 2};
841 rb.Push(RESULT_SUCCESS); 1047 rb.Push(RESULT_SUCCESS);
@@ -843,25 +1049,24 @@ void Hid::SendVibrationValues(Kernel::HLERequestContext& ctx) {
843 1049
844void Hid::GetActualVibrationValue(Kernel::HLERequestContext& ctx) { 1050void Hid::GetActualVibrationValue(Kernel::HLERequestContext& ctx) {
845 IPC::RequestParser rp{ctx}; 1051 IPC::RequestParser rp{ctx};
846 const auto controller_id{rp.Pop<u32>()}; 1052 struct Parameters {
847 const auto applet_resource_user_id{rp.Pop<u64>()}; 1053 Controller_NPad::DeviceHandle vibration_device_handle{};
848 1054 INSERT_PADDING_WORDS(1);
849 LOG_DEBUG(Service_HID, "called, controller_id={}, applet_resource_user_id={}", controller_id, 1055 u64 applet_resource_user_id{};
850 applet_resource_user_id); 1056 };
851 1057
852 IPC::ResponseBuilder rb{ctx, 6}; 1058 const auto parameters{rp.PopRaw<Parameters>()};
853 rb.Push(RESULT_SUCCESS);
854 rb.PushRaw<Controller_NPad::Vibration>(
855 applet_resource->GetController<Controller_NPad>(HidController::NPad).GetLastVibration());
856}
857 1059
858void Hid::GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) { 1060 LOG_DEBUG(Service_HID,
859 LOG_DEBUG(Service_HID, "called"); 1061 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
1062 parameters.vibration_device_handle.npad_type,
1063 parameters.vibration_device_handle.npad_id,
1064 parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id);
860 1065
861 IPC::ResponseBuilder rb{ctx, 4}; 1066 IPC::ResponseBuilder rb{ctx, 6};
862 rb.Push(RESULT_SUCCESS); 1067 rb.Push(RESULT_SUCCESS);
863 rb.Push<u32>(1); 1068 rb.PushRaw(applet_resource->GetController<Controller_NPad>(HidController::NPad)
864 rb.Push<u32>(0); 1069 .GetLastVibration(parameters.vibration_device_handle));
865} 1070}
866 1071
867void Hid::CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx) { 1072void Hid::CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx) {
@@ -869,13 +1074,14 @@ void Hid::CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx) {
869 1074
870 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 1075 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
871 rb.Push(RESULT_SUCCESS); 1076 rb.Push(RESULT_SUCCESS);
872 rb.PushIpcInterface<IActiveVibrationDeviceList>(); 1077 rb.PushIpcInterface<IActiveVibrationDeviceList>(system, applet_resource);
873} 1078}
874 1079
875void Hid::PermitVibration(Kernel::HLERequestContext& ctx) { 1080void Hid::PermitVibration(Kernel::HLERequestContext& ctx) {
876 IPC::RequestParser rp{ctx}; 1081 IPC::RequestParser rp{ctx};
877 const auto can_vibrate{rp.Pop<bool>()}; 1082 const auto can_vibrate{rp.Pop<bool>()};
878 Settings::values.vibration_enabled = can_vibrate; 1083
1084 Settings::values.vibration_enabled.SetValue(can_vibrate);
879 1085
880 LOG_DEBUG(Service_HID, "called, can_vibrate={}", can_vibrate); 1086 LOG_DEBUG(Service_HID, "called, can_vibrate={}", can_vibrate);
881 1087
@@ -888,7 +1094,76 @@ void Hid::IsVibrationPermitted(Kernel::HLERequestContext& ctx) {
888 1094
889 IPC::ResponseBuilder rb{ctx, 3}; 1095 IPC::ResponseBuilder rb{ctx, 3};
890 rb.Push(RESULT_SUCCESS); 1096 rb.Push(RESULT_SUCCESS);
891 rb.Push(Settings::values.vibration_enabled); 1097 rb.Push(Settings::values.vibration_enabled.GetValue());
1098}
1099
1100void Hid::SendVibrationValues(Kernel::HLERequestContext& ctx) {
1101 IPC::RequestParser rp{ctx};
1102 const auto applet_resource_user_id{rp.Pop<u64>()};
1103
1104 const auto handles = ctx.ReadBuffer(0);
1105 const auto vibrations = ctx.ReadBuffer(1);
1106
1107 std::vector<Controller_NPad::DeviceHandle> vibration_device_handles(
1108 handles.size() / sizeof(Controller_NPad::DeviceHandle));
1109 std::vector<Controller_NPad::VibrationValue> vibration_values(
1110 vibrations.size() / sizeof(Controller_NPad::VibrationValue));
1111
1112 std::memcpy(vibration_device_handles.data(), handles.data(), handles.size());
1113 std::memcpy(vibration_values.data(), vibrations.data(), vibrations.size());
1114
1115 applet_resource->GetController<Controller_NPad>(HidController::NPad)
1116 .VibrateControllers(vibration_device_handles, vibration_values);
1117
1118 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
1119
1120 IPC::ResponseBuilder rb{ctx, 2};
1121 rb.Push(RESULT_SUCCESS);
1122}
1123
1124void Hid::BeginPermitVibrationSession(Kernel::HLERequestContext& ctx) {
1125 IPC::RequestParser rp{ctx};
1126 const auto applet_resource_user_id{rp.Pop<u64>()};
1127
1128 applet_resource->GetController<Controller_NPad>(HidController::NPad)
1129 .SetPermitVibrationSession(true);
1130
1131 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
1132
1133 IPC::ResponseBuilder rb{ctx, 2};
1134 rb.Push(RESULT_SUCCESS);
1135}
1136
1137void Hid::EndPermitVibrationSession(Kernel::HLERequestContext& ctx) {
1138 applet_resource->GetController<Controller_NPad>(HidController::NPad)
1139 .SetPermitVibrationSession(false);
1140
1141 LOG_DEBUG(Service_HID, "called");
1142
1143 IPC::ResponseBuilder rb{ctx, 2};
1144 rb.Push(RESULT_SUCCESS);
1145}
1146
1147void Hid::IsVibrationDeviceMounted(Kernel::HLERequestContext& ctx) {
1148 IPC::RequestParser rp{ctx};
1149 struct Parameters {
1150 Controller_NPad::DeviceHandle vibration_device_handle{};
1151 INSERT_PADDING_WORDS(1);
1152 u64 applet_resource_user_id{};
1153 };
1154
1155 const auto parameters{rp.PopRaw<Parameters>()};
1156
1157 LOG_DEBUG(Service_HID,
1158 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
1159 parameters.vibration_device_handle.npad_type,
1160 parameters.vibration_device_handle.npad_id,
1161 parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id);
1162
1163 IPC::ResponseBuilder rb{ctx, 3};
1164 rb.Push(RESULT_SUCCESS);
1165 rb.Push(applet_resource->GetController<Controller_NPad>(HidController::NPad)
1166 .IsVibrationDeviceMounted(parameters.vibration_device_handle));
892} 1167}
893 1168
894void Hid::ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { 1169void Hid::ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {
@@ -904,11 +1179,19 @@ void Hid::ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {
904 1179
905void Hid::StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { 1180void Hid::StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {
906 IPC::RequestParser rp{ctx}; 1181 IPC::RequestParser rp{ctx};
907 const auto handle{rp.Pop<u32>()}; 1182 struct Parameters {
908 const auto applet_resource_user_id{rp.Pop<u64>()}; 1183 Controller_NPad::DeviceHandle sixaxis_handle{};
1184 INSERT_PADDING_WORDS(1);
1185 u64 applet_resource_user_id{};
1186 };
909 1187
910 LOG_WARNING(Service_HID, "(STUBBED) called, handle={}, applet_resource_user_id={}", handle, 1188 const auto parameters{rp.PopRaw<Parameters>()};
911 applet_resource_user_id); 1189
1190 LOG_WARNING(
1191 Service_HID,
1192 "(STUBBED) called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
1193 parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
1194 parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
912 1195
913 IPC::ResponseBuilder rb{ctx, 2}; 1196 IPC::ResponseBuilder rb{ctx, 2};
914 rb.Push(RESULT_SUCCESS); 1197 rb.Push(RESULT_SUCCESS);
@@ -916,11 +1199,19 @@ void Hid::StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {
916 1199
917void Hid::StopConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { 1200void Hid::StopConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {
918 IPC::RequestParser rp{ctx}; 1201 IPC::RequestParser rp{ctx};
919 const auto handle{rp.Pop<u32>()}; 1202 struct Parameters {
920 const auto applet_resource_user_id{rp.Pop<u64>()}; 1203 Controller_NPad::DeviceHandle sixaxis_handle{};
1204 INSERT_PADDING_WORDS(1);
1205 u64 applet_resource_user_id{};
1206 };
921 1207
922 LOG_WARNING(Service_HID, "(STUBBED) called, handle={}, applet_resource_user_id={}", handle, 1208 const auto parameters{rp.PopRaw<Parameters>()};
923 applet_resource_user_id); 1209
1210 LOG_WARNING(
1211 Service_HID,
1212 "(STUBBED) called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
1213 parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
1214 parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
924 1215
925 IPC::ResponseBuilder rb{ctx, 2}; 1216 IPC::ResponseBuilder rb{ctx, 2};
926 rb.Push(RESULT_SUCCESS); 1217 rb.Push(RESULT_SUCCESS);
@@ -1011,9 +1302,37 @@ void Hid::SetPalmaBoostMode(Kernel::HLERequestContext& ctx) {
1011 rb.Push(RESULT_SUCCESS); 1302 rb.Push(RESULT_SUCCESS);
1012} 1303}
1013 1304
1305void Hid::SetNpadCommunicationMode(Kernel::HLERequestContext& ctx) {
1306 IPC::RequestParser rp{ctx};
1307 const auto applet_resource_user_id{rp.Pop<u64>()};
1308 const auto communication_mode{rp.PopEnum<Controller_NPad::NpadCommunicationMode>()};
1309
1310 applet_resource->GetController<Controller_NPad>(HidController::NPad)
1311 .SetNpadCommunicationMode(communication_mode);
1312
1313 LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}, communication_mode={}",
1314 applet_resource_user_id, communication_mode);
1315
1316 IPC::ResponseBuilder rb{ctx, 2};
1317 rb.Push(RESULT_SUCCESS);
1318}
1319
1320void Hid::GetNpadCommunicationMode(Kernel::HLERequestContext& ctx) {
1321 IPC::RequestParser rp{ctx};
1322 const auto applet_resource_user_id{rp.Pop<u64>()};
1323
1324 LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}",
1325 applet_resource_user_id);
1326
1327 IPC::ResponseBuilder rb{ctx, 4};
1328 rb.Push(RESULT_SUCCESS);
1329 rb.PushEnum(applet_resource->GetController<Controller_NPad>(HidController::NPad)
1330 .GetNpadCommunicationMode());
1331}
1332
1014class HidDbg final : public ServiceFramework<HidDbg> { 1333class HidDbg final : public ServiceFramework<HidDbg> {
1015public: 1334public:
1016 explicit HidDbg() : ServiceFramework{"hid:dbg"} { 1335 explicit HidDbg(Core::System& system_) : ServiceFramework{system_, "hid:dbg"} {
1017 // clang-format off 1336 // clang-format off
1018 static const FunctionInfo functions[] = { 1337 static const FunctionInfo functions[] = {
1019 {0, nullptr, "DeactivateDebugPad"}, 1338 {0, nullptr, "DeactivateDebugPad"},
@@ -1140,7 +1459,7 @@ public:
1140 1459
1141class HidSys final : public ServiceFramework<HidSys> { 1460class HidSys final : public ServiceFramework<HidSys> {
1142public: 1461public:
1143 explicit HidSys() : ServiceFramework{"hid:sys"} { 1462 explicit HidSys(Core::System& system_) : ServiceFramework{system_, "hid:sys"} {
1144 // clang-format off 1463 // clang-format off
1145 static const FunctionInfo functions[] = { 1464 static const FunctionInfo functions[] = {
1146 {31, nullptr, "SendKeyboardLockKeyEvent"}, 1465 {31, nullptr, "SendKeyboardLockKeyEvent"},
@@ -1274,7 +1593,7 @@ public:
1274 1593
1275class HidTmp final : public ServiceFramework<HidTmp> { 1594class HidTmp final : public ServiceFramework<HidTmp> {
1276public: 1595public:
1277 explicit HidTmp() : ServiceFramework{"hid:tmp"} { 1596 explicit HidTmp(Core::System& system_) : ServiceFramework{system_, "hid:tmp"} {
1278 // clang-format off 1597 // clang-format off
1279 static const FunctionInfo functions[] = { 1598 static const FunctionInfo functions[] = {
1280 {0, nullptr, "GetConsoleSixAxisSensorCalibrationValues"}, 1599 {0, nullptr, "GetConsoleSixAxisSensorCalibrationValues"},
@@ -1287,7 +1606,7 @@ public:
1287 1606
1288class HidBus final : public ServiceFramework<HidBus> { 1607class HidBus final : public ServiceFramework<HidBus> {
1289public: 1608public:
1290 explicit HidBus() : ServiceFramework{"hidbus"} { 1609 explicit HidBus(Core::System& system_) : ServiceFramework{system_, "hidbus"} {
1291 // clang-format off 1610 // clang-format off
1292 static const FunctionInfo functions[] = { 1611 static const FunctionInfo functions[] = {
1293 {1, nullptr, "GetBusHandle"}, 1612 {1, nullptr, "GetBusHandle"},
@@ -1317,15 +1636,15 @@ void ReloadInputDevices() {
1317 1636
1318void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { 1637void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
1319 std::make_shared<Hid>(system)->InstallAsService(service_manager); 1638 std::make_shared<Hid>(system)->InstallAsService(service_manager);
1320 std::make_shared<HidBus>()->InstallAsService(service_manager); 1639 std::make_shared<HidBus>(system)->InstallAsService(service_manager);
1321 std::make_shared<HidDbg>()->InstallAsService(service_manager); 1640 std::make_shared<HidDbg>(system)->InstallAsService(service_manager);
1322 std::make_shared<HidSys>()->InstallAsService(service_manager); 1641 std::make_shared<HidSys>(system)->InstallAsService(service_manager);
1323 std::make_shared<HidTmp>()->InstallAsService(service_manager); 1642 std::make_shared<HidTmp>(system)->InstallAsService(service_manager);
1324 1643
1325 std::make_shared<IRS>(system)->InstallAsService(service_manager); 1644 std::make_shared<IRS>(system)->InstallAsService(service_manager);
1326 std::make_shared<IRS_SYS>()->InstallAsService(service_manager); 1645 std::make_shared<IRS_SYS>(system)->InstallAsService(service_manager);
1327 1646
1328 std::make_shared<XCD_SYS>()->InstallAsService(service_manager); 1647 std::make_shared<XCD_SYS>(system)->InstallAsService(service_manager);
1329} 1648}
1330 1649
1331} // namespace Service::HID 1650} // namespace Service::HID
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h
index e04aaf1e9..b87bfdde1 100644
--- a/src/core/hle/service/hid/hid.h
+++ b/src/core/hle/service/hid/hid.h
@@ -41,7 +41,7 @@ enum class HidController : std::size_t {
41 41
42class IAppletResource final : public ServiceFramework<IAppletResource> { 42class IAppletResource final : public ServiceFramework<IAppletResource> {
43public: 43public:
44 explicit IAppletResource(Core::System& system); 44 explicit IAppletResource(Core::System& system_);
45 ~IAppletResource() override; 45 ~IAppletResource() override;
46 46
47 void ActivateController(HidController controller); 47 void ActivateController(HidController controller);
@@ -65,11 +65,12 @@ private:
65 65
66 void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx); 66 void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx);
67 void UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); 67 void UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
68 void UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
68 69
69 std::shared_ptr<Kernel::SharedMemory> shared_mem; 70 std::shared_ptr<Kernel::SharedMemory> shared_mem;
70 71
71 std::shared_ptr<Core::Timing::EventType> pad_update_event; 72 std::shared_ptr<Core::Timing::EventType> pad_update_event;
72 Core::System& system; 73 std::shared_ptr<Core::Timing::EventType> motion_update_event;
73 74
74 std::array<std::unique_ptr<ControllerBase>, static_cast<size_t>(HidController::MaxControllers)> 75 std::array<std::unique_ptr<ControllerBase>, static_cast<size_t>(HidController::MaxControllers)>
75 controllers{}; 76 controllers{};
@@ -77,30 +78,30 @@ private:
77 78
78class Hid final : public ServiceFramework<Hid> { 79class Hid final : public ServiceFramework<Hid> {
79public: 80public:
80 explicit Hid(Core::System& system); 81 explicit Hid(Core::System& system_);
81 ~Hid() override; 82 ~Hid() override;
82 83
83 std::shared_ptr<IAppletResource> GetAppletResource(); 84 std::shared_ptr<IAppletResource> GetAppletResource();
84 85
85private: 86private:
86 void CreateAppletResource(Kernel::HLERequestContext& ctx); 87 void CreateAppletResource(Kernel::HLERequestContext& ctx);
87 void ActivateXpad(Kernel::HLERequestContext& ctx);
88 void GetXpadIDs(Kernel::HLERequestContext& ctx);
89 void ActivateSixAxisSensor(Kernel::HLERequestContext& ctx);
90 void DeactivateSixAxisSensor(Kernel::HLERequestContext& ctx);
91 void ActivateDebugPad(Kernel::HLERequestContext& ctx); 88 void ActivateDebugPad(Kernel::HLERequestContext& ctx);
92 void ActivateTouchScreen(Kernel::HLERequestContext& ctx); 89 void ActivateTouchScreen(Kernel::HLERequestContext& ctx);
93 void ActivateMouse(Kernel::HLERequestContext& ctx); 90 void ActivateMouse(Kernel::HLERequestContext& ctx);
94 void ActivateKeyboard(Kernel::HLERequestContext& ctx); 91 void ActivateKeyboard(Kernel::HLERequestContext& ctx);
95 void SendKeyboardLockKeyEvent(Kernel::HLERequestContext& ctx); 92 void SendKeyboardLockKeyEvent(Kernel::HLERequestContext& ctx);
96 void ActivateGesture(Kernel::HLERequestContext& ctx); 93 void ActivateXpad(Kernel::HLERequestContext& ctx);
97 void ActivateNpadWithRevision(Kernel::HLERequestContext& ctx); 94 void GetXpadIDs(Kernel::HLERequestContext& ctx);
95 void ActivateSixAxisSensor(Kernel::HLERequestContext& ctx);
96 void DeactivateSixAxisSensor(Kernel::HLERequestContext& ctx);
98 void StartSixAxisSensor(Kernel::HLERequestContext& ctx); 97 void StartSixAxisSensor(Kernel::HLERequestContext& ctx);
99 void StopSixAxisSensor(Kernel::HLERequestContext& ctx); 98 void StopSixAxisSensor(Kernel::HLERequestContext& ctx);
99 void EnableSixAxisSensorFusion(Kernel::HLERequestContext& ctx);
100 void SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx); 100 void SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx);
101 void GetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx); 101 void GetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx);
102 void ResetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx); 102 void ResetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx);
103 void IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx); 103 void IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx);
104 void ActivateGesture(Kernel::HLERequestContext& ctx);
104 void SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx); 105 void SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx);
105 void GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx); 106 void GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx);
106 void SetSupportedNpadIdType(Kernel::HLERequestContext& ctx); 107 void SetSupportedNpadIdType(Kernel::HLERequestContext& ctx);
@@ -109,6 +110,7 @@ private:
109 void AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx); 110 void AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx);
110 void DisconnectNpad(Kernel::HLERequestContext& ctx); 111 void DisconnectNpad(Kernel::HLERequestContext& ctx);
111 void GetPlayerLedPattern(Kernel::HLERequestContext& ctx); 112 void GetPlayerLedPattern(Kernel::HLERequestContext& ctx);
113 void ActivateNpadWithRevision(Kernel::HLERequestContext& ctx);
112 void SetNpadJoyHoldType(Kernel::HLERequestContext& ctx); 114 void SetNpadJoyHoldType(Kernel::HLERequestContext& ctx);
113 void GetNpadJoyHoldType(Kernel::HLERequestContext& ctx); 115 void GetNpadJoyHoldType(Kernel::HLERequestContext& ctx);
114 void SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx); 116 void SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx);
@@ -120,15 +122,18 @@ private:
120 void SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx); 122 void SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx);
121 void GetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx); 123 void GetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx);
122 void SwapNpadAssignment(Kernel::HLERequestContext& ctx); 124 void SwapNpadAssignment(Kernel::HLERequestContext& ctx);
123 void BeginPermitVibrationSession(Kernel::HLERequestContext& ctx); 125 void IsUnintendedHomeButtonInputProtectionEnabled(Kernel::HLERequestContext& ctx);
124 void EndPermitVibrationSession(Kernel::HLERequestContext& ctx); 126 void EnableUnintendedHomeButtonInputProtection(Kernel::HLERequestContext& ctx);
127 void GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx);
125 void SendVibrationValue(Kernel::HLERequestContext& ctx); 128 void SendVibrationValue(Kernel::HLERequestContext& ctx);
126 void SendVibrationValues(Kernel::HLERequestContext& ctx);
127 void GetActualVibrationValue(Kernel::HLERequestContext& ctx); 129 void GetActualVibrationValue(Kernel::HLERequestContext& ctx);
128 void GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx);
129 void CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx); 130 void CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx);
130 void PermitVibration(Kernel::HLERequestContext& ctx); 131 void PermitVibration(Kernel::HLERequestContext& ctx);
131 void IsVibrationPermitted(Kernel::HLERequestContext& ctx); 132 void IsVibrationPermitted(Kernel::HLERequestContext& ctx);
133 void SendVibrationValues(Kernel::HLERequestContext& ctx);
134 void BeginPermitVibrationSession(Kernel::HLERequestContext& ctx);
135 void EndPermitVibrationSession(Kernel::HLERequestContext& ctx);
136 void IsVibrationDeviceMounted(Kernel::HLERequestContext& ctx);
132 void ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx); 137 void ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx);
133 void StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx); 138 void StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx);
134 void StopConsoleSixAxisSensor(Kernel::HLERequestContext& ctx); 139 void StopConsoleSixAxisSensor(Kernel::HLERequestContext& ctx);
@@ -140,9 +145,26 @@ private:
140 void ResetSevenSixAxisSensorTimestamp(Kernel::HLERequestContext& ctx); 145 void ResetSevenSixAxisSensorTimestamp(Kernel::HLERequestContext& ctx);
141 void SetIsPalmaAllConnectable(Kernel::HLERequestContext& ctx); 146 void SetIsPalmaAllConnectable(Kernel::HLERequestContext& ctx);
142 void SetPalmaBoostMode(Kernel::HLERequestContext& ctx); 147 void SetPalmaBoostMode(Kernel::HLERequestContext& ctx);
148 void SetNpadCommunicationMode(Kernel::HLERequestContext& ctx);
149 void GetNpadCommunicationMode(Kernel::HLERequestContext& ctx);
150
151 enum class VibrationDeviceType : u32 {
152 LinearResonantActuator = 1,
153 };
154
155 enum class VibrationDevicePosition : u32 {
156 None = 0,
157 Left = 1,
158 Right = 2,
159 };
160
161 struct VibrationDeviceInfo {
162 VibrationDeviceType type{};
163 VibrationDevicePosition position{};
164 };
165 static_assert(sizeof(VibrationDeviceInfo) == 0x8, "VibrationDeviceInfo has incorrect size.");
143 166
144 std::shared_ptr<IAppletResource> applet_resource; 167 std::shared_ptr<IAppletResource> applet_resource;
145 Core::System& system;
146}; 168};
147 169
148/// Reload input devices. Used when input configuration changed 170/// Reload input devices. Used when input configuration changed
diff --git a/src/core/hle/service/hid/irs.cpp b/src/core/hle/service/hid/irs.cpp
index e82fd031b..c8413099f 100644
--- a/src/core/hle/service/hid/irs.cpp
+++ b/src/core/hle/service/hid/irs.cpp
@@ -12,7 +12,7 @@
12 12
13namespace Service::HID { 13namespace Service::HID {
14 14
15IRS::IRS(Core::System& system) : ServiceFramework{"irs"}, system(system) { 15IRS::IRS(Core::System& system_) : ServiceFramework{system_, "irs"} {
16 // clang-format off 16 // clang-format off
17 static const FunctionInfo functions[] = { 17 static const FunctionInfo functions[] = {
18 {302, &IRS::ActivateIrsensor, "ActivateIrsensor"}, 18 {302, &IRS::ActivateIrsensor, "ActivateIrsensor"},
@@ -175,7 +175,7 @@ void IRS::ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx) {
175 175
176IRS::~IRS() = default; 176IRS::~IRS() = default;
177 177
178IRS_SYS::IRS_SYS() : ServiceFramework{"irs:sys"} { 178IRS_SYS::IRS_SYS(Core::System& system_) : ServiceFramework{system_, "irs:sys"} {
179 // clang-format off 179 // clang-format off
180 static const FunctionInfo functions[] = { 180 static const FunctionInfo functions[] = {
181 {500, nullptr, "SetAppletResourceUserId"}, 181 {500, nullptr, "SetAppletResourceUserId"},
diff --git a/src/core/hle/service/hid/irs.h b/src/core/hle/service/hid/irs.h
index 8918ad6ca..be0c486ba 100644
--- a/src/core/hle/service/hid/irs.h
+++ b/src/core/hle/service/hid/irs.h
@@ -7,6 +7,10 @@
7#include "core/hle/kernel/object.h" 7#include "core/hle/kernel/object.h"
8#include "core/hle/service/service.h" 8#include "core/hle/service/service.h"
9 9
10namespace Core {
11class System;
12}
13
10namespace Kernel { 14namespace Kernel {
11class SharedMemory; 15class SharedMemory;
12} 16}
@@ -15,7 +19,7 @@ namespace Service::HID {
15 19
16class IRS final : public ServiceFramework<IRS> { 20class IRS final : public ServiceFramework<IRS> {
17public: 21public:
18 explicit IRS(Core::System& system); 22 explicit IRS(Core::System& system_);
19 ~IRS() override; 23 ~IRS() override;
20 24
21private: 25private:
@@ -37,14 +41,14 @@ private:
37 void RunIrLedProcessor(Kernel::HLERequestContext& ctx); 41 void RunIrLedProcessor(Kernel::HLERequestContext& ctx);
38 void StopImageProcessorAsync(Kernel::HLERequestContext& ctx); 42 void StopImageProcessorAsync(Kernel::HLERequestContext& ctx);
39 void ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx); 43 void ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx);
44
40 std::shared_ptr<Kernel::SharedMemory> shared_mem; 45 std::shared_ptr<Kernel::SharedMemory> shared_mem;
41 const u32 device_handle{0xABCD}; 46 const u32 device_handle{0xABCD};
42 Core::System& system;
43}; 47};
44 48
45class IRS_SYS final : public ServiceFramework<IRS_SYS> { 49class IRS_SYS final : public ServiceFramework<IRS_SYS> {
46public: 50public:
47 explicit IRS_SYS(); 51 explicit IRS_SYS(Core::System& system);
48 ~IRS_SYS() override; 52 ~IRS_SYS() override;
49}; 53};
50 54
diff --git a/src/core/hle/service/hid/xcd.cpp b/src/core/hle/service/hid/xcd.cpp
index c8e9125f6..43a8840d0 100644
--- a/src/core/hle/service/hid/xcd.cpp
+++ b/src/core/hle/service/hid/xcd.cpp
@@ -6,7 +6,7 @@
6 6
7namespace Service::HID { 7namespace Service::HID {
8 8
9XCD_SYS::XCD_SYS() : ServiceFramework{"xcd:sys"} { 9XCD_SYS::XCD_SYS(Core::System& system_) : ServiceFramework{system_, "xcd:sys"} {
10 // clang-format off 10 // clang-format off
11 static const FunctionInfo functions[] = { 11 static const FunctionInfo functions[] = {
12 {0, nullptr, "GetDataFormat"}, 12 {0, nullptr, "GetDataFormat"},
diff --git a/src/core/hle/service/hid/xcd.h b/src/core/hle/service/hid/xcd.h
index fd506d303..54932c228 100644
--- a/src/core/hle/service/hid/xcd.h
+++ b/src/core/hle/service/hid/xcd.h
@@ -6,11 +6,15 @@
6 6
7#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
8 8
9namespace Core {
10class System;
11}
12
9namespace Service::HID { 13namespace Service::HID {
10 14
11class XCD_SYS final : public ServiceFramework<XCD_SYS> { 15class XCD_SYS final : public ServiceFramework<XCD_SYS> {
12public: 16public:
13 explicit XCD_SYS(); 17 explicit XCD_SYS(Core::System& system_);
14 ~XCD_SYS() override; 18 ~XCD_SYS() override;
15}; 19};
16 20
diff --git a/src/core/hle/service/lbl/lbl.cpp b/src/core/hle/service/lbl/lbl.cpp
index 17350b403..6ad3a2877 100644
--- a/src/core/hle/service/lbl/lbl.cpp
+++ b/src/core/hle/service/lbl/lbl.cpp
@@ -15,7 +15,7 @@ namespace Service::LBL {
15 15
16class LBL final : public ServiceFramework<LBL> { 16class LBL final : public ServiceFramework<LBL> {
17public: 17public:
18 explicit LBL() : ServiceFramework{"lbl"} { 18 explicit LBL(Core::System& system_) : ServiceFramework{system_, "lbl"} {
19 // clang-format off 19 // clang-format off
20 static const FunctionInfo functions[] = { 20 static const FunctionInfo functions[] = {
21 {0, nullptr, "SaveCurrentSetting"}, 21 {0, nullptr, "SaveCurrentSetting"},
@@ -84,8 +84,8 @@ private:
84 bool vr_mode_enabled = false; 84 bool vr_mode_enabled = false;
85}; 85};
86 86
87void InstallInterfaces(SM::ServiceManager& sm) { 87void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
88 std::make_shared<LBL>()->InstallAsService(sm); 88 std::make_shared<LBL>(system)->InstallAsService(sm);
89} 89}
90 90
91} // namespace Service::LBL 91} // namespace Service::LBL
diff --git a/src/core/hle/service/lbl/lbl.h b/src/core/hle/service/lbl/lbl.h
index bf6f400f8..9c2021026 100644
--- a/src/core/hle/service/lbl/lbl.h
+++ b/src/core/hle/service/lbl/lbl.h
@@ -4,12 +4,16 @@
4 4
5#pragma once 5#pragma once
6 6
7namespace Core {
8class System;
9}
10
7namespace Service::SM { 11namespace Service::SM {
8class ServiceManager; 12class ServiceManager;
9} 13}
10 14
11namespace Service::LBL { 15namespace Service::LBL {
12 16
13void InstallInterfaces(SM::ServiceManager& sm); 17void InstallInterfaces(SM::ServiceManager& sm, Core::System& system);
14 18
15} // namespace Service::LBL 19} // namespace Service::LBL
diff --git a/src/core/hle/service/ldn/ldn.cpp b/src/core/hle/service/ldn/ldn.cpp
index 49972cd69..ee908f399 100644
--- a/src/core/hle/service/ldn/ldn.cpp
+++ b/src/core/hle/service/ldn/ldn.cpp
@@ -13,7 +13,7 @@ namespace Service::LDN {
13 13
14class IMonitorService final : public ServiceFramework<IMonitorService> { 14class IMonitorService final : public ServiceFramework<IMonitorService> {
15public: 15public:
16 explicit IMonitorService() : ServiceFramework{"IMonitorService"} { 16 explicit IMonitorService(Core::System& system_) : ServiceFramework{system_, "IMonitorService"} {
17 // clang-format off 17 // clang-format off
18 static const FunctionInfo functions[] = { 18 static const FunctionInfo functions[] = {
19 {0, nullptr, "GetStateForMonitor"}, 19 {0, nullptr, "GetStateForMonitor"},
@@ -33,7 +33,7 @@ public:
33 33
34class LDNM final : public ServiceFramework<LDNM> { 34class LDNM final : public ServiceFramework<LDNM> {
35public: 35public:
36 explicit LDNM() : ServiceFramework{"ldn:m"} { 36 explicit LDNM(Core::System& system_) : ServiceFramework{system_, "ldn:m"} {
37 // clang-format off 37 // clang-format off
38 static const FunctionInfo functions[] = { 38 static const FunctionInfo functions[] = {
39 {0, &LDNM::CreateMonitorService, "CreateMonitorService"} 39 {0, &LDNM::CreateMonitorService, "CreateMonitorService"}
@@ -48,15 +48,15 @@ public:
48 48
49 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 49 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
50 rb.Push(RESULT_SUCCESS); 50 rb.Push(RESULT_SUCCESS);
51 rb.PushIpcInterface<IMonitorService>(); 51 rb.PushIpcInterface<IMonitorService>(system);
52 } 52 }
53}; 53};
54 54
55class ISystemLocalCommunicationService final 55class ISystemLocalCommunicationService final
56 : public ServiceFramework<ISystemLocalCommunicationService> { 56 : public ServiceFramework<ISystemLocalCommunicationService> {
57public: 57public:
58 explicit ISystemLocalCommunicationService() 58 explicit ISystemLocalCommunicationService(Core::System& system_)
59 : ServiceFramework{"ISystemLocalCommunicationService"} { 59 : ServiceFramework{system_, "ISystemLocalCommunicationService"} {
60 // clang-format off 60 // clang-format off
61 static const FunctionInfo functions[] = { 61 static const FunctionInfo functions[] = {
62 {0, nullptr, "GetState"}, 62 {0, nullptr, "GetState"},
@@ -99,7 +99,8 @@ public:
99class IUserLocalCommunicationService final 99class IUserLocalCommunicationService final
100 : public ServiceFramework<IUserLocalCommunicationService> { 100 : public ServiceFramework<IUserLocalCommunicationService> {
101public: 101public:
102 explicit IUserLocalCommunicationService() : ServiceFramework{"IUserLocalCommunicationService"} { 102 explicit IUserLocalCommunicationService(Core::System& system_)
103 : ServiceFramework{system_, "IUserLocalCommunicationService"} {
103 // clang-format off 104 // clang-format off
104 static const FunctionInfo functions[] = { 105 static const FunctionInfo functions[] = {
105 {0, nullptr, "GetState"}, 106 {0, nullptr, "GetState"},
@@ -148,7 +149,7 @@ public:
148 149
149class LDNS final : public ServiceFramework<LDNS> { 150class LDNS final : public ServiceFramework<LDNS> {
150public: 151public:
151 explicit LDNS() : ServiceFramework{"ldn:s"} { 152 explicit LDNS(Core::System& system_) : ServiceFramework{system_, "ldn:s"} {
152 // clang-format off 153 // clang-format off
153 static const FunctionInfo functions[] = { 154 static const FunctionInfo functions[] = {
154 {0, &LDNS::CreateSystemLocalCommunicationService, "CreateSystemLocalCommunicationService"}, 155 {0, &LDNS::CreateSystemLocalCommunicationService, "CreateSystemLocalCommunicationService"},
@@ -163,13 +164,13 @@ public:
163 164
164 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 165 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
165 rb.Push(RESULT_SUCCESS); 166 rb.Push(RESULT_SUCCESS);
166 rb.PushIpcInterface<ISystemLocalCommunicationService>(); 167 rb.PushIpcInterface<ISystemLocalCommunicationService>(system);
167 } 168 }
168}; 169};
169 170
170class LDNU final : public ServiceFramework<LDNU> { 171class LDNU final : public ServiceFramework<LDNU> {
171public: 172public:
172 explicit LDNU() : ServiceFramework{"ldn:u"} { 173 explicit LDNU(Core::System& system_) : ServiceFramework{system_, "ldn:u"} {
173 // clang-format off 174 // clang-format off
174 static const FunctionInfo functions[] = { 175 static const FunctionInfo functions[] = {
175 {0, &LDNU::CreateUserLocalCommunicationService, "CreateUserLocalCommunicationService"}, 176 {0, &LDNU::CreateUserLocalCommunicationService, "CreateUserLocalCommunicationService"},
@@ -184,14 +185,14 @@ public:
184 185
185 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 186 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
186 rb.Push(RESULT_SUCCESS); 187 rb.Push(RESULT_SUCCESS);
187 rb.PushIpcInterface<IUserLocalCommunicationService>(); 188 rb.PushIpcInterface<IUserLocalCommunicationService>(system);
188 } 189 }
189}; 190};
190 191
191void InstallInterfaces(SM::ServiceManager& sm) { 192void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
192 std::make_shared<LDNM>()->InstallAsService(sm); 193 std::make_shared<LDNM>(system)->InstallAsService(sm);
193 std::make_shared<LDNS>()->InstallAsService(sm); 194 std::make_shared<LDNS>(system)->InstallAsService(sm);
194 std::make_shared<LDNU>()->InstallAsService(sm); 195 std::make_shared<LDNU>(system)->InstallAsService(sm);
195} 196}
196 197
197} // namespace Service::LDN 198} // namespace Service::LDN
diff --git a/src/core/hle/service/ldn/ldn.h b/src/core/hle/service/ldn/ldn.h
index 6b2a3c2b2..3ccd9738b 100644
--- a/src/core/hle/service/ldn/ldn.h
+++ b/src/core/hle/service/ldn/ldn.h
@@ -4,6 +4,10 @@
4 4
5#pragma once 5#pragma once
6 6
7namespace Core {
8class System;
9}
10
7namespace Service::SM { 11namespace Service::SM {
8class ServiceManager; 12class ServiceManager;
9} 13}
@@ -11,6 +15,6 @@ class ServiceManager;
11namespace Service::LDN { 15namespace Service::LDN {
12 16
13/// Registers all LDN services with the specified service manager. 17/// Registers all LDN services with the specified service manager.
14void InstallInterfaces(SM::ServiceManager& sm); 18void InstallInterfaces(SM::ServiceManager& sm, Core::System& system);
15 19
16} // namespace Service::LDN 20} // namespace Service::LDN
diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp
index d8cd10e31..9da786b4e 100644
--- a/src/core/hle/service/ldr/ldr.cpp
+++ b/src/core/hle/service/ldr/ldr.cpp
@@ -9,6 +9,7 @@
9#include "common/alignment.h" 9#include "common/alignment.h"
10#include "common/hex_util.h" 10#include "common/hex_util.h"
11#include "common/scope_exit.h" 11#include "common/scope_exit.h"
12#include "core/core.h"
12#include "core/hle/ipc_helpers.h" 13#include "core/hle/ipc_helpers.h"
13#include "core/hle/kernel/errors.h" 14#include "core/hle/kernel/errors.h"
14#include "core/hle/kernel/memory/page_table.h" 15#include "core/hle/kernel/memory/page_table.h"
@@ -23,7 +24,7 @@ namespace Service::LDR {
23 24
24constexpr ResultCode ERROR_INSUFFICIENT_ADDRESS_SPACE{ErrorModule::RO, 2}; 25constexpr ResultCode ERROR_INSUFFICIENT_ADDRESS_SPACE{ErrorModule::RO, 2};
25 26
26constexpr ResultCode ERROR_INVALID_MEMORY_STATE{ErrorModule::Loader, 51}; 27[[maybe_unused]] constexpr ResultCode ERROR_INVALID_MEMORY_STATE{ErrorModule::Loader, 51};
27constexpr ResultCode ERROR_INVALID_NRO{ErrorModule::Loader, 52}; 28constexpr ResultCode ERROR_INVALID_NRO{ErrorModule::Loader, 52};
28constexpr ResultCode ERROR_INVALID_NRR{ErrorModule::Loader, 53}; 29constexpr ResultCode ERROR_INVALID_NRR{ErrorModule::Loader, 53};
29constexpr ResultCode ERROR_MISSING_NRR_HASH{ErrorModule::Loader, 54}; 30constexpr ResultCode ERROR_MISSING_NRR_HASH{ErrorModule::Loader, 54};
@@ -33,7 +34,7 @@ constexpr ResultCode ERROR_ALREADY_LOADED{ErrorModule::Loader, 57};
33constexpr ResultCode ERROR_INVALID_ALIGNMENT{ErrorModule::Loader, 81}; 34constexpr ResultCode ERROR_INVALID_ALIGNMENT{ErrorModule::Loader, 81};
34constexpr ResultCode ERROR_INVALID_SIZE{ErrorModule::Loader, 82}; 35constexpr ResultCode ERROR_INVALID_SIZE{ErrorModule::Loader, 82};
35constexpr ResultCode ERROR_INVALID_NRO_ADDRESS{ErrorModule::Loader, 84}; 36constexpr ResultCode ERROR_INVALID_NRO_ADDRESS{ErrorModule::Loader, 84};
36constexpr ResultCode ERROR_INVALID_NRR_ADDRESS{ErrorModule::Loader, 85}; 37[[maybe_unused]] constexpr ResultCode ERROR_INVALID_NRR_ADDRESS{ErrorModule::Loader, 85};
37constexpr ResultCode ERROR_NOT_INITIALIZED{ErrorModule::Loader, 87}; 38constexpr ResultCode ERROR_NOT_INITIALIZED{ErrorModule::Loader, 87};
38 39
39constexpr std::size_t MAXIMUM_LOADED_RO{0x40}; 40constexpr std::size_t MAXIMUM_LOADED_RO{0x40};
@@ -114,7 +115,7 @@ static_assert(sizeof(NROInfo) == 0x60, "NROInfo has invalid size.");
114 115
115class DebugMonitor final : public ServiceFramework<DebugMonitor> { 116class DebugMonitor final : public ServiceFramework<DebugMonitor> {
116public: 117public:
117 explicit DebugMonitor() : ServiceFramework{"ldr:dmnt"} { 118 explicit DebugMonitor(Core::System& system_) : ServiceFramework{system_, "ldr:dmnt"} {
118 // clang-format off 119 // clang-format off
119 static const FunctionInfo functions[] = { 120 static const FunctionInfo functions[] = {
120 {0, nullptr, "AddProcessToDebugLaunchQueue"}, 121 {0, nullptr, "AddProcessToDebugLaunchQueue"},
@@ -129,7 +130,7 @@ public:
129 130
130class ProcessManager final : public ServiceFramework<ProcessManager> { 131class ProcessManager final : public ServiceFramework<ProcessManager> {
131public: 132public:
132 explicit ProcessManager() : ServiceFramework{"ldr:pm"} { 133 explicit ProcessManager(Core::System& system_) : ServiceFramework{system_, "ldr:pm"} {
133 // clang-format off 134 // clang-format off
134 static const FunctionInfo functions[] = { 135 static const FunctionInfo functions[] = {
135 {0, nullptr, "CreateProcess"}, 136 {0, nullptr, "CreateProcess"},
@@ -146,7 +147,7 @@ public:
146 147
147class Shell final : public ServiceFramework<Shell> { 148class Shell final : public ServiceFramework<Shell> {
148public: 149public:
149 explicit Shell() : ServiceFramework{"ldr:shel"} { 150 explicit Shell(Core::System& system_) : ServiceFramework{system_, "ldr:shel"} {
150 // clang-format off 151 // clang-format off
151 static const FunctionInfo functions[] = { 152 static const FunctionInfo functions[] = {
152 {0, nullptr, "AddProcessToLaunchQueue"}, 153 {0, nullptr, "AddProcessToLaunchQueue"},
@@ -160,13 +161,13 @@ public:
160 161
161class RelocatableObject final : public ServiceFramework<RelocatableObject> { 162class RelocatableObject final : public ServiceFramework<RelocatableObject> {
162public: 163public:
163 explicit RelocatableObject(Core::System& system) : ServiceFramework{"ldr:ro"}, system(system) { 164 explicit RelocatableObject(Core::System& system_) : ServiceFramework{system_, "ldr:ro"} {
164 // clang-format off 165 // clang-format off
165 static const FunctionInfo functions[] = { 166 static const FunctionInfo functions[] = {
166 {0, &RelocatableObject::LoadNro, "LoadNro"}, 167 {0, &RelocatableObject::LoadNro, "LoadNro"},
167 {1, &RelocatableObject::UnloadNro, "UnloadNro"}, 168 {1, &RelocatableObject::UnloadNro, "UnloadNro"},
168 {2, &RelocatableObject::LoadNrr, "LoadNrr"}, 169 {2, &RelocatableObject::LoadNrr, "LoadNrr"},
169 {3, nullptr, "UnloadNrr"}, 170 {3, &RelocatableObject::UnloadNrr, "UnloadNrr"},
170 {4, &RelocatableObject::Initialize, "Initialize"}, 171 {4, &RelocatableObject::Initialize, "Initialize"},
171 {10, nullptr, "LoadNrrEx"}, 172 {10, nullptr, "LoadNrrEx"},
172 }; 173 };
@@ -272,6 +273,20 @@ public:
272 rb.Push(RESULT_SUCCESS); 273 rb.Push(RESULT_SUCCESS);
273 } 274 }
274 275
276 void UnloadNrr(Kernel::HLERequestContext& ctx) {
277 IPC::RequestParser rp{ctx};
278 const auto pid = rp.Pop<u64>();
279 const auto nrr_address = rp.Pop<VAddr>();
280
281 LOG_DEBUG(Service_LDR, "called with pid={}, nrr_address={:016X}", pid, nrr_address);
282
283 nrr.erase(nrr_address);
284
285 IPC::ResponseBuilder rb{ctx, 2};
286
287 rb.Push(RESULT_SUCCESS);
288 }
289
275 bool ValidateRegionForMap(Kernel::Memory::PageTable& page_table, VAddr start, 290 bool ValidateRegionForMap(Kernel::Memory::PageTable& page_table, VAddr start,
276 std::size_t size) const { 291 std::size_t size) const {
277 constexpr std::size_t padding_size{4 * Kernel::Memory::PageSize}; 292 constexpr std::size_t padding_size{4 * Kernel::Memory::PageSize};
@@ -512,9 +527,6 @@ public:
512 header.segment_headers[RO_INDEX].memory_size, 527 header.segment_headers[RO_INDEX].memory_size,
513 header.segment_headers[DATA_INDEX].memory_size, nro_address}); 528 header.segment_headers[DATA_INDEX].memory_size, nro_address});
514 529
515 // Invalidate JIT caches for the newly mapped process code
516 system.InvalidateCpuInstructionCaches();
517
518 IPC::ResponseBuilder rb{ctx, 4}; 530 IPC::ResponseBuilder rb{ctx, 4};
519 rb.Push(RESULT_SUCCESS); 531 rb.Push(RESULT_SUCCESS);
520 rb.Push(*map_result); 532 rb.Push(*map_result);
@@ -575,8 +587,6 @@ public:
575 587
576 const auto result{UnmapNro(iter->second)}; 588 const auto result{UnmapNro(iter->second)};
577 589
578 system.InvalidateCpuInstructionCaches();
579
580 nro.erase(iter); 590 nro.erase(iter);
581 591
582 IPC::ResponseBuilder rb{ctx, 2}; 592 IPC::ResponseBuilder rb{ctx, 2};
@@ -624,13 +634,12 @@ private:
624 Common::Is4KBAligned(header.segment_headers[RO_INDEX].memory_size) && 634 Common::Is4KBAligned(header.segment_headers[RO_INDEX].memory_size) &&
625 Common::Is4KBAligned(header.segment_headers[DATA_INDEX].memory_size); 635 Common::Is4KBAligned(header.segment_headers[DATA_INDEX].memory_size);
626 } 636 }
627 Core::System& system;
628}; 637};
629 638
630void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) { 639void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
631 std::make_shared<DebugMonitor>()->InstallAsService(sm); 640 std::make_shared<DebugMonitor>(system)->InstallAsService(sm);
632 std::make_shared<ProcessManager>()->InstallAsService(sm); 641 std::make_shared<ProcessManager>(system)->InstallAsService(sm);
633 std::make_shared<Shell>()->InstallAsService(sm); 642 std::make_shared<Shell>(system)->InstallAsService(sm);
634 std::make_shared<RelocatableObject>(system)->InstallAsService(sm); 643 std::make_shared<RelocatableObject>(system)->InstallAsService(sm);
635} 644}
636 645
diff --git a/src/core/hle/service/ldr/ldr.h b/src/core/hle/service/ldr/ldr.h
index 7ac8c0b65..104fc15c5 100644
--- a/src/core/hle/service/ldr/ldr.h
+++ b/src/core/hle/service/ldr/ldr.h
@@ -4,6 +4,10 @@
4 4
5#pragma once 5#pragma once
6 6
7namespace Core {
8class System;
9}
10
7namespace Service::SM { 11namespace Service::SM {
8class ServiceManager; 12class ServiceManager;
9} 13}
diff --git a/src/core/hle/service/lm/lm.cpp b/src/core/hle/service/lm/lm.cpp
index dec96b771..8e49b068c 100644
--- a/src/core/hle/service/lm/lm.cpp
+++ b/src/core/hle/service/lm/lm.cpp
@@ -7,6 +7,7 @@
7 7
8#include "common/logging/log.h" 8#include "common/logging/log.h"
9#include "common/scope_exit.h" 9#include "common/scope_exit.h"
10#include "core/core.h"
10#include "core/hle/ipc_helpers.h" 11#include "core/hle/ipc_helpers.h"
11#include "core/hle/service/lm/lm.h" 12#include "core/hle/service/lm/lm.h"
12#include "core/hle/service/lm/manager.h" 13#include "core/hle/service/lm/manager.h"
@@ -17,8 +18,9 @@ namespace Service::LM {
17 18
18class ILogger final : public ServiceFramework<ILogger> { 19class ILogger final : public ServiceFramework<ILogger> {
19public: 20public:
20 explicit ILogger(Manager& manager_, Core::Memory::Memory& memory_) 21 explicit ILogger(Core::System& system_)
21 : ServiceFramework("ILogger"), manager{manager_}, memory{memory_} { 22 : ServiceFramework{system_, "ILogger"}, manager{system_.GetLogManager()},
23 memory{system_.Memory()} {
22 static const FunctionInfo functions[] = { 24 static const FunctionInfo functions[] = {
23 {0, &ILogger::Log, "Log"}, 25 {0, &ILogger::Log, "Log"},
24 {1, &ILogger::SetDestination, "SetDestination"}, 26 {1, &ILogger::SetDestination, "SetDestination"},
@@ -66,7 +68,7 @@ private:
66 IPC::RequestParser rp{ctx}; 68 IPC::RequestParser rp{ctx};
67 const auto destination = rp.PopEnum<DestinationFlag>(); 69 const auto destination = rp.PopEnum<DestinationFlag>();
68 70
69 LOG_DEBUG(Service_LM, "called, destination={:08X}", static_cast<u32>(destination)); 71 LOG_DEBUG(Service_LM, "called, destination={:08X}", destination);
70 72
71 manager.SetDestination(destination); 73 manager.SetDestination(destination);
72 74
@@ -80,8 +82,7 @@ private:
80 82
81class LM final : public ServiceFramework<LM> { 83class LM final : public ServiceFramework<LM> {
82public: 84public:
83 explicit LM(Manager& manager_, Core::Memory::Memory& memory_) 85 explicit LM(Core::System& system_) : ServiceFramework{system_, "lm"} {
84 : ServiceFramework{"lm"}, manager{manager_}, memory{memory_} {
85 // clang-format off 86 // clang-format off
86 static const FunctionInfo functions[] = { 87 static const FunctionInfo functions[] = {
87 {0, &LM::OpenLogger, "OpenLogger"}, 88 {0, &LM::OpenLogger, "OpenLogger"},
@@ -97,16 +98,12 @@ private:
97 98
98 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 99 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
99 rb.Push(RESULT_SUCCESS); 100 rb.Push(RESULT_SUCCESS);
100 rb.PushIpcInterface<ILogger>(manager, memory); 101 rb.PushIpcInterface<ILogger>(system);
101 } 102 }
102
103 Manager& manager;
104 Core::Memory::Memory& memory;
105}; 103};
106 104
107void InstallInterfaces(Core::System& system) { 105void InstallInterfaces(Core::System& system) {
108 std::make_shared<LM>(system.GetLogManager(), system.Memory()) 106 std::make_shared<LM>(system)->InstallAsService(system.ServiceManager());
109 ->InstallAsService(system.ServiceManager());
110} 107}
111 108
112} // namespace Service::LM 109} // namespace Service::LM
diff --git a/src/core/hle/service/mig/mig.cpp b/src/core/hle/service/mig/mig.cpp
index 113a4665c..1599d941b 100644
--- a/src/core/hle/service/mig/mig.cpp
+++ b/src/core/hle/service/mig/mig.cpp
@@ -12,7 +12,7 @@ namespace Service::Migration {
12 12
13class MIG_USR final : public ServiceFramework<MIG_USR> { 13class MIG_USR final : public ServiceFramework<MIG_USR> {
14public: 14public:
15 explicit MIG_USR() : ServiceFramework{"mig:usr"} { 15 explicit MIG_USR(Core::System& system_) : ServiceFramework{system_, "mig:usr"} {
16 // clang-format off 16 // clang-format off
17 static const FunctionInfo functions[] = { 17 static const FunctionInfo functions[] = {
18 {10, nullptr, "TryGetLastMigrationInfo"}, 18 {10, nullptr, "TryGetLastMigrationInfo"},
@@ -33,8 +33,8 @@ public:
33 } 33 }
34}; 34};
35 35
36void InstallInterfaces(SM::ServiceManager& sm) { 36void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
37 std::make_shared<MIG_USR>()->InstallAsService(sm); 37 std::make_shared<MIG_USR>(system)->InstallAsService(sm);
38} 38}
39 39
40} // namespace Service::Migration 40} // namespace Service::Migration
diff --git a/src/core/hle/service/mig/mig.h b/src/core/hle/service/mig/mig.h
index 288c1c1b3..2b24cdf2c 100644
--- a/src/core/hle/service/mig/mig.h
+++ b/src/core/hle/service/mig/mig.h
@@ -4,12 +4,16 @@
4 4
5#pragma once 5#pragma once
6 6
7namespace Core {
8class System;
9}
10
7namespace Service::SM { 11namespace Service::SM {
8class ServiceManager; 12class ServiceManager;
9} 13}
10 14
11namespace Service::Migration { 15namespace Service::Migration {
12 16
13void InstallInterfaces(SM::ServiceManager& sm); 17void InstallInterfaces(SM::ServiceManager& sm, Core::System& system);
14 18
15} // namespace Service::Migration 19} // namespace Service::Migration
diff --git a/src/core/hle/service/mii/manager.cpp b/src/core/hle/service/mii/manager.cpp
index 4730070cb..d73b90015 100644
--- a/src/core/hle/service/mii/manager.cpp
+++ b/src/core/hle/service/mii/manager.cpp
@@ -131,7 +131,7 @@ template <typename T>
131T GetRandomValue(T min, T max) { 131T GetRandomValue(T min, T max) {
132 std::random_device device; 132 std::random_device device;
133 std::mt19937 gen(device()); 133 std::mt19937 gen(device());
134 std::uniform_int_distribution<u64> distribution(0, static_cast<u64>(max)); 134 std::uniform_int_distribution<u64> distribution(static_cast<u64>(min), static_cast<u64>(max));
135 return static_cast<T>(distribution(gen)); 135 return static_cast<T>(distribution(gen));
136} 136}
137 137
@@ -428,7 +428,7 @@ bool MiiManager::IsFullDatabase() const {
428} 428}
429 429
430u32 MiiManager::GetCount(SourceFlag source_flag) const { 430u32 MiiManager::GetCount(SourceFlag source_flag) const {
431 u32 count{}; 431 std::size_t count{};
432 if ((source_flag & SourceFlag::Database) != SourceFlag::None) { 432 if ((source_flag & SourceFlag::Database) != SourceFlag::None) {
433 // TODO(bunnei): We don't implement the Mii database, but when we do, update this 433 // TODO(bunnei): We don't implement the Mii database, but when we do, update this
434 count += 0; 434 count += 0;
@@ -436,7 +436,7 @@ u32 MiiManager::GetCount(SourceFlag source_flag) const {
436 if ((source_flag & SourceFlag::Default) != SourceFlag::None) { 436 if ((source_flag & SourceFlag::Default) != SourceFlag::None) {
437 count += DefaultMiiCount; 437 count += DefaultMiiCount;
438 } 438 }
439 return count; 439 return static_cast<u32>(count);
440} 440}
441 441
442ResultVal<MiiInfo> MiiManager::UpdateLatest([[maybe_unused]] const MiiInfo& info, 442ResultVal<MiiInfo> MiiManager::UpdateLatest([[maybe_unused]] const MiiInfo& info,
diff --git a/src/core/hle/service/mii/mii.cpp b/src/core/hle/service/mii/mii.cpp
index b81bf6277..26be9e45b 100644
--- a/src/core/hle/service/mii/mii.cpp
+++ b/src/core/hle/service/mii/mii.cpp
@@ -18,7 +18,8 @@ constexpr ResultCode ERROR_INVALID_ARGUMENT{ErrorModule::Mii, 1};
18 18
19class IDatabaseService final : public ServiceFramework<IDatabaseService> { 19class IDatabaseService final : public ServiceFramework<IDatabaseService> {
20public: 20public:
21 explicit IDatabaseService() : ServiceFramework{"IDatabaseService"} { 21 explicit IDatabaseService(Core::System& system_)
22 : ServiceFramework{system_, "IDatabaseService"} {
22 // clang-format off 23 // clang-format off
23 static const FunctionInfo functions[] = { 24 static const FunctionInfo functions[] = {
24 {0, &IDatabaseService::IsUpdated, "IsUpdated"}, 25 {0, &IDatabaseService::IsUpdated, "IsUpdated"},
@@ -47,6 +48,7 @@ public:
47 {23, nullptr, "Convert"}, 48 {23, nullptr, "Convert"},
48 {24, nullptr, "ConvertCoreDataToCharInfo"}, 49 {24, nullptr, "ConvertCoreDataToCharInfo"},
49 {25, nullptr, "ConvertCharInfoToCoreData"}, 50 {25, nullptr, "ConvertCharInfoToCoreData"},
51 {26, nullptr, "Append"},
50 }; 52 };
51 // clang-format on 53 // clang-format on
52 54
@@ -251,7 +253,8 @@ private:
251 253
252class MiiDBModule final : public ServiceFramework<MiiDBModule> { 254class MiiDBModule final : public ServiceFramework<MiiDBModule> {
253public: 255public:
254 explicit MiiDBModule(const char* name) : ServiceFramework{name} { 256 explicit MiiDBModule(Core::System& system_, const char* name)
257 : ServiceFramework{system_, name} {
255 // clang-format off 258 // clang-format off
256 static const FunctionInfo functions[] = { 259 static const FunctionInfo functions[] = {
257 {0, &MiiDBModule::GetDatabaseService, "GetDatabaseService"}, 260 {0, &MiiDBModule::GetDatabaseService, "GetDatabaseService"},
@@ -265,7 +268,7 @@ private:
265 void GetDatabaseService(Kernel::HLERequestContext& ctx) { 268 void GetDatabaseService(Kernel::HLERequestContext& ctx) {
266 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 269 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
267 rb.Push(RESULT_SUCCESS); 270 rb.Push(RESULT_SUCCESS);
268 rb.PushIpcInterface<IDatabaseService>(); 271 rb.PushIpcInterface<IDatabaseService>(system);
269 272
270 LOG_DEBUG(Service_Mii, "called"); 273 LOG_DEBUG(Service_Mii, "called");
271 } 274 }
@@ -273,7 +276,7 @@ private:
273 276
274class MiiImg final : public ServiceFramework<MiiImg> { 277class MiiImg final : public ServiceFramework<MiiImg> {
275public: 278public:
276 explicit MiiImg() : ServiceFramework{"miiimg"} { 279 explicit MiiImg(Core::System& system_) : ServiceFramework{system_, "miiimg"} {
277 // clang-format off 280 // clang-format off
278 static const FunctionInfo functions[] = { 281 static const FunctionInfo functions[] = {
279 {0, nullptr, "Initialize"}, 282 {0, nullptr, "Initialize"},
@@ -297,11 +300,11 @@ public:
297 } 300 }
298}; 301};
299 302
300void InstallInterfaces(SM::ServiceManager& sm) { 303void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
301 std::make_shared<MiiDBModule>("mii:e")->InstallAsService(sm); 304 std::make_shared<MiiDBModule>(system, "mii:e")->InstallAsService(sm);
302 std::make_shared<MiiDBModule>("mii:u")->InstallAsService(sm); 305 std::make_shared<MiiDBModule>(system, "mii:u")->InstallAsService(sm);
303 306
304 std::make_shared<MiiImg>()->InstallAsService(sm); 307 std::make_shared<MiiImg>(system)->InstallAsService(sm);
305} 308}
306 309
307} // namespace Service::Mii 310} // namespace Service::Mii
diff --git a/src/core/hle/service/mii/mii.h b/src/core/hle/service/mii/mii.h
index 7ce9be50e..9d3238e72 100644
--- a/src/core/hle/service/mii/mii.h
+++ b/src/core/hle/service/mii/mii.h
@@ -4,12 +4,16 @@
4 4
5#pragma once 5#pragma once
6 6
7namespace Core {
8class System;
9}
10
7namespace Service::SM { 11namespace Service::SM {
8class ServiceManager; 12class ServiceManager;
9} 13}
10 14
11namespace Service::Mii { 15namespace Service::Mii {
12 16
13void InstallInterfaces(SM::ServiceManager& sm); 17void InstallInterfaces(SM::ServiceManager& sm, Core::System& system);
14 18
15} // namespace Service::Mii 19} // namespace Service::Mii
diff --git a/src/core/hle/service/mm/mm_u.cpp b/src/core/hle/service/mm/mm_u.cpp
index 25c24e537..b0cb07d24 100644
--- a/src/core/hle/service/mm/mm_u.cpp
+++ b/src/core/hle/service/mm/mm_u.cpp
@@ -6,12 +6,13 @@
6#include "core/hle/ipc_helpers.h" 6#include "core/hle/ipc_helpers.h"
7#include "core/hle/kernel/client_session.h" 7#include "core/hle/kernel/client_session.h"
8#include "core/hle/service/mm/mm_u.h" 8#include "core/hle/service/mm/mm_u.h"
9#include "core/hle/service/sm/sm.h"
9 10
10namespace Service::MM { 11namespace Service::MM {
11 12
12class MM_U final : public ServiceFramework<MM_U> { 13class MM_U final : public ServiceFramework<MM_U> {
13public: 14public:
14 explicit MM_U() : ServiceFramework{"mm:u"} { 15 explicit MM_U(Core::System& system_) : ServiceFramework{system_, "mm:u"} {
15 // clang-format off 16 // clang-format off
16 static const FunctionInfo functions[] = { 17 static const FunctionInfo functions[] = {
17 {0, &MM_U::InitializeOld, "InitializeOld"}, 18 {0, &MM_U::InitializeOld, "InitializeOld"},
@@ -104,8 +105,8 @@ private:
104 u32 id{1}; 105 u32 id{1};
105}; 106};
106 107
107void InstallInterfaces(SM::ServiceManager& service_manager) { 108void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
108 std::make_shared<MM_U>()->InstallAsService(service_manager); 109 std::make_shared<MM_U>(system)->InstallAsService(service_manager);
109} 110}
110 111
111} // namespace Service::MM 112} // namespace Service::MM
diff --git a/src/core/hle/service/mm/mm_u.h b/src/core/hle/service/mm/mm_u.h
index 5439fa653..49b6a3355 100644
--- a/src/core/hle/service/mm/mm_u.h
+++ b/src/core/hle/service/mm/mm_u.h
@@ -4,11 +4,17 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "core/hle/service/service.h" 7namespace Core {
8class System;
9}
10
11namespace Service::SM {
12class ServiceManager;
13}
8 14
9namespace Service::MM { 15namespace Service::MM {
10 16
11/// Registers all MM services with the specified service manager. 17/// Registers all MM services with the specified service manager.
12void InstallInterfaces(SM::ServiceManager& service_manager); 18void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system);
13 19
14} // namespace Service::MM 20} // namespace Service::MM
diff --git a/src/core/hle/service/ncm/ncm.cpp b/src/core/hle/service/ncm/ncm.cpp
index e38dea1f4..2dcda16f6 100644
--- a/src/core/hle/service/ncm/ncm.cpp
+++ b/src/core/hle/service/ncm/ncm.cpp
@@ -14,8 +14,8 @@ namespace Service::NCM {
14 14
15class ILocationResolver final : public ServiceFramework<ILocationResolver> { 15class ILocationResolver final : public ServiceFramework<ILocationResolver> {
16public: 16public:
17 explicit ILocationResolver(FileSys::StorageId id) 17 explicit ILocationResolver(Core::System& system_, FileSys::StorageId id)
18 : ServiceFramework{"ILocationResolver"}, storage(id) { 18 : ServiceFramework{system_, "ILocationResolver"}, storage{id} {
19 // clang-format off 19 // clang-format off
20 static const FunctionInfo functions[] = { 20 static const FunctionInfo functions[] = {
21 {0, nullptr, "ResolveProgramPath"}, 21 {0, nullptr, "ResolveProgramPath"},
@@ -45,12 +45,13 @@ public:
45 } 45 }
46 46
47private: 47private:
48 FileSys::StorageId storage; 48 [[maybe_unused]] FileSys::StorageId storage;
49}; 49};
50 50
51class IRegisteredLocationResolver final : public ServiceFramework<IRegisteredLocationResolver> { 51class IRegisteredLocationResolver final : public ServiceFramework<IRegisteredLocationResolver> {
52public: 52public:
53 explicit IRegisteredLocationResolver() : ServiceFramework{"IRegisteredLocationResolver"} { 53 explicit IRegisteredLocationResolver(Core::System& system_)
54 : ServiceFramework{system_, "IRegisteredLocationResolver"} {
54 // clang-format off 55 // clang-format off
55 static const FunctionInfo functions[] = { 56 static const FunctionInfo functions[] = {
56 {0, nullptr, "ResolveProgramPath"}, 57 {0, nullptr, "ResolveProgramPath"},
@@ -72,7 +73,8 @@ public:
72 73
73class IAddOnContentLocationResolver final : public ServiceFramework<IAddOnContentLocationResolver> { 74class IAddOnContentLocationResolver final : public ServiceFramework<IAddOnContentLocationResolver> {
74public: 75public:
75 explicit IAddOnContentLocationResolver() : ServiceFramework{"IAddOnContentLocationResolver"} { 76 explicit IAddOnContentLocationResolver(Core::System& system_)
77 : ServiceFramework{system_, "IAddOnContentLocationResolver"} {
76 // clang-format off 78 // clang-format off
77 static const FunctionInfo functions[] = { 79 static const FunctionInfo functions[] = {
78 {0, nullptr, "ResolveAddOnContentPath"}, 80 {0, nullptr, "ResolveAddOnContentPath"},
@@ -89,7 +91,7 @@ public:
89 91
90class LR final : public ServiceFramework<LR> { 92class LR final : public ServiceFramework<LR> {
91public: 93public:
92 explicit LR() : ServiceFramework{"lr"} { 94 explicit LR(Core::System& system_) : ServiceFramework{system_, "lr"} {
93 // clang-format off 95 // clang-format off
94 static const FunctionInfo functions[] = { 96 static const FunctionInfo functions[] = {
95 {0, nullptr, "OpenLocationResolver"}, 97 {0, nullptr, "OpenLocationResolver"},
@@ -105,7 +107,7 @@ public:
105 107
106class NCM final : public ServiceFramework<NCM> { 108class NCM final : public ServiceFramework<NCM> {
107public: 109public:
108 explicit NCM() : ServiceFramework{"ncm"} { 110 explicit NCM(Core::System& system_) : ServiceFramework{system_, "ncm"} {
109 // clang-format off 111 // clang-format off
110 static const FunctionInfo functions[] = { 112 static const FunctionInfo functions[] = {
111 {0, nullptr, "CreateContentStorage"}, 113 {0, nullptr, "CreateContentStorage"},
@@ -130,9 +132,9 @@ public:
130 } 132 }
131}; 133};
132 134
133void InstallInterfaces(SM::ServiceManager& sm) { 135void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
134 std::make_shared<LR>()->InstallAsService(sm); 136 std::make_shared<LR>(system)->InstallAsService(sm);
135 std::make_shared<NCM>()->InstallAsService(sm); 137 std::make_shared<NCM>(system)->InstallAsService(sm);
136} 138}
137 139
138} // namespace Service::NCM 140} // namespace Service::NCM
diff --git a/src/core/hle/service/ncm/ncm.h b/src/core/hle/service/ncm/ncm.h
index 7bc8518a6..ee01eddc0 100644
--- a/src/core/hle/service/ncm/ncm.h
+++ b/src/core/hle/service/ncm/ncm.h
@@ -4,12 +4,16 @@
4 4
5#pragma once 5#pragma once
6 6
7namespace Core {
8class System;
9}
10
7namespace Service::SM { 11namespace Service::SM {
8class ServiceManager; 12class ServiceManager;
9} 13}
10 14
11namespace Service::NCM { 15namespace Service::NCM {
12 16
13void InstallInterfaces(SM::ServiceManager& sm); 17void InstallInterfaces(SM::ServiceManager& sm, Core::System& system);
14 18
15} // namespace Service::NCM 19} // namespace Service::NCM
diff --git a/src/core/hle/service/nfc/nfc.cpp b/src/core/hle/service/nfc/nfc.cpp
index 780ea30fe..6ab35de47 100644
--- a/src/core/hle/service/nfc/nfc.cpp
+++ b/src/core/hle/service/nfc/nfc.cpp
@@ -16,7 +16,7 @@ namespace Service::NFC {
16 16
17class IAm final : public ServiceFramework<IAm> { 17class IAm final : public ServiceFramework<IAm> {
18public: 18public:
19 explicit IAm() : ServiceFramework{"NFC::IAm"} { 19 explicit IAm(Core::System& system_) : ServiceFramework{system_, "NFC::IAm"} {
20 // clang-format off 20 // clang-format off
21 static const FunctionInfo functions[] = { 21 static const FunctionInfo functions[] = {
22 {0, nullptr, "Initialize"}, 22 {0, nullptr, "Initialize"},
@@ -31,7 +31,7 @@ public:
31 31
32class NFC_AM final : public ServiceFramework<NFC_AM> { 32class NFC_AM final : public ServiceFramework<NFC_AM> {
33public: 33public:
34 explicit NFC_AM() : ServiceFramework{"nfc:am"} { 34 explicit NFC_AM(Core::System& system_) : ServiceFramework{system_, "nfc:am"} {
35 // clang-format off 35 // clang-format off
36 static const FunctionInfo functions[] = { 36 static const FunctionInfo functions[] = {
37 {0, &NFC_AM::CreateAmInterface, "CreateAmInterface"}, 37 {0, &NFC_AM::CreateAmInterface, "CreateAmInterface"},
@@ -47,13 +47,13 @@ private:
47 47
48 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 48 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
49 rb.Push(RESULT_SUCCESS); 49 rb.Push(RESULT_SUCCESS);
50 rb.PushIpcInterface<IAm>(); 50 rb.PushIpcInterface<IAm>(system);
51 } 51 }
52}; 52};
53 53
54class MFIUser final : public ServiceFramework<MFIUser> { 54class MFIUser final : public ServiceFramework<MFIUser> {
55public: 55public:
56 explicit MFIUser() : ServiceFramework{"NFC::MFIUser"} { 56 explicit MFIUser(Core::System& system_) : ServiceFramework{system_, "NFC::MFIUser"} {
57 // clang-format off 57 // clang-format off
58 static const FunctionInfo functions[] = { 58 static const FunctionInfo functions[] = {
59 {0, nullptr, "Initialize"}, 59 {0, nullptr, "Initialize"},
@@ -79,7 +79,7 @@ public:
79 79
80class NFC_MF_U final : public ServiceFramework<NFC_MF_U> { 80class NFC_MF_U final : public ServiceFramework<NFC_MF_U> {
81public: 81public:
82 explicit NFC_MF_U() : ServiceFramework{"nfc:mf:u"} { 82 explicit NFC_MF_U(Core::System& system_) : ServiceFramework{system_, "nfc:mf:u"} {
83 // clang-format off 83 // clang-format off
84 static const FunctionInfo functions[] = { 84 static const FunctionInfo functions[] = {
85 {0, &NFC_MF_U::CreateUserInterface, "CreateUserInterface"}, 85 {0, &NFC_MF_U::CreateUserInterface, "CreateUserInterface"},
@@ -95,13 +95,13 @@ private:
95 95
96 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 96 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
97 rb.Push(RESULT_SUCCESS); 97 rb.Push(RESULT_SUCCESS);
98 rb.PushIpcInterface<MFIUser>(); 98 rb.PushIpcInterface<MFIUser>(system);
99 } 99 }
100}; 100};
101 101
102class IUser final : public ServiceFramework<IUser> { 102class IUser final : public ServiceFramework<IUser> {
103public: 103public:
104 explicit IUser() : ServiceFramework{"NFC::IUser"} { 104 explicit IUser(Core::System& system_) : ServiceFramework{system_, "NFC::IUser"} {
105 // clang-format off 105 // clang-format off
106 static const FunctionInfo functions[] = { 106 static const FunctionInfo functions[] = {
107 {0, &IUser::InitializeOld, "InitializeOld"}, 107 {0, &IUser::InitializeOld, "InitializeOld"},
@@ -171,7 +171,7 @@ private:
171 171
172class NFC_U final : public ServiceFramework<NFC_U> { 172class NFC_U final : public ServiceFramework<NFC_U> {
173public: 173public:
174 explicit NFC_U() : ServiceFramework{"nfc:user"} { 174 explicit NFC_U(Core::System& system_) : ServiceFramework{system_, "nfc:user"} {
175 // clang-format off 175 // clang-format off
176 static const FunctionInfo functions[] = { 176 static const FunctionInfo functions[] = {
177 {0, &NFC_U::CreateUserInterface, "CreateUserInterface"}, 177 {0, &NFC_U::CreateUserInterface, "CreateUserInterface"},
@@ -187,13 +187,13 @@ private:
187 187
188 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 188 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
189 rb.Push(RESULT_SUCCESS); 189 rb.Push(RESULT_SUCCESS);
190 rb.PushIpcInterface<IUser>(); 190 rb.PushIpcInterface<IUser>(system);
191 } 191 }
192}; 192};
193 193
194class ISystem final : public ServiceFramework<ISystem> { 194class ISystem final : public ServiceFramework<ISystem> {
195public: 195public:
196 explicit ISystem() : ServiceFramework{"ISystem"} { 196 explicit ISystem(Core::System& system_) : ServiceFramework{system_, "ISystem"} {
197 // clang-format off 197 // clang-format off
198 static const FunctionInfo functions[] = { 198 static const FunctionInfo functions[] = {
199 {0, nullptr, "Initialize"}, 199 {0, nullptr, "Initialize"},
@@ -230,7 +230,7 @@ public:
230 230
231class NFC_SYS final : public ServiceFramework<NFC_SYS> { 231class NFC_SYS final : public ServiceFramework<NFC_SYS> {
232public: 232public:
233 explicit NFC_SYS() : ServiceFramework{"nfc:sys"} { 233 explicit NFC_SYS(Core::System& system_) : ServiceFramework{system_, "nfc:sys"} {
234 // clang-format off 234 // clang-format off
235 static const FunctionInfo functions[] = { 235 static const FunctionInfo functions[] = {
236 {0, &NFC_SYS::CreateSystemInterface, "CreateSystemInterface"}, 236 {0, &NFC_SYS::CreateSystemInterface, "CreateSystemInterface"},
@@ -246,15 +246,15 @@ private:
246 246
247 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 247 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
248 rb.Push(RESULT_SUCCESS); 248 rb.Push(RESULT_SUCCESS);
249 rb.PushIpcInterface<ISystem>(); 249 rb.PushIpcInterface<ISystem>(system);
250 } 250 }
251}; 251};
252 252
253void InstallInterfaces(SM::ServiceManager& sm) { 253void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
254 std::make_shared<NFC_AM>()->InstallAsService(sm); 254 std::make_shared<NFC_AM>(system)->InstallAsService(sm);
255 std::make_shared<NFC_MF_U>()->InstallAsService(sm); 255 std::make_shared<NFC_MF_U>(system)->InstallAsService(sm);
256 std::make_shared<NFC_U>()->InstallAsService(sm); 256 std::make_shared<NFC_U>(system)->InstallAsService(sm);
257 std::make_shared<NFC_SYS>()->InstallAsService(sm); 257 std::make_shared<NFC_SYS>(system)->InstallAsService(sm);
258} 258}
259 259
260} // namespace Service::NFC 260} // namespace Service::NFC
diff --git a/src/core/hle/service/nfc/nfc.h b/src/core/hle/service/nfc/nfc.h
index 4d2d815f9..5a94b076d 100644
--- a/src/core/hle/service/nfc/nfc.h
+++ b/src/core/hle/service/nfc/nfc.h
@@ -4,12 +4,16 @@
4 4
5#pragma once 5#pragma once
6 6
7namespace Core {
8class System;
9}
10
7namespace Service::SM { 11namespace Service::SM {
8class ServiceManager; 12class ServiceManager;
9} 13}
10 14
11namespace Service::NFC { 15namespace Service::NFC {
12 16
13void InstallInterfaces(SM::ServiceManager& sm); 17void InstallInterfaces(SM::ServiceManager& sm, Core::System& system);
14 18
15} // namespace Service::NFC 19} // namespace Service::NFC
diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp
index a0469ffbd..5557da72e 100644
--- a/src/core/hle/service/nfp/nfp.cpp
+++ b/src/core/hle/service/nfp/nfp.cpp
@@ -21,8 +21,9 @@ namespace ErrCodes {
21constexpr ResultCode ERR_NO_APPLICATION_AREA(ErrorModule::NFP, 152); 21constexpr ResultCode ERR_NO_APPLICATION_AREA(ErrorModule::NFP, 152);
22} // namespace ErrCodes 22} // namespace ErrCodes
23 23
24Module::Interface::Interface(std::shared_ptr<Module> module, Core::System& system, const char* name) 24Module::Interface::Interface(std::shared_ptr<Module> module_, Core::System& system_,
25 : ServiceFramework(name), module(std::move(module)), system(system) { 25 const char* name)
26 : ServiceFramework{system_, name}, module{std::move(module_)} {
26 auto& kernel = system.Kernel(); 27 auto& kernel = system.Kernel();
27 nfc_tag_load = Kernel::WritableEvent::CreateEventPair(kernel, "IUser:NFCTagDetected"); 28 nfc_tag_load = Kernel::WritableEvent::CreateEventPair(kernel, "IUser:NFCTagDetected");
28} 29}
@@ -31,8 +32,8 @@ Module::Interface::~Interface() = default;
31 32
32class IUser final : public ServiceFramework<IUser> { 33class IUser final : public ServiceFramework<IUser> {
33public: 34public:
34 IUser(Module::Interface& nfp_interface, Core::System& system) 35 explicit IUser(Module::Interface& nfp_interface_, Core::System& system_)
35 : ServiceFramework("NFP::IUser"), nfp_interface(nfp_interface) { 36 : ServiceFramework{system_, "NFP::IUser"}, nfp_interface{nfp_interface_} {
36 static const FunctionInfo functions[] = { 37 static const FunctionInfo functions[] = {
37 {0, &IUser::Initialize, "Initialize"}, 38 {0, &IUser::Initialize, "Initialize"},
38 {1, &IUser::Finalize, "Finalize"}, 39 {1, &IUser::Finalize, "Finalize"},
diff --git a/src/core/hle/service/nfp/nfp.h b/src/core/hle/service/nfp/nfp.h
index 200013795..295de535b 100644
--- a/src/core/hle/service/nfp/nfp.h
+++ b/src/core/hle/service/nfp/nfp.h
@@ -16,7 +16,8 @@ class Module final {
16public: 16public:
17 class Interface : public ServiceFramework<Interface> { 17 class Interface : public ServiceFramework<Interface> {
18 public: 18 public:
19 explicit Interface(std::shared_ptr<Module> module, Core::System& system, const char* name); 19 explicit Interface(std::shared_ptr<Module> module_, Core::System& system_,
20 const char* name);
20 ~Interface() override; 21 ~Interface() override;
21 22
22 struct ModelInfo { 23 struct ModelInfo {
@@ -43,7 +44,6 @@ public:
43 44
44 protected: 45 protected:
45 std::shared_ptr<Module> module; 46 std::shared_ptr<Module> module;
46 Core::System& system;
47 }; 47 };
48}; 48};
49 49
diff --git a/src/core/hle/service/nfp/nfp_user.cpp b/src/core/hle/service/nfp/nfp_user.cpp
index 298184f17..10b0ef944 100644
--- a/src/core/hle/service/nfp/nfp_user.cpp
+++ b/src/core/hle/service/nfp/nfp_user.cpp
@@ -6,8 +6,8 @@
6 6
7namespace Service::NFP { 7namespace Service::NFP {
8 8
9NFP_User::NFP_User(std::shared_ptr<Module> module, Core::System& system) 9NFP_User::NFP_User(std::shared_ptr<Module> module_, Core::System& system_)
10 : Module::Interface(std::move(module), system, "nfp:user") { 10 : Interface(std::move(module_), system_, "nfp:user") {
11 static const FunctionInfo functions[] = { 11 static const FunctionInfo functions[] = {
12 {0, &NFP_User::CreateUserInterface, "CreateUserInterface"}, 12 {0, &NFP_User::CreateUserInterface, "CreateUserInterface"},
13 }; 13 };
diff --git a/src/core/hle/service/nfp/nfp_user.h b/src/core/hle/service/nfp/nfp_user.h
index 1686ebf20..7f3c124f6 100644
--- a/src/core/hle/service/nfp/nfp_user.h
+++ b/src/core/hle/service/nfp/nfp_user.h
@@ -10,7 +10,7 @@ namespace Service::NFP {
10 10
11class NFP_User final : public Module::Interface { 11class NFP_User final : public Module::Interface {
12public: 12public:
13 explicit NFP_User(std::shared_ptr<Module> module, Core::System& system); 13 explicit NFP_User(std::shared_ptr<Module> module_, Core::System& system_);
14 ~NFP_User() override; 14 ~NFP_User() override;
15}; 15};
16 16
diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp
index 2e9d95195..ef5176bea 100644
--- a/src/core/hle/service/nifm/nifm.cpp
+++ b/src/core/hle/service/nifm/nifm.cpp
@@ -23,7 +23,7 @@ enum class RequestState : u32 {
23 23
24class IScanRequest final : public ServiceFramework<IScanRequest> { 24class IScanRequest final : public ServiceFramework<IScanRequest> {
25public: 25public:
26 explicit IScanRequest() : ServiceFramework("IScanRequest") { 26 explicit IScanRequest(Core::System& system_) : ServiceFramework{system_, "IScanRequest"} {
27 // clang-format off 27 // clang-format off
28 static const FunctionInfo functions[] = { 28 static const FunctionInfo functions[] = {
29 {0, nullptr, "Submit"}, 29 {0, nullptr, "Submit"},
@@ -40,7 +40,7 @@ public:
40 40
41class IRequest final : public ServiceFramework<IRequest> { 41class IRequest final : public ServiceFramework<IRequest> {
42public: 42public:
43 explicit IRequest(Core::System& system) : ServiceFramework("IRequest") { 43 explicit IRequest(Core::System& system_) : ServiceFramework{system_, "IRequest"} {
44 static const FunctionInfo functions[] = { 44 static const FunctionInfo functions[] = {
45 {0, &IRequest::GetRequestState, "GetRequestState"}, 45 {0, &IRequest::GetRequestState, "GetRequestState"},
46 {1, &IRequest::GetResult, "GetResult"}, 46 {1, &IRequest::GetResult, "GetResult"},
@@ -62,7 +62,7 @@ public:
62 {18, nullptr, "SetRequirementByRevision"}, 62 {18, nullptr, "SetRequirementByRevision"},
63 {19, nullptr, "GetRequirement"}, 63 {19, nullptr, "GetRequirement"},
64 {20, nullptr, "GetRevision"}, 64 {20, nullptr, "GetRevision"},
65 {21, nullptr, "GetAppletInfo"}, 65 {21, &IRequest::GetAppletInfo, "GetAppletInfo"},
66 {22, nullptr, "GetAdditionalInfo"}, 66 {22, nullptr, "GetAdditionalInfo"},
67 {23, nullptr, "SetKeptInSleep"}, 67 {23, nullptr, "SetKeptInSleep"},
68 {24, nullptr, "RegisterSocketDescriptor"}, 68 {24, nullptr, "RegisterSocketDescriptor"},
@@ -125,12 +125,22 @@ private:
125 rb.Push(RESULT_SUCCESS); 125 rb.Push(RESULT_SUCCESS);
126 } 126 }
127 127
128 void GetAppletInfo(Kernel::HLERequestContext& ctx) {
129 LOG_WARNING(Service_NIFM, "(STUBBED) called");
130
131 IPC::ResponseBuilder rb{ctx, 8};
132 rb.Push(RESULT_SUCCESS);
133 rb.Push<u32>(0);
134 rb.Push<u32>(0);
135 rb.Push<u32>(0);
136 }
137
128 Kernel::EventPair event1, event2; 138 Kernel::EventPair event1, event2;
129}; 139};
130 140
131class INetworkProfile final : public ServiceFramework<INetworkProfile> { 141class INetworkProfile final : public ServiceFramework<INetworkProfile> {
132public: 142public:
133 explicit INetworkProfile() : ServiceFramework("INetworkProfile") { 143 explicit INetworkProfile(Core::System& system_) : ServiceFramework{system_, "INetworkProfile"} {
134 static const FunctionInfo functions[] = { 144 static const FunctionInfo functions[] = {
135 {0, nullptr, "Update"}, 145 {0, nullptr, "Update"},
136 {1, nullptr, "PersistOld"}, 146 {1, nullptr, "PersistOld"},
@@ -142,7 +152,7 @@ public:
142 152
143class IGeneralService final : public ServiceFramework<IGeneralService> { 153class IGeneralService final : public ServiceFramework<IGeneralService> {
144public: 154public:
145 IGeneralService(Core::System& system); 155 explicit IGeneralService(Core::System& system_);
146 156
147private: 157private:
148 void GetClientId(Kernel::HLERequestContext& ctx) { 158 void GetClientId(Kernel::HLERequestContext& ctx) {
@@ -159,7 +169,7 @@ private:
159 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 169 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
160 170
161 rb.Push(RESULT_SUCCESS); 171 rb.Push(RESULT_SUCCESS);
162 rb.PushIpcInterface<IScanRequest>(); 172 rb.PushIpcInterface<IScanRequest>(system);
163 } 173 }
164 void CreateRequest(Kernel::HLERequestContext& ctx) { 174 void CreateRequest(Kernel::HLERequestContext& ctx) {
165 LOG_DEBUG(Service_NIFM, "called"); 175 LOG_DEBUG(Service_NIFM, "called");
@@ -197,7 +207,7 @@ private:
197 IPC::ResponseBuilder rb{ctx, 6, 0, 1}; 207 IPC::ResponseBuilder rb{ctx, 6, 0, 1};
198 208
199 rb.Push(RESULT_SUCCESS); 209 rb.Push(RESULT_SUCCESS);
200 rb.PushIpcInterface<INetworkProfile>(); 210 rb.PushIpcInterface<INetworkProfile>(system);
201 rb.PushRaw<u128>(uuid); 211 rb.PushRaw<u128>(uuid);
202 } 212 }
203 void IsWirelessCommunicationEnabled(Kernel::HLERequestContext& ctx) { 213 void IsWirelessCommunicationEnabled(Kernel::HLERequestContext& ctx) {
@@ -229,11 +239,10 @@ private:
229 rb.Push<u8>(1); 239 rb.Push<u8>(1);
230 } 240 }
231 } 241 }
232 Core::System& system;
233}; 242};
234 243
235IGeneralService::IGeneralService(Core::System& system) 244IGeneralService::IGeneralService(Core::System& system_)
236 : ServiceFramework("IGeneralService"), system(system) { 245 : ServiceFramework{system_, "IGeneralService"} {
237 // clang-format off 246 // clang-format off
238 static const FunctionInfo functions[] = { 247 static const FunctionInfo functions[] = {
239 {1, &IGeneralService::GetClientId, "GetClientId"}, 248 {1, &IGeneralService::GetClientId, "GetClientId"},
@@ -286,8 +295,8 @@ IGeneralService::IGeneralService(Core::System& system)
286 295
287class NetworkInterface final : public ServiceFramework<NetworkInterface> { 296class NetworkInterface final : public ServiceFramework<NetworkInterface> {
288public: 297public:
289 explicit NetworkInterface(const char* name, Core::System& system) 298 explicit NetworkInterface(const char* name, Core::System& system_)
290 : ServiceFramework{name}, system(system) { 299 : ServiceFramework{system_, name} {
291 static const FunctionInfo functions[] = { 300 static const FunctionInfo functions[] = {
292 {4, &NetworkInterface::CreateGeneralServiceOld, "CreateGeneralServiceOld"}, 301 {4, &NetworkInterface::CreateGeneralServiceOld, "CreateGeneralServiceOld"},
293 {5, &NetworkInterface::CreateGeneralService, "CreateGeneralService"}, 302 {5, &NetworkInterface::CreateGeneralService, "CreateGeneralService"},
@@ -295,6 +304,7 @@ public:
295 RegisterHandlers(functions); 304 RegisterHandlers(functions);
296 } 305 }
297 306
307private:
298 void CreateGeneralServiceOld(Kernel::HLERequestContext& ctx) { 308 void CreateGeneralServiceOld(Kernel::HLERequestContext& ctx) {
299 LOG_DEBUG(Service_NIFM, "called"); 309 LOG_DEBUG(Service_NIFM, "called");
300 310
@@ -310,9 +320,6 @@ public:
310 rb.Push(RESULT_SUCCESS); 320 rb.Push(RESULT_SUCCESS);
311 rb.PushIpcInterface<IGeneralService>(system); 321 rb.PushIpcInterface<IGeneralService>(system);
312 } 322 }
313
314private:
315 Core::System& system;
316}; 323};
317 324
318void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { 325void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
diff --git a/src/core/hle/service/nifm/nifm.h b/src/core/hle/service/nifm/nifm.h
index 6857e18f9..c3dd4f386 100644
--- a/src/core/hle/service/nifm/nifm.h
+++ b/src/core/hle/service/nifm/nifm.h
@@ -4,14 +4,14 @@
4 4
5#pragma once 5#pragma once
6 6
7namespace Service::SM {
8class ServiceManager;
9}
10
11namespace Core { 7namespace Core {
12class System; 8class System;
13} 9}
14 10
11namespace Service::SM {
12class ServiceManager;
13}
14
15namespace Service::NIFM { 15namespace Service::NIFM {
16 16
17/// Registers all NIFM services with the specified service manager. 17/// Registers all NIFM services with the specified service manager.
diff --git a/src/core/hle/service/nim/nim.cpp b/src/core/hle/service/nim/nim.cpp
index 11aa74828..d16223064 100644
--- a/src/core/hle/service/nim/nim.cpp
+++ b/src/core/hle/service/nim/nim.cpp
@@ -17,7 +17,8 @@ namespace Service::NIM {
17 17
18class IShopServiceAsync final : public ServiceFramework<IShopServiceAsync> { 18class IShopServiceAsync final : public ServiceFramework<IShopServiceAsync> {
19public: 19public:
20 IShopServiceAsync() : ServiceFramework("IShopServiceAsync") { 20 explicit IShopServiceAsync(Core::System& system_)
21 : ServiceFramework{system_, "IShopServiceAsync"} {
21 // clang-format off 22 // clang-format off
22 static const FunctionInfo functions[] = { 23 static const FunctionInfo functions[] = {
23 {0, nullptr, "Cancel"}, 24 {0, nullptr, "Cancel"},
@@ -35,7 +36,8 @@ public:
35 36
36class IShopServiceAccessor final : public ServiceFramework<IShopServiceAccessor> { 37class IShopServiceAccessor final : public ServiceFramework<IShopServiceAccessor> {
37public: 38public:
38 IShopServiceAccessor() : ServiceFramework("IShopServiceAccessor") { 39 explicit IShopServiceAccessor(Core::System& system_)
40 : ServiceFramework{system_, "IShopServiceAccessor"} {
39 // clang-format off 41 // clang-format off
40 static const FunctionInfo functions[] = { 42 static const FunctionInfo functions[] = {
41 {0, &IShopServiceAccessor::CreateAsyncInterface, "CreateAsyncInterface"}, 43 {0, &IShopServiceAccessor::CreateAsyncInterface, "CreateAsyncInterface"},
@@ -50,13 +52,14 @@ private:
50 LOG_WARNING(Service_NIM, "(STUBBED) called"); 52 LOG_WARNING(Service_NIM, "(STUBBED) called");
51 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 53 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
52 rb.Push(RESULT_SUCCESS); 54 rb.Push(RESULT_SUCCESS);
53 rb.PushIpcInterface<IShopServiceAsync>(); 55 rb.PushIpcInterface<IShopServiceAsync>(system);
54 } 56 }
55}; 57};
56 58
57class IShopServiceAccessServer final : public ServiceFramework<IShopServiceAccessServer> { 59class IShopServiceAccessServer final : public ServiceFramework<IShopServiceAccessServer> {
58public: 60public:
59 IShopServiceAccessServer() : ServiceFramework("IShopServiceAccessServer") { 61 explicit IShopServiceAccessServer(Core::System& system_)
62 : ServiceFramework{system_, "IShopServiceAccessServer"} {
60 // clang-format off 63 // clang-format off
61 static const FunctionInfo functions[] = { 64 static const FunctionInfo functions[] = {
62 {0, &IShopServiceAccessServer::CreateAccessorInterface, "CreateAccessorInterface"}, 65 {0, &IShopServiceAccessServer::CreateAccessorInterface, "CreateAccessorInterface"},
@@ -71,13 +74,13 @@ private:
71 LOG_WARNING(Service_NIM, "(STUBBED) called"); 74 LOG_WARNING(Service_NIM, "(STUBBED) called");
72 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 75 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
73 rb.Push(RESULT_SUCCESS); 76 rb.Push(RESULT_SUCCESS);
74 rb.PushIpcInterface<IShopServiceAccessor>(); 77 rb.PushIpcInterface<IShopServiceAccessor>(system);
75 } 78 }
76}; 79};
77 80
78class NIM final : public ServiceFramework<NIM> { 81class NIM final : public ServiceFramework<NIM> {
79public: 82public:
80 explicit NIM() : ServiceFramework{"nim"} { 83 explicit NIM(Core::System& system_) : ServiceFramework{system_, "nim"} {
81 // clang-format off 84 // clang-format off
82 static const FunctionInfo functions[] = { 85 static const FunctionInfo functions[] = {
83 {0, nullptr, "CreateSystemUpdateTask"}, 86 {0, nullptr, "CreateSystemUpdateTask"},
@@ -207,14 +210,14 @@ public:
207 210
208class NIM_ECA final : public ServiceFramework<NIM_ECA> { 211class NIM_ECA final : public ServiceFramework<NIM_ECA> {
209public: 212public:
210 explicit NIM_ECA() : ServiceFramework{"nim:eca"} { 213 explicit NIM_ECA(Core::System& system_) : ServiceFramework{system_, "nim:eca"} {
211 // clang-format off 214 // clang-format off
212 static const FunctionInfo functions[] = { 215 static const FunctionInfo functions[] = {
213 {0, &NIM_ECA::CreateServerInterface, "CreateServerInterface"}, 216 {0, &NIM_ECA::CreateServerInterface, "CreateServerInterface"},
214 {1, nullptr, "RefreshDebugAvailability"}, 217 {1, nullptr, "RefreshDebugAvailability"},
215 {2, nullptr, "ClearDebugResponse"}, 218 {2, nullptr, "ClearDebugResponse"},
216 {3, nullptr, "RegisterDebugResponse"}, 219 {3, nullptr, "RegisterDebugResponse"},
217 {4, nullptr, "IsLargeResourceAvailable"}, 220 {4, &NIM_ECA::IsLargeResourceAvailable, "IsLargeResourceAvailable"},
218 }; 221 };
219 // clang-format on 222 // clang-format on
220 223
@@ -226,13 +229,25 @@ private:
226 LOG_WARNING(Service_NIM, "(STUBBED) called"); 229 LOG_WARNING(Service_NIM, "(STUBBED) called");
227 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 230 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
228 rb.Push(RESULT_SUCCESS); 231 rb.Push(RESULT_SUCCESS);
229 rb.PushIpcInterface<IShopServiceAccessServer>(); 232 rb.PushIpcInterface<IShopServiceAccessServer>(system);
233 }
234
235 void IsLargeResourceAvailable(Kernel::HLERequestContext& ctx) {
236 IPC::RequestParser rp{ctx};
237
238 const auto unknown{rp.Pop<u64>()};
239
240 LOG_INFO(Service_NIM, "(STUBBED) called, unknown={}", unknown);
241
242 IPC::ResponseBuilder rb{ctx, 3};
243 rb.Push(RESULT_SUCCESS);
244 rb.Push(false);
230 } 245 }
231}; 246};
232 247
233class NIM_SHP final : public ServiceFramework<NIM_SHP> { 248class NIM_SHP final : public ServiceFramework<NIM_SHP> {
234public: 249public:
235 explicit NIM_SHP() : ServiceFramework{"nim:shp"} { 250 explicit NIM_SHP(Core::System& system_) : ServiceFramework{system_, "nim:shp"} {
236 // clang-format off 251 // clang-format off
237 static const FunctionInfo functions[] = { 252 static const FunctionInfo functions[] = {
238 {0, nullptr, "RequestDeviceAuthenticationToken"}, 253 {0, nullptr, "RequestDeviceAuthenticationToken"},
@@ -272,8 +287,8 @@ public:
272class IEnsureNetworkClockAvailabilityService final 287class IEnsureNetworkClockAvailabilityService final
273 : public ServiceFramework<IEnsureNetworkClockAvailabilityService> { 288 : public ServiceFramework<IEnsureNetworkClockAvailabilityService> {
274public: 289public:
275 explicit IEnsureNetworkClockAvailabilityService(Core::System& system) 290 explicit IEnsureNetworkClockAvailabilityService(Core::System& system_)
276 : ServiceFramework("IEnsureNetworkClockAvailabilityService") { 291 : ServiceFramework{system_, "IEnsureNetworkClockAvailabilityService"} {
277 static const FunctionInfo functions[] = { 292 static const FunctionInfo functions[] = {
278 {0, &IEnsureNetworkClockAvailabilityService::StartTask, "StartTask"}, 293 {0, &IEnsureNetworkClockAvailabilityService::StartTask, "StartTask"},
279 {1, &IEnsureNetworkClockAvailabilityService::GetFinishNotificationEvent, 294 {1, &IEnsureNetworkClockAvailabilityService::GetFinishNotificationEvent,
@@ -345,7 +360,7 @@ private:
345 360
346class NTC final : public ServiceFramework<NTC> { 361class NTC final : public ServiceFramework<NTC> {
347public: 362public:
348 explicit NTC(Core::System& system) : ServiceFramework{"ntc"}, system(system) { 363 explicit NTC(Core::System& system_) : ServiceFramework{system_, "ntc"} {
349 // clang-format off 364 // clang-format off
350 static const FunctionInfo functions[] = { 365 static const FunctionInfo functions[] = {
351 {0, &NTC::OpenEnsureNetworkClockAvailabilityService, "OpenEnsureNetworkClockAvailabilityService"}, 366 {0, &NTC::OpenEnsureNetworkClockAvailabilityService, "OpenEnsureNetworkClockAvailabilityService"},
@@ -380,13 +395,12 @@ private:
380 IPC::ResponseBuilder rb{ctx, 2}; 395 IPC::ResponseBuilder rb{ctx, 2};
381 rb.Push(RESULT_SUCCESS); 396 rb.Push(RESULT_SUCCESS);
382 } 397 }
383 Core::System& system;
384}; 398};
385 399
386void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) { 400void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
387 std::make_shared<NIM>()->InstallAsService(sm); 401 std::make_shared<NIM>(system)->InstallAsService(sm);
388 std::make_shared<NIM_ECA>()->InstallAsService(sm); 402 std::make_shared<NIM_ECA>(system)->InstallAsService(sm);
389 std::make_shared<NIM_SHP>()->InstallAsService(sm); 403 std::make_shared<NIM_SHP>(system)->InstallAsService(sm);
390 std::make_shared<NTC>(system)->InstallAsService(sm); 404 std::make_shared<NTC>(system)->InstallAsService(sm);
391} 405}
392 406
diff --git a/src/core/hle/service/nim/nim.h b/src/core/hle/service/nim/nim.h
index dbe25dc01..571153fe6 100644
--- a/src/core/hle/service/nim/nim.h
+++ b/src/core/hle/service/nim/nim.h
@@ -4,14 +4,14 @@
4 4
5#pragma once 5#pragma once
6 6
7namespace Service::SM {
8class ServiceManager;
9}
10
11namespace Core { 7namespace Core {
12class System; 8class System;
13} 9}
14 10
11namespace Service::SM {
12class ServiceManager;
13}
14
15namespace Service::NIM { 15namespace Service::NIM {
16 16
17void InstallInterfaces(SM::ServiceManager& sm, Core::System& system); 17void InstallInterfaces(SM::ServiceManager& sm, Core::System& system);
diff --git a/src/core/hle/service/npns/npns.cpp b/src/core/hle/service/npns/npns.cpp
index 8fa16fb08..f7a58f659 100644
--- a/src/core/hle/service/npns/npns.cpp
+++ b/src/core/hle/service/npns/npns.cpp
@@ -12,7 +12,7 @@ namespace Service::NPNS {
12 12
13class NPNS_S final : public ServiceFramework<NPNS_S> { 13class NPNS_S final : public ServiceFramework<NPNS_S> {
14public: 14public:
15 explicit NPNS_S() : ServiceFramework{"npns:s"} { 15 explicit NPNS_S(Core::System& system_) : ServiceFramework{system_, "npns:s"} {
16 // clang-format off 16 // clang-format off
17 static const FunctionInfo functions[] = { 17 static const FunctionInfo functions[] = {
18 {1, nullptr, "ListenAll"}, 18 {1, nullptr, "ListenAll"},
@@ -62,7 +62,7 @@ public:
62 62
63class NPNS_U final : public ServiceFramework<NPNS_U> { 63class NPNS_U final : public ServiceFramework<NPNS_U> {
64public: 64public:
65 explicit NPNS_U() : ServiceFramework{"npns:u"} { 65 explicit NPNS_U(Core::System& system_) : ServiceFramework{system_, "npns:u"} {
66 // clang-format off 66 // clang-format off
67 static const FunctionInfo functions[] = { 67 static const FunctionInfo functions[] = {
68 {1, nullptr, "ListenAll"}, 68 {1, nullptr, "ListenAll"},
@@ -91,9 +91,9 @@ public:
91 } 91 }
92}; 92};
93 93
94void InstallInterfaces(SM::ServiceManager& sm) { 94void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
95 std::make_shared<NPNS_S>()->InstallAsService(sm); 95 std::make_shared<NPNS_S>(system)->InstallAsService(sm);
96 std::make_shared<NPNS_U>()->InstallAsService(sm); 96 std::make_shared<NPNS_U>(system)->InstallAsService(sm);
97} 97}
98 98
99} // namespace Service::NPNS 99} // namespace Service::NPNS
diff --git a/src/core/hle/service/npns/npns.h b/src/core/hle/service/npns/npns.h
index 861cd3e48..3b7596b6b 100644
--- a/src/core/hle/service/npns/npns.h
+++ b/src/core/hle/service/npns/npns.h
@@ -4,12 +4,16 @@
4 4
5#pragma once 5#pragma once
6 6
7namespace Core {
8class System;
9}
10
7namespace Service::SM { 11namespace Service::SM {
8class ServiceManager; 12class ServiceManager;
9} 13}
10 14
11namespace Service::NPNS { 15namespace Service::NPNS {
12 16
13void InstallInterfaces(SM::ServiceManager& sm); 17void InstallInterfaces(SM::ServiceManager& sm, Core::System& system);
14 18
15} // namespace Service::NPNS 19} // namespace Service::NPNS
diff --git a/src/core/hle/service/ns/ns.cpp b/src/core/hle/service/ns/ns.cpp
index 58ee1f712..6ccf8995c 100644
--- a/src/core/hle/service/ns/ns.cpp
+++ b/src/core/hle/service/ns/ns.cpp
@@ -3,6 +3,7 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/logging/log.h" 5#include "common/logging/log.h"
6#include "core/core.h"
6#include "core/file_sys/control_metadata.h" 7#include "core/file_sys/control_metadata.h"
7#include "core/file_sys/patch_manager.h" 8#include "core/file_sys/patch_manager.h"
8#include "core/file_sys/vfs.h" 9#include "core/file_sys/vfs.h"
@@ -17,7 +18,8 @@
17 18
18namespace Service::NS { 19namespace Service::NS {
19 20
20IAccountProxyInterface::IAccountProxyInterface() : ServiceFramework{"IAccountProxyInterface"} { 21IAccountProxyInterface::IAccountProxyInterface(Core::System& system_)
22 : ServiceFramework{system_, "IAccountProxyInterface"} {
21 // clang-format off 23 // clang-format off
22 static const FunctionInfo functions[] = { 24 static const FunctionInfo functions[] = {
23 {0, nullptr, "CreateUserAccount"}, 25 {0, nullptr, "CreateUserAccount"},
@@ -29,8 +31,8 @@ IAccountProxyInterface::IAccountProxyInterface() : ServiceFramework{"IAccountPro
29 31
30IAccountProxyInterface::~IAccountProxyInterface() = default; 32IAccountProxyInterface::~IAccountProxyInterface() = default;
31 33
32IApplicationManagerInterface::IApplicationManagerInterface() 34IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_)
33 : ServiceFramework{"IApplicationManagerInterface"} { 35 : ServiceFramework{system_, "IApplicationManagerInterface"} {
34 // clang-format off 36 // clang-format off
35 static const FunctionInfo functions[] = { 37 static const FunctionInfo functions[] = {
36 {0, nullptr, "ListApplicationRecord"}, 38 {0, nullptr, "ListApplicationRecord"},
@@ -298,7 +300,8 @@ void IApplicationManagerInterface::GetApplicationControlData(Kernel::HLERequestC
298 300
299 const auto size = ctx.GetWriteBufferSize(); 301 const auto size = ctx.GetWriteBufferSize();
300 302
301 const FileSys::PatchManager pm{title_id}; 303 const FileSys::PatchManager pm{title_id, system.GetFileSystemController(),
304 system.GetContentProvider()};
302 const auto control = pm.GetControlMetadata(); 305 const auto control = pm.GetControlMetadata();
303 306
304 std::vector<u8> out; 307 std::vector<u8> out;
@@ -426,8 +429,8 @@ ResultVal<u64> IApplicationManagerInterface::ConvertApplicationLanguageToLanguag
426 return MakeResult(static_cast<u64>(*language_code)); 429 return MakeResult(static_cast<u64>(*language_code));
427} 430}
428 431
429IApplicationVersionInterface::IApplicationVersionInterface() 432IApplicationVersionInterface::IApplicationVersionInterface(Core::System& system_)
430 : ServiceFramework{"IApplicationVersionInterface"} { 433 : ServiceFramework{system_, "IApplicationVersionInterface"} {
431 // clang-format off 434 // clang-format off
432 static const FunctionInfo functions[] = { 435 static const FunctionInfo functions[] = {
433 {0, nullptr, "GetLaunchRequiredVersion"}, 436 {0, nullptr, "GetLaunchRequiredVersion"},
@@ -447,8 +450,8 @@ IApplicationVersionInterface::IApplicationVersionInterface()
447 450
448IApplicationVersionInterface::~IApplicationVersionInterface() = default; 451IApplicationVersionInterface::~IApplicationVersionInterface() = default;
449 452
450IContentManagementInterface::IContentManagementInterface() 453IContentManagementInterface::IContentManagementInterface(Core::System& system_)
451 : ServiceFramework{"IContentManagementInterface"} { 454 : ServiceFramework{system_, "IContentManagementInterface"} {
452 // clang-format off 455 // clang-format off
453 static const FunctionInfo functions[] = { 456 static const FunctionInfo functions[] = {
454 {11, nullptr, "CalculateApplicationOccupiedSize"}, 457 {11, nullptr, "CalculateApplicationOccupiedSize"},
@@ -467,7 +470,8 @@ IContentManagementInterface::IContentManagementInterface()
467 470
468IContentManagementInterface::~IContentManagementInterface() = default; 471IContentManagementInterface::~IContentManagementInterface() = default;
469 472
470IDocumentInterface::IDocumentInterface() : ServiceFramework{"IDocumentInterface"} { 473IDocumentInterface::IDocumentInterface(Core::System& system_)
474 : ServiceFramework{system_, "IDocumentInterface"} {
471 // clang-format off 475 // clang-format off
472 static const FunctionInfo functions[] = { 476 static const FunctionInfo functions[] = {
473 {21, nullptr, "GetApplicationContentPath"}, 477 {21, nullptr, "GetApplicationContentPath"},
@@ -481,7 +485,8 @@ IDocumentInterface::IDocumentInterface() : ServiceFramework{"IDocumentInterface"
481 485
482IDocumentInterface::~IDocumentInterface() = default; 486IDocumentInterface::~IDocumentInterface() = default;
483 487
484IDownloadTaskInterface::IDownloadTaskInterface() : ServiceFramework{"IDownloadTaskInterface"} { 488IDownloadTaskInterface::IDownloadTaskInterface(Core::System& system_)
489 : ServiceFramework{system_, "IDownloadTaskInterface"} {
485 // clang-format off 490 // clang-format off
486 static const FunctionInfo functions[] = { 491 static const FunctionInfo functions[] = {
487 {701, nullptr, "ClearTaskStatusList"}, 492 {701, nullptr, "ClearTaskStatusList"},
@@ -501,7 +506,8 @@ IDownloadTaskInterface::IDownloadTaskInterface() : ServiceFramework{"IDownloadTa
501 506
502IDownloadTaskInterface::~IDownloadTaskInterface() = default; 507IDownloadTaskInterface::~IDownloadTaskInterface() = default;
503 508
504IECommerceInterface::IECommerceInterface() : ServiceFramework{"IECommerceInterface"} { 509IECommerceInterface::IECommerceInterface(Core::System& system_)
510 : ServiceFramework{system_, "IECommerceInterface"} {
505 // clang-format off 511 // clang-format off
506 static const FunctionInfo functions[] = { 512 static const FunctionInfo functions[] = {
507 {0, nullptr, "RequestLinkDevice"}, 513 {0, nullptr, "RequestLinkDevice"},
@@ -519,8 +525,8 @@ IECommerceInterface::IECommerceInterface() : ServiceFramework{"IECommerceInterfa
519 525
520IECommerceInterface::~IECommerceInterface() = default; 526IECommerceInterface::~IECommerceInterface() = default;
521 527
522IFactoryResetInterface::IFactoryResetInterface::IFactoryResetInterface() 528IFactoryResetInterface::IFactoryResetInterface(Core::System& system_)
523 : ServiceFramework{"IFactoryResetInterface"} { 529 : ServiceFramework{system_, "IFactoryResetInterface"} {
524 // clang-format off 530 // clang-format off
525 static const FunctionInfo functions[] = { 531 static const FunctionInfo functions[] = {
526 {100, nullptr, "ResetToFactorySettings"}, 532 {100, nullptr, "ResetToFactorySettings"},
@@ -538,14 +544,14 @@ IFactoryResetInterface::IFactoryResetInterface::IFactoryResetInterface()
538 544
539IFactoryResetInterface::~IFactoryResetInterface() = default; 545IFactoryResetInterface::~IFactoryResetInterface() = default;
540 546
541NS::NS(const char* name) : ServiceFramework{name} { 547NS::NS(const char* name, Core::System& system_) : ServiceFramework{system_, name} {
542 // clang-format off 548 // clang-format off
543 static const FunctionInfo functions[] = { 549 static const FunctionInfo functions[] = {
544 {7992, &NS::PushInterface<IECommerceInterface>, "GetECommerceInterface"}, 550 {7992, &NS::PushInterface<IECommerceInterface>, "GetECommerceInterface"},
545 {7993, &NS::PushInterface<IApplicationVersionInterface>, "GetApplicationVersionInterface"}, 551 {7993, &NS::PushInterface<IApplicationVersionInterface>, "GetApplicationVersionInterface"},
546 {7994, &NS::PushInterface<IFactoryResetInterface>, "GetFactoryResetInterface"}, 552 {7994, &NS::PushInterface<IFactoryResetInterface>, "GetFactoryResetInterface"},
547 {7995, &NS::PushInterface<IAccountProxyInterface>, "GetAccountProxyInterface"}, 553 {7995, &NS::PushInterface<IAccountProxyInterface>, "GetAccountProxyInterface"},
548 {7996, &NS::PushInterface<IApplicationManagerInterface>, "GetApplicationManagerInterface"}, 554 {7996, &NS::PushIApplicationManagerInterface, "GetApplicationManagerInterface"},
549 {7997, &NS::PushInterface<IDownloadTaskInterface>, "GetDownloadTaskInterface"}, 555 {7997, &NS::PushInterface<IDownloadTaskInterface>, "GetDownloadTaskInterface"},
550 {7998, &NS::PushInterface<IContentManagementInterface>, "GetContentManagementInterface"}, 556 {7998, &NS::PushInterface<IContentManagementInterface>, "GetContentManagementInterface"},
551 {7999, &NS::PushInterface<IDocumentInterface>, "GetDocumentInterface"}, 557 {7999, &NS::PushInterface<IDocumentInterface>, "GetDocumentInterface"},
@@ -558,12 +564,12 @@ NS::NS(const char* name) : ServiceFramework{name} {
558NS::~NS() = default; 564NS::~NS() = default;
559 565
560std::shared_ptr<IApplicationManagerInterface> NS::GetApplicationManagerInterface() const { 566std::shared_ptr<IApplicationManagerInterface> NS::GetApplicationManagerInterface() const {
561 return GetInterface<IApplicationManagerInterface>(); 567 return GetInterface<IApplicationManagerInterface>(system);
562} 568}
563 569
564class NS_DEV final : public ServiceFramework<NS_DEV> { 570class NS_DEV final : public ServiceFramework<NS_DEV> {
565public: 571public:
566 explicit NS_DEV() : ServiceFramework{"ns:dev"} { 572 explicit NS_DEV(Core::System& system_) : ServiceFramework{system_, "ns:dev"} {
567 // clang-format off 573 // clang-format off
568 static const FunctionInfo functions[] = { 574 static const FunctionInfo functions[] = {
569 {0, nullptr, "LaunchProgram"}, 575 {0, nullptr, "LaunchProgram"},
@@ -590,7 +596,8 @@ public:
590 596
591class ISystemUpdateControl final : public ServiceFramework<ISystemUpdateControl> { 597class ISystemUpdateControl final : public ServiceFramework<ISystemUpdateControl> {
592public: 598public:
593 explicit ISystemUpdateControl() : ServiceFramework{"ISystemUpdateControl"} { 599 explicit ISystemUpdateControl(Core::System& system_)
600 : ServiceFramework{system_, "ISystemUpdateControl"} {
594 // clang-format off 601 // clang-format off
595 static const FunctionInfo functions[] = { 602 static const FunctionInfo functions[] = {
596 {0, nullptr, "HasDownloaded"}, 603 {0, nullptr, "HasDownloaded"},
@@ -625,7 +632,7 @@ public:
625 632
626class NS_SU final : public ServiceFramework<NS_SU> { 633class NS_SU final : public ServiceFramework<NS_SU> {
627public: 634public:
628 explicit NS_SU() : ServiceFramework{"ns:su"} { 635 explicit NS_SU(Core::System& system_) : ServiceFramework{system_, "ns:su"} {
629 // clang-format off 636 // clang-format off
630 static const FunctionInfo functions[] = { 637 static const FunctionInfo functions[] = {
631 {0, nullptr, "GetBackgroundNetworkUpdateState"}, 638 {0, nullptr, "GetBackgroundNetworkUpdateState"},
@@ -657,16 +664,16 @@ private:
657 664
658 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 665 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
659 rb.Push(RESULT_SUCCESS); 666 rb.Push(RESULT_SUCCESS);
660 rb.PushIpcInterface<ISystemUpdateControl>(); 667 rb.PushIpcInterface<ISystemUpdateControl>(system);
661 } 668 }
662}; 669};
663 670
664class NS_VM final : public ServiceFramework<NS_VM> { 671class NS_VM final : public ServiceFramework<NS_VM> {
665public: 672public:
666 explicit NS_VM() : ServiceFramework{"ns:vm"} { 673 explicit NS_VM(Core::System& system_) : ServiceFramework{system_, "ns:vm"} {
667 // clang-format off 674 // clang-format off
668 static const FunctionInfo functions[] = { 675 static const FunctionInfo functions[] = {
669 {1200, nullptr, "NeedsUpdateVulnerability"}, 676 {1200, &NS_VM::NeedsUpdateVulnerability, "NeedsUpdateVulnerability"},
670 {1201, nullptr, "UpdateSafeSystemVersionForDebug"}, 677 {1201, nullptr, "UpdateSafeSystemVersionForDebug"},
671 {1202, nullptr, "GetSafeSystemVersion"}, 678 {1202, nullptr, "GetSafeSystemVersion"},
672 }; 679 };
@@ -674,19 +681,28 @@ public:
674 681
675 RegisterHandlers(functions); 682 RegisterHandlers(functions);
676 } 683 }
684
685private:
686 void NeedsUpdateVulnerability(Kernel::HLERequestContext& ctx) {
687 LOG_WARNING(Service_NS, "(STUBBED) called");
688
689 IPC::ResponseBuilder rb{ctx, 3};
690 rb.Push(RESULT_SUCCESS);
691 rb.Push(false);
692 }
677}; 693};
678 694
679void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { 695void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
680 696
681 std::make_shared<NS>("ns:am2")->InstallAsService(service_manager); 697 std::make_shared<NS>("ns:am2", system)->InstallAsService(service_manager);
682 std::make_shared<NS>("ns:ec")->InstallAsService(service_manager); 698 std::make_shared<NS>("ns:ec", system)->InstallAsService(service_manager);
683 std::make_shared<NS>("ns:rid")->InstallAsService(service_manager); 699 std::make_shared<NS>("ns:rid", system)->InstallAsService(service_manager);
684 std::make_shared<NS>("ns:rt")->InstallAsService(service_manager); 700 std::make_shared<NS>("ns:rt", system)->InstallAsService(service_manager);
685 std::make_shared<NS>("ns:web")->InstallAsService(service_manager); 701 std::make_shared<NS>("ns:web", system)->InstallAsService(service_manager);
686 702
687 std::make_shared<NS_DEV>()->InstallAsService(service_manager); 703 std::make_shared<NS_DEV>(system)->InstallAsService(service_manager);
688 std::make_shared<NS_SU>()->InstallAsService(service_manager); 704 std::make_shared<NS_SU>(system)->InstallAsService(service_manager);
689 std::make_shared<NS_VM>()->InstallAsService(service_manager); 705 std::make_shared<NS_VM>(system)->InstallAsService(service_manager);
690 706
691 std::make_shared<PL_U>(system)->InstallAsService(service_manager); 707 std::make_shared<PL_U>(system)->InstallAsService(service_manager);
692} 708}
diff --git a/src/core/hle/service/ns/ns.h b/src/core/hle/service/ns/ns.h
index c2554b878..991271f3e 100644
--- a/src/core/hle/service/ns/ns.h
+++ b/src/core/hle/service/ns/ns.h
@@ -6,6 +6,10 @@
6 6
7#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
8 8
9namespace Core {
10class System;
11}
12
9namespace Service { 13namespace Service {
10 14
11namespace FileSystem { 15namespace FileSystem {
@@ -16,13 +20,13 @@ namespace NS {
16 20
17class IAccountProxyInterface final : public ServiceFramework<IAccountProxyInterface> { 21class IAccountProxyInterface final : public ServiceFramework<IAccountProxyInterface> {
18public: 22public:
19 explicit IAccountProxyInterface(); 23 explicit IAccountProxyInterface(Core::System& system_);
20 ~IAccountProxyInterface() override; 24 ~IAccountProxyInterface() override;
21}; 25};
22 26
23class IApplicationManagerInterface final : public ServiceFramework<IApplicationManagerInterface> { 27class IApplicationManagerInterface final : public ServiceFramework<IApplicationManagerInterface> {
24public: 28public:
25 explicit IApplicationManagerInterface(); 29 explicit IApplicationManagerInterface(Core::System& system_);
26 ~IApplicationManagerInterface() override; 30 ~IApplicationManagerInterface() override;
27 31
28 ResultVal<u8> GetApplicationDesiredLanguage(u32 supported_languages); 32 ResultVal<u8> GetApplicationDesiredLanguage(u32 supported_languages);
@@ -36,63 +40,71 @@ private:
36 40
37class IApplicationVersionInterface final : public ServiceFramework<IApplicationVersionInterface> { 41class IApplicationVersionInterface final : public ServiceFramework<IApplicationVersionInterface> {
38public: 42public:
39 explicit IApplicationVersionInterface(); 43 explicit IApplicationVersionInterface(Core::System& system_);
40 ~IApplicationVersionInterface() override; 44 ~IApplicationVersionInterface() override;
41}; 45};
42 46
43class IContentManagementInterface final : public ServiceFramework<IContentManagementInterface> { 47class IContentManagementInterface final : public ServiceFramework<IContentManagementInterface> {
44public: 48public:
45 explicit IContentManagementInterface(); 49 explicit IContentManagementInterface(Core::System& system_);
46 ~IContentManagementInterface() override; 50 ~IContentManagementInterface() override;
47}; 51};
48 52
49class IDocumentInterface final : public ServiceFramework<IDocumentInterface> { 53class IDocumentInterface final : public ServiceFramework<IDocumentInterface> {
50public: 54public:
51 explicit IDocumentInterface(); 55 explicit IDocumentInterface(Core::System& system_);
52 ~IDocumentInterface() override; 56 ~IDocumentInterface() override;
53}; 57};
54 58
55class IDownloadTaskInterface final : public ServiceFramework<IDownloadTaskInterface> { 59class IDownloadTaskInterface final : public ServiceFramework<IDownloadTaskInterface> {
56public: 60public:
57 explicit IDownloadTaskInterface(); 61 explicit IDownloadTaskInterface(Core::System& system_);
58 ~IDownloadTaskInterface() override; 62 ~IDownloadTaskInterface() override;
59}; 63};
60 64
61class IECommerceInterface final : public ServiceFramework<IECommerceInterface> { 65class IECommerceInterface final : public ServiceFramework<IECommerceInterface> {
62public: 66public:
63 explicit IECommerceInterface(); 67 explicit IECommerceInterface(Core::System& system_);
64 ~IECommerceInterface() override; 68 ~IECommerceInterface() override;
65}; 69};
66 70
67class IFactoryResetInterface final : public ServiceFramework<IFactoryResetInterface> { 71class IFactoryResetInterface final : public ServiceFramework<IFactoryResetInterface> {
68public: 72public:
69 explicit IFactoryResetInterface(); 73 explicit IFactoryResetInterface(Core::System& system_);
70 ~IFactoryResetInterface() override; 74 ~IFactoryResetInterface() override;
71}; 75};
72 76
73class NS final : public ServiceFramework<NS> { 77class NS final : public ServiceFramework<NS> {
74public: 78public:
75 explicit NS(const char* name); 79 explicit NS(const char* name, Core::System& system_);
76 ~NS() override; 80 ~NS() override;
77 81
78 std::shared_ptr<IApplicationManagerInterface> GetApplicationManagerInterface() const; 82 std::shared_ptr<IApplicationManagerInterface> GetApplicationManagerInterface() const;
79 83
80private: 84private:
81 template <typename T> 85 template <typename T, typename... Args>
82 void PushInterface(Kernel::HLERequestContext& ctx) { 86 void PushInterface(Kernel::HLERequestContext& ctx) {
83 LOG_DEBUG(Service_NS, "called"); 87 LOG_DEBUG(Service_NS, "called");
84 88
85 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 89 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
86 rb.Push(RESULT_SUCCESS); 90 rb.Push(RESULT_SUCCESS);
87 rb.PushIpcInterface<T>(); 91 rb.PushIpcInterface<T>(system);
92 }
93
94 void PushIApplicationManagerInterface(Kernel::HLERequestContext& ctx) {
95 LOG_DEBUG(Service_NS, "called");
96
97 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
98 rb.Push(RESULT_SUCCESS);
99 rb.PushIpcInterface<IApplicationManagerInterface>(system);
88 } 100 }
89 101
90 template <typename T> 102 template <typename T, typename... Args>
91 std::shared_ptr<T> GetInterface() const { 103 std::shared_ptr<T> GetInterface(Args&&... args) const {
92 static_assert(std::is_base_of_v<Kernel::SessionRequestHandler, T>, 104 static_assert(std::is_base_of_v<Kernel::SessionRequestHandler, T>,
93 "Not a base of ServiceFrameworkBase"); 105 "Not a base of ServiceFrameworkBase");
94 106
95 return std::make_shared<T>(); 107 return std::make_shared<T>(std::forward<Args>(args)...);
96 } 108 }
97}; 109};
98 110
diff --git a/src/core/hle/service/ns/pl_u.cpp b/src/core/hle/service/ns/pl_u.cpp
index 40838a225..71c7587db 100644
--- a/src/core/hle/service/ns/pl_u.cpp
+++ b/src/core/hle/service/ns/pl_u.cpp
@@ -27,42 +27,14 @@
27 27
28namespace Service::NS { 28namespace Service::NS {
29 29
30enum class FontArchives : u64 {
31 Extension = 0x0100000000000810,
32 Standard = 0x0100000000000811,
33 Korean = 0x0100000000000812,
34 ChineseTraditional = 0x0100000000000813,
35 ChineseSimple = 0x0100000000000814,
36};
37
38struct FontRegion { 30struct FontRegion {
39 u32 offset; 31 u32 offset;
40 u32 size; 32 u32 size;
41}; 33};
42 34
43constexpr std::array<std::pair<FontArchives, const char*>, 7> SHARED_FONTS{
44 std::make_pair(FontArchives::Standard, "nintendo_udsg-r_std_003.bfttf"),
45 std::make_pair(FontArchives::ChineseSimple, "nintendo_udsg-r_org_zh-cn_003.bfttf"),
46 std::make_pair(FontArchives::ChineseSimple, "nintendo_udsg-r_ext_zh-cn_003.bfttf"),
47 std::make_pair(FontArchives::ChineseTraditional, "nintendo_udjxh-db_zh-tw_003.bfttf"),
48 std::make_pair(FontArchives::Korean, "nintendo_udsg-r_ko_003.bfttf"),
49 std::make_pair(FontArchives::Extension, "nintendo_ext_003.bfttf"),
50 std::make_pair(FontArchives::Extension, "nintendo_ext2_003.bfttf"),
51};
52
53constexpr std::array<const char*, 7> SHARED_FONTS_TTF{
54 "FontStandard.ttf",
55 "FontChineseSimplified.ttf",
56 "FontExtendedChineseSimplified.ttf",
57 "FontChineseTraditional.ttf",
58 "FontKorean.ttf",
59 "FontNintendoExtended.ttf",
60 "FontNintendoExtended2.ttf",
61};
62
63// The below data is specific to shared font data dumped from Switch on f/w 2.2 35// The below data is specific to shared font data dumped from Switch on f/w 2.2
64// Virtual address and offsets/sizes likely will vary by dump 36// Virtual address and offsets/sizes likely will vary by dump
65constexpr VAddr SHARED_FONT_MEM_VADDR{0x00000009d3016000ULL}; 37[[maybe_unused]] constexpr VAddr SHARED_FONT_MEM_VADDR{0x00000009d3016000ULL};
66constexpr u32 EXPECTED_RESULT{0x7f9a0218}; // What we expect the decrypted bfttf first 4 bytes to be 38constexpr u32 EXPECTED_RESULT{0x7f9a0218}; // What we expect the decrypted bfttf first 4 bytes to be
67constexpr u32 EXPECTED_MAGIC{0x36f81a1e}; // What we expect the encrypted bfttf first 4 bytes to be 39constexpr u32 EXPECTED_MAGIC{0x36f81a1e}; // What we expect the encrypted bfttf first 4 bytes to be
68constexpr u64 SHARED_FONT_MEM_SIZE{0x1100000}; 40constexpr u64 SHARED_FONT_MEM_SIZE{0x1100000};
@@ -90,6 +62,18 @@ static void DecryptSharedFont(const std::vector<u32>& input, Kernel::PhysicalMem
90 offset += transformed_font.size() * sizeof(u32); 62 offset += transformed_font.size() * sizeof(u32);
91} 63}
92 64
65void DecryptSharedFontToTTF(const std::vector<u32>& input, std::vector<u8>& output) {
66 ASSERT_MSG(input[0] == EXPECTED_MAGIC, "Failed to derive key, unexpected magic number");
67
68 const u32 KEY = input[0] ^ EXPECTED_RESULT; // Derive key using an inverse xor
69 std::vector<u32> transformed_font(input.size());
70 // TODO(ogniK): Figure out a better way to do this
71 std::transform(input.begin(), input.end(), transformed_font.begin(),
72 [&KEY](u32 font_data) { return Common::swap32(font_data ^ KEY); });
73 transformed_font[1] = Common::swap32(transformed_font[1]) ^ KEY; // "re-encrypt" the size
74 std::memcpy(output.data(), transformed_font.data() + 2, transformed_font.size() * sizeof(u32));
75}
76
93void EncryptSharedFont(const std::vector<u32>& input, std::vector<u8>& output, 77void EncryptSharedFont(const std::vector<u32>& input, std::vector<u8>& output,
94 std::size_t& offset) { 78 std::size_t& offset) {
95 ASSERT_MSG(offset + (input.size() * sizeof(u32)) < SHARED_FONT_MEM_SIZE, 79 ASSERT_MSG(offset + (input.size() * sizeof(u32)) < SHARED_FONT_MEM_SIZE,
@@ -151,8 +135,8 @@ struct PL_U::Impl {
151 std::vector<FontRegion> shared_font_regions; 135 std::vector<FontRegion> shared_font_regions;
152}; 136};
153 137
154PL_U::PL_U(Core::System& system) 138PL_U::PL_U(Core::System& system_)
155 : ServiceFramework("pl:u"), impl{std::make_unique<Impl>()}, system(system) { 139 : ServiceFramework{system_, "pl:u"}, impl{std::make_unique<Impl>()} {
156 // clang-format off 140 // clang-format off
157 static const FunctionInfo functions[] = { 141 static const FunctionInfo functions[] = {
158 {0, &PL_U::RequestLoad, "RequestLoad"}, 142 {0, &PL_U::RequestLoad, "RequestLoad"},
@@ -192,21 +176,18 @@ PL_U::PL_U(Core::System& system)
192 } 176 }
193 177
194 if (!romfs) { 178 if (!romfs) {
195 LOG_ERROR(Service_NS, "Failed to find or synthesize {:016X}! Skipping", 179 LOG_ERROR(Service_NS, "Failed to find or synthesize {:016X}! Skipping", font.first);
196 static_cast<u64>(font.first));
197 continue; 180 continue;
198 } 181 }
199 182
200 const auto extracted_romfs = FileSys::ExtractRomFS(romfs); 183 const auto extracted_romfs = FileSys::ExtractRomFS(romfs);
201 if (!extracted_romfs) { 184 if (!extracted_romfs) {
202 LOG_ERROR(Service_NS, "Failed to extract RomFS for {:016X}! Skipping", 185 LOG_ERROR(Service_NS, "Failed to extract RomFS for {:016X}! Skipping", font.first);
203 static_cast<u64>(font.first));
204 continue; 186 continue;
205 } 187 }
206 const auto font_fp = extracted_romfs->GetFile(font.second); 188 const auto font_fp = extracted_romfs->GetFile(font.second);
207 if (!font_fp) { 189 if (!font_fp) {
208 LOG_ERROR(Service_NS, "{:016X} has no file \"{}\"! Skipping", 190 LOG_ERROR(Service_NS, "{:016X} has no file \"{}\"! Skipping", font.first, font.second);
209 static_cast<u64>(font.first), font.second);
210 continue; 191 continue;
211 } 192 }
212 std::vector<u32> font_data_u32(font_fp->GetSize() / sizeof(u32)); 193 std::vector<u32> font_data_u32(font_fp->GetSize() / sizeof(u32));
diff --git a/src/core/hle/service/ns/pl_u.h b/src/core/hle/service/ns/pl_u.h
index 27161bd7a..f920c7f69 100644
--- a/src/core/hle/service/ns/pl_u.h
+++ b/src/core/hle/service/ns/pl_u.h
@@ -16,11 +16,30 @@ class FileSystemController;
16 16
17namespace NS { 17namespace NS {
18 18
19enum class FontArchives : u64 {
20 Extension = 0x0100000000000810,
21 Standard = 0x0100000000000811,
22 Korean = 0x0100000000000812,
23 ChineseTraditional = 0x0100000000000813,
24 ChineseSimple = 0x0100000000000814,
25};
26
27constexpr std::array<std::pair<FontArchives, const char*>, 7> SHARED_FONTS{
28 std::make_pair(FontArchives::Standard, "nintendo_udsg-r_std_003.bfttf"),
29 std::make_pair(FontArchives::ChineseSimple, "nintendo_udsg-r_org_zh-cn_003.bfttf"),
30 std::make_pair(FontArchives::ChineseSimple, "nintendo_udsg-r_ext_zh-cn_003.bfttf"),
31 std::make_pair(FontArchives::ChineseTraditional, "nintendo_udjxh-db_zh-tw_003.bfttf"),
32 std::make_pair(FontArchives::Korean, "nintendo_udsg-r_ko_003.bfttf"),
33 std::make_pair(FontArchives::Extension, "nintendo_ext_003.bfttf"),
34 std::make_pair(FontArchives::Extension, "nintendo_ext2_003.bfttf"),
35};
36
37void DecryptSharedFontToTTF(const std::vector<u32>& input, std::vector<u8>& output);
19void EncryptSharedFont(const std::vector<u32>& input, std::vector<u8>& output, std::size_t& offset); 38void EncryptSharedFont(const std::vector<u32>& input, std::vector<u8>& output, std::size_t& offset);
20 39
21class PL_U final : public ServiceFramework<PL_U> { 40class PL_U final : public ServiceFramework<PL_U> {
22public: 41public:
23 explicit PL_U(Core::System& system); 42 explicit PL_U(Core::System& system_);
24 ~PL_U() override; 43 ~PL_U() override;
25 44
26private: 45private:
@@ -33,7 +52,6 @@ private:
33 52
34 struct Impl; 53 struct Impl;
35 std::unique_ptr<Impl> impl; 54 std::unique_ptr<Impl> impl;
36 Core::System& system;
37}; 55};
38 56
39} // namespace NS 57} // namespace NS
diff --git a/src/core/hle/service/nvdrv/devices/nvdevice.h b/src/core/hle/service/nvdrv/devices/nvdevice.h
index 0240d6643..5681599ba 100644
--- a/src/core/hle/service/nvdrv/devices/nvdevice.h
+++ b/src/core/hle/service/nvdrv/devices/nvdevice.h
@@ -24,25 +24,37 @@ public:
24 explicit nvdevice(Core::System& system) : system{system} {} 24 explicit nvdevice(Core::System& system) : system{system} {}
25 virtual ~nvdevice() = default; 25 virtual ~nvdevice() = default;
26 26
27 union Ioctl { 27 /**
28 u32_le raw; 28 * Handles an ioctl1 request.
29 BitField<0, 8, u32> cmd; 29 * @param command The ioctl command id.
30 BitField<8, 8, u32> group; 30 * @param input A buffer containing the input data for the ioctl.
31 BitField<16, 14, u32> length; 31 * @param output A buffer where the output data will be written to.
32 BitField<30, 1, u32> is_in; 32 * @returns The result code of the ioctl.
33 BitField<31, 1, u32> is_out; 33 */
34 }; 34 virtual NvResult Ioctl1(Ioctl command, const std::vector<u8>& input,
35 std::vector<u8>& output) = 0;
36
37 /**
38 * Handles an ioctl2 request.
39 * @param command The ioctl command id.
40 * @param input A buffer containing the input data for the ioctl.
41 * @param inline_input A buffer containing the input data for the ioctl which has been inlined.
42 * @param output A buffer where the output data will be written to.
43 * @returns The result code of the ioctl.
44 */
45 virtual NvResult Ioctl2(Ioctl command, const std::vector<u8>& input,
46 const std::vector<u8>& inline_input, std::vector<u8>& output) = 0;
35 47
36 /** 48 /**
37 * Handles an ioctl request. 49 * Handles an ioctl3 request.
38 * @param command The ioctl command id. 50 * @param command The ioctl command id.
39 * @param input A buffer containing the input data for the ioctl. 51 * @param input A buffer containing the input data for the ioctl.
40 * @param output A buffer where the output data will be written to. 52 * @param output A buffer where the output data will be written to.
53 * @param inline_output A buffer where the inlined output data will be written to.
41 * @returns The result code of the ioctl. 54 * @returns The result code of the ioctl.
42 */ 55 */
43 virtual u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, 56 virtual NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
44 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, 57 std::vector<u8>& inline_output) = 0;
45 IoctlVersion version) = 0;
46 58
47protected: 59protected:
48 Core::System& system; 60 Core::System& system;
diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
index 3f7b8e670..ce615c758 100644
--- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
@@ -18,11 +18,22 @@ nvdisp_disp0::nvdisp_disp0(Core::System& system, std::shared_ptr<nvmap> nvmap_de
18 : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {} 18 : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {}
19nvdisp_disp0 ::~nvdisp_disp0() = default; 19nvdisp_disp0 ::~nvdisp_disp0() = default;
20 20
21u32 nvdisp_disp0::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, 21NvResult nvdisp_disp0::Ioctl1(Ioctl command, const std::vector<u8>& input,
22 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, 22 std::vector<u8>& output) {
23 IoctlVersion version) { 23 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
24 UNIMPLEMENTED_MSG("Unimplemented ioctl"); 24 return NvResult::NotImplemented;
25 return 0; 25}
26
27NvResult nvdisp_disp0::Ioctl2(Ioctl command, const std::vector<u8>& input,
28 const std::vector<u8>& inline_input, std::vector<u8>& output) {
29 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
30 return NvResult::NotImplemented;
31}
32
33NvResult nvdisp_disp0::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
34 std::vector<u8>& inline_output) {
35 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
36 return NvResult::NotImplemented;
26} 37}
27 38
28void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height, 39void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height,
diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h
index 6fcdeee84..55a33b7e4 100644
--- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h
+++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h
@@ -20,9 +20,11 @@ public:
20 explicit nvdisp_disp0(Core::System& system, std::shared_ptr<nvmap> nvmap_dev); 20 explicit nvdisp_disp0(Core::System& system, std::shared_ptr<nvmap> nvmap_dev);
21 ~nvdisp_disp0() override; 21 ~nvdisp_disp0() override;
22 22
23 u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, 23 NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
24 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, 24 NvResult Ioctl2(Ioctl command, const std::vector<u8>& input,
25 IoctlVersion version) override; 25 const std::vector<u8>& inline_input, std::vector<u8>& output) override;
26 NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
27 std::vector<u8>& inline_output) override;
26 28
27 /// Performs a screen flip, drawing the buffer pointed to by the handle. 29 /// Performs a screen flip, drawing the buffer pointed to by the handle.
28 void flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height, u32 stride, 30 void flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height, u32 stride,
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 39bd2a45b..6b062e10e 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
@@ -17,57 +17,77 @@
17 17
18namespace Service::Nvidia::Devices { 18namespace Service::Nvidia::Devices {
19 19
20namespace NvErrCodes {
21constexpr u32 Success{};
22constexpr u32 OutOfMemory{static_cast<u32>(-12)};
23constexpr u32 InvalidInput{static_cast<u32>(-22)};
24} // namespace NvErrCodes
25
26nvhost_as_gpu::nvhost_as_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev) 20nvhost_as_gpu::nvhost_as_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev)
27 : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {} 21 : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {}
28nvhost_as_gpu::~nvhost_as_gpu() = default; 22nvhost_as_gpu::~nvhost_as_gpu() = default;
29 23
30u32 nvhost_as_gpu::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, 24NvResult nvhost_as_gpu::Ioctl1(Ioctl command, const std::vector<u8>& input,
31 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, 25 std::vector<u8>& output) {
32 IoctlVersion version) { 26 switch (command.group) {
33 LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", 27 case 'A':
34 command.raw, input.size(), output.size()); 28 switch (command.cmd) {
35 29 case 0x1:
36 switch (static_cast<IoctlCommand>(command.raw)) { 30 return BindChannel(input, output);
37 case IoctlCommand::IocInitalizeExCommand: 31 case 0x2:
38 return InitalizeEx(input, output); 32 return AllocateSpace(input, output);
39 case IoctlCommand::IocAllocateSpaceCommand: 33 case 0x3:
40 return AllocateSpace(input, output); 34 return FreeSpace(input, output);
41 case IoctlCommand::IocMapBufferExCommand: 35 case 0x5:
42 return MapBufferEx(input, output); 36 return UnmapBuffer(input, output);
43 case IoctlCommand::IocBindChannelCommand: 37 case 0x6:
44 return BindChannel(input, output); 38 return MapBufferEx(input, output);
45 case IoctlCommand::IocGetVaRegionsCommand: 39 case 0x8:
46 return GetVARegions(input, output); 40 return GetVARegions(input, output);
47 case IoctlCommand::IocUnmapBufferCommand: 41 case 0x9:
48 return UnmapBuffer(input, output); 42 return InitalizeEx(input, output);
43 case 0x14:
44 return Remap(input, output);
45 default:
46 break;
47 }
48 break;
49 default: 49 default:
50 break; 50 break;
51 } 51 }
52 52
53 if (static_cast<IoctlCommand>(command.cmd.Value()) == IoctlCommand::IocRemapCommand) { 53 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
54 return Remap(input, output); 54 return NvResult::NotImplemented;
55 } 55}
56 56
57 UNIMPLEMENTED_MSG("Unimplemented ioctl command"); 57NvResult nvhost_as_gpu::Ioctl2(Ioctl command, const std::vector<u8>& input,
58 return 0; 58 const std::vector<u8>& inline_input, std::vector<u8>& output) {
59 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
60 return NvResult::NotImplemented;
59} 61}
60 62
61u32 nvhost_as_gpu::InitalizeEx(const std::vector<u8>& input, std::vector<u8>& output) { 63NvResult nvhost_as_gpu::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
64 std::vector<u8>& inline_output) {
65 switch (command.group) {
66 case 'A':
67 switch (command.cmd) {
68 case 0x8:
69 return GetVARegions(input, output, inline_output);
70 default:
71 break;
72 }
73 break;
74 default:
75 break;
76 }
77 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
78 return NvResult::NotImplemented;
79}
80
81NvResult nvhost_as_gpu::InitalizeEx(const std::vector<u8>& input, std::vector<u8>& output) {
62 IoctlInitalizeEx params{}; 82 IoctlInitalizeEx params{};
63 std::memcpy(&params, input.data(), input.size()); 83 std::memcpy(&params, input.data(), input.size());
64 84
65 LOG_WARNING(Service_NVDRV, "(STUBBED) called, big_page_size=0x{:X}", params.big_page_size); 85 LOG_WARNING(Service_NVDRV, "(STUBBED) called, big_page_size=0x{:X}", params.big_page_size);
66 86
67 return 0; 87 return NvResult::Success;
68} 88}
69 89
70u32 nvhost_as_gpu::AllocateSpace(const std::vector<u8>& input, std::vector<u8>& output) { 90NvResult nvhost_as_gpu::AllocateSpace(const std::vector<u8>& input, std::vector<u8>& output) {
71 IoctlAllocSpace params{}; 91 IoctlAllocSpace params{};
72 std::memcpy(&params, input.data(), input.size()); 92 std::memcpy(&params, input.data(), input.size());
73 93
@@ -81,22 +101,36 @@ u32 nvhost_as_gpu::AllocateSpace(const std::vector<u8>& input, std::vector<u8>&
81 params.offset = system.GPU().MemoryManager().Allocate(size, params.align); 101 params.offset = system.GPU().MemoryManager().Allocate(size, params.align);
82 } 102 }
83 103
84 auto result{NvErrCodes::Success}; 104 auto result = NvResult::Success;
85 if (!params.offset) { 105 if (!params.offset) {
86 LOG_CRITICAL(Service_NVDRV, "allocation failed for size {}", size); 106 LOG_CRITICAL(Service_NVDRV, "allocation failed for size {}", size);
87 result = NvErrCodes::OutOfMemory; 107 result = NvResult::InsufficientMemory;
88 } 108 }
89 109
90 std::memcpy(output.data(), &params, output.size()); 110 std::memcpy(output.data(), &params, output.size());
91 return result; 111 return result;
92} 112}
93 113
94u32 nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output) { 114NvResult nvhost_as_gpu::FreeSpace(const std::vector<u8>& input, std::vector<u8>& output) {
115 IoctlFreeSpace params{};
116 std::memcpy(&params, input.data(), input.size());
117
118 LOG_DEBUG(Service_NVDRV, "called, offset={:X}, pages={:X}, page_size={:X}", params.offset,
119 params.pages, params.page_size);
120
121 system.GPU().MemoryManager().Unmap(params.offset,
122 static_cast<std::size_t>(params.pages) * params.page_size);
123
124 std::memcpy(output.data(), &params, output.size());
125 return NvResult::Success;
126}
127
128NvResult nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output) {
95 const auto num_entries = input.size() / sizeof(IoctlRemapEntry); 129 const auto num_entries = input.size() / sizeof(IoctlRemapEntry);
96 130
97 LOG_DEBUG(Service_NVDRV, "called, num_entries=0x{:X}", num_entries); 131 LOG_DEBUG(Service_NVDRV, "called, num_entries=0x{:X}", num_entries);
98 132
99 auto result{NvErrCodes::Success}; 133 auto result = NvResult::Success;
100 std::vector<IoctlRemapEntry> entries(num_entries); 134 std::vector<IoctlRemapEntry> entries(num_entries);
101 std::memcpy(entries.data(), input.data(), input.size()); 135 std::memcpy(entries.data(), input.data(), input.size());
102 136
@@ -107,7 +141,7 @@ u32 nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output)
107 const auto object{nvmap_dev->GetObject(entry.nvmap_handle)}; 141 const auto object{nvmap_dev->GetObject(entry.nvmap_handle)};
108 if (!object) { 142 if (!object) {
109 LOG_CRITICAL(Service_NVDRV, "invalid nvmap_handle={:X}", entry.nvmap_handle); 143 LOG_CRITICAL(Service_NVDRV, "invalid nvmap_handle={:X}", entry.nvmap_handle);
110 result = NvErrCodes::InvalidInput; 144 result = NvResult::InvalidState;
111 break; 145 break;
112 } 146 }
113 147
@@ -118,7 +152,7 @@ u32 nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output)
118 152
119 if (!addr) { 153 if (!addr) {
120 LOG_CRITICAL(Service_NVDRV, "map returned an invalid address!"); 154 LOG_CRITICAL(Service_NVDRV, "map returned an invalid address!");
121 result = NvErrCodes::InvalidInput; 155 result = NvResult::InvalidState;
122 break; 156 break;
123 } 157 }
124 } 158 }
@@ -127,7 +161,7 @@ u32 nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output)
127 return result; 161 return result;
128} 162}
129 163
130u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output) { 164NvResult nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output) {
131 IoctlMapBufferEx params{}; 165 IoctlMapBufferEx params{};
132 std::memcpy(&params, input.data(), input.size()); 166 std::memcpy(&params, input.data(), input.size());
133 167
@@ -141,7 +175,7 @@ u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& ou
141 if (!object) { 175 if (!object) {
142 LOG_CRITICAL(Service_NVDRV, "invalid nvmap_handle={:X}", params.nvmap_handle); 176 LOG_CRITICAL(Service_NVDRV, "invalid nvmap_handle={:X}", params.nvmap_handle);
143 std::memcpy(output.data(), &params, output.size()); 177 std::memcpy(output.data(), &params, output.size());
144 return NvErrCodes::InvalidInput; 178 return NvResult::InvalidState;
145 } 179 }
146 180
147 // The real nvservices doesn't make a distinction between handles and ids, and 181 // The real nvservices doesn't make a distinction between handles and ids, and
@@ -168,16 +202,16 @@ u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& ou
168 params.mapping_size, params.offset); 202 params.mapping_size, params.offset);
169 203
170 std::memcpy(output.data(), &params, output.size()); 204 std::memcpy(output.data(), &params, output.size());
171 return NvErrCodes::InvalidInput; 205 return NvResult::InvalidState;
172 } 206 }
173 207
174 std::memcpy(output.data(), &params, output.size()); 208 std::memcpy(output.data(), &params, output.size());
175 return NvErrCodes::Success; 209 return NvResult::Success;
176 } else { 210 } else {
177 LOG_CRITICAL(Service_NVDRV, "address not mapped offset={}", params.offset); 211 LOG_CRITICAL(Service_NVDRV, "address not mapped offset={}", params.offset);
178 212
179 std::memcpy(output.data(), &params, output.size()); 213 std::memcpy(output.data(), &params, output.size());
180 return NvErrCodes::InvalidInput; 214 return NvResult::InvalidState;
181 } 215 }
182 } 216 }
183 217
@@ -197,10 +231,10 @@ u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& ou
197 params.offset = gpu.MemoryManager().Map(physical_address, params.offset, size); 231 params.offset = gpu.MemoryManager().Map(physical_address, params.offset, size);
198 } 232 }
199 233
200 auto result{NvErrCodes::Success}; 234 auto result = NvResult::Success;
201 if (!params.offset) { 235 if (!params.offset) {
202 LOG_CRITICAL(Service_NVDRV, "failed to map size={}", size); 236 LOG_CRITICAL(Service_NVDRV, "failed to map size={}", size);
203 result = NvErrCodes::InvalidInput; 237 result = NvResult::InvalidState;
204 } else { 238 } else {
205 AddBufferMap(params.offset, size, physical_address, is_alloc); 239 AddBufferMap(params.offset, size, physical_address, is_alloc);
206 } 240 }
@@ -209,7 +243,7 @@ u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& ou
209 return result; 243 return result;
210} 244}
211 245
212u32 nvhost_as_gpu::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output) { 246NvResult nvhost_as_gpu::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output) {
213 IoctlUnmapBuffer params{}; 247 IoctlUnmapBuffer params{};
214 std::memcpy(&params, input.data(), input.size()); 248 std::memcpy(&params, input.data(), input.size());
215 249
@@ -222,20 +256,42 @@ u32 nvhost_as_gpu::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& ou
222 } 256 }
223 257
224 std::memcpy(output.data(), &params, output.size()); 258 std::memcpy(output.data(), &params, output.size());
225 return NvErrCodes::Success; 259 return NvResult::Success;
226} 260}
227 261
228u32 nvhost_as_gpu::BindChannel(const std::vector<u8>& input, std::vector<u8>& output) { 262NvResult nvhost_as_gpu::BindChannel(const std::vector<u8>& input, std::vector<u8>& output) {
229 IoctlBindChannel params{}; 263 IoctlBindChannel params{};
230 std::memcpy(&params, input.data(), input.size()); 264 std::memcpy(&params, input.data(), input.size());
231 265 LOG_WARNING(Service_NVDRV, "(STUBBED) called, fd={:X}", params.fd);
232 LOG_DEBUG(Service_NVDRV, "called, fd={:X}", params.fd);
233 266
234 channel = params.fd; 267 channel = params.fd;
235 return 0; 268 return NvResult::Success;
269}
270
271NvResult nvhost_as_gpu::GetVARegions(const std::vector<u8>& input, std::vector<u8>& output) {
272 IoctlGetVaRegions params{};
273 std::memcpy(&params, input.data(), input.size());
274
275 LOG_WARNING(Service_NVDRV, "(STUBBED) called, buf_addr={:X}, buf_size={:X}", params.buf_addr,
276 params.buf_size);
277
278 params.buf_size = 0x30;
279 params.regions[0].offset = 0x04000000;
280 params.regions[0].page_size = 0x1000;
281 params.regions[0].pages = 0x3fbfff;
282
283 params.regions[1].offset = 0x04000000;
284 params.regions[1].page_size = 0x10000;
285 params.regions[1].pages = 0x1bffff;
286
287 // TODO(ogniK): This probably can stay stubbed but should add support way way later
288
289 std::memcpy(output.data(), &params, output.size());
290 return NvResult::Success;
236} 291}
237 292
238u32 nvhost_as_gpu::GetVARegions(const std::vector<u8>& input, std::vector<u8>& output) { 293NvResult nvhost_as_gpu::GetVARegions(const std::vector<u8>& input, std::vector<u8>& output,
294 std::vector<u8>& inline_output) {
239 IoctlGetVaRegions params{}; 295 IoctlGetVaRegions params{};
240 std::memcpy(&params, input.data(), input.size()); 296 std::memcpy(&params, input.data(), input.size());
241 297
@@ -254,7 +310,8 @@ u32 nvhost_as_gpu::GetVARegions(const std::vector<u8>& input, std::vector<u8>& o
254 // TODO(ogniK): This probably can stay stubbed but should add support way way later 310 // TODO(ogniK): This probably can stay stubbed but should add support way way later
255 311
256 std::memcpy(output.data(), &params, output.size()); 312 std::memcpy(output.data(), &params, output.size());
257 return 0; 313 std::memcpy(inline_output.data(), &params.regions, inline_output.size());
314 return NvResult::Success;
258} 315}
259 316
260std::optional<nvhost_as_gpu::BufferMap> nvhost_as_gpu::FindBufferMap(GPUVAddr gpu_addr) const { 317std::optional<nvhost_as_gpu::BufferMap> nvhost_as_gpu::FindBufferMap(GPUVAddr gpu_addr) const {
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 9a0cdff0c..08035fa0e 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
@@ -30,9 +30,11 @@ public:
30 explicit nvhost_as_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev); 30 explicit nvhost_as_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev);
31 ~nvhost_as_gpu() override; 31 ~nvhost_as_gpu() override;
32 32
33 u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, 33 NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
34 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, 34 NvResult Ioctl2(Ioctl command, const std::vector<u8>& input,
35 IoctlVersion version) override; 35 const std::vector<u8>& inline_input, std::vector<u8>& output) override;
36 NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
37 std::vector<u8>& inline_output) override;
36 38
37private: 39private:
38 class BufferMap final { 40 class BufferMap final {
@@ -74,31 +76,21 @@ private:
74 bool is_allocated{}; 76 bool is_allocated{};
75 }; 77 };
76 78
77 enum class IoctlCommand : u32_le {
78 IocInitalizeExCommand = 0x40284109,
79 IocAllocateSpaceCommand = 0xC0184102,
80 IocRemapCommand = 0x00000014,
81 IocMapBufferExCommand = 0xC0284106,
82 IocBindChannelCommand = 0x40044101,
83 IocGetVaRegionsCommand = 0xC0404108,
84 IocUnmapBufferCommand = 0xC0084105,
85 };
86
87 struct IoctlInitalizeEx { 79 struct IoctlInitalizeEx {
88 u32_le big_page_size; // depends on GPU's available_big_page_sizes; 0=default 80 u32_le big_page_size{}; // depends on GPU's available_big_page_sizes; 0=default
89 s32_le as_fd; // ignored; passes 0 81 s32_le as_fd{}; // ignored; passes 0
90 u32_le flags; // passes 0 82 u32_le flags{}; // passes 0
91 u32_le reserved; // ignored; passes 0 83 u32_le reserved{}; // ignored; passes 0
92 u64_le unk0; 84 u64_le unk0{};
93 u64_le unk1; 85 u64_le unk1{};
94 u64_le unk2; 86 u64_le unk2{};
95 }; 87 };
96 static_assert(sizeof(IoctlInitalizeEx) == 40, "IoctlInitalizeEx is incorrect size"); 88 static_assert(sizeof(IoctlInitalizeEx) == 40, "IoctlInitalizeEx is incorrect size");
97 89
98 struct IoctlAllocSpace { 90 struct IoctlAllocSpace {
99 u32_le pages; 91 u32_le pages{};
100 u32_le page_size; 92 u32_le page_size{};
101 AddressSpaceFlags flags; 93 AddressSpaceFlags flags{};
102 INSERT_PADDING_WORDS(1); 94 INSERT_PADDING_WORDS(1);
103 union { 95 union {
104 u64_le offset; 96 u64_le offset;
@@ -107,63 +99,74 @@ private:
107 }; 99 };
108 static_assert(sizeof(IoctlAllocSpace) == 24, "IoctlInitalizeEx is incorrect size"); 100 static_assert(sizeof(IoctlAllocSpace) == 24, "IoctlInitalizeEx is incorrect size");
109 101
102 struct IoctlFreeSpace {
103 u64_le offset{};
104 u32_le pages{};
105 u32_le page_size{};
106 };
107 static_assert(sizeof(IoctlFreeSpace) == 16, "IoctlFreeSpace is incorrect size");
108
110 struct IoctlRemapEntry { 109 struct IoctlRemapEntry {
111 u16_le flags; 110 u16_le flags{};
112 u16_le kind; 111 u16_le kind{};
113 u32_le nvmap_handle; 112 u32_le nvmap_handle{};
114 u32_le map_offset; 113 u32_le map_offset{};
115 u32_le offset; 114 u32_le offset{};
116 u32_le pages; 115 u32_le pages{};
117 }; 116 };
118 static_assert(sizeof(IoctlRemapEntry) == 20, "IoctlRemapEntry is incorrect size"); 117 static_assert(sizeof(IoctlRemapEntry) == 20, "IoctlRemapEntry is incorrect size");
119 118
120 struct IoctlMapBufferEx { 119 struct IoctlMapBufferEx {
121 AddressSpaceFlags flags; // bit0: fixed_offset, bit2: cacheable 120 AddressSpaceFlags flags{}; // bit0: fixed_offset, bit2: cacheable
122 u32_le kind; // -1 is default 121 u32_le kind{}; // -1 is default
123 u32_le nvmap_handle; 122 u32_le nvmap_handle{};
124 u32_le page_size; // 0 means don't care 123 u32_le page_size{}; // 0 means don't care
125 s64_le buffer_offset; 124 s64_le buffer_offset{};
126 u64_le mapping_size; 125 u64_le mapping_size{};
127 s64_le offset; 126 s64_le offset{};
128 }; 127 };
129 static_assert(sizeof(IoctlMapBufferEx) == 40, "IoctlMapBufferEx is incorrect size"); 128 static_assert(sizeof(IoctlMapBufferEx) == 40, "IoctlMapBufferEx is incorrect size");
130 129
131 struct IoctlUnmapBuffer { 130 struct IoctlUnmapBuffer {
132 s64_le offset; 131 s64_le offset{};
133 }; 132 };
134 static_assert(sizeof(IoctlUnmapBuffer) == 8, "IoctlUnmapBuffer is incorrect size"); 133 static_assert(sizeof(IoctlUnmapBuffer) == 8, "IoctlUnmapBuffer is incorrect size");
135 134
136 struct IoctlBindChannel { 135 struct IoctlBindChannel {
137 u32_le fd; 136 s32_le fd{};
138 }; 137 };
139 static_assert(sizeof(IoctlBindChannel) == 4, "IoctlBindChannel is incorrect size"); 138 static_assert(sizeof(IoctlBindChannel) == 4, "IoctlBindChannel is incorrect size");
140 139
141 struct IoctlVaRegion { 140 struct IoctlVaRegion {
142 u64_le offset; 141 u64_le offset{};
143 u32_le page_size; 142 u32_le page_size{};
144 INSERT_PADDING_WORDS(1); 143 INSERT_PADDING_WORDS(1);
145 u64_le pages; 144 u64_le pages{};
146 }; 145 };
147 static_assert(sizeof(IoctlVaRegion) == 24, "IoctlVaRegion is incorrect size"); 146 static_assert(sizeof(IoctlVaRegion) == 24, "IoctlVaRegion is incorrect size");
148 147
149 struct IoctlGetVaRegions { 148 struct IoctlGetVaRegions {
150 u64_le buf_addr; // (contained output user ptr on linux, ignored) 149 u64_le buf_addr{}; // (contained output user ptr on linux, ignored)
151 u32_le buf_size; // forced to 2*sizeof(struct va_region) 150 u32_le buf_size{}; // forced to 2*sizeof(struct va_region)
152 u32_le reserved; 151 u32_le reserved{};
153 IoctlVaRegion regions[2]; 152 IoctlVaRegion regions[2]{};
154 }; 153 };
155 static_assert(sizeof(IoctlGetVaRegions) == 16 + sizeof(IoctlVaRegion) * 2, 154 static_assert(sizeof(IoctlGetVaRegions) == 16 + sizeof(IoctlVaRegion) * 2,
156 "IoctlGetVaRegions is incorrect size"); 155 "IoctlGetVaRegions is incorrect size");
157 156
158 u32 channel{}; 157 s32 channel{};
158
159 NvResult InitalizeEx(const std::vector<u8>& input, std::vector<u8>& output);
160 NvResult AllocateSpace(const std::vector<u8>& input, std::vector<u8>& output);
161 NvResult Remap(const std::vector<u8>& input, std::vector<u8>& output);
162 NvResult MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output);
163 NvResult UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output);
164 NvResult FreeSpace(const std::vector<u8>& input, std::vector<u8>& output);
165 NvResult BindChannel(const std::vector<u8>& input, std::vector<u8>& output);
159 166
160 u32 InitalizeEx(const std::vector<u8>& input, std::vector<u8>& output); 167 NvResult GetVARegions(const std::vector<u8>& input, std::vector<u8>& output);
161 u32 AllocateSpace(const std::vector<u8>& input, std::vector<u8>& output); 168 NvResult GetVARegions(const std::vector<u8>& input, std::vector<u8>& output,
162 u32 Remap(const std::vector<u8>& input, std::vector<u8>& output); 169 std::vector<u8>& inline_output);
163 u32 MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output);
164 u32 UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output);
165 u32 BindChannel(const std::vector<u8>& input, std::vector<u8>& output);
166 u32 GetVARegions(const std::vector<u8>& input, std::vector<u8>& output);
167 170
168 std::optional<BufferMap> FindBufferMap(GPUVAddr gpu_addr) const; 171 std::optional<BufferMap> FindBufferMap(GPUVAddr gpu_addr) const;
169 void AddBufferMap(GPUVAddr gpu_addr, std::size_t size, VAddr cpu_addr, bool is_allocated); 172 void AddBufferMap(GPUVAddr gpu_addr, std::size_t size, VAddr cpu_addr, bool is_allocated);
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
index b27ee0502..fea3b7b9f 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
@@ -15,45 +15,59 @@
15 15
16namespace Service::Nvidia::Devices { 16namespace Service::Nvidia::Devices {
17 17
18nvhost_ctrl::nvhost_ctrl(Core::System& system, EventInterface& events_interface) 18nvhost_ctrl::nvhost_ctrl(Core::System& system, EventInterface& events_interface,
19 : nvdevice(system), events_interface{events_interface} {} 19 SyncpointManager& syncpoint_manager)
20 : nvdevice(system), events_interface{events_interface}, syncpoint_manager{syncpoint_manager} {}
20nvhost_ctrl::~nvhost_ctrl() = default; 21nvhost_ctrl::~nvhost_ctrl() = default;
21 22
22u32 nvhost_ctrl::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, 23NvResult nvhost_ctrl::Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) {
23 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, 24 switch (command.group) {
24 IoctlVersion version) { 25 case 0x0:
25 LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", 26 switch (command.cmd) {
26 command.raw, input.size(), output.size()); 27 case 0x1b:
27 28 return NvOsGetConfigU32(input, output);
28 switch (static_cast<IoctlCommand>(command.raw)) { 29 case 0x1c:
29 case IoctlCommand::IocGetConfigCommand: 30 return IocCtrlClearEventWait(input, output);
30 return NvOsGetConfigU32(input, output); 31 case 0x1d:
31 case IoctlCommand::IocCtrlEventWaitCommand: 32 return IocCtrlEventWait(input, output, false);
32 return IocCtrlEventWait(input, output, false, ctrl); 33 case 0x1e:
33 case IoctlCommand::IocCtrlEventWaitAsyncCommand: 34 return IocCtrlEventWait(input, output, true);
34 return IocCtrlEventWait(input, output, true, ctrl); 35 case 0x1f:
35 case IoctlCommand::IocCtrlEventRegisterCommand: 36 return IocCtrlEventRegister(input, output);
36 return IocCtrlEventRegister(input, output); 37 case 0x20:
37 case IoctlCommand::IocCtrlEventUnregisterCommand: 38 return IocCtrlEventUnregister(input, output);
38 return IocCtrlEventUnregister(input, output); 39 }
39 case IoctlCommand::IocCtrlEventSignalCommand: 40 break;
40 return IocCtrlEventSignal(input, output);
41 default: 41 default:
42 UNIMPLEMENTED_MSG("Unimplemented ioctl"); 42 break;
43 return 0;
44 } 43 }
44
45 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
46 return NvResult::NotImplemented;
47}
48
49NvResult nvhost_ctrl::Ioctl2(Ioctl command, const std::vector<u8>& input,
50 const std::vector<u8>& inline_input, std::vector<u8>& output) {
51 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
52 return NvResult::NotImplemented;
53}
54
55NvResult nvhost_ctrl::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
56 std::vector<u8>& inline_outpu) {
57 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
58 return NvResult::NotImplemented;
45} 59}
46 60
47u32 nvhost_ctrl::NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output) { 61NvResult nvhost_ctrl::NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output) {
48 IocGetConfigParams params{}; 62 IocGetConfigParams params{};
49 std::memcpy(&params, input.data(), sizeof(params)); 63 std::memcpy(&params, input.data(), sizeof(params));
50 LOG_TRACE(Service_NVDRV, "called, setting={}!{}", params.domain_str.data(), 64 LOG_TRACE(Service_NVDRV, "called, setting={}!{}", params.domain_str.data(),
51 params.param_str.data()); 65 params.param_str.data());
52 return 0x30006; // Returns error on production mode 66 return NvResult::ConfigVarNotFound; // Returns error on production mode
53} 67}
54 68
55u32 nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output, 69NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output,
56 bool is_async, IoctlCtrl& ctrl) { 70 bool is_async) {
57 IocCtrlEventWaitParams params{}; 71 IocCtrlEventWaitParams params{};
58 std::memcpy(&params, input.data(), sizeof(params)); 72 std::memcpy(&params, input.data(), sizeof(params));
59 LOG_DEBUG(Service_NVDRV, "syncpt_id={}, threshold={}, timeout={}, is_async={}", 73 LOG_DEBUG(Service_NVDRV, "syncpt_id={}, threshold={}, timeout={}, is_async={}",
@@ -70,19 +84,33 @@ u32 nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>&
70 return NvResult::BadParameter; 84 return NvResult::BadParameter;
71 } 85 }
72 86
87 if (syncpoint_manager.IsSyncpointExpired(params.syncpt_id, params.threshold)) {
88 params.value = syncpoint_manager.GetSyncpointMin(params.syncpt_id);
89 std::memcpy(output.data(), &params, sizeof(params));
90 return NvResult::Success;
91 }
92
93 if (const auto new_value = syncpoint_manager.RefreshSyncpoint(params.syncpt_id);
94 syncpoint_manager.IsSyncpointExpired(params.syncpt_id, params.threshold)) {
95 params.value = new_value;
96 std::memcpy(output.data(), &params, sizeof(params));
97 return NvResult::Success;
98 }
99
73 auto event = events_interface.events[event_id]; 100 auto event = events_interface.events[event_id];
74 auto& gpu = system.GPU(); 101 auto& gpu = system.GPU();
102
75 // This is mostly to take into account unimplemented features. As synced 103 // This is mostly to take into account unimplemented features. As synced
76 // gpu is always synced. 104 // gpu is always synced.
77 if (!gpu.IsAsync()) { 105 if (!gpu.IsAsync()) {
78 event.writable->Signal(); 106 event.event.writable->Signal();
79 return NvResult::Success; 107 return NvResult::Success;
80 } 108 }
81 auto lock = gpu.LockSync(); 109 auto lock = gpu.LockSync();
82 const u32 current_syncpoint_value = gpu.GetSyncpointValue(params.syncpt_id); 110 const u32 current_syncpoint_value = event.fence.value;
83 const s32 diff = current_syncpoint_value - params.threshold; 111 const s32 diff = current_syncpoint_value - params.threshold;
84 if (diff >= 0) { 112 if (diff >= 0) {
85 event.writable->Signal(); 113 event.event.writable->Signal();
86 params.value = current_syncpoint_value; 114 params.value = current_syncpoint_value;
87 std::memcpy(output.data(), &params, sizeof(params)); 115 std::memcpy(output.data(), &params, sizeof(params));
88 return NvResult::Success; 116 return NvResult::Success;
@@ -109,14 +137,8 @@ u32 nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>&
109 params.value = ((params.syncpt_id & 0xfff) << 16) | 0x10000000; 137 params.value = ((params.syncpt_id & 0xfff) << 16) | 0x10000000;
110 } 138 }
111 params.value |= event_id; 139 params.value |= event_id;
112 event.writable->Clear(); 140 event.event.writable->Clear();
113 gpu.RegisterSyncptInterrupt(params.syncpt_id, target_value); 141 gpu.RegisterSyncptInterrupt(params.syncpt_id, target_value);
114 if (!is_async && ctrl.fresh_call) {
115 ctrl.must_delay = true;
116 ctrl.timeout = params.timeout;
117 ctrl.event_id = event_id;
118 return NvResult::Timeout;
119 }
120 std::memcpy(output.data(), &params, sizeof(params)); 142 std::memcpy(output.data(), &params, sizeof(params));
121 return NvResult::Timeout; 143 return NvResult::Timeout;
122 } 144 }
@@ -124,7 +146,7 @@ u32 nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>&
124 return NvResult::BadParameter; 146 return NvResult::BadParameter;
125} 147}
126 148
127u32 nvhost_ctrl::IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output) { 149NvResult nvhost_ctrl::IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output) {
128 IocCtrlEventRegisterParams params{}; 150 IocCtrlEventRegisterParams params{};
129 std::memcpy(&params, input.data(), sizeof(params)); 151 std::memcpy(&params, input.data(), sizeof(params));
130 const u32 event_id = params.user_event_id & 0x00FF; 152 const u32 event_id = params.user_event_id & 0x00FF;
@@ -139,7 +161,8 @@ u32 nvhost_ctrl::IocCtrlEventRegister(const std::vector<u8>& input, std::vector<
139 return NvResult::Success; 161 return NvResult::Success;
140} 162}
141 163
142u32 nvhost_ctrl::IocCtrlEventUnregister(const std::vector<u8>& input, std::vector<u8>& output) { 164NvResult nvhost_ctrl::IocCtrlEventUnregister(const std::vector<u8>& input,
165 std::vector<u8>& output) {
143 IocCtrlEventUnregisterParams params{}; 166 IocCtrlEventUnregisterParams params{};
144 std::memcpy(&params, input.data(), sizeof(params)); 167 std::memcpy(&params, input.data(), sizeof(params));
145 const u32 event_id = params.user_event_id & 0x00FF; 168 const u32 event_id = params.user_event_id & 0x00FF;
@@ -154,24 +177,22 @@ u32 nvhost_ctrl::IocCtrlEventUnregister(const std::vector<u8>& input, std::vecto
154 return NvResult::Success; 177 return NvResult::Success;
155} 178}
156 179
157u32 nvhost_ctrl::IocCtrlEventSignal(const std::vector<u8>& input, std::vector<u8>& output) { 180NvResult nvhost_ctrl::IocCtrlClearEventWait(const std::vector<u8>& input, std::vector<u8>& output) {
158 IocCtrlEventSignalParams params{}; 181 IocCtrlEventSignalParams params{};
159 std::memcpy(&params, input.data(), sizeof(params)); 182 std::memcpy(&params, input.data(), sizeof(params));
160 // TODO(Blinkhawk): This is normally called when an NvEvents timeout on WaitSynchronization 183
161 // It is believed from RE to cancel the GPU Event. However, better research is required 184 u32 event_id = params.event_id & 0x00FF;
162 u32 event_id = params.user_event_id & 0x00FF; 185 LOG_WARNING(Service_NVDRV, "cleared event wait on, event_id: {:X}", event_id);
163 LOG_WARNING(Service_NVDRV, "(STUBBED) called, user_event_id: {:X}", event_id); 186
164 if (event_id >= MaxNvEvents) { 187 if (event_id >= MaxNvEvents) {
165 return NvResult::BadParameter; 188 return NvResult::BadParameter;
166 } 189 }
167 if (events_interface.status[event_id] == EventState::Waiting) { 190 if (events_interface.status[event_id] == EventState::Waiting) {
168 auto& gpu = system.GPU(); 191 events_interface.LiberateEvent(event_id);
169 if (gpu.CancelSyncptInterrupt(events_interface.assigned_syncpt[event_id],
170 events_interface.assigned_value[event_id])) {
171 events_interface.LiberateEvent(event_id);
172 events_interface.events[event_id].writable->Signal();
173 }
174 } 192 }
193
194 syncpoint_manager.RefreshSyncpoint(events_interface.events[event_id].fence.id);
195
175 return NvResult::Success; 196 return NvResult::Success;
176} 197}
177 198
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h
index 9898623de..c5aa1362a 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h
@@ -14,137 +14,120 @@ namespace Service::Nvidia::Devices {
14 14
15class nvhost_ctrl final : public nvdevice { 15class nvhost_ctrl final : public nvdevice {
16public: 16public:
17 explicit nvhost_ctrl(Core::System& system, EventInterface& events_interface); 17 explicit nvhost_ctrl(Core::System& system, EventInterface& events_interface,
18 SyncpointManager& syncpoint_manager);
18 ~nvhost_ctrl() override; 19 ~nvhost_ctrl() override;
19 20
20 u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, 21 NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
21 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, 22 NvResult Ioctl2(Ioctl command, const std::vector<u8>& input,
22 IoctlVersion version) override; 23 const std::vector<u8>& inline_input, std::vector<u8>& output) override;
24 NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
25 std::vector<u8>& inline_output) override;
23 26
24private: 27private:
25 enum class IoctlCommand : u32_le {
26 IocSyncptReadCommand = 0xC0080014,
27 IocSyncptIncrCommand = 0x40040015,
28 IocSyncptWaitCommand = 0xC00C0016,
29 IocModuleMutexCommand = 0x40080017,
30 IocModuleRegRDWRCommand = 0xC0180018,
31 IocSyncptWaitexCommand = 0xC0100019,
32 IocSyncptReadMaxCommand = 0xC008001A,
33 IocGetConfigCommand = 0xC183001B,
34 IocCtrlEventSignalCommand = 0xC004001C,
35 IocCtrlEventWaitCommand = 0xC010001D,
36 IocCtrlEventWaitAsyncCommand = 0xC010001E,
37 IocCtrlEventRegisterCommand = 0xC004001F,
38 IocCtrlEventUnregisterCommand = 0xC0040020,
39 IocCtrlEventKillCommand = 0x40080021,
40 };
41 struct IocSyncptReadParams { 28 struct IocSyncptReadParams {
42 u32_le id; 29 u32_le id{};
43 u32_le value; 30 u32_le value{};
44 }; 31 };
45 static_assert(sizeof(IocSyncptReadParams) == 8, "IocSyncptReadParams is incorrect size"); 32 static_assert(sizeof(IocSyncptReadParams) == 8, "IocSyncptReadParams is incorrect size");
46 33
47 struct IocSyncptIncrParams { 34 struct IocSyncptIncrParams {
48 u32_le id; 35 u32_le id{};
49 }; 36 };
50 static_assert(sizeof(IocSyncptIncrParams) == 4, "IocSyncptIncrParams is incorrect size"); 37 static_assert(sizeof(IocSyncptIncrParams) == 4, "IocSyncptIncrParams is incorrect size");
51 38
52 struct IocSyncptWaitParams { 39 struct IocSyncptWaitParams {
53 u32_le id; 40 u32_le id{};
54 u32_le thresh; 41 u32_le thresh{};
55 s32_le timeout; 42 s32_le timeout{};
56 }; 43 };
57 static_assert(sizeof(IocSyncptWaitParams) == 12, "IocSyncptWaitParams is incorrect size"); 44 static_assert(sizeof(IocSyncptWaitParams) == 12, "IocSyncptWaitParams is incorrect size");
58 45
59 struct IocModuleMutexParams { 46 struct IocModuleMutexParams {
60 u32_le id; 47 u32_le id{};
61 u32_le lock; // (0 = unlock and 1 = lock) 48 u32_le lock{}; // (0 = unlock and 1 = lock)
62 }; 49 };
63 static_assert(sizeof(IocModuleMutexParams) == 8, "IocModuleMutexParams is incorrect size"); 50 static_assert(sizeof(IocModuleMutexParams) == 8, "IocModuleMutexParams is incorrect size");
64 51
65 struct IocModuleRegRDWRParams { 52 struct IocModuleRegRDWRParams {
66 u32_le id; 53 u32_le id{};
67 u32_le num_offsets; 54 u32_le num_offsets{};
68 u32_le block_size; 55 u32_le block_size{};
69 u32_le offsets; 56 u32_le offsets{};
70 u32_le values; 57 u32_le values{};
71 u32_le write; 58 u32_le write{};
72 }; 59 };
73 static_assert(sizeof(IocModuleRegRDWRParams) == 24, "IocModuleRegRDWRParams is incorrect size"); 60 static_assert(sizeof(IocModuleRegRDWRParams) == 24, "IocModuleRegRDWRParams is incorrect size");
74 61
75 struct IocSyncptWaitexParams { 62 struct IocSyncptWaitexParams {
76 u32_le id; 63 u32_le id{};
77 u32_le thresh; 64 u32_le thresh{};
78 s32_le timeout; 65 s32_le timeout{};
79 u32_le value; 66 u32_le value{};
80 }; 67 };
81 static_assert(sizeof(IocSyncptWaitexParams) == 16, "IocSyncptWaitexParams is incorrect size"); 68 static_assert(sizeof(IocSyncptWaitexParams) == 16, "IocSyncptWaitexParams is incorrect size");
82 69
83 struct IocSyncptReadMaxParams { 70 struct IocSyncptReadMaxParams {
84 u32_le id; 71 u32_le id{};
85 u32_le value; 72 u32_le value{};
86 }; 73 };
87 static_assert(sizeof(IocSyncptReadMaxParams) == 8, "IocSyncptReadMaxParams is incorrect size"); 74 static_assert(sizeof(IocSyncptReadMaxParams) == 8, "IocSyncptReadMaxParams is incorrect size");
88 75
89 struct IocGetConfigParams { 76 struct IocGetConfigParams {
90 std::array<char, 0x41> domain_str; 77 std::array<char, 0x41> domain_str{};
91 std::array<char, 0x41> param_str; 78 std::array<char, 0x41> param_str{};
92 std::array<char, 0x101> config_str; 79 std::array<char, 0x101> config_str{};
93 }; 80 };
94 static_assert(sizeof(IocGetConfigParams) == 387, "IocGetConfigParams is incorrect size"); 81 static_assert(sizeof(IocGetConfigParams) == 387, "IocGetConfigParams is incorrect size");
95 82
96 struct IocCtrlEventSignalParams { 83 struct IocCtrlEventSignalParams {
97 u32_le user_event_id; 84 u32_le event_id{};
98 }; 85 };
99 static_assert(sizeof(IocCtrlEventSignalParams) == 4, 86 static_assert(sizeof(IocCtrlEventSignalParams) == 4,
100 "IocCtrlEventSignalParams is incorrect size"); 87 "IocCtrlEventSignalParams is incorrect size");
101 88
102 struct IocCtrlEventWaitParams { 89 struct IocCtrlEventWaitParams {
103 u32_le syncpt_id; 90 u32_le syncpt_id{};
104 u32_le threshold; 91 u32_le threshold{};
105 s32_le timeout; 92 s32_le timeout{};
106 u32_le value; 93 u32_le value{};
107 }; 94 };
108 static_assert(sizeof(IocCtrlEventWaitParams) == 16, "IocCtrlEventWaitParams is incorrect size"); 95 static_assert(sizeof(IocCtrlEventWaitParams) == 16, "IocCtrlEventWaitParams is incorrect size");
109 96
110 struct IocCtrlEventWaitAsyncParams { 97 struct IocCtrlEventWaitAsyncParams {
111 u32_le syncpt_id; 98 u32_le syncpt_id{};
112 u32_le threshold; 99 u32_le threshold{};
113 u32_le timeout; 100 u32_le timeout{};
114 u32_le value; 101 u32_le value{};
115 }; 102 };
116 static_assert(sizeof(IocCtrlEventWaitAsyncParams) == 16, 103 static_assert(sizeof(IocCtrlEventWaitAsyncParams) == 16,
117 "IocCtrlEventWaitAsyncParams is incorrect size"); 104 "IocCtrlEventWaitAsyncParams is incorrect size");
118 105
119 struct IocCtrlEventRegisterParams { 106 struct IocCtrlEventRegisterParams {
120 u32_le user_event_id; 107 u32_le user_event_id{};
121 }; 108 };
122 static_assert(sizeof(IocCtrlEventRegisterParams) == 4, 109 static_assert(sizeof(IocCtrlEventRegisterParams) == 4,
123 "IocCtrlEventRegisterParams is incorrect size"); 110 "IocCtrlEventRegisterParams is incorrect size");
124 111
125 struct IocCtrlEventUnregisterParams { 112 struct IocCtrlEventUnregisterParams {
126 u32_le user_event_id; 113 u32_le user_event_id{};
127 }; 114 };
128 static_assert(sizeof(IocCtrlEventUnregisterParams) == 4, 115 static_assert(sizeof(IocCtrlEventUnregisterParams) == 4,
129 "IocCtrlEventUnregisterParams is incorrect size"); 116 "IocCtrlEventUnregisterParams is incorrect size");
130 117
131 struct IocCtrlEventKill { 118 struct IocCtrlEventKill {
132 u64_le user_events; 119 u64_le user_events{};
133 }; 120 };
134 static_assert(sizeof(IocCtrlEventKill) == 8, "IocCtrlEventKill is incorrect size"); 121 static_assert(sizeof(IocCtrlEventKill) == 8, "IocCtrlEventKill is incorrect size");
135 122
136 u32 NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output); 123 NvResult NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output);
137 124 NvResult IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output, bool is_async);
138 u32 IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output, bool is_async, 125 NvResult IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output);
139 IoctlCtrl& ctrl); 126 NvResult IocCtrlEventUnregister(const std::vector<u8>& input, std::vector<u8>& output);
140 127 NvResult IocCtrlClearEventWait(const std::vector<u8>& input, std::vector<u8>& output);
141 u32 IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output);
142
143 u32 IocCtrlEventUnregister(const std::vector<u8>& input, std::vector<u8>& output);
144
145 u32 IocCtrlEventSignal(const std::vector<u8>& input, std::vector<u8>& output);
146 128
147 EventInterface& events_interface; 129 EventInterface& events_interface;
130 SyncpointManager& syncpoint_manager;
148}; 131};
149 132
150} // namespace Service::Nvidia::Devices 133} // namespace Service::Nvidia::Devices
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 fba89e7a6..0320d3ae2 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
@@ -15,39 +15,66 @@ namespace Service::Nvidia::Devices {
15nvhost_ctrl_gpu::nvhost_ctrl_gpu(Core::System& system) : nvdevice(system) {} 15nvhost_ctrl_gpu::nvhost_ctrl_gpu(Core::System& system) : nvdevice(system) {}
16nvhost_ctrl_gpu::~nvhost_ctrl_gpu() = default; 16nvhost_ctrl_gpu::~nvhost_ctrl_gpu() = default;
17 17
18u32 nvhost_ctrl_gpu::ioctl(Ioctl command, const std::vector<u8>& input, 18NvResult nvhost_ctrl_gpu::Ioctl1(Ioctl command, const std::vector<u8>& input,
19 const std::vector<u8>& input2, std::vector<u8>& output, 19 std::vector<u8>& output) {
20 std::vector<u8>& output2, IoctlCtrl& ctrl, IoctlVersion version) { 20 switch (command.group) {
21 LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", 21 case 'G':
22 command.raw, input.size(), output.size()); 22 switch (command.cmd) {
23 23 case 0x1:
24 switch (static_cast<IoctlCommand>(command.raw)) { 24 return ZCullGetCtxSize(input, output);
25 case IoctlCommand::IocGetCharacteristicsCommand: 25 case 0x2:
26 return GetCharacteristics(input, output, output2, version); 26 return ZCullGetInfo(input, output);
27 case IoctlCommand::IocGetTPCMasksCommand: 27 case 0x3:
28 return GetTPCMasks(input, output, output2, version); 28 return ZBCSetTable(input, output);
29 case IoctlCommand::IocGetActiveSlotMaskCommand: 29 case 0x4:
30 return GetActiveSlotMask(input, output); 30 return ZBCQueryTable(input, output);
31 case IoctlCommand::IocZcullGetCtxSizeCommand: 31 case 0x5:
32 return ZCullGetCtxSize(input, output); 32 return GetCharacteristics(input, output);
33 case IoctlCommand::IocZcullGetInfo: 33 case 0x6:
34 return ZCullGetInfo(input, output); 34 return GetTPCMasks(input, output);
35 case IoctlCommand::IocZbcSetTable: 35 case 0x7:
36 return ZBCSetTable(input, output); 36 return FlushL2(input, output);
37 case IoctlCommand::IocZbcQueryTable: 37 case 0x14:
38 return ZBCQueryTable(input, output); 38 return GetActiveSlotMask(input, output);
39 case IoctlCommand::IocFlushL2: 39 case 0x1c:
40 return FlushL2(input, output); 40 return GetGpuTime(input, output);
41 case IoctlCommand::IocGetGpuTime: 41 default:
42 return GetGpuTime(input, output); 42 break;
43 }
44 break;
45 }
46 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
47 return NvResult::NotImplemented;
48}
49
50NvResult nvhost_ctrl_gpu::Ioctl2(Ioctl command, const std::vector<u8>& input,
51 const std::vector<u8>& inline_input, std::vector<u8>& output) {
52 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
53 return NvResult::NotImplemented;
54}
55
56NvResult nvhost_ctrl_gpu::Ioctl3(Ioctl command, const std::vector<u8>& input,
57 std::vector<u8>& output, std::vector<u8>& inline_output) {
58 switch (command.group) {
59 case 'G':
60 switch (command.cmd) {
61 case 0x5:
62 return GetCharacteristics(input, output, inline_output);
63 case 0x6:
64 return GetTPCMasks(input, output, inline_output);
65 default:
66 break;
67 }
68 break;
43 default: 69 default:
44 UNIMPLEMENTED_MSG("Unimplemented ioctl"); 70 break;
45 return 0;
46 } 71 }
72 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
73 return NvResult::NotImplemented;
47} 74}
48 75
49u32 nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output, 76NvResult nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input,
50 std::vector<u8>& output2, IoctlVersion version) { 77 std::vector<u8>& output) {
51 LOG_DEBUG(Service_NVDRV, "called"); 78 LOG_DEBUG(Service_NVDRV, "called");
52 IoctlCharacteristics params{}; 79 IoctlCharacteristics params{};
53 std::memcpy(&params, input.data(), input.size()); 80 std::memcpy(&params, input.data(), input.size());
@@ -88,36 +115,83 @@ u32 nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input, std::vecto
88 params.gc.gr_compbit_store_base_hw = 0x0; 115 params.gc.gr_compbit_store_base_hw = 0x0;
89 params.gpu_characteristics_buf_size = 0xA0; 116 params.gpu_characteristics_buf_size = 0xA0;
90 params.gpu_characteristics_buf_addr = 0xdeadbeef; // Cannot be 0 (UNUSED) 117 params.gpu_characteristics_buf_addr = 0xdeadbeef; // Cannot be 0 (UNUSED)
118 std::memcpy(output.data(), &params, output.size());
119 return NvResult::Success;
120}
91 121
92 if (version == IoctlVersion::Version3) { 122NvResult nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output,
93 std::memcpy(output.data(), input.data(), output.size()); 123 std::vector<u8>& inline_output) {
94 std::memcpy(output2.data(), &params.gc, output2.size()); 124 LOG_DEBUG(Service_NVDRV, "called");
95 } else { 125 IoctlCharacteristics params{};
96 std::memcpy(output.data(), &params, output.size()); 126 std::memcpy(&params, input.data(), input.size());
97 } 127 params.gc.arch = 0x120;
98 return 0; 128 params.gc.impl = 0xb;
129 params.gc.rev = 0xa1;
130 params.gc.num_gpc = 0x1;
131 params.gc.l2_cache_size = 0x40000;
132 params.gc.on_board_video_memory_size = 0x0;
133 params.gc.num_tpc_per_gpc = 0x2;
134 params.gc.bus_type = 0x20;
135 params.gc.big_page_size = 0x20000;
136 params.gc.compression_page_size = 0x20000;
137 params.gc.pde_coverage_bit_count = 0x1B;
138 params.gc.available_big_page_sizes = 0x30000;
139 params.gc.gpc_mask = 0x1;
140 params.gc.sm_arch_sm_version = 0x503;
141 params.gc.sm_arch_spa_version = 0x503;
142 params.gc.sm_arch_warp_count = 0x80;
143 params.gc.gpu_va_bit_count = 0x28;
144 params.gc.reserved = 0x0;
145 params.gc.flags = 0x55;
146 params.gc.twod_class = 0x902D;
147 params.gc.threed_class = 0xB197;
148 params.gc.compute_class = 0xB1C0;
149 params.gc.gpfifo_class = 0xB06F;
150 params.gc.inline_to_memory_class = 0xA140;
151 params.gc.dma_copy_class = 0xB0B5;
152 params.gc.max_fbps_count = 0x1;
153 params.gc.fbp_en_mask = 0x0;
154 params.gc.max_ltc_per_fbp = 0x2;
155 params.gc.max_lts_per_ltc = 0x1;
156 params.gc.max_tex_per_tpc = 0x0;
157 params.gc.max_gpc_count = 0x1;
158 params.gc.rop_l2_en_mask_0 = 0x21D70;
159 params.gc.rop_l2_en_mask_1 = 0x0;
160 params.gc.chipname = 0x6230326D67;
161 params.gc.gr_compbit_store_base_hw = 0x0;
162 params.gpu_characteristics_buf_size = 0xA0;
163 params.gpu_characteristics_buf_addr = 0xdeadbeef; // Cannot be 0 (UNUSED)
164
165 std::memcpy(output.data(), &params, output.size());
166 std::memcpy(inline_output.data(), &params.gc, inline_output.size());
167 return NvResult::Success;
99} 168}
100 169
101u32 nvhost_ctrl_gpu::GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output, 170NvResult nvhost_ctrl_gpu::GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output) {
102 std::vector<u8>& output2, IoctlVersion version) {
103 IoctlGpuGetTpcMasksArgs params{}; 171 IoctlGpuGetTpcMasksArgs params{};
104 std::memcpy(&params, input.data(), input.size()); 172 std::memcpy(&params, input.data(), input.size());
105 LOG_DEBUG(Service_NVDRV, "called, mask_buffer_size=0x{:X}", params.mask_buffer_size); 173 LOG_DEBUG(Service_NVDRV, "called, mask_buffer_size=0x{:X}", params.mask_buffer_size);
106 if (params.mask_buffer_size != 0) { 174 if (params.mask_buffer_size != 0) {
107 params.tcp_mask = 3; 175 params.tcp_mask = 3;
108 } 176 }
177 std::memcpy(output.data(), &params, output.size());
178 return NvResult::Success;
179}
109 180
110 if (version == IoctlVersion::Version3) { 181NvResult nvhost_ctrl_gpu::GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output,
111 std::memcpy(output.data(), input.data(), output.size()); 182 std::vector<u8>& inline_output) {
112 std::memcpy(output2.data(), &params.tcp_mask, output2.size()); 183 IoctlGpuGetTpcMasksArgs params{};
113 } else { 184 std::memcpy(&params, input.data(), input.size());
114 std::memcpy(output.data(), &params, output.size()); 185 LOG_DEBUG(Service_NVDRV, "called, mask_buffer_size=0x{:X}", params.mask_buffer_size);
186 if (params.mask_buffer_size != 0) {
187 params.tcp_mask = 3;
115 } 188 }
116 189 std::memcpy(output.data(), &params, output.size());
117 return 0; 190 std::memcpy(inline_output.data(), &params.tcp_mask, inline_output.size());
191 return NvResult::Success;
118} 192}
119 193
120u32 nvhost_ctrl_gpu::GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output) { 194NvResult nvhost_ctrl_gpu::GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output) {
121 LOG_DEBUG(Service_NVDRV, "called"); 195 LOG_DEBUG(Service_NVDRV, "called");
122 196
123 IoctlActiveSlotMask params{}; 197 IoctlActiveSlotMask params{};
@@ -127,10 +201,10 @@ u32 nvhost_ctrl_gpu::GetActiveSlotMask(const std::vector<u8>& input, std::vector
127 params.slot = 0x07; 201 params.slot = 0x07;
128 params.mask = 0x01; 202 params.mask = 0x01;
129 std::memcpy(output.data(), &params, output.size()); 203 std::memcpy(output.data(), &params, output.size());
130 return 0; 204 return NvResult::Success;
131} 205}
132 206
133u32 nvhost_ctrl_gpu::ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output) { 207NvResult nvhost_ctrl_gpu::ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output) {
134 LOG_DEBUG(Service_NVDRV, "called"); 208 LOG_DEBUG(Service_NVDRV, "called");
135 209
136 IoctlZcullGetCtxSize params{}; 210 IoctlZcullGetCtxSize params{};
@@ -139,10 +213,10 @@ u32 nvhost_ctrl_gpu::ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u
139 } 213 }
140 params.size = 0x1; 214 params.size = 0x1;
141 std::memcpy(output.data(), &params, output.size()); 215 std::memcpy(output.data(), &params, output.size());
142 return 0; 216 return NvResult::Success;
143} 217}
144 218
145u32 nvhost_ctrl_gpu::ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& output) { 219NvResult nvhost_ctrl_gpu::ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& output) {
146 LOG_DEBUG(Service_NVDRV, "called"); 220 LOG_DEBUG(Service_NVDRV, "called");
147 221
148 IoctlNvgpuGpuZcullGetInfoArgs params{}; 222 IoctlNvgpuGpuZcullGetInfoArgs params{};
@@ -162,47 +236,47 @@ u32 nvhost_ctrl_gpu::ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>&
162 params.subregion_height_align_pixels = 0x40; 236 params.subregion_height_align_pixels = 0x40;
163 params.subregion_count = 0x10; 237 params.subregion_count = 0x10;
164 std::memcpy(output.data(), &params, output.size()); 238 std::memcpy(output.data(), &params, output.size());
165 return 0; 239 return NvResult::Success;
166} 240}
167 241
168u32 nvhost_ctrl_gpu::ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output) { 242NvResult nvhost_ctrl_gpu::ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output) {
169 LOG_WARNING(Service_NVDRV, "(STUBBED) called"); 243 LOG_WARNING(Service_NVDRV, "(STUBBED) called");
170 244
171 IoctlZbcSetTable params{}; 245 IoctlZbcSetTable params{};
172 std::memcpy(&params, input.data(), input.size()); 246 std::memcpy(&params, input.data(), input.size());
173 // TODO(ogniK): What does this even actually do? 247 // TODO(ogniK): What does this even actually do?
174 std::memcpy(output.data(), &params, output.size()); 248 std::memcpy(output.data(), &params, output.size());
175 return 0; 249 return NvResult::Success;
176} 250}
177 251
178u32 nvhost_ctrl_gpu::ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output) { 252NvResult nvhost_ctrl_gpu::ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output) {
179 LOG_WARNING(Service_NVDRV, "(STUBBED) called"); 253 LOG_WARNING(Service_NVDRV, "(STUBBED) called");
180 254
181 IoctlZbcQueryTable params{}; 255 IoctlZbcQueryTable params{};
182 std::memcpy(&params, input.data(), input.size()); 256 std::memcpy(&params, input.data(), input.size());
183 // TODO : To implement properly 257 // TODO : To implement properly
184 std::memcpy(output.data(), &params, output.size()); 258 std::memcpy(output.data(), &params, output.size());
185 return 0; 259 return NvResult::Success;
186} 260}
187 261
188u32 nvhost_ctrl_gpu::FlushL2(const std::vector<u8>& input, std::vector<u8>& output) { 262NvResult nvhost_ctrl_gpu::FlushL2(const std::vector<u8>& input, std::vector<u8>& output) {
189 LOG_WARNING(Service_NVDRV, "(STUBBED) called"); 263 LOG_WARNING(Service_NVDRV, "(STUBBED) called");
190 264
191 IoctlFlushL2 params{}; 265 IoctlFlushL2 params{};
192 std::memcpy(&params, input.data(), input.size()); 266 std::memcpy(&params, input.data(), input.size());
193 // TODO : To implement properly 267 // TODO : To implement properly
194 std::memcpy(output.data(), &params, output.size()); 268 std::memcpy(output.data(), &params, output.size());
195 return 0; 269 return NvResult::Success;
196} 270}
197 271
198u32 nvhost_ctrl_gpu::GetGpuTime(const std::vector<u8>& input, std::vector<u8>& output) { 272NvResult nvhost_ctrl_gpu::GetGpuTime(const std::vector<u8>& input, std::vector<u8>& output) {
199 LOG_DEBUG(Service_NVDRV, "called"); 273 LOG_DEBUG(Service_NVDRV, "called");
200 274
201 IoctlGetGpuTime params{}; 275 IoctlGetGpuTime params{};
202 std::memcpy(&params, input.data(), input.size()); 276 std::memcpy(&params, input.data(), input.size());
203 params.gpu_time = static_cast<u64_le>(system.CoreTiming().GetGlobalTimeNs().count()); 277 params.gpu_time = static_cast<u64_le>(system.CoreTiming().GetGlobalTimeNs().count());
204 std::memcpy(output.data(), &params, output.size()); 278 std::memcpy(output.data(), &params, output.size());
205 return 0; 279 return NvResult::Success;
206} 280}
207 281
208} // namespace Service::Nvidia::Devices 282} // namespace Service::Nvidia::Devices
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 ef60f72ce..137b88238 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h
@@ -16,32 +16,13 @@ public:
16 explicit nvhost_ctrl_gpu(Core::System& system); 16 explicit nvhost_ctrl_gpu(Core::System& system);
17 ~nvhost_ctrl_gpu() override; 17 ~nvhost_ctrl_gpu() override;
18 18
19 u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, 19 NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
20 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, 20 NvResult Ioctl2(Ioctl command, const std::vector<u8>& input,
21 IoctlVersion version) override; 21 const std::vector<u8>& inline_input, std::vector<u8>& output) override;
22 NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
23 std::vector<u8>& inline_output) override;
22 24
23private: 25private:
24 enum class IoctlCommand : u32_le {
25 IocGetCharacteristicsCommand = 0xC0B04705,
26 IocGetTPCMasksCommand = 0xC0184706,
27 IocGetActiveSlotMaskCommand = 0x80084714,
28 IocZcullGetCtxSizeCommand = 0x80044701,
29 IocZcullGetInfo = 0x80284702,
30 IocZbcSetTable = 0x402C4703,
31 IocZbcQueryTable = 0xC0344704,
32 IocFlushL2 = 0x40084707,
33 IocInvalICache = 0x4008470D,
34 IocSetMmudebugMode = 0x4008470E,
35 IocSetSmDebugMode = 0x4010470F,
36 IocWaitForPause = 0xC0084710,
37 IocGetTcpExceptionEnStatus = 0x80084711,
38 IocNumVsms = 0x80084712,
39 IocVsmsMapping = 0xC0044713,
40 IocGetErrorChannelUserData = 0xC008471B,
41 IocGetGpuTime = 0xC010471C,
42 IocGetCpuTimeCorrelationInfo = 0xC108471D,
43 };
44
45 struct IoctlGpuCharacteristics { 26 struct IoctlGpuCharacteristics {
46 u32_le arch; // 0x120 (NVGPU_GPU_ARCH_GM200) 27 u32_le arch; // 0x120 (NVGPU_GPU_ARCH_GM200)
47 u32_le impl; // 0xB (NVGPU_GPU_IMPL_GM20B) 28 u32_le impl; // 0xB (NVGPU_GPU_IMPL_GM20B)
@@ -159,17 +140,21 @@ private:
159 }; 140 };
160 static_assert(sizeof(IoctlGetGpuTime) == 0x10, "IoctlGetGpuTime is incorrect size"); 141 static_assert(sizeof(IoctlGetGpuTime) == 0x10, "IoctlGetGpuTime is incorrect size");
161 142
162 u32 GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output, 143 NvResult GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output);
163 std::vector<u8>& output2, IoctlVersion version); 144 NvResult GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output,
164 u32 GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output, std::vector<u8>& output2, 145 std::vector<u8>& inline_output);
165 IoctlVersion version); 146
166 u32 GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output); 147 NvResult GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output);
167 u32 ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output); 148 NvResult GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output,
168 u32 ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& output); 149 std::vector<u8>& inline_output);
169 u32 ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output); 150
170 u32 ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output); 151 NvResult GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output);
171 u32 FlushL2(const std::vector<u8>& input, std::vector<u8>& output); 152 NvResult ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output);
172 u32 GetGpuTime(const std::vector<u8>& input, std::vector<u8>& output); 153 NvResult ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& output);
154 NvResult ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output);
155 NvResult ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output);
156 NvResult FlushL2(const std::vector<u8>& input, std::vector<u8>& output);
157 NvResult GetGpuTime(const std::vector<u8>& input, std::vector<u8>& output);
173}; 158};
174 159
175} // namespace Service::Nvidia::Devices 160} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
index f1966ac0e..af8b3d9f1 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
@@ -7,117 +7,148 @@
7#include "common/logging/log.h" 7#include "common/logging/log.h"
8#include "core/core.h" 8#include "core/core.h"
9#include "core/hle/service/nvdrv/devices/nvhost_gpu.h" 9#include "core/hle/service/nvdrv/devices/nvhost_gpu.h"
10#include "core/hle/service/nvdrv/syncpoint_manager.h"
10#include "core/memory.h" 11#include "core/memory.h"
11#include "video_core/gpu.h" 12#include "video_core/gpu.h"
12#include "video_core/memory_manager.h" 13#include "video_core/memory_manager.h"
13 14
14namespace Service::Nvidia::Devices { 15namespace Service::Nvidia::Devices {
15 16
16nvhost_gpu::nvhost_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev) 17nvhost_gpu::nvhost_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev,
17 : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {} 18 SyncpointManager& syncpoint_manager)
19 : nvdevice(system), nvmap_dev(std::move(nvmap_dev)), syncpoint_manager{syncpoint_manager} {
20 channel_fence.id = syncpoint_manager.AllocateSyncpoint();
21 channel_fence.value = system.GPU().GetSyncpointValue(channel_fence.id);
22}
23
18nvhost_gpu::~nvhost_gpu() = default; 24nvhost_gpu::~nvhost_gpu() = default;
19 25
20u32 nvhost_gpu::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, 26NvResult nvhost_gpu::Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) {
21 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, 27 switch (command.group) {
22 IoctlVersion version) { 28 case 0x0:
23 LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", 29 switch (command.cmd) {
24 command.raw, input.size(), output.size()); 30 case 0x3:
25 31 return GetWaitbase(input, output);
26 switch (static_cast<IoctlCommand>(command.raw)) { 32 default:
27 case IoctlCommand::IocSetNVMAPfdCommand: 33 break;
28 return SetNVMAPfd(input, output); 34 }
29 case IoctlCommand::IocSetClientDataCommand: 35 break;
30 return SetClientData(input, output); 36 case 'H':
31 case IoctlCommand::IocGetClientDataCommand: 37 switch (command.cmd) {
32 return GetClientData(input, output); 38 case 0x1:
33 case IoctlCommand::IocZCullBind: 39 return SetNVMAPfd(input, output);
34 return ZCullBind(input, output); 40 case 0x3:
35 case IoctlCommand::IocSetErrorNotifierCommand: 41 return ChannelSetTimeout(input, output);
36 return SetErrorNotifier(input, output); 42 case 0x8:
37 case IoctlCommand::IocChannelSetPriorityCommand: 43 return SubmitGPFIFOBase(input, output, false);
38 return SetChannelPriority(input, output); 44 case 0x9:
39 case IoctlCommand::IocAllocGPFIFOEx2Command: 45 return AllocateObjectContext(input, output);
40 return AllocGPFIFOEx2(input, output); 46 case 0xb:
41 case IoctlCommand::IocAllocObjCtxCommand: 47 return ZCullBind(input, output);
42 return AllocateObjectContext(input, output); 48 case 0xc:
43 case IoctlCommand::IocChannelGetWaitbaseCommand: 49 return SetErrorNotifier(input, output);
44 return GetWaitbase(input, output); 50 case 0xd:
45 case IoctlCommand::IocChannelSetTimeoutCommand: 51 return SetChannelPriority(input, output);
46 return ChannelSetTimeout(input, output); 52 case 0x1a:
47 case IoctlCommand::IocChannelSetTimeslice: 53 return AllocGPFIFOEx2(input, output);
48 return ChannelSetTimeslice(input, output); 54 case 0x1b:
49 default: 55 return SubmitGPFIFOBase(input, output, true);
56 case 0x1d:
57 return ChannelSetTimeslice(input, output);
58 default:
59 break;
60 }
61 break;
62 case 'G':
63 switch (command.cmd) {
64 case 0x14:
65 return SetClientData(input, output);
66 case 0x15:
67 return GetClientData(input, output);
68 default:
69 break;
70 }
50 break; 71 break;
51 } 72 }
73 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
74 return NvResult::NotImplemented;
75};
52 76
53 if (command.group == NVGPU_IOCTL_MAGIC) { 77NvResult nvhost_gpu::Ioctl2(Ioctl command, const std::vector<u8>& input,
54 if (command.cmd == NVGPU_IOCTL_CHANNEL_SUBMIT_GPFIFO) { 78 const std::vector<u8>& inline_input, std::vector<u8>& output) {
55 return SubmitGPFIFO(input, output); 79 switch (command.group) {
56 } 80 case 'H':
57 if (command.cmd == NVGPU_IOCTL_CHANNEL_KICKOFF_PB) { 81 switch (command.cmd) {
58 return KickoffPB(input, output, input2, version); 82 case 0x1b:
83 return SubmitGPFIFOBase(input, inline_input, output);
59 } 84 }
85 break;
60 } 86 }
87 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
88 return NvResult::NotImplemented;
89}
61 90
62 UNIMPLEMENTED_MSG("Unimplemented ioctl"); 91NvResult nvhost_gpu::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
63 return 0; 92 std::vector<u8>& inline_output) {
64}; 93 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
94 return NvResult::NotImplemented;
95}
65 96
66u32 nvhost_gpu::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) { 97NvResult nvhost_gpu::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) {
67 IoctlSetNvmapFD params{}; 98 IoctlSetNvmapFD params{};
68 std::memcpy(&params, input.data(), input.size()); 99 std::memcpy(&params, input.data(), input.size());
69 LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); 100 LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
70 101
71 nvmap_fd = params.nvmap_fd; 102 nvmap_fd = params.nvmap_fd;
72 return 0; 103 return NvResult::Success;
73} 104}
74 105
75u32 nvhost_gpu::SetClientData(const std::vector<u8>& input, std::vector<u8>& output) { 106NvResult nvhost_gpu::SetClientData(const std::vector<u8>& input, std::vector<u8>& output) {
76 LOG_DEBUG(Service_NVDRV, "called"); 107 LOG_DEBUG(Service_NVDRV, "called");
77 108
78 IoctlClientData params{}; 109 IoctlClientData params{};
79 std::memcpy(&params, input.data(), input.size()); 110 std::memcpy(&params, input.data(), input.size());
80 user_data = params.data; 111 user_data = params.data;
81 return 0; 112 return NvResult::Success;
82} 113}
83 114
84u32 nvhost_gpu::GetClientData(const std::vector<u8>& input, std::vector<u8>& output) { 115NvResult nvhost_gpu::GetClientData(const std::vector<u8>& input, std::vector<u8>& output) {
85 LOG_DEBUG(Service_NVDRV, "called"); 116 LOG_DEBUG(Service_NVDRV, "called");
86 117
87 IoctlClientData params{}; 118 IoctlClientData params{};
88 std::memcpy(&params, input.data(), input.size()); 119 std::memcpy(&params, input.data(), input.size());
89 params.data = user_data; 120 params.data = user_data;
90 std::memcpy(output.data(), &params, output.size()); 121 std::memcpy(output.data(), &params, output.size());
91 return 0; 122 return NvResult::Success;
92} 123}
93 124
94u32 nvhost_gpu::ZCullBind(const std::vector<u8>& input, std::vector<u8>& output) { 125NvResult nvhost_gpu::ZCullBind(const std::vector<u8>& input, std::vector<u8>& output) {
95 std::memcpy(&zcull_params, input.data(), input.size()); 126 std::memcpy(&zcull_params, input.data(), input.size());
96 LOG_DEBUG(Service_NVDRV, "called, gpu_va={:X}, mode={:X}", zcull_params.gpu_va, 127 LOG_DEBUG(Service_NVDRV, "called, gpu_va={:X}, mode={:X}", zcull_params.gpu_va,
97 zcull_params.mode); 128 zcull_params.mode);
98 129
99 std::memcpy(output.data(), &zcull_params, output.size()); 130 std::memcpy(output.data(), &zcull_params, output.size());
100 return 0; 131 return NvResult::Success;
101} 132}
102 133
103u32 nvhost_gpu::SetErrorNotifier(const std::vector<u8>& input, std::vector<u8>& output) { 134NvResult nvhost_gpu::SetErrorNotifier(const std::vector<u8>& input, std::vector<u8>& output) {
104 IoctlSetErrorNotifier params{}; 135 IoctlSetErrorNotifier params{};
105 std::memcpy(&params, input.data(), input.size()); 136 std::memcpy(&params, input.data(), input.size());
106 LOG_WARNING(Service_NVDRV, "(STUBBED) called, offset={:X}, size={:X}, mem={:X}", params.offset, 137 LOG_WARNING(Service_NVDRV, "(STUBBED) called, offset={:X}, size={:X}, mem={:X}", params.offset,
107 params.size, params.mem); 138 params.size, params.mem);
108 139
109 std::memcpy(output.data(), &params, output.size()); 140 std::memcpy(output.data(), &params, output.size());
110 return 0; 141 return NvResult::Success;
111} 142}
112 143
113u32 nvhost_gpu::SetChannelPriority(const std::vector<u8>& input, std::vector<u8>& output) { 144NvResult nvhost_gpu::SetChannelPriority(const std::vector<u8>& input, std::vector<u8>& output) {
114 std::memcpy(&channel_priority, input.data(), input.size()); 145 std::memcpy(&channel_priority, input.data(), input.size());
115 LOG_DEBUG(Service_NVDRV, "(STUBBED) called, priority={:X}", channel_priority); 146 LOG_DEBUG(Service_NVDRV, "(STUBBED) called, priority={:X}", channel_priority);
116 147
117 return 0; 148 return NvResult::Success;
118} 149}
119 150
120u32 nvhost_gpu::AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& output) { 151NvResult nvhost_gpu::AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& output) {
121 IoctlAllocGpfifoEx2 params{}; 152 IoctlAllocGpfifoEx2 params{};
122 std::memcpy(&params, input.data(), input.size()); 153 std::memcpy(&params, input.data(), input.size());
123 LOG_WARNING(Service_NVDRV, 154 LOG_WARNING(Service_NVDRV,
@@ -126,15 +157,15 @@ u32 nvhost_gpu::AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& ou
126 params.num_entries, params.flags, params.unk0, params.unk1, params.unk2, 157 params.num_entries, params.flags, params.unk0, params.unk1, params.unk2,
127 params.unk3); 158 params.unk3);
128 159
129 auto& gpu = system.GPU(); 160 channel_fence.value = system.GPU().GetSyncpointValue(channel_fence.id);
130 params.fence_out.id = assigned_syncpoints; 161
131 params.fence_out.value = gpu.GetSyncpointValue(assigned_syncpoints); 162 params.fence_out = channel_fence;
132 assigned_syncpoints++; 163
133 std::memcpy(output.data(), &params, output.size()); 164 std::memcpy(output.data(), &params, output.size());
134 return 0; 165 return NvResult::Success;
135} 166}
136 167
137u32 nvhost_gpu::AllocateObjectContext(const std::vector<u8>& input, std::vector<u8>& output) { 168NvResult nvhost_gpu::AllocateObjectContext(const std::vector<u8>& input, std::vector<u8>& output) {
138 IoctlAllocObjCtx params{}; 169 IoctlAllocObjCtx params{};
139 std::memcpy(&params, input.data(), input.size()); 170 std::memcpy(&params, input.data(), input.size());
140 LOG_WARNING(Service_NVDRV, "(STUBBED) called, class_num={:X}, flags={:X}", params.class_num, 171 LOG_WARNING(Service_NVDRV, "(STUBBED) called, class_num={:X}, flags={:X}", params.class_num,
@@ -142,102 +173,149 @@ u32 nvhost_gpu::AllocateObjectContext(const std::vector<u8>& input, std::vector<
142 173
143 params.obj_id = 0x0; 174 params.obj_id = 0x0;
144 std::memcpy(output.data(), &params, output.size()); 175 std::memcpy(output.data(), &params, output.size());
145 return 0; 176 return NvResult::Success;
146} 177}
147 178
148u32 nvhost_gpu::SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& output) { 179static std::vector<Tegra::CommandHeader> BuildWaitCommandList(Fence fence) {
149 if (input.size() < sizeof(IoctlSubmitGpfifo)) { 180 return {
150 UNIMPLEMENTED(); 181 Tegra::BuildCommandHeader(Tegra::BufferMethods::FenceValue, 1,
182 Tegra::SubmissionMode::Increasing),
183 {fence.value},
184 Tegra::BuildCommandHeader(Tegra::BufferMethods::FenceAction, 1,
185 Tegra::SubmissionMode::Increasing),
186 Tegra::GPU::FenceAction::Build(Tegra::GPU::FenceOperation::Acquire, fence.id),
187 };
188}
189
190static std::vector<Tegra::CommandHeader> BuildIncrementCommandList(Fence fence, u32 add_increment) {
191 std::vector<Tegra::CommandHeader> result{
192 Tegra::BuildCommandHeader(Tegra::BufferMethods::FenceValue, 1,
193 Tegra::SubmissionMode::Increasing),
194 {}};
195
196 for (u32 count = 0; count < add_increment; ++count) {
197 result.emplace_back(Tegra::BuildCommandHeader(Tegra::BufferMethods::FenceAction, 1,
198 Tegra::SubmissionMode::Increasing));
199 result.emplace_back(
200 Tegra::GPU::FenceAction::Build(Tegra::GPU::FenceOperation::Increment, fence.id));
151 } 201 }
152 IoctlSubmitGpfifo params{}; 202
153 std::memcpy(&params, input.data(), sizeof(IoctlSubmitGpfifo)); 203 return result;
204}
205
206static std::vector<Tegra::CommandHeader> BuildIncrementWithWfiCommandList(Fence fence,
207 u32 add_increment) {
208 std::vector<Tegra::CommandHeader> result{
209 Tegra::BuildCommandHeader(Tegra::BufferMethods::WaitForInterrupt, 1,
210 Tegra::SubmissionMode::Increasing),
211 {}};
212 const std::vector<Tegra::CommandHeader> increment{
213 BuildIncrementCommandList(fence, add_increment)};
214
215 result.insert(result.end(), increment.begin(), increment.end());
216
217 return result;
218}
219
220NvResult nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector<u8>& output,
221 Tegra::CommandList&& entries) {
154 LOG_TRACE(Service_NVDRV, "called, gpfifo={:X}, num_entries={:X}, flags={:X}", params.address, 222 LOG_TRACE(Service_NVDRV, "called, gpfifo={:X}, num_entries={:X}, flags={:X}", params.address,
155 params.num_entries, params.flags.raw); 223 params.num_entries, params.flags.raw);
156 224
157 ASSERT_MSG(input.size() == sizeof(IoctlSubmitGpfifo) + 225 auto& gpu = system.GPU();
158 params.num_entries * sizeof(Tegra::CommandListHeader),
159 "Incorrect input size");
160 226
161 Tegra::CommandList entries(params.num_entries); 227 params.fence_out.id = channel_fence.id;
162 std::memcpy(entries.data(), &input[sizeof(IoctlSubmitGpfifo)],
163 params.num_entries * sizeof(Tegra::CommandListHeader));
164 228
165 UNIMPLEMENTED_IF(params.flags.add_wait.Value() != 0); 229 if (params.flags.add_wait.Value() &&
166 UNIMPLEMENTED_IF(params.flags.add_increment.Value() != 0); 230 !syncpoint_manager.IsSyncpointExpired(params.fence_out.id, params.fence_out.value)) {
231 gpu.PushGPUEntries(Tegra::CommandList{BuildWaitCommandList(params.fence_out)});
232 }
167 233
168 auto& gpu = system.GPU(); 234 if (params.flags.add_increment.Value() || params.flags.increment.Value()) {
169 u32 current_syncpoint_value = gpu.GetSyncpointValue(params.fence_out.id); 235 const u32 increment_value = params.flags.increment.Value() ? params.fence_out.value : 0;
170 if (params.flags.increment.Value()) { 236 params.fence_out.value = syncpoint_manager.IncreaseSyncpoint(
171 params.fence_out.value += current_syncpoint_value; 237 params.fence_out.id, params.AddIncrementValue() + increment_value);
172 } else { 238 } else {
173 params.fence_out.value = current_syncpoint_value; 239 params.fence_out.value = syncpoint_manager.GetSyncpointMax(params.fence_out.id);
174 } 240 }
241
175 gpu.PushGPUEntries(std::move(entries)); 242 gpu.PushGPUEntries(std::move(entries));
176 243
244 if (params.flags.add_increment.Value()) {
245 if (params.flags.suppress_wfi) {
246 gpu.PushGPUEntries(Tegra::CommandList{
247 BuildIncrementCommandList(params.fence_out, params.AddIncrementValue())});
248 } else {
249 gpu.PushGPUEntries(Tegra::CommandList{
250 BuildIncrementWithWfiCommandList(params.fence_out, params.AddIncrementValue())});
251 }
252 }
253
177 std::memcpy(output.data(), &params, sizeof(IoctlSubmitGpfifo)); 254 std::memcpy(output.data(), &params, sizeof(IoctlSubmitGpfifo));
178 return 0; 255 return NvResult::Success;
179} 256}
180 257
181u32 nvhost_gpu::KickoffPB(const std::vector<u8>& input, std::vector<u8>& output, 258NvResult nvhost_gpu::SubmitGPFIFOBase(const std::vector<u8>& input, std::vector<u8>& output,
182 const std::vector<u8>& input2, IoctlVersion version) { 259 bool kickoff) {
183 if (input.size() < sizeof(IoctlSubmitGpfifo)) { 260 if (input.size() < sizeof(IoctlSubmitGpfifo)) {
184 UNIMPLEMENTED(); 261 UNIMPLEMENTED();
262 return NvResult::InvalidSize;
185 } 263 }
186 IoctlSubmitGpfifo params{}; 264 IoctlSubmitGpfifo params{};
187 std::memcpy(&params, input.data(), sizeof(IoctlSubmitGpfifo)); 265 std::memcpy(&params, input.data(), sizeof(IoctlSubmitGpfifo));
188 LOG_TRACE(Service_NVDRV, "called, gpfifo={:X}, num_entries={:X}, flags={:X}", params.address,
189 params.num_entries, params.flags.raw);
190
191 Tegra::CommandList entries(params.num_entries); 266 Tegra::CommandList entries(params.num_entries);
192 if (version == IoctlVersion::Version2) {
193 std::memcpy(entries.data(), input2.data(),
194 params.num_entries * sizeof(Tegra::CommandListHeader));
195 } else {
196 system.Memory().ReadBlock(params.address, entries.data(),
197 params.num_entries * sizeof(Tegra::CommandListHeader));
198 }
199 UNIMPLEMENTED_IF(params.flags.add_wait.Value() != 0);
200 UNIMPLEMENTED_IF(params.flags.add_increment.Value() != 0);
201 267
202 auto& gpu = system.GPU(); 268 if (kickoff) {
203 u32 current_syncpoint_value = gpu.GetSyncpointValue(params.fence_out.id); 269 system.Memory().ReadBlock(params.address, entries.command_lists.data(),
204 if (params.flags.increment.Value()) { 270 params.num_entries * sizeof(Tegra::CommandListHeader));
205 params.fence_out.value += current_syncpoint_value;
206 } else { 271 } else {
207 params.fence_out.value = current_syncpoint_value; 272 std::memcpy(entries.command_lists.data(), &input[sizeof(IoctlSubmitGpfifo)],
273 params.num_entries * sizeof(Tegra::CommandListHeader));
208 } 274 }
209 gpu.PushGPUEntries(std::move(entries));
210 275
211 std::memcpy(output.data(), &params, output.size()); 276 return SubmitGPFIFOImpl(params, output, std::move(entries));
212 return 0; 277}
278
279NvResult nvhost_gpu::SubmitGPFIFOBase(const std::vector<u8>& input,
280 const std::vector<u8>& input_inline,
281 std::vector<u8>& output) {
282 if (input.size() < sizeof(IoctlSubmitGpfifo)) {
283 UNIMPLEMENTED();
284 return NvResult::InvalidSize;
285 }
286 IoctlSubmitGpfifo params{};
287 std::memcpy(&params, input.data(), sizeof(IoctlSubmitGpfifo));
288 Tegra::CommandList entries(params.num_entries);
289 std::memcpy(entries.command_lists.data(), input_inline.data(), input_inline.size());
290 return SubmitGPFIFOImpl(params, output, std::move(entries));
213} 291}
214 292
215u32 nvhost_gpu::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) { 293NvResult nvhost_gpu::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) {
216 IoctlGetWaitbase params{}; 294 IoctlGetWaitbase params{};
217 std::memcpy(&params, input.data(), sizeof(IoctlGetWaitbase)); 295 std::memcpy(&params, input.data(), sizeof(IoctlGetWaitbase));
218 LOG_INFO(Service_NVDRV, "called, unknown=0x{:X}", params.unknown); 296 LOG_INFO(Service_NVDRV, "called, unknown=0x{:X}", params.unknown);
219 297
220 params.value = 0; // Seems to be hard coded at 0 298 params.value = 0; // Seems to be hard coded at 0
221 std::memcpy(output.data(), &params, output.size()); 299 std::memcpy(output.data(), &params, output.size());
222 return 0; 300 return NvResult::Success;
223} 301}
224 302
225u32 nvhost_gpu::ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& output) { 303NvResult nvhost_gpu::ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& output) {
226 IoctlChannelSetTimeout params{}; 304 IoctlChannelSetTimeout params{};
227 std::memcpy(&params, input.data(), sizeof(IoctlChannelSetTimeout)); 305 std::memcpy(&params, input.data(), sizeof(IoctlChannelSetTimeout));
228 LOG_INFO(Service_NVDRV, "called, timeout=0x{:X}", params.timeout); 306 LOG_INFO(Service_NVDRV, "called, timeout=0x{:X}", params.timeout);
229 307
230 return 0; 308 return NvResult::Success;
231} 309}
232 310
233u32 nvhost_gpu::ChannelSetTimeslice(const std::vector<u8>& input, std::vector<u8>& output) { 311NvResult nvhost_gpu::ChannelSetTimeslice(const std::vector<u8>& input, std::vector<u8>& output) {
234 IoctlSetTimeslice params{}; 312 IoctlSetTimeslice params{};
235 std::memcpy(&params, input.data(), sizeof(IoctlSetTimeslice)); 313 std::memcpy(&params, input.data(), sizeof(IoctlSetTimeslice));
236 LOG_INFO(Service_NVDRV, "called, timeslice=0x{:X}", params.timeslice); 314 LOG_INFO(Service_NVDRV, "called, timeslice=0x{:X}", params.timeslice);
237 315
238 channel_timeslice = params.timeslice; 316 channel_timeslice = params.timeslice;
239 317
240 return 0; 318 return NvResult::Success;
241} 319}
242 320
243} // namespace Service::Nvidia::Devices 321} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
index 2ac74743f..e0298b4fe 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
@@ -11,46 +11,28 @@
11#include "common/swap.h" 11#include "common/swap.h"
12#include "core/hle/service/nvdrv/devices/nvdevice.h" 12#include "core/hle/service/nvdrv/devices/nvdevice.h"
13#include "core/hle/service/nvdrv/nvdata.h" 13#include "core/hle/service/nvdrv/nvdata.h"
14#include "video_core/dma_pusher.h"
15
16namespace Service::Nvidia {
17class SyncpointManager;
18}
14 19
15namespace Service::Nvidia::Devices { 20namespace Service::Nvidia::Devices {
16 21
17class nvmap; 22class nvmap;
18constexpr u32 NVGPU_IOCTL_MAGIC('H');
19constexpr u32 NVGPU_IOCTL_CHANNEL_SUBMIT_GPFIFO(0x8);
20constexpr u32 NVGPU_IOCTL_CHANNEL_KICKOFF_PB(0x1b);
21
22class nvhost_gpu final : public nvdevice { 23class nvhost_gpu final : public nvdevice {
23public: 24public:
24 explicit nvhost_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev); 25 explicit nvhost_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev,
26 SyncpointManager& syncpoint_manager);
25 ~nvhost_gpu() override; 27 ~nvhost_gpu() override;
26 28
27 u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, 29 NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
28 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, 30 NvResult Ioctl2(Ioctl command, const std::vector<u8>& input,
29 IoctlVersion version) override; 31 const std::vector<u8>& inline_input, std::vector<u8>& output) override;
32 NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
33 std::vector<u8>& inline_output) override;
30 34
31private: 35private:
32 enum class IoctlCommand : u32_le {
33 IocSetNVMAPfdCommand = 0x40044801,
34 IocAllocGPFIFOCommand = 0x40084805,
35 IocSetClientDataCommand = 0x40084714,
36 IocGetClientDataCommand = 0x80084715,
37 IocZCullBind = 0xc010480b,
38 IocSetErrorNotifierCommand = 0xC018480C,
39 IocChannelSetPriorityCommand = 0x4004480D,
40 IocEnableCommand = 0x0000480E,
41 IocDisableCommand = 0x0000480F,
42 IocPreemptCommand = 0x00004810,
43 IocForceResetCommand = 0x00004811,
44 IocEventIdControlCommand = 0x40084812,
45 IocGetErrorNotificationCommand = 0xC0104817,
46 IocAllocGPFIFOExCommand = 0x40204818,
47 IocAllocGPFIFOEx2Command = 0xC020481A,
48 IocAllocObjCtxCommand = 0xC0104809,
49 IocChannelGetWaitbaseCommand = 0xC0080003,
50 IocChannelSetTimeoutCommand = 0x40044803,
51 IocChannelSetTimeslice = 0xC004481D,
52 };
53
54 enum class CtxObjects : u32_le { 36 enum class CtxObjects : u32_le {
55 Ctx2D = 0x902D, 37 Ctx2D = 0x902D,
56 Ctx3D = 0xB197, 38 Ctx3D = 0xB197,
@@ -61,63 +43,63 @@ private:
61 }; 43 };
62 44
63 struct IoctlSetNvmapFD { 45 struct IoctlSetNvmapFD {
64 u32_le nvmap_fd; 46 s32_le nvmap_fd{};
65 }; 47 };
66 static_assert(sizeof(IoctlSetNvmapFD) == 4, "IoctlSetNvmapFD is incorrect size"); 48 static_assert(sizeof(IoctlSetNvmapFD) == 4, "IoctlSetNvmapFD is incorrect size");
67 49
68 struct IoctlChannelSetTimeout { 50 struct IoctlChannelSetTimeout {
69 u32_le timeout; 51 u32_le timeout{};
70 }; 52 };
71 static_assert(sizeof(IoctlChannelSetTimeout) == 4, "IoctlChannelSetTimeout is incorrect size"); 53 static_assert(sizeof(IoctlChannelSetTimeout) == 4, "IoctlChannelSetTimeout is incorrect size");
72 54
73 struct IoctlAllocGPFIFO { 55 struct IoctlAllocGPFIFO {
74 u32_le num_entries; 56 u32_le num_entries{};
75 u32_le flags; 57 u32_le flags{};
76 }; 58 };
77 static_assert(sizeof(IoctlAllocGPFIFO) == 8, "IoctlAllocGPFIFO is incorrect size"); 59 static_assert(sizeof(IoctlAllocGPFIFO) == 8, "IoctlAllocGPFIFO is incorrect size");
78 60
79 struct IoctlClientData { 61 struct IoctlClientData {
80 u64_le data; 62 u64_le data{};
81 }; 63 };
82 static_assert(sizeof(IoctlClientData) == 8, "IoctlClientData is incorrect size"); 64 static_assert(sizeof(IoctlClientData) == 8, "IoctlClientData is incorrect size");
83 65
84 struct IoctlZCullBind { 66 struct IoctlZCullBind {
85 u64_le gpu_va; 67 u64_le gpu_va{};
86 u32_le mode; // 0=global, 1=no_ctxsw, 2=separate_buffer, 3=part_of_regular_buf 68 u32_le mode{}; // 0=global, 1=no_ctxsw, 2=separate_buffer, 3=part_of_regular_buf
87 INSERT_PADDING_WORDS(1); 69 INSERT_PADDING_WORDS(1);
88 }; 70 };
89 static_assert(sizeof(IoctlZCullBind) == 16, "IoctlZCullBind is incorrect size"); 71 static_assert(sizeof(IoctlZCullBind) == 16, "IoctlZCullBind is incorrect size");
90 72
91 struct IoctlSetErrorNotifier { 73 struct IoctlSetErrorNotifier {
92 u64_le offset; 74 u64_le offset{};
93 u64_le size; 75 u64_le size{};
94 u32_le mem; // nvmap object handle 76 u32_le mem{}; // nvmap object handle
95 INSERT_PADDING_WORDS(1); 77 INSERT_PADDING_WORDS(1);
96 }; 78 };
97 static_assert(sizeof(IoctlSetErrorNotifier) == 24, "IoctlSetErrorNotifier is incorrect size"); 79 static_assert(sizeof(IoctlSetErrorNotifier) == 24, "IoctlSetErrorNotifier is incorrect size");
98 80
99 struct IoctlChannelSetPriority { 81 struct IoctlChannelSetPriority {
100 u32_le priority; 82 u32_le priority{};
101 }; 83 };
102 static_assert(sizeof(IoctlChannelSetPriority) == 4, 84 static_assert(sizeof(IoctlChannelSetPriority) == 4,
103 "IoctlChannelSetPriority is incorrect size"); 85 "IoctlChannelSetPriority is incorrect size");
104 86
105 struct IoctlSetTimeslice { 87 struct IoctlSetTimeslice {
106 u32_le timeslice; 88 u32_le timeslice{};
107 }; 89 };
108 static_assert(sizeof(IoctlSetTimeslice) == 4, "IoctlSetTimeslice is incorrect size"); 90 static_assert(sizeof(IoctlSetTimeslice) == 4, "IoctlSetTimeslice is incorrect size");
109 91
110 struct IoctlEventIdControl { 92 struct IoctlEventIdControl {
111 u32_le cmd; // 0=disable, 1=enable, 2=clear 93 u32_le cmd{}; // 0=disable, 1=enable, 2=clear
112 u32_le id; 94 u32_le id{};
113 }; 95 };
114 static_assert(sizeof(IoctlEventIdControl) == 8, "IoctlEventIdControl is incorrect size"); 96 static_assert(sizeof(IoctlEventIdControl) == 8, "IoctlEventIdControl is incorrect size");
115 97
116 struct IoctlGetErrorNotification { 98 struct IoctlGetErrorNotification {
117 u64_le timestamp; 99 u64_le timestamp{};
118 u32_le info32; 100 u32_le info32{};
119 u16_le info16; 101 u16_le info16{};
120 u16_le status; // always 0xFFFF 102 u16_le status{}; // always 0xFFFF
121 }; 103 };
122 static_assert(sizeof(IoctlGetErrorNotification) == 16, 104 static_assert(sizeof(IoctlGetErrorNotification) == 16,
123 "IoctlGetErrorNotification is incorrect size"); 105 "IoctlGetErrorNotification is incorrect size");
@@ -125,80 +107,89 @@ private:
125 static_assert(sizeof(Fence) == 8, "Fence is incorrect size"); 107 static_assert(sizeof(Fence) == 8, "Fence is incorrect size");
126 108
127 struct IoctlAllocGpfifoEx { 109 struct IoctlAllocGpfifoEx {
128 u32_le num_entries; 110 u32_le num_entries{};
129 u32_le flags; 111 u32_le flags{};
130 u32_le unk0; 112 u32_le unk0{};
131 u32_le unk1; 113 u32_le unk1{};
132 u32_le unk2; 114 u32_le unk2{};
133 u32_le unk3; 115 u32_le unk3{};
134 u32_le unk4; 116 u32_le unk4{};
135 u32_le unk5; 117 u32_le unk5{};
136 }; 118 };
137 static_assert(sizeof(IoctlAllocGpfifoEx) == 32, "IoctlAllocGpfifoEx is incorrect size"); 119 static_assert(sizeof(IoctlAllocGpfifoEx) == 32, "IoctlAllocGpfifoEx is incorrect size");
138 120
139 struct IoctlAllocGpfifoEx2 { 121 struct IoctlAllocGpfifoEx2 {
140 u32_le num_entries; // in 122 u32_le num_entries{}; // in
141 u32_le flags; // in 123 u32_le flags{}; // in
142 u32_le unk0; // in (1 works) 124 u32_le unk0{}; // in (1 works)
143 Fence fence_out; // out 125 Fence fence_out{}; // out
144 u32_le unk1; // in 126 u32_le unk1{}; // in
145 u32_le unk2; // in 127 u32_le unk2{}; // in
146 u32_le unk3; // in 128 u32_le unk3{}; // in
147 }; 129 };
148 static_assert(sizeof(IoctlAllocGpfifoEx2) == 32, "IoctlAllocGpfifoEx2 is incorrect size"); 130 static_assert(sizeof(IoctlAllocGpfifoEx2) == 32, "IoctlAllocGpfifoEx2 is incorrect size");
149 131
150 struct IoctlAllocObjCtx { 132 struct IoctlAllocObjCtx {
151 u32_le class_num; // 0x902D=2d, 0xB197=3d, 0xB1C0=compute, 0xA140=kepler, 0xB0B5=DMA, 133 u32_le class_num{}; // 0x902D=2d, 0xB197=3d, 0xB1C0=compute, 0xA140=kepler, 0xB0B5=DMA,
152 // 0xB06F=channel_gpfifo 134 // 0xB06F=channel_gpfifo
153 u32_le flags; 135 u32_le flags{};
154 u64_le obj_id; // (ignored) used for FREE_OBJ_CTX ioctl, which is not supported 136 u64_le obj_id{}; // (ignored) used for FREE_OBJ_CTX ioctl, which is not supported
155 }; 137 };
156 static_assert(sizeof(IoctlAllocObjCtx) == 16, "IoctlAllocObjCtx is incorrect size"); 138 static_assert(sizeof(IoctlAllocObjCtx) == 16, "IoctlAllocObjCtx is incorrect size");
157 139
158 struct IoctlSubmitGpfifo { 140 struct IoctlSubmitGpfifo {
159 u64_le address; // pointer to gpfifo entry structs 141 u64_le address{}; // pointer to gpfifo entry structs
160 u32_le num_entries; // number of fence objects being submitted 142 u32_le num_entries{}; // number of fence objects being submitted
161 union { 143 union {
162 u32_le raw; 144 u32_le raw;
163 BitField<0, 1, u32_le> add_wait; // append a wait sync_point to the list 145 BitField<0, 1, u32_le> add_wait; // append a wait sync_point to the list
164 BitField<1, 1, u32_le> add_increment; // append an increment to the list 146 BitField<1, 1, u32_le> add_increment; // append an increment to the list
165 BitField<2, 1, u32_le> new_hw_format; // Mostly ignored 147 BitField<2, 1, u32_le> new_hw_format; // mostly ignored
148 BitField<4, 1, u32_le> suppress_wfi; // suppress wait for interrupt
166 BitField<8, 1, u32_le> increment; // increment the returned fence 149 BitField<8, 1, u32_le> increment; // increment the returned fence
167 } flags; 150 } flags;
168 Fence fence_out; // returned new fence object for others to wait on 151 Fence fence_out{}; // returned new fence object for others to wait on
152
153 u32 AddIncrementValue() const {
154 return flags.add_increment.Value() << 1;
155 }
169 }; 156 };
170 static_assert(sizeof(IoctlSubmitGpfifo) == 16 + sizeof(Fence), 157 static_assert(sizeof(IoctlSubmitGpfifo) == 16 + sizeof(Fence),
171 "IoctlSubmitGpfifo is incorrect size"); 158 "IoctlSubmitGpfifo is incorrect size");
172 159
173 struct IoctlGetWaitbase { 160 struct IoctlGetWaitbase {
174 u32 unknown; // seems to be ignored? Nintendo added this 161 u32 unknown{}; // seems to be ignored? Nintendo added this
175 u32 value; 162 u32 value{};
176 }; 163 };
177 static_assert(sizeof(IoctlGetWaitbase) == 8, "IoctlGetWaitbase is incorrect size"); 164 static_assert(sizeof(IoctlGetWaitbase) == 8, "IoctlGetWaitbase is incorrect size");
178 165
179 u32_le nvmap_fd{}; 166 s32_le nvmap_fd{};
180 u64_le user_data{}; 167 u64_le user_data{};
181 IoctlZCullBind zcull_params{}; 168 IoctlZCullBind zcull_params{};
182 u32_le channel_priority{}; 169 u32_le channel_priority{};
183 u32_le channel_timeslice{}; 170 u32_le channel_timeslice{};
184 171
185 u32 SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output); 172 NvResult SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output);
186 u32 SetClientData(const std::vector<u8>& input, std::vector<u8>& output); 173 NvResult SetClientData(const std::vector<u8>& input, std::vector<u8>& output);
187 u32 GetClientData(const std::vector<u8>& input, std::vector<u8>& output); 174 NvResult GetClientData(const std::vector<u8>& input, std::vector<u8>& output);
188 u32 ZCullBind(const std::vector<u8>& input, std::vector<u8>& output); 175 NvResult ZCullBind(const std::vector<u8>& input, std::vector<u8>& output);
189 u32 SetErrorNotifier(const std::vector<u8>& input, std::vector<u8>& output); 176 NvResult SetErrorNotifier(const std::vector<u8>& input, std::vector<u8>& output);
190 u32 SetChannelPriority(const std::vector<u8>& input, std::vector<u8>& output); 177 NvResult SetChannelPriority(const std::vector<u8>& input, std::vector<u8>& output);
191 u32 AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& output); 178 NvResult AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& output);
192 u32 AllocateObjectContext(const std::vector<u8>& input, std::vector<u8>& output); 179 NvResult AllocateObjectContext(const std::vector<u8>& input, std::vector<u8>& output);
193 u32 SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& output); 180 NvResult SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector<u8>& output,
194 u32 KickoffPB(const std::vector<u8>& input, std::vector<u8>& output, 181 Tegra::CommandList&& entries);
195 const std::vector<u8>& input2, IoctlVersion version); 182 NvResult SubmitGPFIFOBase(const std::vector<u8>& input, std::vector<u8>& output,
196 u32 GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output); 183 bool kickoff = false);
197 u32 ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& output); 184 NvResult SubmitGPFIFOBase(const std::vector<u8>& input, const std::vector<u8>& input_inline,
198 u32 ChannelSetTimeslice(const std::vector<u8>& input, std::vector<u8>& output); 185 std::vector<u8>& output);
186 NvResult GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output);
187 NvResult ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& output);
188 NvResult ChannelSetTimeslice(const std::vector<u8>& input, std::vector<u8>& output);
199 189
200 std::shared_ptr<nvmap> nvmap_dev; 190 std::shared_ptr<nvmap> nvmap_dev;
201 u32 assigned_syncpoints{}; 191 SyncpointManager& syncpoint_manager;
192 Fence channel_fence;
202}; 193};
203 194
204} // namespace Service::Nvidia::Devices 195} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
index bdae8b887..36970f828 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
@@ -2,39 +2,72 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <cstring>
6
7#include "common/assert.h" 5#include "common/assert.h"
8#include "common/logging/log.h" 6#include "common/logging/log.h"
7#include "core/core.h"
9#include "core/hle/service/nvdrv/devices/nvhost_nvdec.h" 8#include "core/hle/service/nvdrv/devices/nvhost_nvdec.h"
9#include "video_core/memory_manager.h"
10#include "video_core/renderer_base.h"
10 11
11namespace Service::Nvidia::Devices { 12namespace Service::Nvidia::Devices {
12 13
13nvhost_nvdec::nvhost_nvdec(Core::System& system) : nvdevice(system) {} 14nvhost_nvdec::nvhost_nvdec(Core::System& system, std::shared_ptr<nvmap> nvmap_dev,
15 SyncpointManager& syncpoint_manager)
16 : nvhost_nvdec_common(system, std::move(nvmap_dev), syncpoint_manager) {}
14nvhost_nvdec::~nvhost_nvdec() = default; 17nvhost_nvdec::~nvhost_nvdec() = default;
15 18
16u32 nvhost_nvdec::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, 19NvResult nvhost_nvdec::Ioctl1(Ioctl command, const std::vector<u8>& input,
17 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, 20 std::vector<u8>& output) {
18 IoctlVersion version) { 21 switch (command.group) {
19 LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", 22 case 0x0:
20 command.raw, input.size(), output.size()); 23 switch (command.cmd) {
21 24 case 0x1:
22 switch (static_cast<IoctlCommand>(command.raw)) { 25 return Submit(input, output);
23 case IoctlCommand::IocSetNVMAPfdCommand: 26 case 0x2:
24 return SetNVMAPfd(input, output); 27 return GetSyncpoint(input, output);
28 case 0x3:
29 return GetWaitbase(input, output);
30 case 0x7:
31 return SetSubmitTimeout(input, output);
32 case 0x9:
33 return MapBuffer(input, output);
34 case 0xa: {
35 if (command.length == 0x1c) {
36 LOG_INFO(Service_NVDRV, "NVDEC video stream ended");
37 Tegra::ChCommandHeaderList cmdlist(1);
38 cmdlist[0] = Tegra::ChCommandHeader{0xDEADB33F};
39 system.GPU().PushCommandBuffer(cmdlist);
40 }
41 return UnmapBuffer(input, output);
42 }
43 default:
44 break;
45 }
46 break;
47 case 'H':
48 switch (command.cmd) {
49 case 0x1:
50 return SetNVMAPfd(input);
51 default:
52 break;
53 }
54 break;
25 } 55 }
26 56
27 UNIMPLEMENTED_MSG("Unimplemented ioctl"); 57 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
28 return 0; 58 return NvResult::NotImplemented;
29} 59}
30 60
31u32 nvhost_nvdec::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) { 61NvResult nvhost_nvdec::Ioctl2(Ioctl command, const std::vector<u8>& input,
32 IoctlSetNvmapFD params{}; 62 const std::vector<u8>& inline_input, std::vector<u8>& output) {
33 std::memcpy(&params, input.data(), input.size()); 63 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
34 LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); 64 return NvResult::NotImplemented;
65}
35 66
36 nvmap_fd = params.nvmap_fd; 67NvResult nvhost_nvdec::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
37 return 0; 68 std::vector<u8>& inline_output) {
69 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
70 return NvResult::NotImplemented;
38} 71}
39 72
40} // namespace Service::Nvidia::Devices 73} // 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 cbdac8069..77ef53cdd 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h
@@ -4,35 +4,22 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <vector> 7#include <memory>
8#include "common/common_types.h" 8#include "core/hle/service/nvdrv/devices/nvhost_nvdec_common.h"
9#include "common/swap.h"
10#include "core/hle/service/nvdrv/devices/nvdevice.h"
11 9
12namespace Service::Nvidia::Devices { 10namespace Service::Nvidia::Devices {
13 11
14class nvhost_nvdec final : public nvdevice { 12class nvhost_nvdec final : public nvhost_nvdec_common {
15public: 13public:
16 explicit nvhost_nvdec(Core::System& system); 14 explicit nvhost_nvdec(Core::System& system, std::shared_ptr<nvmap> nvmap_dev,
15 SyncpointManager& syncpoint_manager);
17 ~nvhost_nvdec() override; 16 ~nvhost_nvdec() override;
18 17
19 u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, 18 NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
20 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, 19 NvResult Ioctl2(Ioctl command, const std::vector<u8>& input,
21 IoctlVersion version) override; 20 const std::vector<u8>& inline_input, std::vector<u8>& output) override;
22 21 NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
23private: 22 std::vector<u8>& inline_output) override;
24 enum class IoctlCommand : u32_le {
25 IocSetNVMAPfdCommand = 0x40044801,
26 };
27
28 struct IoctlSetNvmapFD {
29 u32_le nvmap_fd;
30 };
31 static_assert(sizeof(IoctlSetNvmapFD) == 4, "IoctlSetNvmapFD is incorrect size");
32
33 u32_le nvmap_fd{};
34
35 u32 SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output);
36}; 23};
37 24
38} // namespace Service::Nvidia::Devices 25} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp
new file mode 100644
index 000000000..4898dc27a
--- /dev/null
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp
@@ -0,0 +1,244 @@
1// Copyright 2020 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <algorithm>
6#include <cstring>
7
8#include "common/assert.h"
9#include "common/common_types.h"
10#include "common/logging/log.h"
11#include "core/core.h"
12#include "core/hle/service/nvdrv/devices/nvhost_nvdec_common.h"
13#include "core/hle/service/nvdrv/devices/nvmap.h"
14#include "core/hle/service/nvdrv/syncpoint_manager.h"
15#include "core/memory.h"
16#include "video_core/memory_manager.h"
17#include "video_core/renderer_base.h"
18
19namespace Service::Nvidia::Devices {
20
21namespace {
22// Splice vectors will copy count amount of type T from the input vector into the dst vector.
23template <typename T>
24std::size_t SpliceVectors(const std::vector<u8>& input, std::vector<T>& dst, std::size_t count,
25 std::size_t offset) {
26 std::memcpy(dst.data(), input.data() + offset, count * sizeof(T));
27 offset += count * sizeof(T);
28 return offset;
29}
30
31// Write vectors will write data to the output buffer
32template <typename T>
33std::size_t WriteVectors(std::vector<u8>& dst, const std::vector<T>& src, std::size_t offset) {
34 std::memcpy(dst.data() + offset, src.data(), src.size() * sizeof(T));
35 offset += src.size() * sizeof(T);
36 return offset;
37}
38} // Anonymous namespace
39
40nvhost_nvdec_common::nvhost_nvdec_common(Core::System& system, std::shared_ptr<nvmap> nvmap_dev,
41 SyncpointManager& syncpoint_manager)
42 : nvdevice(system), nvmap_dev(std::move(nvmap_dev)), syncpoint_manager(syncpoint_manager) {}
43nvhost_nvdec_common::~nvhost_nvdec_common() = default;
44
45NvResult nvhost_nvdec_common::SetNVMAPfd(const std::vector<u8>& input) {
46 IoctlSetNvmapFD params{};
47 std::memcpy(&params, input.data(), sizeof(IoctlSetNvmapFD));
48 LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
49
50 nvmap_fd = params.nvmap_fd;
51 return NvResult::Success;
52}
53
54NvResult nvhost_nvdec_common::Submit(const std::vector<u8>& input, std::vector<u8>& output) {
55 IoctlSubmit params{};
56 std::memcpy(&params, input.data(), sizeof(IoctlSubmit));
57 LOG_DEBUG(Service_NVDRV, "called NVDEC Submit, cmd_buffer_count={}", params.cmd_buffer_count);
58
59 // Instantiate param buffers
60 std::size_t offset = sizeof(IoctlSubmit);
61 std::vector<CommandBuffer> command_buffers(params.cmd_buffer_count);
62 std::vector<Reloc> relocs(params.relocation_count);
63 std::vector<u32> reloc_shifts(params.relocation_count);
64 std::vector<SyncptIncr> syncpt_increments(params.syncpoint_count);
65 std::vector<SyncptIncr> wait_checks(params.syncpoint_count);
66 std::vector<Fence> fences(params.fence_count);
67
68 // Splice input into their respective buffers
69 offset = SpliceVectors(input, command_buffers, params.cmd_buffer_count, offset);
70 offset = SpliceVectors(input, relocs, params.relocation_count, offset);
71 offset = SpliceVectors(input, reloc_shifts, params.relocation_count, offset);
72 offset = SpliceVectors(input, syncpt_increments, params.syncpoint_count, offset);
73 offset = SpliceVectors(input, wait_checks, params.syncpoint_count, offset);
74 offset = SpliceVectors(input, fences, params.fence_count, offset);
75
76 auto& gpu = system.GPU();
77 if (gpu.UseNvdec()) {
78 for (std::size_t i = 0; i < syncpt_increments.size(); i++) {
79 const SyncptIncr& syncpt_incr = syncpt_increments[i];
80 fences[i].id = syncpt_incr.id;
81 fences[i].value =
82 syncpoint_manager.IncreaseSyncpoint(syncpt_incr.id, syncpt_incr.increments);
83 }
84 }
85 for (const auto& cmd_buffer : command_buffers) {
86 auto object = nvmap_dev->GetObject(cmd_buffer.memory_id);
87 ASSERT_OR_EXECUTE(object, return NvResult::InvalidState;);
88 const auto map = FindBufferMap(object->dma_map_addr);
89 if (!map) {
90 LOG_ERROR(Service_NVDRV, "Tried to submit an invalid offset 0x{:X} dma 0x{:X}",
91 object->addr, object->dma_map_addr);
92 return NvResult::Success;
93 }
94 Tegra::ChCommandHeaderList cmdlist(cmd_buffer.word_count);
95 gpu.MemoryManager().ReadBlock(map->StartAddr() + cmd_buffer.offset, cmdlist.data(),
96 cmdlist.size() * sizeof(u32));
97 gpu.PushCommandBuffer(cmdlist);
98 }
99 if (gpu.UseNvdec()) {
100
101 fences[0].value = syncpoint_manager.IncreaseSyncpoint(fences[0].id, 1);
102
103 Tegra::ChCommandHeaderList cmdlist{{(4 << 28) | fences[0].id}};
104 gpu.PushCommandBuffer(cmdlist);
105 }
106 std::memcpy(output.data(), &params, sizeof(IoctlSubmit));
107 // Some games expect command_buffers to be written back
108 offset = sizeof(IoctlSubmit);
109 offset = WriteVectors(output, command_buffers, offset);
110 offset = WriteVectors(output, relocs, offset);
111 offset = WriteVectors(output, reloc_shifts, offset);
112 offset = WriteVectors(output, syncpt_increments, offset);
113 offset = WriteVectors(output, wait_checks, offset);
114 offset = WriteVectors(output, fences, offset);
115
116 return NvResult::Success;
117}
118
119NvResult nvhost_nvdec_common::GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output) {
120 IoctlGetSyncpoint params{};
121 std::memcpy(&params, input.data(), sizeof(IoctlGetSyncpoint));
122 LOG_DEBUG(Service_NVDRV, "called GetSyncpoint, id={}", params.param);
123
124 if (device_syncpoints[params.param] == 0 && system.GPU().UseNvdec()) {
125 device_syncpoints[params.param] = syncpoint_manager.AllocateSyncpoint();
126 }
127 params.value = device_syncpoints[params.param];
128 std::memcpy(output.data(), &params, sizeof(IoctlGetSyncpoint));
129
130 return NvResult::Success;
131}
132
133NvResult nvhost_nvdec_common::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) {
134 IoctlGetWaitbase params{};
135 std::memcpy(&params, input.data(), sizeof(IoctlGetWaitbase));
136 params.value = 0; // Seems to be hard coded at 0
137 std::memcpy(output.data(), &params, sizeof(IoctlGetWaitbase));
138 return NvResult::Success;
139}
140
141NvResult nvhost_nvdec_common::MapBuffer(const std::vector<u8>& input, std::vector<u8>& output) {
142 IoctlMapBuffer params{};
143 std::memcpy(&params, input.data(), sizeof(IoctlMapBuffer));
144 std::vector<MapBufferEntry> cmd_buffer_handles(params.num_entries);
145
146 SpliceVectors(input, cmd_buffer_handles, params.num_entries, sizeof(IoctlMapBuffer));
147
148 auto& gpu = system.GPU();
149
150 for (auto& cmf_buff : cmd_buffer_handles) {
151 auto object{nvmap_dev->GetObject(cmf_buff.map_handle)};
152 if (!object) {
153 LOG_ERROR(Service_NVDRV, "invalid cmd_buffer nvmap_handle={:X}", cmf_buff.map_handle);
154 std::memcpy(output.data(), &params, output.size());
155 return NvResult::InvalidState;
156 }
157 if (object->dma_map_addr == 0) {
158 // NVDEC and VIC memory is in the 32-bit address space
159 // MapAllocate32 will attempt to map a lower 32-bit value in the shared gpu memory space
160 const GPUVAddr low_addr = gpu.MemoryManager().MapAllocate32(object->addr, object->size);
161 object->dma_map_addr = static_cast<u32>(low_addr);
162 // Ensure that the dma_map_addr is indeed in the lower 32-bit address space.
163 ASSERT(object->dma_map_addr == low_addr);
164 }
165 if (!object->dma_map_addr) {
166 LOG_ERROR(Service_NVDRV, "failed to map size={}", object->size);
167 } else {
168 cmf_buff.map_address = object->dma_map_addr;
169 AddBufferMap(object->dma_map_addr, object->size, object->addr,
170 object->status == nvmap::Object::Status::Allocated);
171 }
172 }
173 std::memcpy(output.data(), &params, sizeof(IoctlMapBuffer));
174 std::memcpy(output.data() + sizeof(IoctlMapBuffer), cmd_buffer_handles.data(),
175 cmd_buffer_handles.size() * sizeof(MapBufferEntry));
176
177 return NvResult::Success;
178}
179
180NvResult nvhost_nvdec_common::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output) {
181 IoctlMapBuffer params{};
182 std::memcpy(&params, input.data(), sizeof(IoctlMapBuffer));
183 std::vector<MapBufferEntry> cmd_buffer_handles(params.num_entries);
184 SpliceVectors(input, cmd_buffer_handles, params.num_entries, sizeof(IoctlMapBuffer));
185
186 auto& gpu = system.GPU();
187
188 for (auto& cmf_buff : cmd_buffer_handles) {
189 const auto object{nvmap_dev->GetObject(cmf_buff.map_handle)};
190 if (!object) {
191 LOG_ERROR(Service_NVDRV, "invalid cmd_buffer nvmap_handle={:X}", cmf_buff.map_handle);
192 std::memcpy(output.data(), &params, output.size());
193 return NvResult::InvalidState;
194 }
195 if (const auto size{RemoveBufferMap(object->dma_map_addr)}; size) {
196 gpu.MemoryManager().Unmap(object->dma_map_addr, *size);
197 } else {
198 // This occurs quite frequently, however does not seem to impact functionality
199 LOG_DEBUG(Service_NVDRV, "invalid offset=0x{:X} dma=0x{:X}", object->addr,
200 object->dma_map_addr);
201 }
202 object->dma_map_addr = 0;
203 }
204 std::memset(output.data(), 0, output.size());
205 return NvResult::Success;
206}
207
208NvResult nvhost_nvdec_common::SetSubmitTimeout(const std::vector<u8>& input,
209 std::vector<u8>& output) {
210 std::memcpy(&submit_timeout, input.data(), input.size());
211 LOG_WARNING(Service_NVDRV, "(STUBBED) called");
212 return NvResult::Success;
213}
214
215std::optional<nvhost_nvdec_common::BufferMap> nvhost_nvdec_common::FindBufferMap(
216 GPUVAddr gpu_addr) const {
217 const auto it = std::find_if(
218 buffer_mappings.begin(), buffer_mappings.upper_bound(gpu_addr), [&](const auto& entry) {
219 return (gpu_addr >= entry.second.StartAddr() && gpu_addr < entry.second.EndAddr());
220 });
221
222 ASSERT(it != buffer_mappings.end());
223 return it->second;
224}
225
226void nvhost_nvdec_common::AddBufferMap(GPUVAddr gpu_addr, std::size_t size, VAddr cpu_addr,
227 bool is_allocated) {
228 buffer_mappings.insert_or_assign(gpu_addr, BufferMap{gpu_addr, size, cpu_addr, is_allocated});
229}
230
231std::optional<std::size_t> nvhost_nvdec_common::RemoveBufferMap(GPUVAddr gpu_addr) {
232 const auto iter{buffer_mappings.find(gpu_addr)};
233 if (iter == buffer_mappings.end()) {
234 return std::nullopt;
235 }
236 std::size_t size = 0;
237 if (iter->second.IsAllocated()) {
238 size = iter->second.Size();
239 }
240 buffer_mappings.erase(iter);
241 return size;
242}
243
244} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h
new file mode 100644
index 000000000..4c9d4ba41
--- /dev/null
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h
@@ -0,0 +1,170 @@
1// Copyright 2020 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <map>
8#include <vector>
9#include "common/common_types.h"
10#include "common/swap.h"
11#include "core/hle/service/nvdrv/devices/nvdevice.h"
12
13namespace Service::Nvidia {
14class SyncpointManager;
15
16namespace Devices {
17class nvmap;
18
19class nvhost_nvdec_common : public nvdevice {
20public:
21 explicit nvhost_nvdec_common(Core::System& system, std::shared_ptr<nvmap> nvmap_dev,
22 SyncpointManager& syncpoint_manager);
23 ~nvhost_nvdec_common() override;
24
25protected:
26 class BufferMap final {
27 public:
28 constexpr BufferMap() = default;
29
30 constexpr BufferMap(GPUVAddr start_addr, std::size_t size)
31 : start_addr{start_addr}, end_addr{start_addr + size} {}
32
33 constexpr BufferMap(GPUVAddr start_addr, std::size_t size, VAddr cpu_addr,
34 bool is_allocated)
35 : start_addr{start_addr}, end_addr{start_addr + size}, cpu_addr{cpu_addr},
36 is_allocated{is_allocated} {}
37
38 constexpr VAddr StartAddr() const {
39 return start_addr;
40 }
41
42 constexpr VAddr EndAddr() const {
43 return end_addr;
44 }
45
46 constexpr std::size_t Size() const {
47 return end_addr - start_addr;
48 }
49
50 constexpr VAddr CpuAddr() const {
51 return cpu_addr;
52 }
53
54 constexpr bool IsAllocated() const {
55 return is_allocated;
56 }
57
58 private:
59 GPUVAddr start_addr{};
60 GPUVAddr end_addr{};
61 VAddr cpu_addr{};
62 bool is_allocated{};
63 };
64
65 struct IoctlSetNvmapFD {
66 s32_le nvmap_fd{};
67 };
68 static_assert(sizeof(IoctlSetNvmapFD) == 4, "IoctlSetNvmapFD is incorrect size");
69
70 struct IoctlSubmitCommandBuffer {
71 u32_le id{};
72 u32_le offset{};
73 u32_le count{};
74 };
75 static_assert(sizeof(IoctlSubmitCommandBuffer) == 0xC,
76 "IoctlSubmitCommandBuffer is incorrect size");
77 struct IoctlSubmit {
78 u32_le cmd_buffer_count{};
79 u32_le relocation_count{};
80 u32_le syncpoint_count{};
81 u32_le fence_count{};
82 };
83 static_assert(sizeof(IoctlSubmit) == 0x10, "IoctlSubmit has incorrect size");
84
85 struct CommandBuffer {
86 s32 memory_id{};
87 u32 offset{};
88 s32 word_count{};
89 };
90 static_assert(sizeof(CommandBuffer) == 0xC, "CommandBuffer has incorrect size");
91
92 struct Reloc {
93 s32 cmdbuffer_memory{};
94 s32 cmdbuffer_offset{};
95 s32 target{};
96 s32 target_offset{};
97 };
98 static_assert(sizeof(Reloc) == 0x10, "CommandBuffer has incorrect size");
99
100 struct SyncptIncr {
101 u32 id{};
102 u32 increments{};
103 };
104 static_assert(sizeof(SyncptIncr) == 0x8, "CommandBuffer has incorrect size");
105
106 struct Fence {
107 u32 id{};
108 u32 value{};
109 };
110 static_assert(sizeof(Fence) == 0x8, "CommandBuffer has incorrect size");
111
112 struct IoctlGetSyncpoint {
113 // Input
114 u32_le param{};
115 // Output
116 u32_le value{};
117 };
118 static_assert(sizeof(IoctlGetSyncpoint) == 8, "IocGetIdParams has wrong size");
119
120 struct IoctlGetWaitbase {
121 u32_le unknown{}; // seems to be ignored? Nintendo added this
122 u32_le value{};
123 };
124 static_assert(sizeof(IoctlGetWaitbase) == 0x8, "IoctlGetWaitbase is incorrect size");
125
126 struct IoctlMapBuffer {
127 u32_le num_entries{};
128 u32_le data_address{}; // Ignored by the driver.
129 u32_le attach_host_ch_das{};
130 };
131 static_assert(sizeof(IoctlMapBuffer) == 0x0C, "IoctlMapBuffer is incorrect size");
132
133 struct IocGetIdParams {
134 // Input
135 u32_le param{};
136 // Output
137 u32_le value{};
138 };
139 static_assert(sizeof(IocGetIdParams) == 8, "IocGetIdParams has wrong size");
140
141 // Used for mapping and unmapping command buffers
142 struct MapBufferEntry {
143 u32_le map_handle{};
144 u32_le map_address{};
145 };
146 static_assert(sizeof(IoctlMapBuffer) == 0x0C, "IoctlMapBuffer is incorrect size");
147
148 /// Ioctl command implementations
149 NvResult SetNVMAPfd(const std::vector<u8>& input);
150 NvResult Submit(const std::vector<u8>& input, std::vector<u8>& output);
151 NvResult GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output);
152 NvResult GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output);
153 NvResult MapBuffer(const std::vector<u8>& input, std::vector<u8>& output);
154 NvResult UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output);
155 NvResult SetSubmitTimeout(const std::vector<u8>& input, std::vector<u8>& output);
156
157 std::optional<BufferMap> FindBufferMap(GPUVAddr gpu_addr) const;
158 void AddBufferMap(GPUVAddr gpu_addr, std::size_t size, VAddr cpu_addr, bool is_allocated);
159 std::optional<std::size_t> RemoveBufferMap(GPUVAddr gpu_addr);
160
161 s32_le nvmap_fd{};
162 u32_le submit_timeout{};
163 std::shared_ptr<nvmap> nvmap_dev;
164 SyncpointManager& syncpoint_manager;
165 std::array<u32, MaxSyncPoints> device_syncpoints{};
166 // This is expected to be ordered, therefore we must use a map, not unordered_map
167 std::map<GPUVAddr, BufferMap> buffer_mappings;
168};
169}; // namespace Devices
170} // namespace Service::Nvidia
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp
index 96e7b7dab..2d06955c0 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp
@@ -13,28 +13,44 @@ namespace Service::Nvidia::Devices {
13nvhost_nvjpg::nvhost_nvjpg(Core::System& system) : nvdevice(system) {} 13nvhost_nvjpg::nvhost_nvjpg(Core::System& system) : nvdevice(system) {}
14nvhost_nvjpg::~nvhost_nvjpg() = default; 14nvhost_nvjpg::~nvhost_nvjpg() = default;
15 15
16u32 nvhost_nvjpg::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, 16NvResult nvhost_nvjpg::Ioctl1(Ioctl command, const std::vector<u8>& input,
17 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, 17 std::vector<u8>& output) {
18 IoctlVersion version) { 18 switch (command.group) {
19 LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", 19 case 'H':
20 command.raw, input.size(), output.size()); 20 switch (command.cmd) {
21 21 case 0x1:
22 switch (static_cast<IoctlCommand>(command.raw)) { 22 return SetNVMAPfd(input, output);
23 case IoctlCommand::IocSetNVMAPfdCommand: 23 default:
24 return SetNVMAPfd(input, output); 24 break;
25 }
26 break;
27 default:
28 break;
25 } 29 }
26 30
27 UNIMPLEMENTED_MSG("Unimplemented ioctl"); 31 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
28 return 0; 32 return NvResult::NotImplemented;
29} 33}
30 34
31u32 nvhost_nvjpg::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) { 35NvResult nvhost_nvjpg::Ioctl2(Ioctl command, const std::vector<u8>& input,
36 const std::vector<u8>& inline_input, std::vector<u8>& output) {
37 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
38 return NvResult::NotImplemented;
39}
40
41NvResult nvhost_nvjpg::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
42 std::vector<u8>& inline_output) {
43 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
44 return NvResult::NotImplemented;
45}
46
47NvResult nvhost_nvjpg::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) {
32 IoctlSetNvmapFD params{}; 48 IoctlSetNvmapFD params{};
33 std::memcpy(&params, input.data(), input.size()); 49 std::memcpy(&params, input.data(), input.size());
34 LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); 50 LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
35 51
36 nvmap_fd = params.nvmap_fd; 52 nvmap_fd = params.nvmap_fd;
37 return 0; 53 return NvResult::Success;
38} 54}
39 55
40} // namespace Service::Nvidia::Devices 56} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h
index 98dcac52f..43948d18d 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h
@@ -16,23 +16,21 @@ public:
16 explicit nvhost_nvjpg(Core::System& system); 16 explicit nvhost_nvjpg(Core::System& system);
17 ~nvhost_nvjpg() override; 17 ~nvhost_nvjpg() override;
18 18
19 u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, 19 NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
20 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, 20 NvResult Ioctl2(Ioctl command, const std::vector<u8>& input,
21 IoctlVersion version) override; 21 const std::vector<u8>& inline_input, std::vector<u8>& output) override;
22 NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
23 std::vector<u8>& inline_output) override;
22 24
23private: 25private:
24 enum class IoctlCommand : u32_le {
25 IocSetNVMAPfdCommand = 0x40044801,
26 };
27
28 struct IoctlSetNvmapFD { 26 struct IoctlSetNvmapFD {
29 u32_le nvmap_fd; 27 s32_le nvmap_fd{};
30 }; 28 };
31 static_assert(sizeof(IoctlSetNvmapFD) == 4, "IoctlSetNvmapFD is incorrect size"); 29 static_assert(sizeof(IoctlSetNvmapFD) == 4, "IoctlSetNvmapFD is incorrect size");
32 30
33 u32_le nvmap_fd{}; 31 s32_le nvmap_fd{};
34 32
35 u32 SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output); 33 NvResult SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output);
36}; 34};
37 35
38} // namespace Service::Nvidia::Devices 36} // 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 c695b8863..72499654c 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
@@ -2,39 +2,64 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <cstring>
6
7#include "common/assert.h" 5#include "common/assert.h"
8#include "common/logging/log.h" 6#include "common/logging/log.h"
7#include "core/core.h"
9#include "core/hle/service/nvdrv/devices/nvhost_vic.h" 8#include "core/hle/service/nvdrv/devices/nvhost_vic.h"
9#include "video_core/memory_manager.h"
10#include "video_core/renderer_base.h"
10 11
11namespace Service::Nvidia::Devices { 12namespace Service::Nvidia::Devices {
13nvhost_vic::nvhost_vic(Core::System& system, std::shared_ptr<nvmap> nvmap_dev,
14 SyncpointManager& syncpoint_manager)
15 : nvhost_nvdec_common(system, std::move(nvmap_dev), syncpoint_manager) {}
12 16
13nvhost_vic::nvhost_vic(Core::System& system) : nvdevice(system) {}
14nvhost_vic::~nvhost_vic() = default; 17nvhost_vic::~nvhost_vic() = default;
15 18
16u32 nvhost_vic::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, 19NvResult nvhost_vic::Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) {
17 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, 20 switch (command.group) {
18 IoctlVersion version) { 21 case 0x0:
19 LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", 22 switch (command.cmd) {
20 command.raw, input.size(), output.size()); 23 case 0x1:
21 24 return Submit(input, output);
22 switch (static_cast<IoctlCommand>(command.raw)) { 25 case 0x2:
23 case IoctlCommand::IocSetNVMAPfdCommand: 26 return GetSyncpoint(input, output);
24 return SetNVMAPfd(input, output); 27 case 0x3:
28 return GetWaitbase(input, output);
29 case 0x9:
30 return MapBuffer(input, output);
31 case 0xa:
32 return UnmapBuffer(input, output);
33 default:
34 break;
35 }
36 break;
37 case 'H':
38 switch (command.cmd) {
39 case 0x1:
40 return SetNVMAPfd(input);
41 default:
42 break;
43 }
44 break;
45 default:
46 break;
25 } 47 }
26 48
27 UNIMPLEMENTED_MSG("Unimplemented ioctl"); 49 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
28 return 0; 50 return NvResult::NotImplemented;
29} 51}
30 52
31u32 nvhost_vic::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) { 53NvResult nvhost_vic::Ioctl2(Ioctl command, const std::vector<u8>& input,
32 IoctlSetNvmapFD params{}; 54 const std::vector<u8>& inline_input, std::vector<u8>& output) {
33 std::memcpy(&params, input.data(), input.size()); 55 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
34 LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); 56 return NvResult::NotImplemented;
57}
35 58
36 nvmap_fd = params.nvmap_fd; 59NvResult nvhost_vic::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
37 return 0; 60 std::vector<u8>& inline_output) {
61 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
62 return NvResult::NotImplemented;
38} 63}
39 64
40} // namespace Service::Nvidia::Devices 65} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.h b/src/core/hle/service/nvdrv/devices/nvhost_vic.h
index bec32bea1..f401c61fa 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_vic.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.h
@@ -4,35 +4,20 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <vector> 7#include "core/hle/service/nvdrv/devices/nvhost_nvdec_common.h"
8#include "common/common_types.h"
9#include "common/swap.h"
10#include "core/hle/service/nvdrv/devices/nvdevice.h"
11 8
12namespace Service::Nvidia::Devices { 9namespace Service::Nvidia::Devices {
13 10
14class nvhost_vic final : public nvdevice { 11class nvhost_vic final : public nvhost_nvdec_common {
15public: 12public:
16 explicit nvhost_vic(Core::System& system); 13 explicit nvhost_vic(Core::System& system, std::shared_ptr<nvmap> nvmap_dev,
17 ~nvhost_vic() override; 14 SyncpointManager& syncpoint_manager);
18 15 ~nvhost_vic();
19 u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, 16
20 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, 17 NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
21 IoctlVersion version) override; 18 NvResult Ioctl2(Ioctl command, const std::vector<u8>& input,
22 19 const std::vector<u8>& inline_input, std::vector<u8>& output) override;
23private: 20 NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
24 enum class IoctlCommand : u32_le { 21 std::vector<u8>& inline_output) override;
25 IocSetNVMAPfdCommand = 0x40044801,
26 };
27
28 struct IoctlSetNvmapFD {
29 u32_le nvmap_fd;
30 };
31 static_assert(sizeof(IoctlSetNvmapFD) == 4, "IoctlSetNvmapFD is incorrect size");
32
33 u32_le nvmap_fd{};
34
35 u32 SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output);
36}; 22};
37
38} // namespace Service::Nvidia::Devices 23} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp
index 9436e16ad..4015a2740 100644
--- a/src/core/hle/service/nvdrv/devices/nvmap.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp
@@ -11,13 +11,6 @@
11 11
12namespace Service::Nvidia::Devices { 12namespace Service::Nvidia::Devices {
13 13
14namespace NvErrCodes {
15enum {
16 OperationNotPermitted = -1,
17 InvalidValue = -22,
18};
19}
20
21nvmap::nvmap(Core::System& system) : nvdevice(system) { 14nvmap::nvmap(Core::System& system) : nvdevice(system) {
22 // Handle 0 appears to be used when remapping, so we create a placeholder empty nvmap object to 15 // Handle 0 appears to be used when remapping, so we create a placeholder empty nvmap object to
23 // represent this. 16 // represent this.
@@ -26,6 +19,46 @@ nvmap::nvmap(Core::System& system) : nvdevice(system) {
26 19
27nvmap::~nvmap() = default; 20nvmap::~nvmap() = default;
28 21
22NvResult nvmap::Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) {
23 switch (command.group) {
24 case 0x1:
25 switch (command.cmd) {
26 case 0x1:
27 return IocCreate(input, output);
28 case 0x3:
29 return IocFromId(input, output);
30 case 0x4:
31 return IocAlloc(input, output);
32 case 0x5:
33 return IocFree(input, output);
34 case 0x9:
35 return IocParam(input, output);
36 case 0xe:
37 return IocGetId(input, output);
38 default:
39 break;
40 }
41 break;
42 default:
43 break;
44 }
45
46 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
47 return NvResult::NotImplemented;
48}
49
50NvResult nvmap::Ioctl2(Ioctl command, const std::vector<u8>& input,
51 const std::vector<u8>& inline_input, std::vector<u8>& output) {
52 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
53 return NvResult::NotImplemented;
54}
55
56NvResult nvmap::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
57 std::vector<u8>& inline_output) {
58 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
59 return NvResult::NotImplemented;
60}
61
29VAddr nvmap::GetObjectAddress(u32 handle) const { 62VAddr nvmap::GetObjectAddress(u32 handle) const {
30 auto object = GetObject(handle); 63 auto object = GetObject(handle);
31 ASSERT(object); 64 ASSERT(object);
@@ -33,28 +66,6 @@ VAddr nvmap::GetObjectAddress(u32 handle) const {
33 return object->addr; 66 return object->addr;
34} 67}
35 68
36u32 nvmap::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
37 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
38 IoctlVersion version) {
39 switch (static_cast<IoctlCommand>(command.raw)) {
40 case IoctlCommand::Create:
41 return IocCreate(input, output);
42 case IoctlCommand::Alloc:
43 return IocAlloc(input, output);
44 case IoctlCommand::GetId:
45 return IocGetId(input, output);
46 case IoctlCommand::FromId:
47 return IocFromId(input, output);
48 case IoctlCommand::Param:
49 return IocParam(input, output);
50 case IoctlCommand::Free:
51 return IocFree(input, output);
52 }
53
54 UNIMPLEMENTED_MSG("Unimplemented ioctl");
55 return 0;
56}
57
58u32 nvmap::CreateObject(u32 size) { 69u32 nvmap::CreateObject(u32 size) {
59 // Create a new nvmap object and obtain a handle to it. 70 // Create a new nvmap object and obtain a handle to it.
60 auto object = std::make_shared<Object>(); 71 auto object = std::make_shared<Object>();
@@ -70,35 +81,35 @@ u32 nvmap::CreateObject(u32 size) {
70 return handle; 81 return handle;
71} 82}
72 83
73u32 nvmap::IocCreate(const std::vector<u8>& input, std::vector<u8>& output) { 84NvResult nvmap::IocCreate(const std::vector<u8>& input, std::vector<u8>& output) {
74 IocCreateParams params; 85 IocCreateParams params;
75 std::memcpy(&params, input.data(), sizeof(params)); 86 std::memcpy(&params, input.data(), sizeof(params));
76 LOG_DEBUG(Service_NVDRV, "size=0x{:08X}", params.size); 87 LOG_DEBUG(Service_NVDRV, "size=0x{:08X}", params.size);
77 88
78 if (!params.size) { 89 if (!params.size) {
79 LOG_ERROR(Service_NVDRV, "Size is 0"); 90 LOG_ERROR(Service_NVDRV, "Size is 0");
80 return static_cast<u32>(NvErrCodes::InvalidValue); 91 return NvResult::BadValue;
81 } 92 }
82 93
83 params.handle = CreateObject(params.size); 94 params.handle = CreateObject(params.size);
84 95
85 std::memcpy(output.data(), &params, sizeof(params)); 96 std::memcpy(output.data(), &params, sizeof(params));
86 return 0; 97 return NvResult::Success;
87} 98}
88 99
89u32 nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) { 100NvResult nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) {
90 IocAllocParams params; 101 IocAllocParams params;
91 std::memcpy(&params, input.data(), sizeof(params)); 102 std::memcpy(&params, input.data(), sizeof(params));
92 LOG_DEBUG(Service_NVDRV, "called, addr={:X}", params.addr); 103 LOG_DEBUG(Service_NVDRV, "called, addr={:X}", params.addr);
93 104
94 if (!params.handle) { 105 if (!params.handle) {
95 LOG_ERROR(Service_NVDRV, "Handle is 0"); 106 LOG_ERROR(Service_NVDRV, "Handle is 0");
96 return static_cast<u32>(NvErrCodes::InvalidValue); 107 return NvResult::BadValue;
97 } 108 }
98 109
99 if ((params.align - 1) & params.align) { 110 if ((params.align - 1) & params.align) {
100 LOG_ERROR(Service_NVDRV, "Incorrect alignment used, alignment={:08X}", params.align); 111 LOG_ERROR(Service_NVDRV, "Incorrect alignment used, alignment={:08X}", params.align);
101 return static_cast<u32>(NvErrCodes::InvalidValue); 112 return NvResult::BadValue;
102 } 113 }
103 114
104 const u32 min_alignment = 0x1000; 115 const u32 min_alignment = 0x1000;
@@ -109,12 +120,12 @@ u32 nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) {
109 auto object = GetObject(params.handle); 120 auto object = GetObject(params.handle);
110 if (!object) { 121 if (!object) {
111 LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle); 122 LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle);
112 return static_cast<u32>(NvErrCodes::InvalidValue); 123 return NvResult::BadValue;
113 } 124 }
114 125
115 if (object->status == Object::Status::Allocated) { 126 if (object->status == Object::Status::Allocated) {
116 LOG_ERROR(Service_NVDRV, "Object is already allocated, handle={:08X}", params.handle); 127 LOG_ERROR(Service_NVDRV, "Object is already allocated, handle={:08X}", params.handle);
117 return static_cast<u32>(NvErrCodes::OperationNotPermitted); 128 return NvResult::InsufficientMemory;
118 } 129 }
119 130
120 object->flags = params.flags; 131 object->flags = params.flags;
@@ -124,10 +135,10 @@ u32 nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) {
124 object->status = Object::Status::Allocated; 135 object->status = Object::Status::Allocated;
125 136
126 std::memcpy(output.data(), &params, sizeof(params)); 137 std::memcpy(output.data(), &params, sizeof(params));
127 return 0; 138 return NvResult::Success;
128} 139}
129 140
130u32 nvmap::IocGetId(const std::vector<u8>& input, std::vector<u8>& output) { 141NvResult nvmap::IocGetId(const std::vector<u8>& input, std::vector<u8>& output) {
131 IocGetIdParams params; 142 IocGetIdParams params;
132 std::memcpy(&params, input.data(), sizeof(params)); 143 std::memcpy(&params, input.data(), sizeof(params));
133 144
@@ -135,22 +146,22 @@ u32 nvmap::IocGetId(const std::vector<u8>& input, std::vector<u8>& output) {
135 146
136 if (!params.handle) { 147 if (!params.handle) {
137 LOG_ERROR(Service_NVDRV, "Handle is zero"); 148 LOG_ERROR(Service_NVDRV, "Handle is zero");
138 return static_cast<u32>(NvErrCodes::InvalidValue); 149 return NvResult::BadValue;
139 } 150 }
140 151
141 auto object = GetObject(params.handle); 152 auto object = GetObject(params.handle);
142 if (!object) { 153 if (!object) {
143 LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle); 154 LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle);
144 return static_cast<u32>(NvErrCodes::OperationNotPermitted); 155 return NvResult::BadValue;
145 } 156 }
146 157
147 params.id = object->id; 158 params.id = object->id;
148 159
149 std::memcpy(output.data(), &params, sizeof(params)); 160 std::memcpy(output.data(), &params, sizeof(params));
150 return 0; 161 return NvResult::Success;
151} 162}
152 163
153u32 nvmap::IocFromId(const std::vector<u8>& input, std::vector<u8>& output) { 164NvResult nvmap::IocFromId(const std::vector<u8>& input, std::vector<u8>& output) {
154 IocFromIdParams params; 165 IocFromIdParams params;
155 std::memcpy(&params, input.data(), sizeof(params)); 166 std::memcpy(&params, input.data(), sizeof(params));
156 167
@@ -160,13 +171,13 @@ u32 nvmap::IocFromId(const std::vector<u8>& input, std::vector<u8>& output) {
160 [&](const auto& entry) { return entry.second->id == params.id; }); 171 [&](const auto& entry) { return entry.second->id == params.id; });
161 if (itr == handles.end()) { 172 if (itr == handles.end()) {
162 LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle); 173 LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle);
163 return static_cast<u32>(NvErrCodes::InvalidValue); 174 return NvResult::BadValue;
164 } 175 }
165 176
166 auto& object = itr->second; 177 auto& object = itr->second;
167 if (object->status != Object::Status::Allocated) { 178 if (object->status != Object::Status::Allocated) {
168 LOG_ERROR(Service_NVDRV, "Object is not allocated, handle={:08X}", params.handle); 179 LOG_ERROR(Service_NVDRV, "Object is not allocated, handle={:08X}", params.handle);
169 return static_cast<u32>(NvErrCodes::InvalidValue); 180 return NvResult::BadValue;
170 } 181 }
171 182
172 itr->second->refcount++; 183 itr->second->refcount++;
@@ -175,10 +186,10 @@ u32 nvmap::IocFromId(const std::vector<u8>& input, std::vector<u8>& output) {
175 params.handle = itr->first; 186 params.handle = itr->first;
176 187
177 std::memcpy(output.data(), &params, sizeof(params)); 188 std::memcpy(output.data(), &params, sizeof(params));
178 return 0; 189 return NvResult::Success;
179} 190}
180 191
181u32 nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output) { 192NvResult nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output) {
182 enum class ParamTypes { Size = 1, Alignment = 2, Base = 3, Heap = 4, Kind = 5, Compr = 6 }; 193 enum class ParamTypes { Size = 1, Alignment = 2, Base = 3, Heap = 4, Kind = 5, Compr = 6 };
183 194
184 IocParamParams params; 195 IocParamParams params;
@@ -189,12 +200,12 @@ u32 nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output) {
189 auto object = GetObject(params.handle); 200 auto object = GetObject(params.handle);
190 if (!object) { 201 if (!object) {
191 LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle); 202 LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle);
192 return static_cast<u32>(NvErrCodes::InvalidValue); 203 return NvResult::BadValue;
193 } 204 }
194 205
195 if (object->status != Object::Status::Allocated) { 206 if (object->status != Object::Status::Allocated) {
196 LOG_ERROR(Service_NVDRV, "Object is not allocated, handle={:08X}", params.handle); 207 LOG_ERROR(Service_NVDRV, "Object is not allocated, handle={:08X}", params.handle);
197 return static_cast<u32>(NvErrCodes::OperationNotPermitted); 208 return NvResult::BadValue;
198 } 209 }
199 210
200 switch (static_cast<ParamTypes>(params.param)) { 211 switch (static_cast<ParamTypes>(params.param)) {
@@ -216,10 +227,10 @@ u32 nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output) {
216 } 227 }
217 228
218 std::memcpy(output.data(), &params, sizeof(params)); 229 std::memcpy(output.data(), &params, sizeof(params));
219 return 0; 230 return NvResult::Success;
220} 231}
221 232
222u32 nvmap::IocFree(const std::vector<u8>& input, std::vector<u8>& output) { 233NvResult nvmap::IocFree(const std::vector<u8>& input, std::vector<u8>& output) {
223 // TODO(Subv): These flags are unconfirmed. 234 // TODO(Subv): These flags are unconfirmed.
224 enum FreeFlags { 235 enum FreeFlags {
225 Freed = 0, 236 Freed = 0,
@@ -234,14 +245,14 @@ u32 nvmap::IocFree(const std::vector<u8>& input, std::vector<u8>& output) {
234 auto itr = handles.find(params.handle); 245 auto itr = handles.find(params.handle);
235 if (itr == handles.end()) { 246 if (itr == handles.end()) {
236 LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle); 247 LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle);
237 return static_cast<u32>(NvErrCodes::InvalidValue); 248 return NvResult::BadValue;
238 } 249 }
239 if (!itr->second->refcount) { 250 if (!itr->second->refcount) {
240 LOG_ERROR( 251 LOG_ERROR(
241 Service_NVDRV, 252 Service_NVDRV,
242 "There is no references to this object. The object is already freed. handle={:08X}", 253 "There is no references to this object. The object is already freed. handle={:08X}",
243 params.handle); 254 params.handle);
244 return static_cast<u32>(NvErrCodes::InvalidValue); 255 return NvResult::BadValue;
245 } 256 }
246 257
247 itr->second->refcount--; 258 itr->second->refcount--;
@@ -261,7 +272,7 @@ u32 nvmap::IocFree(const std::vector<u8>& input, std::vector<u8>& output) {
261 handles.erase(params.handle); 272 handles.erase(params.handle);
262 273
263 std::memcpy(output.data(), &params, sizeof(params)); 274 std::memcpy(output.data(), &params, sizeof(params));
264 return 0; 275 return NvResult::Success;
265} 276}
266 277
267} // namespace Service::Nvidia::Devices 278} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvmap.h b/src/core/hle/service/nvdrv/devices/nvmap.h
index 84624be00..4484bd79f 100644
--- a/src/core/hle/service/nvdrv/devices/nvmap.h
+++ b/src/core/hle/service/nvdrv/devices/nvmap.h
@@ -19,13 +19,15 @@ public:
19 explicit nvmap(Core::System& system); 19 explicit nvmap(Core::System& system);
20 ~nvmap() override; 20 ~nvmap() override;
21 21
22 NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
23 NvResult Ioctl2(Ioctl command, const std::vector<u8>& input,
24 const std::vector<u8>& inline_input, std::vector<u8>& output) override;
25 NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
26 std::vector<u8>& inline_output) override;
27
22 /// Returns the allocated address of an nvmap object given its handle. 28 /// Returns the allocated address of an nvmap object given its handle.
23 VAddr GetObjectAddress(u32 handle) const; 29 VAddr GetObjectAddress(u32 handle) const;
24 30
25 u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
26 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
27 IoctlVersion version) override;
28
29 /// Represents an nvmap object. 31 /// Represents an nvmap object.
30 struct Object { 32 struct Object {
31 enum class Status { Created, Allocated }; 33 enum class Status { Created, Allocated };
@@ -37,6 +39,7 @@ public:
37 VAddr addr; 39 VAddr addr;
38 Status status; 40 Status status;
39 u32 refcount; 41 u32 refcount;
42 u32 dma_map_addr;
40 }; 43 };
41 44
42 std::shared_ptr<Object> GetObject(u32 handle) const { 45 std::shared_ptr<Object> GetObject(u32 handle) const {
@@ -57,76 +60,68 @@ private:
57 /// Mapping of currently allocated handles to the objects they represent. 60 /// Mapping of currently allocated handles to the objects they represent.
58 std::unordered_map<u32, std::shared_ptr<Object>> handles; 61 std::unordered_map<u32, std::shared_ptr<Object>> handles;
59 62
60 enum class IoctlCommand : u32 {
61 Create = 0xC0080101,
62 FromId = 0xC0080103,
63 Alloc = 0xC0200104,
64 Free = 0xC0180105,
65 Param = 0xC00C0109,
66 GetId = 0xC008010E,
67 };
68 struct IocCreateParams { 63 struct IocCreateParams {
69 // Input 64 // Input
70 u32_le size; 65 u32_le size{};
71 // Output 66 // Output
72 u32_le handle; 67 u32_le handle{};
73 }; 68 };
74 static_assert(sizeof(IocCreateParams) == 8, "IocCreateParams has wrong size"); 69 static_assert(sizeof(IocCreateParams) == 8, "IocCreateParams has wrong size");
75 70
76 struct IocFromIdParams { 71 struct IocFromIdParams {
77 // Input 72 // Input
78 u32_le id; 73 u32_le id{};
79 // Output 74 // Output
80 u32_le handle; 75 u32_le handle{};
81 }; 76 };
82 static_assert(sizeof(IocFromIdParams) == 8, "IocFromIdParams has wrong size"); 77 static_assert(sizeof(IocFromIdParams) == 8, "IocFromIdParams has wrong size");
83 78
84 struct IocAllocParams { 79 struct IocAllocParams {
85 // Input 80 // Input
86 u32_le handle; 81 u32_le handle{};
87 u32_le heap_mask; 82 u32_le heap_mask{};
88 u32_le flags; 83 u32_le flags{};
89 u32_le align; 84 u32_le align{};
90 u8 kind; 85 u8 kind{};
91 INSERT_PADDING_BYTES(7); 86 INSERT_PADDING_BYTES(7);
92 u64_le addr; 87 u64_le addr{};
93 }; 88 };
94 static_assert(sizeof(IocAllocParams) == 32, "IocAllocParams has wrong size"); 89 static_assert(sizeof(IocAllocParams) == 32, "IocAllocParams has wrong size");
95 90
96 struct IocFreeParams { 91 struct IocFreeParams {
97 u32_le handle; 92 u32_le handle{};
98 INSERT_PADDING_BYTES(4); 93 INSERT_PADDING_BYTES(4);
99 u64_le address; 94 u64_le address{};
100 u32_le size; 95 u32_le size{};
101 u32_le flags; 96 u32_le flags{};
102 }; 97 };
103 static_assert(sizeof(IocFreeParams) == 24, "IocFreeParams has wrong size"); 98 static_assert(sizeof(IocFreeParams) == 24, "IocFreeParams has wrong size");
104 99
105 struct IocParamParams { 100 struct IocParamParams {
106 // Input 101 // Input
107 u32_le handle; 102 u32_le handle{};
108 u32_le param; 103 u32_le param{};
109 // Output 104 // Output
110 u32_le result; 105 u32_le result{};
111 }; 106 };
112 static_assert(sizeof(IocParamParams) == 12, "IocParamParams has wrong size"); 107 static_assert(sizeof(IocParamParams) == 12, "IocParamParams has wrong size");
113 108
114 struct IocGetIdParams { 109 struct IocGetIdParams {
115 // Output 110 // Output
116 u32_le id; 111 u32_le id{};
117 // Input 112 // Input
118 u32_le handle; 113 u32_le handle{};
119 }; 114 };
120 static_assert(sizeof(IocGetIdParams) == 8, "IocGetIdParams has wrong size"); 115 static_assert(sizeof(IocGetIdParams) == 8, "IocGetIdParams has wrong size");
121 116
122 u32 CreateObject(u32 size); 117 u32 CreateObject(u32 size);
123 118
124 u32 IocCreate(const std::vector<u8>& input, std::vector<u8>& output); 119 NvResult IocCreate(const std::vector<u8>& input, std::vector<u8>& output);
125 u32 IocAlloc(const std::vector<u8>& input, std::vector<u8>& output); 120 NvResult IocAlloc(const std::vector<u8>& input, std::vector<u8>& output);
126 u32 IocGetId(const std::vector<u8>& input, std::vector<u8>& output); 121 NvResult IocGetId(const std::vector<u8>& input, std::vector<u8>& output);
127 u32 IocFromId(const std::vector<u8>& input, std::vector<u8>& output); 122 NvResult IocFromId(const std::vector<u8>& input, std::vector<u8>& output);
128 u32 IocParam(const std::vector<u8>& input, std::vector<u8>& output); 123 NvResult IocParam(const std::vector<u8>& input, std::vector<u8>& output);
129 u32 IocFree(const std::vector<u8>& input, std::vector<u8>& output); 124 NvResult IocFree(const std::vector<u8>& input, std::vector<u8>& output);
130}; 125};
131 126
132} // namespace Service::Nvidia::Devices 127} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/interface.cpp b/src/core/hle/service/nvdrv/interface.cpp
index 88fbfa9b0..cc23b001c 100644
--- a/src/core/hle/service/nvdrv/interface.cpp
+++ b/src/core/hle/service/nvdrv/interface.cpp
@@ -23,124 +23,167 @@ void NVDRV::SignalGPUInterruptSyncpt(const u32 syncpoint_id, const u32 value) {
23void NVDRV::Open(Kernel::HLERequestContext& ctx) { 23void NVDRV::Open(Kernel::HLERequestContext& ctx) {
24 LOG_DEBUG(Service_NVDRV, "called"); 24 LOG_DEBUG(Service_NVDRV, "called");
25 25
26 if (!is_initialized) {
27 ServiceError(ctx, NvResult::NotInitialized);
28 LOG_ERROR(Service_NVDRV, "NvServices is not initalized!");
29 return;
30 }
31
26 const auto& buffer = ctx.ReadBuffer(); 32 const auto& buffer = ctx.ReadBuffer();
27 std::string device_name(buffer.begin(), buffer.end()); 33 const std::string device_name(buffer.begin(), buffer.end());
34 DeviceFD fd = nvdrv->Open(device_name);
28 35
29 u32 fd = nvdrv->Open(device_name);
30 IPC::ResponseBuilder rb{ctx, 4}; 36 IPC::ResponseBuilder rb{ctx, 4};
31 rb.Push(RESULT_SUCCESS); 37 rb.Push(RESULT_SUCCESS);
32 rb.Push<u32>(fd); 38 rb.Push<DeviceFD>(fd);
33 rb.Push<u32>(0); 39 rb.PushEnum(fd != INVALID_NVDRV_FD ? NvResult::Success : NvResult::FileOperationFailed);
40}
41
42void NVDRV::ServiceError(Kernel::HLERequestContext& ctx, NvResult result) {
43 IPC::ResponseBuilder rb{ctx, 3};
44 rb.Push(RESULT_SUCCESS);
45 rb.PushEnum(result);
34} 46}
35 47
36void NVDRV::IoctlBase(Kernel::HLERequestContext& ctx, IoctlVersion version) { 48void NVDRV::Ioctl1(Kernel::HLERequestContext& ctx) {
37 IPC::RequestParser rp{ctx}; 49 IPC::RequestParser rp{ctx};
38 u32 fd = rp.Pop<u32>(); 50 const auto fd = rp.Pop<DeviceFD>();
39 u32 command = rp.Pop<u32>(); 51 const auto command = rp.PopRaw<Ioctl>();
40 52 LOG_DEBUG(Service_NVDRV, "called fd={}, ioctl=0x{:08X}", fd, command.raw);
41 /// Ioctl 3 has 2 outputs, first in the input params, second is the result 53
42 std::vector<u8> output(ctx.GetWriteBufferSize(0)); 54 if (!is_initialized) {
43 std::vector<u8> output2; 55 ServiceError(ctx, NvResult::NotInitialized);
44 if (version == IoctlVersion::Version3) { 56 LOG_ERROR(Service_NVDRV, "NvServices is not initalized!");
45 output2.resize((ctx.GetWriteBufferSize(1))); 57 return;
46 } 58 }
47 59
48 /// Ioctl2 has 2 inputs. It's used to pass data directly instead of providing a pointer. 60 // Check device
49 /// KickOfPB uses this 61 std::vector<u8> output_buffer(ctx.GetWriteBufferSize(0));
50 auto input = ctx.ReadBuffer(0); 62 const auto input_buffer = ctx.ReadBuffer(0);
51 63
52 std::vector<u8> input2; 64 const auto nv_result = nvdrv->Ioctl1(fd, command, input_buffer, output_buffer);
53 if (version == IoctlVersion::Version2) { 65 if (command.is_out != 0) {
54 input2 = ctx.ReadBuffer(1); 66 ctx.WriteBuffer(output_buffer);
55 } 67 }
56 68
57 IoctlCtrl ctrl{};
58
59 u32 result = nvdrv->Ioctl(fd, command, input, input2, output, output2, ctrl, version);
60
61 if (ctrl.must_delay) {
62 ctrl.fresh_call = false;
63 ctx.SleepClientThread(
64 "NVServices::DelayedResponse", ctrl.timeout,
65 [=, this](std::shared_ptr<Kernel::Thread> thread, Kernel::HLERequestContext& ctx_,
66 Kernel::ThreadWakeupReason reason) {
67 IoctlCtrl ctrl2{ctrl};
68 std::vector<u8> tmp_output = output;
69 std::vector<u8> tmp_output2 = output2;
70 const u32 ioctl_result = nvdrv->Ioctl(fd, command, input, input2, tmp_output,
71 tmp_output2, ctrl2, version);
72 ctx_.WriteBuffer(tmp_output, 0);
73 if (version == IoctlVersion::Version3) {
74 ctx_.WriteBuffer(tmp_output2, 1);
75 }
76 IPC::ResponseBuilder rb{ctx_, 3};
77 rb.Push(RESULT_SUCCESS);
78 rb.Push(ioctl_result);
79 },
80 nvdrv->GetEventWriteable(ctrl.event_id));
81 } else {
82 ctx.WriteBuffer(output);
83 if (version == IoctlVersion::Version3) {
84 ctx.WriteBuffer(output2, 1);
85 }
86 }
87 IPC::ResponseBuilder rb{ctx, 3}; 69 IPC::ResponseBuilder rb{ctx, 3};
88 rb.Push(RESULT_SUCCESS); 70 rb.Push(RESULT_SUCCESS);
89 rb.Push(result); 71 rb.PushEnum(nv_result);
90}
91
92void NVDRV::Ioctl(Kernel::HLERequestContext& ctx) {
93 LOG_DEBUG(Service_NVDRV, "called");
94 IoctlBase(ctx, IoctlVersion::Version1);
95} 72}
96 73
97void NVDRV::Ioctl2(Kernel::HLERequestContext& ctx) { 74void NVDRV::Ioctl2(Kernel::HLERequestContext& ctx) {
98 LOG_DEBUG(Service_NVDRV, "called"); 75 IPC::RequestParser rp{ctx};
99 IoctlBase(ctx, IoctlVersion::Version2); 76 const auto fd = rp.Pop<DeviceFD>();
77 const auto command = rp.PopRaw<Ioctl>();
78 LOG_DEBUG(Service_NVDRV, "called fd={}, ioctl=0x{:08X}", fd, command.raw);
79
80 if (!is_initialized) {
81 ServiceError(ctx, NvResult::NotInitialized);
82 LOG_ERROR(Service_NVDRV, "NvServices is not initalized!");
83 return;
84 }
85
86 const auto input_buffer = ctx.ReadBuffer(0);
87 const auto input_inlined_buffer = ctx.ReadBuffer(1);
88 std::vector<u8> output_buffer(ctx.GetWriteBufferSize(0));
89
90 const auto nv_result =
91 nvdrv->Ioctl2(fd, command, input_buffer, input_inlined_buffer, output_buffer);
92 if (command.is_out != 0) {
93 ctx.WriteBuffer(output_buffer);
94 }
95
96 IPC::ResponseBuilder rb{ctx, 3};
97 rb.Push(RESULT_SUCCESS);
98 rb.PushEnum(nv_result);
100} 99}
101 100
102void NVDRV::Ioctl3(Kernel::HLERequestContext& ctx) { 101void NVDRV::Ioctl3(Kernel::HLERequestContext& ctx) {
103 LOG_DEBUG(Service_NVDRV, "called"); 102 IPC::RequestParser rp{ctx};
104 IoctlBase(ctx, IoctlVersion::Version3); 103 const auto fd = rp.Pop<DeviceFD>();
104 const auto command = rp.PopRaw<Ioctl>();
105 LOG_DEBUG(Service_NVDRV, "called fd={}, ioctl=0x{:08X}", fd, command.raw);
106
107 if (!is_initialized) {
108 ServiceError(ctx, NvResult::NotInitialized);
109 LOG_ERROR(Service_NVDRV, "NvServices is not initalized!");
110 return;
111 }
112
113 const auto input_buffer = ctx.ReadBuffer(0);
114 std::vector<u8> output_buffer(ctx.GetWriteBufferSize(0));
115 std::vector<u8> output_buffer_inline(ctx.GetWriteBufferSize(1));
116
117 const auto nv_result =
118 nvdrv->Ioctl3(fd, command, input_buffer, output_buffer, output_buffer_inline);
119 if (command.is_out != 0) {
120 ctx.WriteBuffer(output_buffer, 0);
121 ctx.WriteBuffer(output_buffer_inline, 1);
122 }
123
124 IPC::ResponseBuilder rb{ctx, 3};
125 rb.Push(RESULT_SUCCESS);
126 rb.PushEnum(nv_result);
105} 127}
106 128
107void NVDRV::Close(Kernel::HLERequestContext& ctx) { 129void NVDRV::Close(Kernel::HLERequestContext& ctx) {
108 LOG_DEBUG(Service_NVDRV, "called"); 130 LOG_DEBUG(Service_NVDRV, "called");
109 131
110 IPC::RequestParser rp{ctx}; 132 if (!is_initialized) {
111 u32 fd = rp.Pop<u32>(); 133 ServiceError(ctx, NvResult::NotInitialized);
134 LOG_ERROR(Service_NVDRV, "NvServices is not initalized!");
135 return;
136 }
112 137
113 auto result = nvdrv->Close(fd); 138 IPC::RequestParser rp{ctx};
139 const auto fd = rp.Pop<DeviceFD>();
140 const auto result = nvdrv->Close(fd);
114 141
115 IPC::ResponseBuilder rb{ctx, 2}; 142 IPC::ResponseBuilder rb{ctx, 3};
116 rb.Push(result); 143 rb.Push(RESULT_SUCCESS);
144 rb.PushEnum(result);
117} 145}
118 146
119void NVDRV::Initialize(Kernel::HLERequestContext& ctx) { 147void NVDRV::Initialize(Kernel::HLERequestContext& ctx) {
120 LOG_WARNING(Service_NVDRV, "(STUBBED) called"); 148 LOG_WARNING(Service_NVDRV, "(STUBBED) called");
121 149
150 is_initialized = true;
151
122 IPC::ResponseBuilder rb{ctx, 3}; 152 IPC::ResponseBuilder rb{ctx, 3};
123 rb.Push(RESULT_SUCCESS); 153 rb.Push(RESULT_SUCCESS);
124 rb.Push<u32>(0); 154 rb.PushEnum(NvResult::Success);
125} 155}
126 156
127void NVDRV::QueryEvent(Kernel::HLERequestContext& ctx) { 157void NVDRV::QueryEvent(Kernel::HLERequestContext& ctx) {
128 IPC::RequestParser rp{ctx}; 158 IPC::RequestParser rp{ctx};
129 u32 fd = rp.Pop<u32>(); 159 const auto fd = rp.Pop<DeviceFD>();
130 // TODO(Blinkhawk): Figure the meaning of the flag at bit 16 160 const auto event_id = rp.Pop<u32>() & 0x00FF;
131 u32 event_id = rp.Pop<u32>() & 0x000000FF;
132 LOG_WARNING(Service_NVDRV, "(STUBBED) called, fd={:X}, event_id={:X}", fd, event_id); 161 LOG_WARNING(Service_NVDRV, "(STUBBED) called, fd={:X}, event_id={:X}", fd, event_id);
133 162
134 IPC::ResponseBuilder rb{ctx, 3, 1}; 163 if (!is_initialized) {
135 rb.Push(RESULT_SUCCESS); 164 ServiceError(ctx, NvResult::NotInitialized);
165 LOG_ERROR(Service_NVDRV, "NvServices is not initalized!");
166 return;
167 }
168
169 const auto nv_result = nvdrv->VerifyFD(fd);
170 if (nv_result != NvResult::Success) {
171 LOG_ERROR(Service_NVDRV, "Invalid FD specified DeviceFD={}!", fd);
172 ServiceError(ctx, nv_result);
173 return;
174 }
175
136 if (event_id < MaxNvEvents) { 176 if (event_id < MaxNvEvents) {
177 IPC::ResponseBuilder rb{ctx, 3, 1};
178 rb.Push(RESULT_SUCCESS);
137 auto event = nvdrv->GetEvent(event_id); 179 auto event = nvdrv->GetEvent(event_id);
138 event->Clear(); 180 event->Clear();
139 rb.PushCopyObjects(event); 181 rb.PushCopyObjects(event);
140 rb.Push<u32>(NvResult::Success); 182 rb.PushEnum(NvResult::Success);
141 } else { 183 } else {
142 rb.Push<u32>(0); 184 IPC::ResponseBuilder rb{ctx, 3};
143 rb.Push<u32>(NvResult::BadParameter); 185 rb.Push(RESULT_SUCCESS);
186 rb.PushEnum(NvResult::BadParameter);
144 } 187 }
145} 188}
146 189
@@ -151,7 +194,7 @@ void NVDRV::SetAruid(Kernel::HLERequestContext& ctx) {
151 194
152 IPC::ResponseBuilder rb{ctx, 3}; 195 IPC::ResponseBuilder rb{ctx, 3};
153 rb.Push(RESULT_SUCCESS); 196 rb.Push(RESULT_SUCCESS);
154 rb.Push<u32>(0); 197 rb.PushEnum(NvResult::Success);
155} 198}
156 199
157void NVDRV::SetGraphicsFirmwareMemoryMarginEnabled(Kernel::HLERequestContext& ctx) { 200void NVDRV::SetGraphicsFirmwareMemoryMarginEnabled(Kernel::HLERequestContext& ctx) {
@@ -164,8 +207,9 @@ void NVDRV::SetGraphicsFirmwareMemoryMarginEnabled(Kernel::HLERequestContext& ct
164void NVDRV::GetStatus(Kernel::HLERequestContext& ctx) { 207void NVDRV::GetStatus(Kernel::HLERequestContext& ctx) {
165 LOG_WARNING(Service_NVDRV, "(STUBBED) called"); 208 LOG_WARNING(Service_NVDRV, "(STUBBED) called");
166 209
167 IPC::ResponseBuilder rb{ctx, 2}; 210 IPC::ResponseBuilder rb{ctx, 3};
168 rb.Push(RESULT_SUCCESS); 211 rb.Push(RESULT_SUCCESS);
212 rb.PushEnum(NvResult::Success);
169} 213}
170 214
171void NVDRV::DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx) { 215void NVDRV::DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx) {
@@ -177,11 +221,11 @@ void NVDRV::DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx) {
177 rb.Push(RESULT_SUCCESS); 221 rb.Push(RESULT_SUCCESS);
178} 222}
179 223
180NVDRV::NVDRV(std::shared_ptr<Module> nvdrv, const char* name) 224NVDRV::NVDRV(Core::System& system_, std::shared_ptr<Module> nvdrv_, const char* name)
181 : ServiceFramework(name), nvdrv(std::move(nvdrv)) { 225 : ServiceFramework{system_, name}, nvdrv{std::move(nvdrv_)} {
182 static const FunctionInfo functions[] = { 226 static const FunctionInfo functions[] = {
183 {0, &NVDRV::Open, "Open"}, 227 {0, &NVDRV::Open, "Open"},
184 {1, &NVDRV::Ioctl, "Ioctl"}, 228 {1, &NVDRV::Ioctl1, "Ioctl"},
185 {2, &NVDRV::Close, "Close"}, 229 {2, &NVDRV::Close, "Close"},
186 {3, &NVDRV::Initialize, "Initialize"}, 230 {3, &NVDRV::Initialize, "Initialize"},
187 {4, &NVDRV::QueryEvent, "QueryEvent"}, 231 {4, &NVDRV::QueryEvent, "QueryEvent"},
diff --git a/src/core/hle/service/nvdrv/interface.h b/src/core/hle/service/nvdrv/interface.h
index 72e17a728..5c777c59b 100644
--- a/src/core/hle/service/nvdrv/interface.h
+++ b/src/core/hle/service/nvdrv/interface.h
@@ -16,14 +16,14 @@ namespace Service::Nvidia {
16 16
17class NVDRV final : public ServiceFramework<NVDRV> { 17class NVDRV final : public ServiceFramework<NVDRV> {
18public: 18public:
19 NVDRV(std::shared_ptr<Module> nvdrv, const char* name); 19 explicit NVDRV(Core::System& system_, std::shared_ptr<Module> nvdrv_, const char* name);
20 ~NVDRV() override; 20 ~NVDRV() override;
21 21
22 void SignalGPUInterruptSyncpt(const u32 syncpoint_id, const u32 value); 22 void SignalGPUInterruptSyncpt(u32 syncpoint_id, u32 value);
23 23
24private: 24private:
25 void Open(Kernel::HLERequestContext& ctx); 25 void Open(Kernel::HLERequestContext& ctx);
26 void Ioctl(Kernel::HLERequestContext& ctx); 26 void Ioctl1(Kernel::HLERequestContext& ctx);
27 void Ioctl2(Kernel::HLERequestContext& ctx); 27 void Ioctl2(Kernel::HLERequestContext& ctx);
28 void Ioctl3(Kernel::HLERequestContext& ctx); 28 void Ioctl3(Kernel::HLERequestContext& ctx);
29 void Close(Kernel::HLERequestContext& ctx); 29 void Close(Kernel::HLERequestContext& ctx);
@@ -33,11 +33,13 @@ private:
33 void SetGraphicsFirmwareMemoryMarginEnabled(Kernel::HLERequestContext& ctx); 33 void SetGraphicsFirmwareMemoryMarginEnabled(Kernel::HLERequestContext& ctx);
34 void GetStatus(Kernel::HLERequestContext& ctx); 34 void GetStatus(Kernel::HLERequestContext& ctx);
35 void DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx); 35 void DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx);
36 void IoctlBase(Kernel::HLERequestContext& ctx, IoctlVersion version); 36
37 void ServiceError(Kernel::HLERequestContext& ctx, NvResult result);
37 38
38 std::shared_ptr<Module> nvdrv; 39 std::shared_ptr<Module> nvdrv;
39 40
40 u64 pid{}; 41 u64 pid{};
42 bool is_initialized{};
41}; 43};
42 44
43} // namespace Service::Nvidia 45} // namespace Service::Nvidia
diff --git a/src/core/hle/service/nvdrv/nvdata.h b/src/core/hle/service/nvdrv/nvdata.h
index 529b03471..3294bc0e7 100644
--- a/src/core/hle/service/nvdrv/nvdata.h
+++ b/src/core/hle/service/nvdrv/nvdata.h
@@ -1,12 +1,16 @@
1#pragma once 1#pragma once
2 2
3#include <array> 3#include <array>
4#include "common/bit_field.h"
4#include "common/common_types.h" 5#include "common/common_types.h"
5 6
6namespace Service::Nvidia { 7namespace Service::Nvidia {
7 8
8constexpr u32 MaxSyncPoints = 192; 9constexpr u32 MaxSyncPoints = 192;
9constexpr u32 MaxNvEvents = 64; 10constexpr u32 MaxNvEvents = 64;
11using DeviceFD = s32;
12
13constexpr DeviceFD INVALID_NVDRV_FD = -1;
10 14
11struct Fence { 15struct Fence {
12 s32 id; 16 s32 id;
@@ -20,11 +24,61 @@ struct MultiFence {
20 std::array<Fence, 4> fences; 24 std::array<Fence, 4> fences;
21}; 25};
22 26
23enum NvResult : u32 { 27enum class NvResult : u32 {
24 Success = 0, 28 Success = 0x0,
25 BadParameter = 4, 29 NotImplemented = 0x1,
26 Timeout = 5, 30 NotSupported = 0x2,
27 ResourceError = 15, 31 NotInitialized = 0x3,
32 BadParameter = 0x4,
33 Timeout = 0x5,
34 InsufficientMemory = 0x6,
35 ReadOnlyAttribute = 0x7,
36 InvalidState = 0x8,
37 InvalidAddress = 0x9,
38 InvalidSize = 0xA,
39 BadValue = 0xB,
40 AlreadyAllocated = 0xD,
41 Busy = 0xE,
42 ResourceError = 0xF,
43 CountMismatch = 0x10,
44 OverFlow = 0x11,
45 InsufficientTransferMemory = 0x1000,
46 InsufficientVideoMemory = 0x10000,
47 BadSurfaceColorScheme = 0x10001,
48 InvalidSurface = 0x10002,
49 SurfaceNotSupported = 0x10003,
50 DispInitFailed = 0x20000,
51 DispAlreadyAttached = 0x20001,
52 DispTooManyDisplays = 0x20002,
53 DispNoDisplaysAttached = 0x20003,
54 DispModeNotSupported = 0x20004,
55 DispNotFound = 0x20005,
56 DispAttachDissallowed = 0x20006,
57 DispTypeNotSupported = 0x20007,
58 DispAuthenticationFailed = 0x20008,
59 DispNotAttached = 0x20009,
60 DispSamePwrState = 0x2000A,
61 DispEdidFailure = 0x2000B,
62 DispDsiReadAckError = 0x2000C,
63 DispDsiReadInvalidResp = 0x2000D,
64 FileWriteFailed = 0x30000,
65 FileReadFailed = 0x30001,
66 EndOfFile = 0x30002,
67 FileOperationFailed = 0x30003,
68 DirOperationFailed = 0x30004,
69 EndOfDirList = 0x30005,
70 ConfigVarNotFound = 0x30006,
71 InvalidConfigVar = 0x30007,
72 LibraryNotFound = 0x30008,
73 SymbolNotFound = 0x30009,
74 MemoryMapFailed = 0x3000A,
75 IoctlFailed = 0x3000F,
76 AccessDenied = 0x30010,
77 DeviceNotFound = 0x30011,
78 KernelDriverNotFound = 0x30012,
79 FileNotFound = 0x30013,
80 PathAlreadyExists = 0x30014,
81 ModuleNotPresent = 0xA000E,
28}; 82};
29 83
30enum class EventState { 84enum class EventState {
@@ -34,21 +88,13 @@ enum class EventState {
34 Busy = 3, 88 Busy = 3,
35}; 89};
36 90
37enum class IoctlVersion : u32 { 91union Ioctl {
38 Version1, 92 u32_le raw;
39 Version2, 93 BitField<0, 8, u32> cmd;
40 Version3, 94 BitField<8, 8, u32> group;
41}; 95 BitField<16, 14, u32> length;
42 96 BitField<30, 1, u32> is_in;
43struct IoctlCtrl { 97 BitField<31, 1, u32> is_out;
44 // First call done to the servioce for services that call itself again after a call.
45 bool fresh_call{true};
46 // Tells the Ioctl Wrapper that it must delay the IPC response and send the thread to sleep
47 bool must_delay{};
48 // Timeout for the delay
49 s64 timeout{};
50 // NV Event Id
51 s32 event_id{-1};
52}; 98};
53 99
54} // namespace Service::Nvidia 100} // namespace Service::Nvidia
diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp
index 197c77db0..620c18728 100644
--- a/src/core/hle/service/nvdrv/nvdrv.cpp
+++ b/src/core/hle/service/nvdrv/nvdrv.cpp
@@ -5,6 +5,7 @@
5#include <utility> 5#include <utility>
6 6
7#include <fmt/format.h> 7#include <fmt/format.h>
8#include "core/core.h"
8#include "core/hle/ipc_helpers.h" 9#include "core/hle/ipc_helpers.h"
9#include "core/hle/kernel/readable_event.h" 10#include "core/hle/kernel/readable_event.h"
10#include "core/hle/kernel/writable_event.h" 11#include "core/hle/kernel/writable_event.h"
@@ -21,6 +22,7 @@
21#include "core/hle/service/nvdrv/interface.h" 22#include "core/hle/service/nvdrv/interface.h"
22#include "core/hle/service/nvdrv/nvdrv.h" 23#include "core/hle/service/nvdrv/nvdrv.h"
23#include "core/hle/service/nvdrv/nvmemp.h" 24#include "core/hle/service/nvdrv/nvmemp.h"
25#include "core/hle/service/nvdrv/syncpoint_manager.h"
24#include "core/hle/service/nvflinger/nvflinger.h" 26#include "core/hle/service/nvflinger/nvflinger.h"
25 27
26namespace Service::Nvidia { 28namespace Service::Nvidia {
@@ -28,66 +30,135 @@ namespace Service::Nvidia {
28void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nvflinger, 30void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nvflinger,
29 Core::System& system) { 31 Core::System& system) {
30 auto module_ = std::make_shared<Module>(system); 32 auto module_ = std::make_shared<Module>(system);
31 std::make_shared<NVDRV>(module_, "nvdrv")->InstallAsService(service_manager); 33 std::make_shared<NVDRV>(system, module_, "nvdrv")->InstallAsService(service_manager);
32 std::make_shared<NVDRV>(module_, "nvdrv:a")->InstallAsService(service_manager); 34 std::make_shared<NVDRV>(system, module_, "nvdrv:a")->InstallAsService(service_manager);
33 std::make_shared<NVDRV>(module_, "nvdrv:s")->InstallAsService(service_manager); 35 std::make_shared<NVDRV>(system, module_, "nvdrv:s")->InstallAsService(service_manager);
34 std::make_shared<NVDRV>(module_, "nvdrv:t")->InstallAsService(service_manager); 36 std::make_shared<NVDRV>(system, module_, "nvdrv:t")->InstallAsService(service_manager);
35 std::make_shared<NVMEMP>()->InstallAsService(service_manager); 37 std::make_shared<NVMEMP>(system)->InstallAsService(service_manager);
36 nvflinger.SetNVDrvInstance(module_); 38 nvflinger.SetNVDrvInstance(module_);
37} 39}
38 40
39Module::Module(Core::System& system) { 41Module::Module(Core::System& system) : syncpoint_manager{system.GPU()} {
40 auto& kernel = system.Kernel(); 42 auto& kernel = system.Kernel();
41 for (u32 i = 0; i < MaxNvEvents; i++) { 43 for (u32 i = 0; i < MaxNvEvents; i++) {
42 std::string event_label = fmt::format("NVDRV::NvEvent_{}", i); 44 std::string event_label = fmt::format("NVDRV::NvEvent_{}", i);
43 events_interface.events[i] = Kernel::WritableEvent::CreateEventPair(kernel, event_label); 45 events_interface.events[i] = {Kernel::WritableEvent::CreateEventPair(kernel, event_label)};
44 events_interface.status[i] = EventState::Free; 46 events_interface.status[i] = EventState::Free;
45 events_interface.registered[i] = false; 47 events_interface.registered[i] = false;
46 } 48 }
47 auto nvmap_dev = std::make_shared<Devices::nvmap>(system); 49 auto nvmap_dev = std::make_shared<Devices::nvmap>(system);
48 devices["/dev/nvhost-as-gpu"] = std::make_shared<Devices::nvhost_as_gpu>(system, nvmap_dev); 50 devices["/dev/nvhost-as-gpu"] = std::make_shared<Devices::nvhost_as_gpu>(system, nvmap_dev);
49 devices["/dev/nvhost-gpu"] = std::make_shared<Devices::nvhost_gpu>(system, nvmap_dev); 51 devices["/dev/nvhost-gpu"] =
52 std::make_shared<Devices::nvhost_gpu>(system, nvmap_dev, syncpoint_manager);
50 devices["/dev/nvhost-ctrl-gpu"] = std::make_shared<Devices::nvhost_ctrl_gpu>(system); 53 devices["/dev/nvhost-ctrl-gpu"] = std::make_shared<Devices::nvhost_ctrl_gpu>(system);
51 devices["/dev/nvmap"] = nvmap_dev; 54 devices["/dev/nvmap"] = nvmap_dev;
52 devices["/dev/nvdisp_disp0"] = std::make_shared<Devices::nvdisp_disp0>(system, nvmap_dev); 55 devices["/dev/nvdisp_disp0"] = std::make_shared<Devices::nvdisp_disp0>(system, nvmap_dev);
53 devices["/dev/nvhost-ctrl"] = std::make_shared<Devices::nvhost_ctrl>(system, events_interface); 56 devices["/dev/nvhost-ctrl"] =
54 devices["/dev/nvhost-nvdec"] = std::make_shared<Devices::nvhost_nvdec>(system); 57 std::make_shared<Devices::nvhost_ctrl>(system, events_interface, syncpoint_manager);
58 devices["/dev/nvhost-nvdec"] =
59 std::make_shared<Devices::nvhost_nvdec>(system, nvmap_dev, syncpoint_manager);
55 devices["/dev/nvhost-nvjpg"] = std::make_shared<Devices::nvhost_nvjpg>(system); 60 devices["/dev/nvhost-nvjpg"] = std::make_shared<Devices::nvhost_nvjpg>(system);
56 devices["/dev/nvhost-vic"] = std::make_shared<Devices::nvhost_vic>(system); 61 devices["/dev/nvhost-vic"] =
62 std::make_shared<Devices::nvhost_vic>(system, nvmap_dev, syncpoint_manager);
57} 63}
58 64
59Module::~Module() = default; 65Module::~Module() = default;
60 66
61u32 Module::Open(const std::string& device_name) { 67NvResult Module::VerifyFD(DeviceFD fd) const {
62 ASSERT_MSG(devices.find(device_name) != devices.end(), "Trying to open unknown device {}", 68 if (fd < 0) {
63 device_name); 69 LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd);
70 return NvResult::InvalidState;
71 }
72
73 if (open_files.find(fd) == open_files.end()) {
74 LOG_ERROR(Service_NVDRV, "Could not find DeviceFD={}!", fd);
75 return NvResult::NotImplemented;
76 }
77
78 return NvResult::Success;
79}
80
81DeviceFD Module::Open(const std::string& device_name) {
82 if (devices.find(device_name) == devices.end()) {
83 LOG_ERROR(Service_NVDRV, "Trying to open unknown device {}", device_name);
84 return INVALID_NVDRV_FD;
85 }
64 86
65 auto device = devices[device_name]; 87 auto device = devices[device_name];
66 const u32 fd = next_fd++; 88 const DeviceFD fd = next_fd++;
67 89
68 open_files[fd] = std::move(device); 90 open_files[fd] = std::move(device);
69 91
70 return fd; 92 return fd;
71} 93}
72 94
73u32 Module::Ioctl(u32 fd, u32 command, const std::vector<u8>& input, const std::vector<u8>& input2, 95NvResult Module::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
74 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, 96 std::vector<u8>& output) {
75 IoctlVersion version) { 97 if (fd < 0) {
76 auto itr = open_files.find(fd); 98 LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd);
77 ASSERT_MSG(itr != open_files.end(), "Tried to talk to an invalid device"); 99 return NvResult::InvalidState;
100 }
78 101
79 auto& device = itr->second; 102 const auto itr = open_files.find(fd);
80 return device->ioctl({command}, input, input2, output, output2, ctrl, version); 103
104 if (itr == open_files.end()) {
105 LOG_ERROR(Service_NVDRV, "Could not find DeviceFD={}!", fd);
106 return NvResult::NotImplemented;
107 }
108
109 return itr->second->Ioctl1(command, input, output);
81} 110}
82 111
83ResultCode Module::Close(u32 fd) { 112NvResult Module::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
84 auto itr = open_files.find(fd); 113 const std::vector<u8>& inline_input, std::vector<u8>& output) {
85 ASSERT_MSG(itr != open_files.end(), "Tried to talk to an invalid device"); 114 if (fd < 0) {
115 LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd);
116 return NvResult::InvalidState;
117 }
118
119 const auto itr = open_files.find(fd);
120
121 if (itr == open_files.end()) {
122 LOG_ERROR(Service_NVDRV, "Could not find DeviceFD={}!", fd);
123 return NvResult::NotImplemented;
124 }
125
126 return itr->second->Ioctl2(command, input, inline_input, output);
127}
128
129NvResult Module::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
130 std::vector<u8>& output, std::vector<u8>& inline_output) {
131 if (fd < 0) {
132 LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd);
133 return NvResult::InvalidState;
134 }
135
136 const auto itr = open_files.find(fd);
137
138 if (itr == open_files.end()) {
139 LOG_ERROR(Service_NVDRV, "Could not find DeviceFD={}!", fd);
140 return NvResult::NotImplemented;
141 }
142
143 return itr->second->Ioctl3(command, input, output, inline_output);
144}
145
146NvResult Module::Close(DeviceFD fd) {
147 if (fd < 0) {
148 LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd);
149 return NvResult::InvalidState;
150 }
151
152 const auto itr = open_files.find(fd);
153
154 if (itr == open_files.end()) {
155 LOG_ERROR(Service_NVDRV, "Could not find DeviceFD={}!", fd);
156 return NvResult::NotImplemented;
157 }
86 158
87 open_files.erase(itr); 159 open_files.erase(itr);
88 160
89 // TODO(flerovium): return correct result code if operation failed. 161 return NvResult::Success;
90 return RESULT_SUCCESS;
91} 162}
92 163
93void Module::SignalSyncpt(const u32 syncpoint_id, const u32 value) { 164void Module::SignalSyncpt(const u32 syncpoint_id, const u32 value) {
@@ -95,17 +166,17 @@ void Module::SignalSyncpt(const u32 syncpoint_id, const u32 value) {
95 if (events_interface.assigned_syncpt[i] == syncpoint_id && 166 if (events_interface.assigned_syncpt[i] == syncpoint_id &&
96 events_interface.assigned_value[i] == value) { 167 events_interface.assigned_value[i] == value) {
97 events_interface.LiberateEvent(i); 168 events_interface.LiberateEvent(i);
98 events_interface.events[i].writable->Signal(); 169 events_interface.events[i].event.writable->Signal();
99 } 170 }
100 } 171 }
101} 172}
102 173
103std::shared_ptr<Kernel::ReadableEvent> Module::GetEvent(const u32 event_id) const { 174std::shared_ptr<Kernel::ReadableEvent> Module::GetEvent(const u32 event_id) const {
104 return events_interface.events[event_id].readable; 175 return events_interface.events[event_id].event.readable;
105} 176}
106 177
107std::shared_ptr<Kernel::WritableEvent> Module::GetEventWriteable(const u32 event_id) const { 178std::shared_ptr<Kernel::WritableEvent> Module::GetEventWriteable(const u32 event_id) const {
108 return events_interface.events[event_id].writable; 179 return events_interface.events[event_id].event.writable;
109} 180}
110 181
111} // namespace Service::Nvidia 182} // namespace Service::Nvidia
diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h
index 7706a5590..144e657e5 100644
--- a/src/core/hle/service/nvdrv/nvdrv.h
+++ b/src/core/hle/service/nvdrv/nvdrv.h
@@ -10,6 +10,7 @@
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "core/hle/kernel/writable_event.h" 11#include "core/hle/kernel/writable_event.h"
12#include "core/hle/service/nvdrv/nvdata.h" 12#include "core/hle/service/nvdrv/nvdata.h"
13#include "core/hle/service/nvdrv/syncpoint_manager.h"
13#include "core/hle/service/service.h" 14#include "core/hle/service/service.h"
14 15
15namespace Core { 16namespace Core {
@@ -22,15 +23,23 @@ class NVFlinger;
22 23
23namespace Service::Nvidia { 24namespace Service::Nvidia {
24 25
26class SyncpointManager;
27
25namespace Devices { 28namespace Devices {
26class nvdevice; 29class nvdevice;
27} 30}
28 31
32/// Represents an Nvidia event
33struct NvEvent {
34 Kernel::EventPair event;
35 Fence fence{};
36};
37
29struct EventInterface { 38struct EventInterface {
30 // Mask representing currently busy events 39 // Mask representing currently busy events
31 u64 events_mask{}; 40 u64 events_mask{};
32 // Each kernel event associated to an NV event 41 // Each kernel event associated to an NV event
33 std::array<Kernel::EventPair, MaxNvEvents> events; 42 std::array<NvEvent, MaxNvEvents> events;
34 // The status of the current NVEvent 43 // The status of the current NVEvent
35 std::array<EventState, MaxNvEvents> status{}; 44 std::array<EventState, MaxNvEvents> status{};
36 // Tells if an NVEvent is registered or not 45 // Tells if an NVEvent is registered or not
@@ -91,7 +100,7 @@ struct EventInterface {
91 100
92class Module final { 101class Module final {
93public: 102public:
94 Module(Core::System& system); 103 explicit Module(Core::System& system_);
95 ~Module(); 104 ~Module();
96 105
97 /// Returns a pointer to one of the available devices, identified by its name. 106 /// Returns a pointer to one of the available devices, identified by its name.
@@ -103,14 +112,23 @@ public:
103 return std::static_pointer_cast<T>(itr->second); 112 return std::static_pointer_cast<T>(itr->second);
104 } 113 }
105 114
115 NvResult VerifyFD(DeviceFD fd) const;
116
106 /// Opens a device node and returns a file descriptor to it. 117 /// Opens a device node and returns a file descriptor to it.
107 u32 Open(const std::string& device_name); 118 DeviceFD Open(const std::string& device_name);
119
108 /// Sends an ioctl command to the specified file descriptor. 120 /// Sends an ioctl command to the specified file descriptor.
109 u32 Ioctl(u32 fd, u32 command, const std::vector<u8>& input, const std::vector<u8>& input2, 121 NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
110 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, 122 std::vector<u8>& output);
111 IoctlVersion version); 123
124 NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
125 const std::vector<u8>& inline_input, std::vector<u8>& output);
126
127 NvResult Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
128 std::vector<u8>& output, std::vector<u8>& inline_output);
129
112 /// Closes a device file descriptor and returns operation success. 130 /// Closes a device file descriptor and returns operation success.
113 ResultCode Close(u32 fd); 131 NvResult Close(DeviceFD fd);
114 132
115 void SignalSyncpt(const u32 syncpoint_id, const u32 value); 133 void SignalSyncpt(const u32 syncpoint_id, const u32 value);
116 134
@@ -119,11 +137,14 @@ public:
119 std::shared_ptr<Kernel::WritableEvent> GetEventWriteable(u32 event_id) const; 137 std::shared_ptr<Kernel::WritableEvent> GetEventWriteable(u32 event_id) const;
120 138
121private: 139private:
140 /// Manages syncpoints on the host
141 SyncpointManager syncpoint_manager;
142
122 /// Id to use for the next open file descriptor. 143 /// Id to use for the next open file descriptor.
123 u32 next_fd = 1; 144 DeviceFD next_fd = 1;
124 145
125 /// Mapping of file descriptors to the devices they reference. 146 /// Mapping of file descriptors to the devices they reference.
126 std::unordered_map<u32, std::shared_ptr<Devices::nvdevice>> open_files; 147 std::unordered_map<DeviceFD, std::shared_ptr<Devices::nvdevice>> open_files;
127 148
128 /// Mapping of device node names to their implementation. 149 /// Mapping of device node names to their implementation.
129 std::unordered_map<std::string, std::shared_ptr<Devices::nvdevice>> devices; 150 std::unordered_map<std::string, std::shared_ptr<Devices::nvdevice>> devices;
diff --git a/src/core/hle/service/nvdrv/nvmemp.cpp b/src/core/hle/service/nvdrv/nvmemp.cpp
index 73b37e805..331c02243 100644
--- a/src/core/hle/service/nvdrv/nvmemp.cpp
+++ b/src/core/hle/service/nvdrv/nvmemp.cpp
@@ -8,7 +8,7 @@
8 8
9namespace Service::Nvidia { 9namespace Service::Nvidia {
10 10
11NVMEMP::NVMEMP() : ServiceFramework("nvmemp") { 11NVMEMP::NVMEMP(Core::System& system_) : ServiceFramework{system_, "nvmemp"} {
12 static const FunctionInfo functions[] = { 12 static const FunctionInfo functions[] = {
13 {0, &NVMEMP::Open, "Open"}, 13 {0, &NVMEMP::Open, "Open"},
14 {1, &NVMEMP::GetAruid, "GetAruid"}, 14 {1, &NVMEMP::GetAruid, "GetAruid"},
diff --git a/src/core/hle/service/nvdrv/nvmemp.h b/src/core/hle/service/nvdrv/nvmemp.h
index c453ee4db..724c27ef9 100644
--- a/src/core/hle/service/nvdrv/nvmemp.h
+++ b/src/core/hle/service/nvdrv/nvmemp.h
@@ -6,11 +6,15 @@
6 6
7#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
8 8
9namespace Core {
10class System;
11}
12
9namespace Service::Nvidia { 13namespace Service::Nvidia {
10 14
11class NVMEMP final : public ServiceFramework<NVMEMP> { 15class NVMEMP final : public ServiceFramework<NVMEMP> {
12public: 16public:
13 NVMEMP(); 17 explicit NVMEMP(Core::System& system_);
14 ~NVMEMP() override; 18 ~NVMEMP() override;
15 19
16private: 20private:
diff --git a/src/core/hle/service/nvdrv/syncpoint_manager.cpp b/src/core/hle/service/nvdrv/syncpoint_manager.cpp
new file mode 100644
index 000000000..0151a03b7
--- /dev/null
+++ b/src/core/hle/service/nvdrv/syncpoint_manager.cpp
@@ -0,0 +1,39 @@
1// Copyright 2020 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/assert.h"
6#include "core/hle/service/nvdrv/syncpoint_manager.h"
7#include "video_core/gpu.h"
8
9namespace Service::Nvidia {
10
11SyncpointManager::SyncpointManager(Tegra::GPU& gpu) : gpu{gpu} {}
12
13SyncpointManager::~SyncpointManager() = default;
14
15u32 SyncpointManager::RefreshSyncpoint(u32 syncpoint_id) {
16 syncpoints[syncpoint_id].min = gpu.GetSyncpointValue(syncpoint_id);
17 return GetSyncpointMin(syncpoint_id);
18}
19
20u32 SyncpointManager::AllocateSyncpoint() {
21 for (u32 syncpoint_id = 1; syncpoint_id < MaxSyncPoints; syncpoint_id++) {
22 if (!syncpoints[syncpoint_id].is_allocated) {
23 syncpoints[syncpoint_id].is_allocated = true;
24 return syncpoint_id;
25 }
26 }
27 UNREACHABLE_MSG("No more available syncpoints!");
28 return {};
29}
30
31u32 SyncpointManager::IncreaseSyncpoint(u32 syncpoint_id, u32 value) {
32 for (u32 index = 0; index < value; ++index) {
33 syncpoints[syncpoint_id].max.fetch_add(1, std::memory_order_relaxed);
34 }
35
36 return GetSyncpointMax(syncpoint_id);
37}
38
39} // namespace Service::Nvidia
diff --git a/src/core/hle/service/nvdrv/syncpoint_manager.h b/src/core/hle/service/nvdrv/syncpoint_manager.h
new file mode 100644
index 000000000..d395c5d0b
--- /dev/null
+++ b/src/core/hle/service/nvdrv/syncpoint_manager.h
@@ -0,0 +1,85 @@
1// Copyright 2020 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <array>
8#include <atomic>
9
10#include "common/common_types.h"
11#include "core/hle/service/nvdrv/nvdata.h"
12
13namespace Tegra {
14class GPU;
15}
16
17namespace Service::Nvidia {
18
19class SyncpointManager final {
20public:
21 explicit SyncpointManager(Tegra::GPU& gpu);
22 ~SyncpointManager();
23
24 /**
25 * Returns true if the specified syncpoint is expired for the given value.
26 * @param syncpoint_id Syncpoint ID to check.
27 * @param value Value to check against the specified syncpoint.
28 * @returns True if the specified syncpoint is expired for the given value, otherwise False.
29 */
30 bool IsSyncpointExpired(u32 syncpoint_id, u32 value) const {
31 return (GetSyncpointMax(syncpoint_id) - value) >= (GetSyncpointMin(syncpoint_id) - value);
32 }
33
34 /**
35 * Gets the lower bound for the specified syncpoint.
36 * @param syncpoint_id Syncpoint ID to get the lower bound for.
37 * @returns The lower bound for the specified syncpoint.
38 */
39 u32 GetSyncpointMin(u32 syncpoint_id) const {
40 return syncpoints.at(syncpoint_id).min.load(std::memory_order_relaxed);
41 }
42
43 /**
44 * Gets the uper bound for the specified syncpoint.
45 * @param syncpoint_id Syncpoint ID to get the upper bound for.
46 * @returns The upper bound for the specified syncpoint.
47 */
48 u32 GetSyncpointMax(u32 syncpoint_id) const {
49 return syncpoints.at(syncpoint_id).max.load(std::memory_order_relaxed);
50 }
51
52 /**
53 * Refreshes the minimum value for the specified syncpoint.
54 * @param syncpoint_id Syncpoint ID to be refreshed.
55 * @returns The new syncpoint minimum value.
56 */
57 u32 RefreshSyncpoint(u32 syncpoint_id);
58
59 /**
60 * Allocates a new syncoint.
61 * @returns The syncpoint ID for the newly allocated syncpoint.
62 */
63 u32 AllocateSyncpoint();
64
65 /**
66 * Increases the maximum value for the specified syncpoint.
67 * @param syncpoint_id Syncpoint ID to be increased.
68 * @param value Value to increase the specified syncpoint by.
69 * @returns The new syncpoint maximum value.
70 */
71 u32 IncreaseSyncpoint(u32 syncpoint_id, u32 value);
72
73private:
74 struct Syncpoint {
75 std::atomic<u32> min;
76 std::atomic<u32> max;
77 std::atomic<bool> is_allocated;
78 };
79
80 std::array<Syncpoint, MaxSyncPoints> syncpoints{};
81
82 Tegra::GPU& gpu;
83};
84
85} // namespace Service::Nvidia
diff --git a/src/core/hle/service/nvflinger/buffer_queue.cpp b/src/core/hle/service/nvflinger/buffer_queue.cpp
index 637b310d7..5578181a4 100644
--- a/src/core/hle/service/nvflinger/buffer_queue.cpp
+++ b/src/core/hle/service/nvflinger/buffer_queue.cpp
@@ -22,127 +22,169 @@ BufferQueue::BufferQueue(Kernel::KernelCore& kernel, u32 id, u64 layer_id)
22BufferQueue::~BufferQueue() = default; 22BufferQueue::~BufferQueue() = default;
23 23
24void BufferQueue::SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer) { 24void BufferQueue::SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer) {
25 ASSERT(slot < buffer_slots);
25 LOG_WARNING(Service, "Adding graphics buffer {}", slot); 26 LOG_WARNING(Service, "Adding graphics buffer {}", slot);
26 27
27 free_buffers.push_back(slot); 28 {
28 queue.push_back({ 29 std::unique_lock lock{free_buffers_mutex};
30 free_buffers.push_back(slot);
31 }
32 free_buffers_condition.notify_one();
33
34 buffers[slot] = {
29 .slot = slot, 35 .slot = slot,
30 .status = Buffer::Status::Free, 36 .status = Buffer::Status::Free,
31 .igbp_buffer = igbp_buffer, 37 .igbp_buffer = igbp_buffer,
32 }); 38 .transform = {},
39 .crop_rect = {},
40 .swap_interval = 0,
41 .multi_fence = {},
42 };
33 43
34 buffer_wait_event.writable->Signal(); 44 buffer_wait_event.writable->Signal();
35} 45}
36 46
37std::optional<std::pair<u32, Service::Nvidia::MultiFence*>> BufferQueue::DequeueBuffer(u32 width, 47std::optional<std::pair<u32, Service::Nvidia::MultiFence*>> BufferQueue::DequeueBuffer(u32 width,
38 u32 height) { 48 u32 height) {
49 // Wait for first request before trying to dequeue
50 {
51 std::unique_lock lock{free_buffers_mutex};
52 free_buffers_condition.wait(lock, [this] { return !free_buffers.empty() || !is_connect; });
53 }
39 54
40 if (free_buffers.empty()) { 55 if (!is_connect) {
56 // Buffer was disconnected while the thread was blocked, this is most likely due to
57 // emulation being stopped
41 return std::nullopt; 58 return std::nullopt;
42 } 59 }
43 60
61 std::unique_lock lock{free_buffers_mutex};
62
44 auto f_itr = free_buffers.begin(); 63 auto f_itr = free_buffers.begin();
45 auto itr = queue.end(); 64 auto slot = buffers.size();
46 65
47 while (f_itr != free_buffers.end()) { 66 while (f_itr != free_buffers.end()) {
48 auto slot = *f_itr; 67 const Buffer& buffer = buffers[*f_itr];
49 itr = std::find_if(queue.begin(), queue.end(), [&](const Buffer& buffer) { 68 if (buffer.status == Buffer::Status::Free && buffer.igbp_buffer.width == width &&
50 // Only consider free buffers. Buffers become free once again after they've been 69 buffer.igbp_buffer.height == height) {
51 // Acquired and Released by the compositor, see the NVFlinger::Compose method. 70 slot = *f_itr;
52 if (buffer.status != Buffer::Status::Free) {
53 return false;
54 }
55
56 if (buffer.slot != slot) {
57 return false;
58 }
59
60 // Make sure that the parameters match.
61 return buffer.igbp_buffer.width == width && buffer.igbp_buffer.height == height;
62 });
63
64 if (itr != queue.end()) {
65 free_buffers.erase(f_itr); 71 free_buffers.erase(f_itr);
66 break; 72 break;
67 } 73 }
68 ++f_itr; 74 ++f_itr;
69 } 75 }
70 76 if (slot == buffers.size()) {
71 if (itr == queue.end()) {
72 return std::nullopt; 77 return std::nullopt;
73 } 78 }
74 79 buffers[slot].status = Buffer::Status::Dequeued;
75 itr->status = Buffer::Status::Dequeued; 80 return {{buffers[slot].slot, &buffers[slot].multi_fence}};
76 return {{itr->slot, &itr->multi_fence}};
77} 81}
78 82
79const IGBPBuffer& BufferQueue::RequestBuffer(u32 slot) const { 83const IGBPBuffer& BufferQueue::RequestBuffer(u32 slot) const {
80 auto itr = std::find_if(queue.begin(), queue.end(), 84 ASSERT(slot < buffers.size());
81 [&](const Buffer& buffer) { return buffer.slot == slot; }); 85 ASSERT(buffers[slot].status == Buffer::Status::Dequeued);
82 ASSERT(itr != queue.end()); 86 ASSERT(buffers[slot].slot == slot);
83 ASSERT(itr->status == Buffer::Status::Dequeued); 87
84 return itr->igbp_buffer; 88 return buffers[slot].igbp_buffer;
85} 89}
86 90
87void BufferQueue::QueueBuffer(u32 slot, BufferTransformFlags transform, 91void BufferQueue::QueueBuffer(u32 slot, BufferTransformFlags transform,
88 const Common::Rectangle<int>& crop_rect, u32 swap_interval, 92 const Common::Rectangle<int>& crop_rect, u32 swap_interval,
89 Service::Nvidia::MultiFence& multi_fence) { 93 Service::Nvidia::MultiFence& multi_fence) {
90 auto itr = std::find_if(queue.begin(), queue.end(), 94 ASSERT(slot < buffers.size());
91 [&](const Buffer& buffer) { return buffer.slot == slot; }); 95 ASSERT(buffers[slot].status == Buffer::Status::Dequeued);
92 ASSERT(itr != queue.end()); 96 ASSERT(buffers[slot].slot == slot);
93 ASSERT(itr->status == Buffer::Status::Dequeued); 97
94 itr->status = Buffer::Status::Queued; 98 buffers[slot].status = Buffer::Status::Queued;
95 itr->transform = transform; 99 buffers[slot].transform = transform;
96 itr->crop_rect = crop_rect; 100 buffers[slot].crop_rect = crop_rect;
97 itr->swap_interval = swap_interval; 101 buffers[slot].swap_interval = swap_interval;
98 itr->multi_fence = multi_fence; 102 buffers[slot].multi_fence = multi_fence;
103 std::unique_lock lock{queue_sequence_mutex};
99 queue_sequence.push_back(slot); 104 queue_sequence.push_back(slot);
100} 105}
101 106
107void BufferQueue::CancelBuffer(u32 slot, const Service::Nvidia::MultiFence& multi_fence) {
108 ASSERT(slot < buffers.size());
109 ASSERT(buffers[slot].status != Buffer::Status::Free);
110 ASSERT(buffers[slot].slot == slot);
111
112 buffers[slot].status = Buffer::Status::Free;
113 buffers[slot].multi_fence = multi_fence;
114 buffers[slot].swap_interval = 0;
115
116 {
117 std::unique_lock lock{free_buffers_mutex};
118 free_buffers.push_back(slot);
119 }
120 free_buffers_condition.notify_one();
121
122 buffer_wait_event.writable->Signal();
123}
124
102std::optional<std::reference_wrapper<const BufferQueue::Buffer>> BufferQueue::AcquireBuffer() { 125std::optional<std::reference_wrapper<const BufferQueue::Buffer>> BufferQueue::AcquireBuffer() {
103 auto itr = queue.end(); 126 std::unique_lock lock{queue_sequence_mutex};
127 std::size_t buffer_slot = buffers.size();
104 // Iterate to find a queued buffer matching the requested slot. 128 // Iterate to find a queued buffer matching the requested slot.
105 while (itr == queue.end() && !queue_sequence.empty()) { 129 while (buffer_slot == buffers.size() && !queue_sequence.empty()) {
106 const u32 slot = queue_sequence.front(); 130 const auto slot = static_cast<std::size_t>(queue_sequence.front());
107 itr = std::find_if(queue.begin(), queue.end(), [&slot](const Buffer& buffer) { 131 ASSERT(slot < buffers.size());
108 return buffer.status == Buffer::Status::Queued && buffer.slot == slot; 132 if (buffers[slot].status == Buffer::Status::Queued) {
109 }); 133 ASSERT(buffers[slot].slot == slot);
134 buffer_slot = slot;
135 }
110 queue_sequence.pop_front(); 136 queue_sequence.pop_front();
111 } 137 }
112 if (itr == queue.end()) { 138 if (buffer_slot == buffers.size()) {
113 return std::nullopt; 139 return std::nullopt;
114 } 140 }
115 itr->status = Buffer::Status::Acquired; 141 buffers[buffer_slot].status = Buffer::Status::Acquired;
116 return *itr; 142 return {{buffers[buffer_slot]}};
117} 143}
118 144
119void BufferQueue::ReleaseBuffer(u32 slot) { 145void BufferQueue::ReleaseBuffer(u32 slot) {
120 auto itr = std::find_if(queue.begin(), queue.end(), 146 ASSERT(slot < buffers.size());
121 [&](const Buffer& buffer) { return buffer.slot == slot; }); 147 ASSERT(buffers[slot].status == Buffer::Status::Acquired);
122 ASSERT(itr != queue.end()); 148 ASSERT(buffers[slot].slot == slot);
123 ASSERT(itr->status == Buffer::Status::Acquired); 149
124 itr->status = Buffer::Status::Free; 150 buffers[slot].status = Buffer::Status::Free;
125 free_buffers.push_back(slot); 151 {
152 std::unique_lock lock{free_buffers_mutex};
153 free_buffers.push_back(slot);
154 }
155 free_buffers_condition.notify_one();
126 156
127 buffer_wait_event.writable->Signal(); 157 buffer_wait_event.writable->Signal();
128} 158}
129 159
130void BufferQueue::Disconnect() { 160void BufferQueue::Connect() {
131 queue.clear(); 161 std::unique_lock lock{queue_sequence_mutex};
132 queue_sequence.clear(); 162 queue_sequence.clear();
133 id = 1; 163 is_connect = true;
134 layer_id = 1; 164}
165
166void BufferQueue::Disconnect() {
167 buffers.fill({});
168 {
169 std::unique_lock lock{queue_sequence_mutex};
170 queue_sequence.clear();
171 }
172 buffer_wait_event.writable->Signal();
173 is_connect = false;
174 free_buffers_condition.notify_one();
135} 175}
136 176
137u32 BufferQueue::Query(QueryType type) { 177u32 BufferQueue::Query(QueryType type) {
138 LOG_WARNING(Service, "(STUBBED) called type={}", static_cast<u32>(type)); 178 LOG_WARNING(Service, "(STUBBED) called type={}", type);
139 179
140 switch (type) { 180 switch (type) {
141 case QueryType::NativeWindowFormat: 181 case QueryType::NativeWindowFormat:
142 return static_cast<u32>(PixelFormat::RGBA8888); 182 return static_cast<u32>(PixelFormat::RGBA8888);
183 case QueryType::NativeWindowWidth:
184 case QueryType::NativeWindowHeight:
185 break;
143 } 186 }
144 187 UNIMPLEMENTED_MSG("Unimplemented query type={}", type);
145 UNIMPLEMENTED();
146 return 0; 188 return 0;
147} 189}
148 190
diff --git a/src/core/hle/service/nvflinger/buffer_queue.h b/src/core/hle/service/nvflinger/buffer_queue.h
index 8a837e5aa..ad7469277 100644
--- a/src/core/hle/service/nvflinger/buffer_queue.h
+++ b/src/core/hle/service/nvflinger/buffer_queue.h
@@ -4,7 +4,9 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <condition_variable>
7#include <list> 8#include <list>
9#include <mutex>
8#include <optional> 10#include <optional>
9#include <vector> 11#include <vector>
10 12
@@ -21,6 +23,7 @@ class KernelCore;
21 23
22namespace Service::NVFlinger { 24namespace Service::NVFlinger {
23 25
26constexpr u32 buffer_slots = 0x40;
24struct IGBPBuffer { 27struct IGBPBuffer {
25 u32_le magic; 28 u32_le magic;
26 u32_le width; 29 u32_le width;
@@ -95,8 +98,10 @@ public:
95 void QueueBuffer(u32 slot, BufferTransformFlags transform, 98 void QueueBuffer(u32 slot, BufferTransformFlags transform,
96 const Common::Rectangle<int>& crop_rect, u32 swap_interval, 99 const Common::Rectangle<int>& crop_rect, u32 swap_interval,
97 Service::Nvidia::MultiFence& multi_fence); 100 Service::Nvidia::MultiFence& multi_fence);
101 void CancelBuffer(u32 slot, const Service::Nvidia::MultiFence& multi_fence);
98 std::optional<std::reference_wrapper<const Buffer>> AcquireBuffer(); 102 std::optional<std::reference_wrapper<const Buffer>> AcquireBuffer();
99 void ReleaseBuffer(u32 slot); 103 void ReleaseBuffer(u32 slot);
104 void Connect();
100 void Disconnect(); 105 void Disconnect();
101 u32 Query(QueryType type); 106 u32 Query(QueryType type);
102 107
@@ -104,18 +109,30 @@ public:
104 return id; 109 return id;
105 } 110 }
106 111
112 bool IsConnected() const {
113 return is_connect;
114 }
115
107 std::shared_ptr<Kernel::WritableEvent> GetWritableBufferWaitEvent() const; 116 std::shared_ptr<Kernel::WritableEvent> GetWritableBufferWaitEvent() const;
108 117
109 std::shared_ptr<Kernel::ReadableEvent> GetBufferWaitEvent() const; 118 std::shared_ptr<Kernel::ReadableEvent> GetBufferWaitEvent() const;
110 119
111private: 120private:
112 u32 id; 121 BufferQueue(const BufferQueue&) = delete;
113 u64 layer_id; 122
123 u32 id{};
124 u64 layer_id{};
125 std::atomic_bool is_connect{};
114 126
115 std::list<u32> free_buffers; 127 std::list<u32> free_buffers;
116 std::vector<Buffer> queue; 128 std::array<Buffer, buffer_slots> buffers;
117 std::list<u32> queue_sequence; 129 std::list<u32> queue_sequence;
118 Kernel::EventPair buffer_wait_event; 130 Kernel::EventPair buffer_wait_event;
131
132 std::mutex free_buffers_mutex;
133 std::condition_variable free_buffers_condition;
134
135 std::mutex queue_sequence_mutex;
119}; 136};
120 137
121} // namespace Service::NVFlinger 138} // namespace Service::NVFlinger
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp
index c64673dba..4b3581949 100644
--- a/src/core/hle/service/nvflinger/nvflinger.cpp
+++ b/src/core/hle/service/nvflinger/nvflinger.cpp
@@ -88,6 +88,10 @@ NVFlinger::NVFlinger(Core::System& system) : system(system) {
88} 88}
89 89
90NVFlinger::~NVFlinger() { 90NVFlinger::~NVFlinger() {
91 for (auto& buffer_queue : buffer_queues) {
92 buffer_queue->Disconnect();
93 }
94
91 if (system.IsMulticore()) { 95 if (system.IsMulticore()) {
92 is_running = false; 96 is_running = false;
93 wait_event->Set(); 97 wait_event->Set();
@@ -104,6 +108,8 @@ void NVFlinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) {
104} 108}
105 109
106std::optional<u64> NVFlinger::OpenDisplay(std::string_view name) { 110std::optional<u64> NVFlinger::OpenDisplay(std::string_view name) {
111 const auto guard = Lock();
112
107 LOG_DEBUG(Service, "Opening \"{}\" display", name); 113 LOG_DEBUG(Service, "Opening \"{}\" display", name);
108 114
109 // TODO(Subv): Currently we only support the Default display. 115 // TODO(Subv): Currently we only support the Default display.
@@ -121,6 +127,7 @@ std::optional<u64> NVFlinger::OpenDisplay(std::string_view name) {
121} 127}
122 128
123std::optional<u64> NVFlinger::CreateLayer(u64 display_id) { 129std::optional<u64> NVFlinger::CreateLayer(u64 display_id) {
130 const auto guard = Lock();
124 auto* const display = FindDisplay(display_id); 131 auto* const display = FindDisplay(display_id);
125 132
126 if (display == nullptr) { 133 if (display == nullptr) {
@@ -129,18 +136,22 @@ std::optional<u64> NVFlinger::CreateLayer(u64 display_id) {
129 136
130 const u64 layer_id = next_layer_id++; 137 const u64 layer_id = next_layer_id++;
131 const u32 buffer_queue_id = next_buffer_queue_id++; 138 const u32 buffer_queue_id = next_buffer_queue_id++;
132 buffer_queues.emplace_back(system.Kernel(), buffer_queue_id, layer_id); 139 buffer_queues.emplace_back(
133 display->CreateLayer(layer_id, buffer_queues.back()); 140 std::make_unique<BufferQueue>(system.Kernel(), buffer_queue_id, layer_id));
141 display->CreateLayer(layer_id, *buffer_queues.back());
134 return layer_id; 142 return layer_id;
135} 143}
136 144
137void NVFlinger::CloseLayer(u64 layer_id) { 145void NVFlinger::CloseLayer(u64 layer_id) {
146 const auto guard = Lock();
147
138 for (auto& display : displays) { 148 for (auto& display : displays) {
139 display.CloseLayer(layer_id); 149 display.CloseLayer(layer_id);
140 } 150 }
141} 151}
142 152
143std::optional<u32> NVFlinger::FindBufferQueueId(u64 display_id, u64 layer_id) const { 153std::optional<u32> NVFlinger::FindBufferQueueId(u64 display_id, u64 layer_id) const {
154 const auto guard = Lock();
144 const auto* const layer = FindLayer(display_id, layer_id); 155 const auto* const layer = FindLayer(display_id, layer_id);
145 156
146 if (layer == nullptr) { 157 if (layer == nullptr) {
@@ -151,6 +162,7 @@ std::optional<u32> NVFlinger::FindBufferQueueId(u64 display_id, u64 layer_id) co
151} 162}
152 163
153std::shared_ptr<Kernel::ReadableEvent> NVFlinger::FindVsyncEvent(u64 display_id) const { 164std::shared_ptr<Kernel::ReadableEvent> NVFlinger::FindVsyncEvent(u64 display_id) const {
165 const auto guard = Lock();
154 auto* const display = FindDisplay(display_id); 166 auto* const display = FindDisplay(display_id);
155 167
156 if (display == nullptr) { 168 if (display == nullptr) {
@@ -160,20 +172,16 @@ std::shared_ptr<Kernel::ReadableEvent> NVFlinger::FindVsyncEvent(u64 display_id)
160 return display->GetVSyncEvent(); 172 return display->GetVSyncEvent();
161} 173}
162 174
163BufferQueue& NVFlinger::FindBufferQueue(u32 id) { 175BufferQueue* NVFlinger::FindBufferQueue(u32 id) {
176 const auto guard = Lock();
164 const auto itr = std::find_if(buffer_queues.begin(), buffer_queues.end(), 177 const auto itr = std::find_if(buffer_queues.begin(), buffer_queues.end(),
165 [id](const auto& queue) { return queue.GetId() == id; }); 178 [id](const auto& queue) { return queue->GetId() == id; });
166
167 ASSERT(itr != buffer_queues.end());
168 return *itr;
169}
170 179
171const BufferQueue& NVFlinger::FindBufferQueue(u32 id) const { 180 if (itr == buffer_queues.end()) {
172 const auto itr = std::find_if(buffer_queues.begin(), buffer_queues.end(), 181 return nullptr;
173 [id](const auto& queue) { return queue.GetId() == id; }); 182 }
174 183
175 ASSERT(itr != buffer_queues.end()); 184 return itr->get();
176 return *itr;
177} 185}
178 186
179VI::Display* NVFlinger::FindDisplay(u64 display_id) { 187VI::Display* NVFlinger::FindDisplay(u64 display_id) {
@@ -242,6 +250,10 @@ void NVFlinger::Compose() {
242 250
243 const auto& igbp_buffer = buffer->get().igbp_buffer; 251 const auto& igbp_buffer = buffer->get().igbp_buffer;
244 252
253 if (!system.IsPoweredOn()) {
254 return; // We are likely shutting down
255 }
256
245 auto& gpu = system.GPU(); 257 auto& gpu = system.GPU();
246 const auto& multi_fence = buffer->get().multi_fence; 258 const auto& multi_fence = buffer->get().multi_fence;
247 guard->unlock(); 259 guard->unlock();
diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h
index 1ebe949c0..c6765259f 100644
--- a/src/core/hle/service/nvflinger/nvflinger.h
+++ b/src/core/hle/service/nvflinger/nvflinger.h
@@ -75,10 +75,7 @@ public:
75 [[nodiscard]] std::shared_ptr<Kernel::ReadableEvent> FindVsyncEvent(u64 display_id) const; 75 [[nodiscard]] std::shared_ptr<Kernel::ReadableEvent> FindVsyncEvent(u64 display_id) const;
76 76
77 /// Obtains a buffer queue identified by the ID. 77 /// Obtains a buffer queue identified by the ID.
78 [[nodiscard]] BufferQueue& FindBufferQueue(u32 id); 78 [[nodiscard]] BufferQueue* FindBufferQueue(u32 id);
79
80 /// Obtains a buffer queue identified by the ID.
81 [[nodiscard]] const BufferQueue& FindBufferQueue(u32 id) const;
82 79
83 /// Performs a composition request to the emulated nvidia GPU and triggers the vsync events when 80 /// Performs a composition request to the emulated nvidia GPU and triggers the vsync events when
84 /// finished. 81 /// finished.
@@ -86,11 +83,11 @@ public:
86 83
87 [[nodiscard]] s64 GetNextTicks() const; 84 [[nodiscard]] s64 GetNextTicks() const;
88 85
86private:
89 [[nodiscard]] std::unique_lock<std::mutex> Lock() const { 87 [[nodiscard]] std::unique_lock<std::mutex> Lock() const {
90 return std::unique_lock{*guard}; 88 return std::unique_lock{*guard};
91 } 89 }
92 90
93private:
94 /// Finds the display identified by the specified ID. 91 /// Finds the display identified by the specified ID.
95 [[nodiscard]] VI::Display* FindDisplay(u64 display_id); 92 [[nodiscard]] VI::Display* FindDisplay(u64 display_id);
96 93
@@ -110,7 +107,7 @@ private:
110 std::shared_ptr<Nvidia::Module> nvdrv; 107 std::shared_ptr<Nvidia::Module> nvdrv;
111 108
112 std::vector<VI::Display> displays; 109 std::vector<VI::Display> displays;
113 std::vector<BufferQueue> buffer_queues; 110 std::vector<std::unique_ptr<BufferQueue>> buffer_queues;
114 111
115 /// Id to use for the next layer that is created, this counter is shared among all displays. 112 /// Id to use for the next layer that is created, this counter is shared among all displays.
116 u64 next_layer_id = 1; 113 u64 next_layer_id = 1;
diff --git a/src/core/hle/service/olsc/olsc.cpp b/src/core/hle/service/olsc/olsc.cpp
new file mode 100644
index 000000000..4440135ed
--- /dev/null
+++ b/src/core/hle/service/olsc/olsc.cpp
@@ -0,0 +1,69 @@
1// Copyright 2020 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "core/hle/ipc_helpers.h"
6#include "core/hle/kernel/hle_ipc.h"
7#include "core/hle/service/olsc/olsc.h"
8#include "core/hle/service/service.h"
9#include "core/hle/service/sm/sm.h"
10
11namespace Service::OLSC {
12
13class OLSC final : public ServiceFramework<OLSC> {
14public:
15 explicit OLSC(Core::System& system_) : ServiceFramework{system_, "olsc:u"} {
16 // clang-format off
17 static const FunctionInfo functions[] = {
18 {0, &OLSC::Initialize, "Initialize"},
19 {10, nullptr, "VerifySaveDataBackupLicenseAsync"},
20 {13, nullptr, "GetSaveDataBackupSetting"},
21 {14, &OLSC::SetSaveDataBackupSettingEnabled, "SetSaveDataBackupSettingEnabled"},
22 {15, nullptr, "SetCustomData"},
23 {16, nullptr, "DeleteSaveDataBackupSetting"},
24 {18, nullptr, "GetSaveDataBackupInfoCache"},
25 {19, nullptr, "UpdateSaveDataBackupInfoCacheAsync"},
26 {22, nullptr, "DeleteSaveDataBackupAsync"},
27 {25, nullptr, "ListDownloadableSaveDataBackupInfoAsync"},
28 {26, nullptr, "DownloadSaveDataBackupAsync"},
29 {9010, nullptr, "VerifySaveDataBackupLicenseAsyncForDebug"},
30 {9013, nullptr, "GetSaveDataBackupSettingForDebug"},
31 {9014, nullptr, "SetSaveDataBackupSettingEnabledForDebug"},
32 {9015, nullptr, "SetCustomDataForDebug"},
33 {9016, nullptr, "DeleteSaveDataBackupSettingForDebug"},
34 {9018, nullptr, "GetSaveDataBackupInfoCacheForDebug"},
35 {9019, nullptr, "UpdateSaveDataBackupInfoCacheAsyncForDebug"},
36 {9022, nullptr, "DeleteSaveDataBackupAsyncForDebug"},
37 {9025, nullptr, "ListDownloadableSaveDataBackupInfoAsyncForDebug"},
38 {9026, nullptr, "DownloadSaveDataBackupAsyncForDebug"},
39 };
40 // clang-format on
41
42 RegisterHandlers(functions);
43 }
44
45private:
46 void Initialize(Kernel::HLERequestContext& ctx) {
47 LOG_WARNING(Service_OLSC, "(STUBBED) called");
48
49 initialized = true;
50
51 IPC::ResponseBuilder rb{ctx, 2};
52 rb.Push(RESULT_SUCCESS);
53 }
54
55 void SetSaveDataBackupSettingEnabled(Kernel::HLERequestContext& ctx) {
56 LOG_WARNING(Service_OLSC, "(STUBBED) called");
57
58 IPC::ResponseBuilder rb{ctx, 2};
59 rb.Push(RESULT_SUCCESS);
60 }
61
62 bool initialized{};
63};
64
65void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
66 std::make_shared<OLSC>(system)->InstallAsService(service_manager);
67}
68
69} // namespace Service::OLSC
diff --git a/src/core/hle/service/olsc/olsc.h b/src/core/hle/service/olsc/olsc.h
new file mode 100644
index 000000000..24f24ca6b
--- /dev/null
+++ b/src/core/hle/service/olsc/olsc.h
@@ -0,0 +1,20 @@
1// Copyright 2020 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7namespace Core {
8class System;
9}
10
11namespace Service::SM {
12class ServiceManager;
13}
14
15namespace Service::OLSC {
16
17/// Registers all SSL services with the specified service manager.
18void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system);
19
20} // namespace Service::OLSC
diff --git a/src/core/hle/service/pcie/pcie.cpp b/src/core/hle/service/pcie/pcie.cpp
index c568a0adc..f6686fc4d 100644
--- a/src/core/hle/service/pcie/pcie.cpp
+++ b/src/core/hle/service/pcie/pcie.cpp
@@ -12,7 +12,7 @@ namespace Service::PCIe {
12 12
13class ISession final : public ServiceFramework<ISession> { 13class ISession final : public ServiceFramework<ISession> {
14public: 14public:
15 explicit ISession() : ServiceFramework{"ISession"} { 15 explicit ISession(Core::System& system_) : ServiceFramework{system_, "ISession"} {
16 // clang-format off 16 // clang-format off
17 static const FunctionInfo functions[] = { 17 static const FunctionInfo functions[] = {
18 {0, nullptr, "QueryFunctions"}, 18 {0, nullptr, "QueryFunctions"},
@@ -48,7 +48,7 @@ public:
48 48
49class PCIe final : public ServiceFramework<PCIe> { 49class PCIe final : public ServiceFramework<PCIe> {
50public: 50public:
51 explicit PCIe() : ServiceFramework{"pcie"} { 51 explicit PCIe(Core::System& system_) : ServiceFramework{system_, "pcie"} {
52 // clang-format off 52 // clang-format off
53 static const FunctionInfo functions[] = { 53 static const FunctionInfo functions[] = {
54 {0, nullptr, "RegisterClassDriver"}, 54 {0, nullptr, "RegisterClassDriver"},
@@ -60,8 +60,8 @@ public:
60 } 60 }
61}; 61};
62 62
63void InstallInterfaces(SM::ServiceManager& sm) { 63void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
64 std::make_shared<PCIe>()->InstallAsService(sm); 64 std::make_shared<PCIe>(system)->InstallAsService(sm);
65} 65}
66 66
67} // namespace Service::PCIe 67} // namespace Service::PCIe
diff --git a/src/core/hle/service/pcie/pcie.h b/src/core/hle/service/pcie/pcie.h
index 59c22ca45..e5709a72f 100644
--- a/src/core/hle/service/pcie/pcie.h
+++ b/src/core/hle/service/pcie/pcie.h
@@ -4,12 +4,16 @@
4 4
5#pragma once 5#pragma once
6 6
7namespace Core {
8class System;
9}
10
7namespace Service::SM { 11namespace Service::SM {
8class ServiceManager; 12class ServiceManager;
9} 13}
10 14
11namespace Service::PCIe { 15namespace Service::PCIe {
12 16
13void InstallInterfaces(SM::ServiceManager& sm); 17void InstallInterfaces(SM::ServiceManager& sm, Core::System& system);
14 18
15} // namespace Service::PCIe 19} // namespace Service::PCIe
diff --git a/src/core/hle/service/pctl/module.cpp b/src/core/hle/service/pctl/module.cpp
index caf14ed61..6ab1e4124 100644
--- a/src/core/hle/service/pctl/module.cpp
+++ b/src/core/hle/service/pctl/module.cpp
@@ -11,7 +11,8 @@ namespace Service::PCTL {
11 11
12class IParentalControlService final : public ServiceFramework<IParentalControlService> { 12class IParentalControlService final : public ServiceFramework<IParentalControlService> {
13public: 13public:
14 IParentalControlService() : ServiceFramework("IParentalControlService") { 14 explicit IParentalControlService(Core::System& system_)
15 : ServiceFramework{system_, "IParentalControlService"} {
15 // clang-format off 16 // clang-format off
16 static const FunctionInfo functions[] = { 17 static const FunctionInfo functions[] = {
17 {1, &IParentalControlService::Initialize, "Initialize"}, 18 {1, &IParentalControlService::Initialize, "Initialize"},
@@ -137,7 +138,7 @@ void Module::Interface::CreateService(Kernel::HLERequestContext& ctx) {
137 138
138 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 139 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
139 rb.Push(RESULT_SUCCESS); 140 rb.Push(RESULT_SUCCESS);
140 rb.PushIpcInterface<IParentalControlService>(); 141 rb.PushIpcInterface<IParentalControlService>(system);
141} 142}
142 143
143void Module::Interface::CreateServiceWithoutInitialize(Kernel::HLERequestContext& ctx) { 144void Module::Interface::CreateServiceWithoutInitialize(Kernel::HLERequestContext& ctx) {
@@ -145,20 +146,20 @@ void Module::Interface::CreateServiceWithoutInitialize(Kernel::HLERequestContext
145 146
146 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 147 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
147 rb.Push(RESULT_SUCCESS); 148 rb.Push(RESULT_SUCCESS);
148 rb.PushIpcInterface<IParentalControlService>(); 149 rb.PushIpcInterface<IParentalControlService>(system);
149} 150}
150 151
151Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) 152Module::Interface::Interface(Core::System& system_, std::shared_ptr<Module> module_, const char* name)
152 : ServiceFramework(name), module(std::move(module)) {} 153 : ServiceFramework{system_, name}, module{std::move(module_)} {}
153 154
154Module::Interface::~Interface() = default; 155Module::Interface::~Interface() = default;
155 156
156void InstallInterfaces(SM::ServiceManager& service_manager) { 157void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
157 auto module = std::make_shared<Module>(); 158 auto module = std::make_shared<Module>();
158 std::make_shared<PCTL>(module, "pctl")->InstallAsService(service_manager); 159 std::make_shared<PCTL>(system, module, "pctl")->InstallAsService(service_manager);
159 std::make_shared<PCTL>(module, "pctl:a")->InstallAsService(service_manager); 160 std::make_shared<PCTL>(system, module, "pctl:a")->InstallAsService(service_manager);
160 std::make_shared<PCTL>(module, "pctl:r")->InstallAsService(service_manager); 161 std::make_shared<PCTL>(system, module, "pctl:r")->InstallAsService(service_manager);
161 std::make_shared<PCTL>(module, "pctl:s")->InstallAsService(service_manager); 162 std::make_shared<PCTL>(system, module, "pctl:s")->InstallAsService(service_manager);
162} 163}
163 164
164} // namespace Service::PCTL 165} // namespace Service::PCTL
diff --git a/src/core/hle/service/pctl/module.h b/src/core/hle/service/pctl/module.h
index 3e449110d..4c7e09a3b 100644
--- a/src/core/hle/service/pctl/module.h
+++ b/src/core/hle/service/pctl/module.h
@@ -6,13 +6,18 @@
6 6
7#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
8 8
9namespace Core {
10class System;
11}
12
9namespace Service::PCTL { 13namespace Service::PCTL {
10 14
11class Module final { 15class Module final {
12public: 16public:
13 class Interface : public ServiceFramework<Interface> { 17 class Interface : public ServiceFramework<Interface> {
14 public: 18 public:
15 explicit Interface(std::shared_ptr<Module> module, const char* name); 19 explicit Interface(Core::System& system_, std::shared_ptr<Module> module_,
20 const char* name);
16 ~Interface() override; 21 ~Interface() override;
17 22
18 void CreateService(Kernel::HLERequestContext& ctx); 23 void CreateService(Kernel::HLERequestContext& ctx);
@@ -24,6 +29,6 @@ public:
24}; 29};
25 30
26/// Registers all PCTL services with the specified service manager. 31/// Registers all PCTL services with the specified service manager.
27void InstallInterfaces(SM::ServiceManager& service_manager); 32void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system);
28 33
29} // namespace Service::PCTL 34} // namespace Service::PCTL
diff --git a/src/core/hle/service/pctl/pctl.cpp b/src/core/hle/service/pctl/pctl.cpp
index af9d1433a..16dd34f90 100644
--- a/src/core/hle/service/pctl/pctl.cpp
+++ b/src/core/hle/service/pctl/pctl.cpp
@@ -6,8 +6,8 @@
6 6
7namespace Service::PCTL { 7namespace Service::PCTL {
8 8
9PCTL::PCTL(std::shared_ptr<Module> module, const char* name) 9PCTL::PCTL(Core::System& system_, std::shared_ptr<Module> module_, const char* name)
10 : Module::Interface(std::move(module), name) { 10 : Interface{system_, std::move(module_), name} {
11 static const FunctionInfo functions[] = { 11 static const FunctionInfo functions[] = {
12 {0, &PCTL::CreateService, "CreateService"}, 12 {0, &PCTL::CreateService, "CreateService"},
13 {1, &PCTL::CreateServiceWithoutInitialize, "CreateServiceWithoutInitialize"}, 13 {1, &PCTL::CreateServiceWithoutInitialize, "CreateServiceWithoutInitialize"},
diff --git a/src/core/hle/service/pctl/pctl.h b/src/core/hle/service/pctl/pctl.h
index c33ea80b6..275d23007 100644
--- a/src/core/hle/service/pctl/pctl.h
+++ b/src/core/hle/service/pctl/pctl.h
@@ -6,11 +6,15 @@
6 6
7#include "core/hle/service/pctl/module.h" 7#include "core/hle/service/pctl/module.h"
8 8
9namespace Core {
10class System;
11}
12
9namespace Service::PCTL { 13namespace Service::PCTL {
10 14
11class PCTL final : public Module::Interface { 15class PCTL final : public Module::Interface {
12public: 16public:
13 explicit PCTL(std::shared_ptr<Module> module, const char* name); 17 explicit PCTL(Core::System& system_, std::shared_ptr<Module> module_, const char* name);
14 ~PCTL() override; 18 ~PCTL() override;
15}; 19};
16 20
diff --git a/src/core/hle/service/pcv/pcv.cpp b/src/core/hle/service/pcv/pcv.cpp
index 8bfc0276e..68b2c4178 100644
--- a/src/core/hle/service/pcv/pcv.cpp
+++ b/src/core/hle/service/pcv/pcv.cpp
@@ -12,7 +12,7 @@ namespace Service::PCV {
12 12
13class PCV final : public ServiceFramework<PCV> { 13class PCV final : public ServiceFramework<PCV> {
14public: 14public:
15 explicit PCV() : ServiceFramework{"pcv"} { 15 explicit PCV(Core::System& system_) : ServiceFramework{system_, "pcv"} {
16 // clang-format off 16 // clang-format off
17 static const FunctionInfo functions[] = { 17 static const FunctionInfo functions[] = {
18 {0, nullptr, "SetPowerEnabled"}, 18 {0, nullptr, "SetPowerEnabled"},
@@ -54,7 +54,7 @@ public:
54 54
55class PCV_ARB final : public ServiceFramework<PCV_ARB> { 55class PCV_ARB final : public ServiceFramework<PCV_ARB> {
56public: 56public:
57 explicit PCV_ARB() : ServiceFramework{"pcv:arb"} { 57 explicit PCV_ARB(Core::System& system_) : ServiceFramework{system_, "pcv:arb"} {
58 // clang-format off 58 // clang-format off
59 static const FunctionInfo functions[] = { 59 static const FunctionInfo functions[] = {
60 {0, nullptr, "ReleaseControl"}, 60 {0, nullptr, "ReleaseControl"},
@@ -67,7 +67,7 @@ public:
67 67
68class PCV_IMM final : public ServiceFramework<PCV_IMM> { 68class PCV_IMM final : public ServiceFramework<PCV_IMM> {
69public: 69public:
70 explicit PCV_IMM() : ServiceFramework{"pcv:imm"} { 70 explicit PCV_IMM(Core::System& system_) : ServiceFramework{system_, "pcv:imm"} {
71 // clang-format off 71 // clang-format off
72 static const FunctionInfo functions[] = { 72 static const FunctionInfo functions[] = {
73 {0, nullptr, "SetClockRate"}, 73 {0, nullptr, "SetClockRate"},
@@ -78,10 +78,10 @@ public:
78 } 78 }
79}; 79};
80 80
81void InstallInterfaces(SM::ServiceManager& sm) { 81void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
82 std::make_shared<PCV>()->InstallAsService(sm); 82 std::make_shared<PCV>(system)->InstallAsService(sm);
83 std::make_shared<PCV_ARB>()->InstallAsService(sm); 83 std::make_shared<PCV_ARB>(system)->InstallAsService(sm);
84 std::make_shared<PCV_IMM>()->InstallAsService(sm); 84 std::make_shared<PCV_IMM>(system)->InstallAsService(sm);
85} 85}
86 86
87} // namespace Service::PCV 87} // namespace Service::PCV
diff --git a/src/core/hle/service/pcv/pcv.h b/src/core/hle/service/pcv/pcv.h
index 219a893c3..c61a0b591 100644
--- a/src/core/hle/service/pcv/pcv.h
+++ b/src/core/hle/service/pcv/pcv.h
@@ -4,12 +4,16 @@
4 4
5#pragma once 5#pragma once
6 6
7namespace Core {
8class System;
9}
10
7namespace Service::SM { 11namespace Service::SM {
8class ServiceManager; 12class ServiceManager;
9} 13}
10 14
11namespace Service::PCV { 15namespace Service::PCV {
12 16
13void InstallInterfaces(SM::ServiceManager& sm); 17void InstallInterfaces(SM::ServiceManager& sm, Core::System& system);
14 18
15} // namespace Service::PCV 19} // namespace Service::PCV
diff --git a/src/core/hle/service/pm/pm.cpp b/src/core/hle/service/pm/pm.cpp
index f43122ad2..68736c40c 100644
--- a/src/core/hle/service/pm/pm.cpp
+++ b/src/core/hle/service/pm/pm.cpp
@@ -2,6 +2,7 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "core/core.h"
5#include "core/hle/ipc_helpers.h" 6#include "core/hle/ipc_helpers.h"
6#include "core/hle/kernel/kernel.h" 7#include "core/hle/kernel/kernel.h"
7#include "core/hle/kernel/process.h" 8#include "core/hle/kernel/process.h"
@@ -43,7 +44,7 @@ void GetApplicationPidGeneric(Kernel::HLERequestContext& ctx,
43 44
44class BootMode final : public ServiceFramework<BootMode> { 45class BootMode final : public ServiceFramework<BootMode> {
45public: 46public:
46 explicit BootMode() : ServiceFramework{"pm:bm"} { 47 explicit BootMode(Core::System& system_) : ServiceFramework{system_, "pm:bm"} {
47 static const FunctionInfo functions[] = { 48 static const FunctionInfo functions[] = {
48 {0, &BootMode::GetBootMode, "GetBootMode"}, 49 {0, &BootMode::GetBootMode, "GetBootMode"},
49 {1, &BootMode::SetMaintenanceBoot, "SetMaintenanceBoot"}, 50 {1, &BootMode::SetMaintenanceBoot, "SetMaintenanceBoot"},
@@ -74,8 +75,8 @@ private:
74 75
75class DebugMonitor final : public ServiceFramework<DebugMonitor> { 76class DebugMonitor final : public ServiceFramework<DebugMonitor> {
76public: 77public:
77 explicit DebugMonitor(const Kernel::KernelCore& kernel) 78 explicit DebugMonitor(Core::System& system_)
78 : ServiceFramework{"pm:dmnt"}, kernel(kernel) { 79 : ServiceFramework{system_, "pm:dmnt"}, kernel{system_.Kernel()} {
79 // clang-format off 80 // clang-format off
80 static const FunctionInfo functions[] = { 81 static const FunctionInfo functions[] = {
81 {0, nullptr, "GetJitDebugProcessIdList"}, 82 {0, nullptr, "GetJitDebugProcessIdList"},
@@ -124,8 +125,9 @@ private:
124 125
125class Info final : public ServiceFramework<Info> { 126class Info final : public ServiceFramework<Info> {
126public: 127public:
127 explicit Info(const std::vector<std::shared_ptr<Kernel::Process>>& process_list) 128 explicit Info(Core::System& system_,
128 : ServiceFramework{"pm:info"}, process_list(process_list) { 129 const std::vector<std::shared_ptr<Kernel::Process>>& process_list_)
130 : ServiceFramework{system_, "pm:info"}, process_list{process_list_} {
129 static const FunctionInfo functions[] = { 131 static const FunctionInfo functions[] = {
130 {0, &Info::GetTitleId, "GetTitleId"}, 132 {0, &Info::GetTitleId, "GetTitleId"},
131 }; 133 };
@@ -159,8 +161,8 @@ private:
159 161
160class Shell final : public ServiceFramework<Shell> { 162class Shell final : public ServiceFramework<Shell> {
161public: 163public:
162 explicit Shell(const Kernel::KernelCore& kernel) 164 explicit Shell(Core::System& system_)
163 : ServiceFramework{"pm:shell"}, kernel(kernel) { 165 : ServiceFramework{system_, "pm:shell"}, kernel{system_.Kernel()} {
164 // clang-format off 166 // clang-format off
165 static const FunctionInfo functions[] = { 167 static const FunctionInfo functions[] = {
166 {0, nullptr, "LaunchProgram"}, 168 {0, nullptr, "LaunchProgram"},
@@ -189,11 +191,11 @@ private:
189}; 191};
190 192
191void InstallInterfaces(Core::System& system) { 193void InstallInterfaces(Core::System& system) {
192 std::make_shared<BootMode>()->InstallAsService(system.ServiceManager()); 194 std::make_shared<BootMode>(system)->InstallAsService(system.ServiceManager());
193 std::make_shared<DebugMonitor>(system.Kernel())->InstallAsService(system.ServiceManager()); 195 std::make_shared<DebugMonitor>(system)->InstallAsService(system.ServiceManager());
194 std::make_shared<Info>(system.Kernel().GetProcessList()) 196 std::make_shared<Info>(system, system.Kernel().GetProcessList())
195 ->InstallAsService(system.ServiceManager()); 197 ->InstallAsService(system.ServiceManager());
196 std::make_shared<Shell>(system.Kernel())->InstallAsService(system.ServiceManager()); 198 std::make_shared<Shell>(system)->InstallAsService(system.ServiceManager());
197} 199}
198 200
199} // namespace Service::PM 201} // namespace Service::PM
diff --git a/src/core/hle/service/prepo/prepo.cpp b/src/core/hle/service/prepo/prepo.cpp
index cde3312da..b417624c9 100644
--- a/src/core/hle/service/prepo/prepo.cpp
+++ b/src/core/hle/service/prepo/prepo.cpp
@@ -4,6 +4,7 @@
4 4
5#include "common/hex_util.h" 5#include "common/hex_util.h"
6#include "common/logging/log.h" 6#include "common/logging/log.h"
7#include "core/core.h"
7#include "core/hle/ipc_helpers.h" 8#include "core/hle/ipc_helpers.h"
8#include "core/hle/kernel/process.h" 9#include "core/hle/kernel/process.h"
9#include "core/hle/service/acc/profile_manager.h" 10#include "core/hle/service/acc/profile_manager.h"
@@ -15,8 +16,7 @@ namespace Service::PlayReport {
15 16
16class PlayReport final : public ServiceFramework<PlayReport> { 17class PlayReport final : public ServiceFramework<PlayReport> {
17public: 18public:
18 explicit PlayReport(const char* name, Core::System& system) 19 explicit PlayReport(const char* name, Core::System& system_) : ServiceFramework{system_, name} {
19 : ServiceFramework{name}, system(system) {
20 // clang-format off 20 // clang-format off
21 static const FunctionInfo functions[] = { 21 static const FunctionInfo functions[] = {
22 {10100, &PlayReport::SaveReport<Core::Reporter::PlayReportType::Old>, "SaveReportOld"}, 22 {10100, &PlayReport::SaveReport<Core::Reporter::PlayReportType::Old>, "SaveReportOld"},
@@ -65,7 +65,7 @@ private:
65 } 65 }
66 66
67 LOG_DEBUG(Service_PREPO, "called, type={:02X}, process_id={:016X}, data1_size={:016X}", 67 LOG_DEBUG(Service_PREPO, "called, type={:02X}, process_id={:016X}, data1_size={:016X}",
68 static_cast<u8>(Type), process_id, data[0].size()); 68 Type, process_id, data[0].size());
69 69
70 const auto& reporter{system.GetReporter()}; 70 const auto& reporter{system.GetReporter()};
71 reporter.SavePlayReport(Type, system.CurrentProcess()->GetTitleID(), data, process_id); 71 reporter.SavePlayReport(Type, system.CurrentProcess()->GetTitleID(), data, process_id);
@@ -92,7 +92,7 @@ private:
92 LOG_DEBUG( 92 LOG_DEBUG(
93 Service_PREPO, 93 Service_PREPO,
94 "called, type={:02X}, user_id={:016X}{:016X}, process_id={:016X}, data1_size={:016X}", 94 "called, type={:02X}, user_id={:016X}{:016X}, process_id={:016X}, data1_size={:016X}",
95 static_cast<u8>(Type), user_id[1], user_id[0], process_id, data[0].size()); 95 Type, user_id[1], user_id[0], process_id, data[0].size());
96 96
97 const auto& reporter{system.GetReporter()}; 97 const auto& reporter{system.GetReporter()};
98 reporter.SavePlayReport(Type, system.CurrentProcess()->GetTitleID(), data, process_id, 98 reporter.SavePlayReport(Type, system.CurrentProcess()->GetTitleID(), data, process_id,
@@ -139,8 +139,6 @@ private:
139 IPC::ResponseBuilder rb{ctx, 2}; 139 IPC::ResponseBuilder rb{ctx, 2};
140 rb.Push(RESULT_SUCCESS); 140 rb.Push(RESULT_SUCCESS);
141 } 141 }
142
143 Core::System& system;
144}; 142};
145 143
146void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { 144void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
diff --git a/src/core/hle/service/prepo/prepo.h b/src/core/hle/service/prepo/prepo.h
index a5682ee26..395b57ead 100644
--- a/src/core/hle/service/prepo/prepo.h
+++ b/src/core/hle/service/prepo/prepo.h
@@ -4,14 +4,14 @@
4 4
5#pragma once 5#pragma once
6 6
7namespace Service::SM {
8class ServiceManager;
9}
10
11namespace Core { 7namespace Core {
12class System; 8class System;
13} 9}
14 10
11namespace Service::SM {
12class ServiceManager;
13}
14
15namespace Service::PlayReport { 15namespace Service::PlayReport {
16 16
17void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system); 17void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system);
diff --git a/src/core/hle/service/psc/psc.cpp b/src/core/hle/service/psc/psc.cpp
index 99e1c9042..5a52b2b05 100644
--- a/src/core/hle/service/psc/psc.cpp
+++ b/src/core/hle/service/psc/psc.cpp
@@ -14,7 +14,7 @@ namespace Service::PSC {
14 14
15class PSC_C final : public ServiceFramework<PSC_C> { 15class PSC_C final : public ServiceFramework<PSC_C> {
16public: 16public:
17 explicit PSC_C() : ServiceFramework{"psc:c"} { 17 explicit PSC_C(Core::System& system_) : ServiceFramework{system_, "psc:c"} {
18 // clang-format off 18 // clang-format off
19 static const FunctionInfo functions[] = { 19 static const FunctionInfo functions[] = {
20 {0, nullptr, "Initialize"}, 20 {0, nullptr, "Initialize"},
@@ -35,7 +35,7 @@ public:
35 35
36class IPmModule final : public ServiceFramework<IPmModule> { 36class IPmModule final : public ServiceFramework<IPmModule> {
37public: 37public:
38 explicit IPmModule() : ServiceFramework{"IPmModule"} { 38 explicit IPmModule(Core::System& system_) : ServiceFramework{system_, "IPmModule"} {
39 // clang-format off 39 // clang-format off
40 static const FunctionInfo functions[] = { 40 static const FunctionInfo functions[] = {
41 {0, nullptr, "Initialize"}, 41 {0, nullptr, "Initialize"},
@@ -52,7 +52,7 @@ public:
52 52
53class PSC_M final : public ServiceFramework<PSC_M> { 53class PSC_M final : public ServiceFramework<PSC_M> {
54public: 54public:
55 explicit PSC_M() : ServiceFramework{"psc:m"} { 55 explicit PSC_M(Core::System& system_) : ServiceFramework{system_, "psc:m"} {
56 // clang-format off 56 // clang-format off
57 static const FunctionInfo functions[] = { 57 static const FunctionInfo functions[] = {
58 {0, &PSC_M::GetPmModule, "GetPmModule"}, 58 {0, &PSC_M::GetPmModule, "GetPmModule"},
@@ -68,13 +68,13 @@ private:
68 68
69 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 69 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
70 rb.Push(RESULT_SUCCESS); 70 rb.Push(RESULT_SUCCESS);
71 rb.PushIpcInterface<IPmModule>(); 71 rb.PushIpcInterface<IPmModule>(system);
72 } 72 }
73}; 73};
74 74
75void InstallInterfaces(SM::ServiceManager& sm) { 75void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
76 std::make_shared<PSC_C>()->InstallAsService(sm); 76 std::make_shared<PSC_C>(system)->InstallAsService(sm);
77 std::make_shared<PSC_M>()->InstallAsService(sm); 77 std::make_shared<PSC_M>(system)->InstallAsService(sm);
78} 78}
79 79
80} // namespace Service::PSC 80} // namespace Service::PSC
diff --git a/src/core/hle/service/psc/psc.h b/src/core/hle/service/psc/psc.h
index 5052eb02c..89344f32d 100644
--- a/src/core/hle/service/psc/psc.h
+++ b/src/core/hle/service/psc/psc.h
@@ -4,12 +4,16 @@
4 4
5#pragma once 5#pragma once
6 6
7namespace Core {
8class System;
9}
10
7namespace Service::SM { 11namespace Service::SM {
8class ServiceManager; 12class ServiceManager;
9} 13}
10 14
11namespace Service::PSC { 15namespace Service::PSC {
12 16
13void InstallInterfaces(SM::ServiceManager& sm); 17void InstallInterfaces(SM::ServiceManager& sm, Core::System& system);
14 18
15} // namespace Service::PSC 19} // namespace Service::PSC
diff --git a/src/core/hle/service/ptm/psm.cpp b/src/core/hle/service/ptm/psm.cpp
index 6d9e6bd09..b4b0dd241 100644
--- a/src/core/hle/service/ptm/psm.cpp
+++ b/src/core/hle/service/ptm/psm.cpp
@@ -14,7 +14,7 @@ namespace Service::PSM {
14 14
15class PSM final : public ServiceFramework<PSM> { 15class PSM final : public ServiceFramework<PSM> {
16public: 16public:
17 explicit PSM() : ServiceFramework{"psm"} { 17 explicit PSM(Core::System& system_) : ServiceFramework{system_, "psm"} {
18 // clang-format off 18 // clang-format off
19 static const FunctionInfo functions[] = { 19 static const FunctionInfo functions[] = {
20 {0, &PSM::GetBatteryChargePercentage, "GetBatteryChargePercentage"}, 20 {0, &PSM::GetBatteryChargePercentage, "GetBatteryChargePercentage"},
@@ -72,8 +72,8 @@ private:
72 ChargerType charger_type{ChargerType::RegularCharger}; 72 ChargerType charger_type{ChargerType::RegularCharger};
73}; 73};
74 74
75void InstallInterfaces(SM::ServiceManager& sm) { 75void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
76 std::make_shared<PSM>()->InstallAsService(sm); 76 std::make_shared<PSM>(system)->InstallAsService(sm);
77} 77}
78 78
79} // namespace Service::PSM 79} // namespace Service::PSM
diff --git a/src/core/hle/service/ptm/psm.h b/src/core/hle/service/ptm/psm.h
index a286793ae..2930ce26a 100644
--- a/src/core/hle/service/ptm/psm.h
+++ b/src/core/hle/service/ptm/psm.h
@@ -4,12 +4,16 @@
4 4
5#pragma once 5#pragma once
6 6
7namespace Core {
8class System;
9}
10
7namespace Service::SM { 11namespace Service::SM {
8class ServiceManager; 12class ServiceManager;
9} 13}
10 14
11namespace Service::PSM { 15namespace Service::PSM {
12 16
13void InstallInterfaces(SM::ServiceManager& sm); 17void InstallInterfaces(SM::ServiceManager& sm, Core::System& system);
14 18
15} // namespace Service::PSM 19} // namespace Service::PSM
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index 76b3533ec..ff2a5b1db 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -51,6 +51,7 @@
51#include "core/hle/service/ns/ns.h" 51#include "core/hle/service/ns/ns.h"
52#include "core/hle/service/nvdrv/nvdrv.h" 52#include "core/hle/service/nvdrv/nvdrv.h"
53#include "core/hle/service/nvflinger/nvflinger.h" 53#include "core/hle/service/nvflinger/nvflinger.h"
54#include "core/hle/service/olsc/olsc.h"
54#include "core/hle/service/pcie/pcie.h" 55#include "core/hle/service/pcie/pcie.h"
55#include "core/hle/service/pctl/module.h" 56#include "core/hle/service/pctl/module.h"
56#include "core/hle/service/pcv/pcv.h" 57#include "core/hle/service/pcv/pcv.h"
@@ -72,13 +73,36 @@
72 73
73namespace Service { 74namespace Service {
74 75
75ServiceFrameworkBase::ServiceFrameworkBase(const char* service_name, u32 max_sessions, 76/**
76 InvokerFn* handler_invoker) 77 * Creates a function string for logging, complete with the name (or header code, depending
77 : service_name(service_name), max_sessions(max_sessions), handler_invoker(handler_invoker) {} 78 * on what's passed in) the port name, and all the cmd_buff arguments.
79 */
80[[maybe_unused]] static std::string MakeFunctionString(std::string_view name,
81 std::string_view port_name,
82 const u32* cmd_buff) {
83 // Number of params == bits 0-5 + bits 6-11
84 int num_params = (cmd_buff[0] & 0x3F) + ((cmd_buff[0] >> 6) & 0x3F);
78 85
79ServiceFrameworkBase::~ServiceFrameworkBase() = default; 86 std::string function_string = fmt::format("function '{}': port={}", name, port_name);
87 for (int i = 1; i <= num_params; ++i) {
88 function_string += fmt::format(", cmd_buff[{}]=0x{:X}", i, cmd_buff[i]);
89 }
90 return function_string;
91}
92
93ServiceFrameworkBase::ServiceFrameworkBase(Core::System& system_, const char* service_name_,
94 u32 max_sessions_, InvokerFn* handler_invoker_)
95 : system{system_}, service_name{service_name_}, max_sessions{max_sessions_},
96 handler_invoker{handler_invoker_} {}
97
98ServiceFrameworkBase::~ServiceFrameworkBase() {
99 // Wait for other threads to release access before destroying
100 const auto guard = LockService();
101}
80 102
81void ServiceFrameworkBase::InstallAsService(SM::ServiceManager& service_manager) { 103void ServiceFrameworkBase::InstallAsService(SM::ServiceManager& service_manager) {
104 const auto guard = LockService();
105
82 ASSERT(!port_installed); 106 ASSERT(!port_installed);
83 107
84 auto port = service_manager.RegisterService(service_name, max_sessions).Unwrap(); 108 auto port = service_manager.RegisterService(service_name, max_sessions).Unwrap();
@@ -87,6 +111,8 @@ void ServiceFrameworkBase::InstallAsService(SM::ServiceManager& service_manager)
87} 111}
88 112
89void ServiceFrameworkBase::InstallAsNamedPort(Kernel::KernelCore& kernel) { 113void ServiceFrameworkBase::InstallAsNamedPort(Kernel::KernelCore& kernel) {
114 const auto guard = LockService();
115
90 ASSERT(!port_installed); 116 ASSERT(!port_installed);
91 117
92 auto [server_port, client_port] = 118 auto [server_port, client_port] =
@@ -96,17 +122,6 @@ void ServiceFrameworkBase::InstallAsNamedPort(Kernel::KernelCore& kernel) {
96 port_installed = true; 122 port_installed = true;
97} 123}
98 124
99std::shared_ptr<Kernel::ClientPort> ServiceFrameworkBase::CreatePort(Kernel::KernelCore& kernel) {
100 ASSERT(!port_installed);
101
102 auto [server_port, client_port] =
103 Kernel::ServerPort::CreatePortPair(kernel, max_sessions, service_name);
104 auto port = MakeResult(std::move(server_port)).Unwrap();
105 port->SetHleHandler(shared_from_this());
106 port_installed = true;
107 return client_port;
108}
109
110void ServiceFrameworkBase::RegisterHandlersBase(const FunctionInfoBase* functions, std::size_t n) { 125void ServiceFrameworkBase::RegisterHandlersBase(const FunctionInfoBase* functions, std::size_t n) {
111 handlers.reserve(handlers.size() + n); 126 handlers.reserve(handlers.size() + n);
112 for (std::size_t i = 0; i < n; ++i) { 127 for (std::size_t i = 0; i < n; ++i) {
@@ -128,8 +143,8 @@ void ServiceFrameworkBase::ReportUnimplementedFunction(Kernel::HLERequestContext
128 } 143 }
129 buf.push_back('}'); 144 buf.push_back('}');
130 145
131 Core::System::GetInstance().GetReporter().SaveUnimplementedFunctionReport( 146 system.GetReporter().SaveUnimplementedFunctionReport(ctx, ctx.GetCommand(), function_name,
132 ctx, ctx.GetCommand(), function_name, service_name); 147 service_name);
133 UNIMPLEMENTED_MSG("Unknown / unimplemented {}", fmt::to_string(buf)); 148 UNIMPLEMENTED_MSG("Unknown / unimplemented {}", fmt::to_string(buf));
134} 149}
135 150
@@ -145,6 +160,8 @@ void ServiceFrameworkBase::InvokeRequest(Kernel::HLERequestContext& ctx) {
145} 160}
146 161
147ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::HLERequestContext& context) { 162ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::HLERequestContext& context) {
163 const auto guard = LockService();
164
148 switch (context.GetCommandType()) { 165 switch (context.GetCommandType()) {
149 case IPC::CommandType::Close: { 166 case IPC::CommandType::Close: {
150 IPC::ResponseBuilder rb{context, 2}; 167 IPC::ResponseBuilder rb{context, 2};
@@ -153,7 +170,7 @@ ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::HLERequestContext& co
153 } 170 }
154 case IPC::CommandType::ControlWithContext: 171 case IPC::CommandType::ControlWithContext:
155 case IPC::CommandType::Control: { 172 case IPC::CommandType::Control: {
156 Core::System::GetInstance().ServiceManager().InvokeControlRequest(context); 173 system.ServiceManager().InvokeControlRequest(context);
157 break; 174 break;
158 } 175 }
159 case IPC::CommandType::RequestWithContext: 176 case IPC::CommandType::RequestWithContext:
@@ -162,79 +179,82 @@ ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::HLERequestContext& co
162 break; 179 break;
163 } 180 }
164 default: 181 default:
165 UNIMPLEMENTED_MSG("command_type={}", static_cast<int>(context.GetCommandType())); 182 UNIMPLEMENTED_MSG("command_type={}", context.GetCommandType());
166 } 183 }
167 184
168 context.WriteToOutgoingCommandBuffer(context.GetThread()); 185 // If emulation was shutdown, we are closing service threads, do not write the response back to
186 // memory that may be shutting down as well.
187 if (system.IsPoweredOn()) {
188 context.WriteToOutgoingCommandBuffer(context.GetThread());
189 }
169 190
170 return RESULT_SUCCESS; 191 return RESULT_SUCCESS;
171} 192}
172 193
173/// Initialize ServiceManager 194/// Initialize Services
174void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system) { 195Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system)
196 : nv_flinger{std::make_unique<NVFlinger::NVFlinger>(system)} {
197
175 // NVFlinger needs to be accessed by several services like Vi and AppletOE so we instantiate it 198 // NVFlinger needs to be accessed by several services like Vi and AppletOE so we instantiate it
176 // here and pass it into the respective InstallInterfaces functions. 199 // here and pass it into the respective InstallInterfaces functions.
177 auto nv_flinger = std::make_shared<NVFlinger::NVFlinger>(system); 200
178 system.GetFileSystemController().CreateFactories(*system.GetFilesystem(), false); 201 system.GetFileSystemController().CreateFactories(*system.GetFilesystem(), false);
179 202
180 SM::ServiceManager::InstallInterfaces(sm, system.Kernel()); 203 SM::ServiceManager::InstallInterfaces(sm, system);
181 204
182 Account::InstallInterfaces(system); 205 Account::InstallInterfaces(system);
183 AM::InstallInterfaces(*sm, nv_flinger, system); 206 AM::InstallInterfaces(*sm, *nv_flinger, system);
184 AOC::InstallInterfaces(*sm, system); 207 AOC::InstallInterfaces(*sm, system);
185 APM::InstallInterfaces(system); 208 APM::InstallInterfaces(system);
186 Audio::InstallInterfaces(*sm, system); 209 Audio::InstallInterfaces(*sm, system);
187 BCAT::InstallInterfaces(system); 210 BCAT::InstallInterfaces(system);
188 BPC::InstallInterfaces(*sm); 211 BPC::InstallInterfaces(*sm, system);
189 BtDrv::InstallInterfaces(*sm, system); 212 BtDrv::InstallInterfaces(*sm, system);
190 BTM::InstallInterfaces(*sm, system); 213 BTM::InstallInterfaces(*sm, system);
191 Capture::InstallInterfaces(*sm); 214 Capture::InstallInterfaces(*sm, system);
192 ERPT::InstallInterfaces(*sm); 215 ERPT::InstallInterfaces(*sm, system);
193 ES::InstallInterfaces(*sm); 216 ES::InstallInterfaces(*sm, system);
194 EUPLD::InstallInterfaces(*sm); 217 EUPLD::InstallInterfaces(*sm, system);
195 Fatal::InstallInterfaces(*sm, system); 218 Fatal::InstallInterfaces(*sm, system);
196 FGM::InstallInterfaces(*sm); 219 FGM::InstallInterfaces(*sm, system);
197 FileSystem::InstallInterfaces(system); 220 FileSystem::InstallInterfaces(system);
198 Friend::InstallInterfaces(*sm, system); 221 Friend::InstallInterfaces(*sm, system);
199 Glue::InstallInterfaces(system); 222 Glue::InstallInterfaces(system);
200 GRC::InstallInterfaces(*sm); 223 GRC::InstallInterfaces(*sm, system);
201 HID::InstallInterfaces(*sm, system); 224 HID::InstallInterfaces(*sm, system);
202 LBL::InstallInterfaces(*sm); 225 LBL::InstallInterfaces(*sm, system);
203 LDN::InstallInterfaces(*sm); 226 LDN::InstallInterfaces(*sm, system);
204 LDR::InstallInterfaces(*sm, system); 227 LDR::InstallInterfaces(*sm, system);
205 LM::InstallInterfaces(system); 228 LM::InstallInterfaces(system);
206 Migration::InstallInterfaces(*sm); 229 Migration::InstallInterfaces(*sm, system);
207 Mii::InstallInterfaces(*sm); 230 Mii::InstallInterfaces(*sm, system);
208 MM::InstallInterfaces(*sm); 231 MM::InstallInterfaces(*sm, system);
209 NCM::InstallInterfaces(*sm); 232 NCM::InstallInterfaces(*sm, system);
210 NFC::InstallInterfaces(*sm); 233 NFC::InstallInterfaces(*sm, system);
211 NFP::InstallInterfaces(*sm, system); 234 NFP::InstallInterfaces(*sm, system);
212 NIFM::InstallInterfaces(*sm, system); 235 NIFM::InstallInterfaces(*sm, system);
213 NIM::InstallInterfaces(*sm, system); 236 NIM::InstallInterfaces(*sm, system);
214 NPNS::InstallInterfaces(*sm); 237 NPNS::InstallInterfaces(*sm, system);
215 NS::InstallInterfaces(*sm, system); 238 NS::InstallInterfaces(*sm, system);
216 Nvidia::InstallInterfaces(*sm, *nv_flinger, system); 239 Nvidia::InstallInterfaces(*sm, *nv_flinger, system);
217 PCIe::InstallInterfaces(*sm); 240 OLSC::InstallInterfaces(*sm, system);
218 PCTL::InstallInterfaces(*sm); 241 PCIe::InstallInterfaces(*sm, system);
219 PCV::InstallInterfaces(*sm); 242 PCTL::InstallInterfaces(*sm, system);
243 PCV::InstallInterfaces(*sm, system);
220 PlayReport::InstallInterfaces(*sm, system); 244 PlayReport::InstallInterfaces(*sm, system);
221 PM::InstallInterfaces(system); 245 PM::InstallInterfaces(system);
222 PSC::InstallInterfaces(*sm); 246 PSC::InstallInterfaces(*sm, system);
223 PSM::InstallInterfaces(*sm); 247 PSM::InstallInterfaces(*sm, system);
224 Set::InstallInterfaces(*sm); 248 Set::InstallInterfaces(*sm, system);
225 Sockets::InstallInterfaces(*sm, system); 249 Sockets::InstallInterfaces(*sm, system);
226 SPL::InstallInterfaces(*sm); 250 SPL::InstallInterfaces(*sm, system);
227 SSL::InstallInterfaces(*sm); 251 SSL::InstallInterfaces(*sm, system);
228 Time::InstallInterfaces(system); 252 Time::InstallInterfaces(system);
229 USB::InstallInterfaces(*sm); 253 USB::InstallInterfaces(*sm, system);
230 VI::InstallInterfaces(*sm, nv_flinger); 254 VI::InstallInterfaces(*sm, system, *nv_flinger);
231 WLAN::InstallInterfaces(*sm); 255 WLAN::InstallInterfaces(*sm, system);
232
233 LOG_DEBUG(Service, "initialized OK");
234} 256}
235 257
236/// Shutdown ServiceManager 258Services::~Services() = default;
237void Shutdown() { 259
238 LOG_DEBUG(Service, "shutdown OK");
239}
240} // namespace Service 260} // namespace Service
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index a01ef3353..916445517 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -5,9 +5,11 @@
5#pragma once 5#pragma once
6 6
7#include <cstddef> 7#include <cstddef>
8#include <mutex>
8#include <string> 9#include <string>
9#include <boost/container/flat_map.hpp> 10#include <boost/container/flat_map.hpp>
10#include "common/common_types.h" 11#include "common/common_types.h"
12#include "common/spin_lock.h"
11#include "core/hle/kernel/hle_ipc.h" 13#include "core/hle/kernel/hle_ipc.h"
12#include "core/hle/kernel/object.h" 14#include "core/hle/kernel/object.h"
13 15
@@ -29,7 +31,11 @@ namespace Service {
29 31
30namespace FileSystem { 32namespace FileSystem {
31class FileSystemController; 33class FileSystemController;
32} // namespace FileSystem 34}
35
36namespace NVFlinger {
37class NVFlinger;
38}
33 39
34namespace SM { 40namespace SM {
35class ServiceManager; 41class ServiceManager;
@@ -64,11 +70,9 @@ public:
64 void InstallAsService(SM::ServiceManager& service_manager); 70 void InstallAsService(SM::ServiceManager& service_manager);
65 /// Creates a port pair and registers it on the kernel's global port registry. 71 /// Creates a port pair and registers it on the kernel's global port registry.
66 void InstallAsNamedPort(Kernel::KernelCore& kernel); 72 void InstallAsNamedPort(Kernel::KernelCore& kernel);
67 /// Creates and returns an unregistered port for the service. 73 /// Invokes a service request routine.
68 std::shared_ptr<Kernel::ClientPort> CreatePort(Kernel::KernelCore& kernel);
69
70 void InvokeRequest(Kernel::HLERequestContext& ctx); 74 void InvokeRequest(Kernel::HLERequestContext& ctx);
71 75 /// Handles a synchronization request for the service.
72 ResultCode HandleSyncRequest(Kernel::HLERequestContext& context) override; 76 ResultCode HandleSyncRequest(Kernel::HLERequestContext& context) override;
73 77
74protected: 78protected:
@@ -76,6 +80,14 @@ protected:
76 template <typename Self> 80 template <typename Self>
77 using HandlerFnP = void (Self::*)(Kernel::HLERequestContext&); 81 using HandlerFnP = void (Self::*)(Kernel::HLERequestContext&);
78 82
83 /// Used to gain exclusive access to the service members, e.g. from CoreTiming thread.
84 [[nodiscard]] std::scoped_lock<Common::SpinLock> LockService() {
85 return std::scoped_lock{lock_service};
86 }
87
88 /// System context that the service operates under.
89 Core::System& system;
90
79private: 91private:
80 template <typename T> 92 template <typename T>
81 friend class ServiceFramework; 93 friend class ServiceFramework;
@@ -89,7 +101,8 @@ private:
89 using InvokerFn = void(ServiceFrameworkBase* object, HandlerFnP<ServiceFrameworkBase> member, 101 using InvokerFn = void(ServiceFrameworkBase* object, HandlerFnP<ServiceFrameworkBase> member,
90 Kernel::HLERequestContext& ctx); 102 Kernel::HLERequestContext& ctx);
91 103
92 ServiceFrameworkBase(const char* service_name, u32 max_sessions, InvokerFn* handler_invoker); 104 explicit ServiceFrameworkBase(Core::System& system_, const char* service_name_,
105 u32 max_sessions_, InvokerFn* handler_invoker_);
93 ~ServiceFrameworkBase() override; 106 ~ServiceFrameworkBase() override;
94 107
95 void RegisterHandlersBase(const FunctionInfoBase* functions, std::size_t n); 108 void RegisterHandlersBase(const FunctionInfoBase* functions, std::size_t n);
@@ -107,6 +120,9 @@ private:
107 /// Function used to safely up-cast pointers to the derived class before invoking a handler. 120 /// Function used to safely up-cast pointers to the derived class before invoking a handler.
108 InvokerFn* handler_invoker; 121 InvokerFn* handler_invoker;
109 boost::container::flat_map<u32, FunctionInfoBase> handlers; 122 boost::container::flat_map<u32, FunctionInfoBase> handlers;
123
124 /// Used to gain exclusive access to the service members, e.g. from CoreTiming thread.
125 Common::SpinLock lock_service;
110}; 126};
111 127
112/** 128/**
@@ -147,11 +163,15 @@ protected:
147 163
148 /** 164 /**
149 * Initializes the handler with no functions installed. 165 * Initializes the handler with no functions installed.
150 * @param max_sessions Maximum number of sessions that can be 166 *
151 * connected to this service at the same time. 167 * @param system_ The system context to construct this service under.
168 * @param service_name_ Name of the service.
169 * @param max_sessions_ Maximum number of sessions that can be
170 * connected to this service at the same time.
152 */ 171 */
153 explicit ServiceFramework(const char* service_name, u32 max_sessions = DefaultMaxSessions) 172 explicit ServiceFramework(Core::System& system_, const char* service_name_,
154 : ServiceFrameworkBase(service_name, max_sessions, Invoker) {} 173 u32 max_sessions_ = DefaultMaxSessions)
174 : ServiceFrameworkBase(system_, service_name_, max_sessions_, Invoker) {}
155 175
156 /// Registers handlers in the service. 176 /// Registers handlers in the service.
157 template <std::size_t N> 177 template <std::size_t N>
@@ -181,10 +201,17 @@ private:
181 } 201 }
182}; 202};
183 203
184/// Initialize ServiceManager 204/**
185void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system); 205 * The purpose of this class is to own any objects that need to be shared across the other service
206 * implementations. Will be torn down when the global system instance is shutdown.
207 */
208class Services final {
209public:
210 explicit Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system);
211 ~Services();
186 212
187/// Shutdown ServiceManager 213private:
188void Shutdown(); 214 std::unique_ptr<NVFlinger::NVFlinger> nv_flinger;
215};
189 216
190} // namespace Service 217} // namespace Service
diff --git a/src/core/hle/service/set/set.cpp b/src/core/hle/service/set/set.cpp
index e64777668..d953b4303 100644
--- a/src/core/hle/service/set/set.cpp
+++ b/src/core/hle/service/set/set.cpp
@@ -188,7 +188,7 @@ void SET::GetKeyCodeMap2(Kernel::HLERequestContext& ctx) {
188 GetKeyCodeMapImpl(ctx); 188 GetKeyCodeMapImpl(ctx);
189} 189}
190 190
191SET::SET() : ServiceFramework("set") { 191SET::SET(Core::System& system_) : ServiceFramework{system_, "set"} {
192 // clang-format off 192 // clang-format off
193 static const FunctionInfo functions[] = { 193 static const FunctionInfo functions[] = {
194 {0, &SET::GetLanguageCode, "GetLanguageCode"}, 194 {0, &SET::GetLanguageCode, "GetLanguageCode"},
@@ -202,6 +202,7 @@ SET::SET() : ServiceFramework("set") {
202 {8, &SET::GetQuestFlag, "GetQuestFlag"}, 202 {8, &SET::GetQuestFlag, "GetQuestFlag"},
203 {9, &SET::GetKeyCodeMap2, "GetKeyCodeMap2"}, 203 {9, &SET::GetKeyCodeMap2, "GetKeyCodeMap2"},
204 {10, nullptr, "GetFirmwareVersionForDebug"}, 204 {10, nullptr, "GetFirmwareVersionForDebug"},
205 {11, nullptr, "GetDeviceNickName"},
205 }; 206 };
206 // clang-format on 207 // clang-format on
207 208
diff --git a/src/core/hle/service/set/set.h b/src/core/hle/service/set/set.h
index 8ac9c169d..d5bd7828d 100644
--- a/src/core/hle/service/set/set.h
+++ b/src/core/hle/service/set/set.h
@@ -6,6 +6,10 @@
6 6
7#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
8 8
9namespace Core {
10class System;
11}
12
9namespace Service::Set { 13namespace Service::Set {
10 14
11/// This is "nn::settings::LanguageCode", which is a NUL-terminated string stored in a u64. 15/// This is "nn::settings::LanguageCode", which is a NUL-terminated string stored in a u64.
@@ -32,7 +36,7 @@ LanguageCode GetLanguageCodeFromIndex(std::size_t idx);
32 36
33class SET final : public ServiceFramework<SET> { 37class SET final : public ServiceFramework<SET> {
34public: 38public:
35 explicit SET(); 39 explicit SET(Core::System& system_);
36 ~SET() override; 40 ~SET() override;
37 41
38private: 42private:
diff --git a/src/core/hle/service/set/set_cal.cpp b/src/core/hle/service/set/set_cal.cpp
index 3fbfecc9e..b2aa7bc0c 100644
--- a/src/core/hle/service/set/set_cal.cpp
+++ b/src/core/hle/service/set/set_cal.cpp
@@ -6,7 +6,7 @@
6 6
7namespace Service::Set { 7namespace Service::Set {
8 8
9SET_CAL::SET_CAL() : ServiceFramework("set:cal") { 9SET_CAL::SET_CAL(Core::System& system_) : ServiceFramework{system_, "set:cal"} {
10 // clang-format off 10 // clang-format off
11 static const FunctionInfo functions[] = { 11 static const FunctionInfo functions[] = {
12 {0, nullptr, "GetBluetoothBdAddress"}, 12 {0, nullptr, "GetBluetoothBdAddress"},
diff --git a/src/core/hle/service/set/set_cal.h b/src/core/hle/service/set/set_cal.h
index a0677e815..a29fc3ddd 100644
--- a/src/core/hle/service/set/set_cal.h
+++ b/src/core/hle/service/set/set_cal.h
@@ -6,11 +6,15 @@
6 6
7#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
8 8
9namespace Core {
10class System;
11}
12
9namespace Service::Set { 13namespace Service::Set {
10 14
11class SET_CAL final : public ServiceFramework<SET_CAL> { 15class SET_CAL final : public ServiceFramework<SET_CAL> {
12public: 16public:
13 explicit SET_CAL(); 17 explicit SET_CAL(Core::System& system_);
14 ~SET_CAL() override; 18 ~SET_CAL() override;
15}; 19};
16 20
diff --git a/src/core/hle/service/set/set_fd.cpp b/src/core/hle/service/set/set_fd.cpp
index 565882a31..f04dc5047 100644
--- a/src/core/hle/service/set/set_fd.cpp
+++ b/src/core/hle/service/set/set_fd.cpp
@@ -6,7 +6,7 @@
6 6
7namespace Service::Set { 7namespace Service::Set {
8 8
9SET_FD::SET_FD() : ServiceFramework("set:fd") { 9SET_FD::SET_FD(Core::System& system_) : ServiceFramework{system_, "set:fd"} {
10 // clang-format off 10 // clang-format off
11 static const FunctionInfo functions[] = { 11 static const FunctionInfo functions[] = {
12 {2, nullptr, "SetSettingsItemValue"}, 12 {2, nullptr, "SetSettingsItemValue"},
diff --git a/src/core/hle/service/set/set_fd.h b/src/core/hle/service/set/set_fd.h
index 216e65f1f..c28cb301e 100644
--- a/src/core/hle/service/set/set_fd.h
+++ b/src/core/hle/service/set/set_fd.h
@@ -6,11 +6,15 @@
6 6
7#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
8 8
9namespace Core {
10class System;
11}
12
9namespace Service::Set { 13namespace Service::Set {
10 14
11class SET_FD final : public ServiceFramework<SET_FD> { 15class SET_FD final : public ServiceFramework<SET_FD> {
12public: 16public:
13 explicit SET_FD(); 17 explicit SET_FD(Core::System& system_);
14 ~SET_FD() override; 18 ~SET_FD() override;
15}; 19};
16 20
diff --git a/src/core/hle/service/set/set_sys.cpp b/src/core/hle/service/set/set_sys.cpp
index 8bd4c7e79..b58b2c8c5 100644
--- a/src/core/hle/service/set/set_sys.cpp
+++ b/src/core/hle/service/set/set_sys.cpp
@@ -34,9 +34,9 @@ void GetFirmwareVersionImpl(Kernel::HLERequestContext& ctx, GetFirmwareVersionTy
34 // consistence (currently reports as 5.1.0-0.0) 34 // consistence (currently reports as 5.1.0-0.0)
35 const auto archive = FileSys::SystemArchive::SystemVersion(); 35 const auto archive = FileSys::SystemArchive::SystemVersion();
36 36
37 const auto early_exit_failure = [&ctx](const std::string& desc, ResultCode code) { 37 const auto early_exit_failure = [&ctx](std::string_view desc, ResultCode code) {
38 LOG_ERROR(Service_SET, "General failure while attempting to resolve firmware version ({}).", 38 LOG_ERROR(Service_SET, "General failure while attempting to resolve firmware version ({}).",
39 desc.c_str()); 39 desc);
40 IPC::ResponseBuilder rb{ctx, 2}; 40 IPC::ResponseBuilder rb{ctx, 2};
41 rb.Push(code); 41 rb.Push(code);
42 }; 42 };
@@ -103,7 +103,7 @@ void SET_SYS::SetColorSetId(Kernel::HLERequestContext& ctx) {
103 rb.Push(RESULT_SUCCESS); 103 rb.Push(RESULT_SUCCESS);
104} 104}
105 105
106SET_SYS::SET_SYS() : ServiceFramework("set:sys") { 106SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"} {
107 // clang-format off 107 // clang-format off
108 static const FunctionInfo functions[] = { 108 static const FunctionInfo functions[] = {
109 {0, nullptr, "SetLanguageCode"}, 109 {0, nullptr, "SetLanguageCode"},
@@ -300,6 +300,8 @@ SET_SYS::SET_SYS() : ServiceFramework("set:sys") {
300 {198, nullptr, "SetButtonConfigRegisteredSettingsEmbedded"}, 300 {198, nullptr, "SetButtonConfigRegisteredSettingsEmbedded"},
301 {199, nullptr, "GetButtonConfigRegisteredSettings"}, 301 {199, nullptr, "GetButtonConfigRegisteredSettings"},
302 {200, nullptr, "SetButtonConfigRegisteredSettings"}, 302 {200, nullptr, "SetButtonConfigRegisteredSettings"},
303 {201, nullptr, "GetFieldTestingFlag"},
304 {202, nullptr, "SetFieldTestingFlag"},
303 }; 305 };
304 // clang-format on 306 // clang-format on
305 307
diff --git a/src/core/hle/service/set/set_sys.h b/src/core/hle/service/set/set_sys.h
index 13ee2cf46..edb185a68 100644
--- a/src/core/hle/service/set/set_sys.h
+++ b/src/core/hle/service/set/set_sys.h
@@ -6,11 +6,15 @@
6 6
7#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
8 8
9namespace Core {
10class System;
11}
12
9namespace Service::Set { 13namespace Service::Set {
10 14
11class SET_SYS final : public ServiceFramework<SET_SYS> { 15class SET_SYS final : public ServiceFramework<SET_SYS> {
12public: 16public:
13 explicit SET_SYS(); 17 explicit SET_SYS(Core::System& system_);
14 ~SET_SYS() override; 18 ~SET_SYS() override;
15 19
16private: 20private:
diff --git a/src/core/hle/service/set/settings.cpp b/src/core/hle/service/set/settings.cpp
index cf5541ca8..212ebc427 100644
--- a/src/core/hle/service/set/settings.cpp
+++ b/src/core/hle/service/set/settings.cpp
@@ -7,14 +7,15 @@
7#include "core/hle/service/set/set_fd.h" 7#include "core/hle/service/set/set_fd.h"
8#include "core/hle/service/set/set_sys.h" 8#include "core/hle/service/set/set_sys.h"
9#include "core/hle/service/set/settings.h" 9#include "core/hle/service/set/settings.h"
10#include "core/hle/service/sm/sm.h"
10 11
11namespace Service::Set { 12namespace Service::Set {
12 13
13void InstallInterfaces(SM::ServiceManager& service_manager) { 14void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
14 std::make_shared<SET>()->InstallAsService(service_manager); 15 std::make_shared<SET>(system)->InstallAsService(service_manager);
15 std::make_shared<SET_CAL>()->InstallAsService(service_manager); 16 std::make_shared<SET_CAL>(system)->InstallAsService(service_manager);
16 std::make_shared<SET_FD>()->InstallAsService(service_manager); 17 std::make_shared<SET_FD>(system)->InstallAsService(service_manager);
17 std::make_shared<SET_SYS>()->InstallAsService(service_manager); 18 std::make_shared<SET_SYS>(system)->InstallAsService(service_manager);
18} 19}
19 20
20} // namespace Service::Set 21} // namespace Service::Set
diff --git a/src/core/hle/service/set/settings.h b/src/core/hle/service/set/settings.h
index 6606ce776..7a6950dd0 100644
--- a/src/core/hle/service/set/settings.h
+++ b/src/core/hle/service/set/settings.h
@@ -4,11 +4,17 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "core/hle/service/service.h" 7namespace Core {
8class System;
9}
10
11namespace Service::SM {
12class ServiceManager;
13}
8 14
9namespace Service::Set { 15namespace Service::Set {
10 16
11/// Registers all Settings services with the specified service manager. 17/// Registers all Settings services with the specified service manager.
12void InstallInterfaces(SM::ServiceManager& service_manager); 18void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system);
13 19
14} // namespace Service::Set 20} // namespace Service::Set
diff --git a/src/core/hle/service/sm/controller.cpp b/src/core/hle/service/sm/controller.cpp
index 972aaa6d9..916177efd 100644
--- a/src/core/hle/service/sm/controller.cpp
+++ b/src/core/hle/service/sm/controller.cpp
@@ -48,7 +48,7 @@ void Controller::QueryPointerBufferSize(Kernel::HLERequestContext& ctx) {
48} 48}
49 49
50// https://switchbrew.org/wiki/IPC_Marshalling 50// https://switchbrew.org/wiki/IPC_Marshalling
51Controller::Controller() : ServiceFramework("IpcController") { 51Controller::Controller(Core::System& system_) : ServiceFramework{system_, "IpcController"} {
52 static const FunctionInfo functions[] = { 52 static const FunctionInfo functions[] = {
53 {0, &Controller::ConvertCurrentObjectToDomain, "ConvertCurrentObjectToDomain"}, 53 {0, &Controller::ConvertCurrentObjectToDomain, "ConvertCurrentObjectToDomain"},
54 {1, nullptr, "CopyFromCurrentDomain"}, 54 {1, nullptr, "CopyFromCurrentDomain"},
diff --git a/src/core/hle/service/sm/controller.h b/src/core/hle/service/sm/controller.h
index 180c6da50..7494f898d 100644
--- a/src/core/hle/service/sm/controller.h
+++ b/src/core/hle/service/sm/controller.h
@@ -6,11 +6,15 @@
6 6
7#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
8 8
9namespace Core {
10class System;
11}
12
9namespace Service::SM { 13namespace Service::SM {
10 14
11class Controller final : public ServiceFramework<Controller> { 15class Controller final : public ServiceFramework<Controller> {
12public: 16public:
13 Controller(); 17 explicit Controller(Core::System& system_);
14 ~Controller() override; 18 ~Controller() override;
15 19
16private: 20private:
diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp
index 9c1da361b..4da69f503 100644
--- a/src/core/hle/service/sm/sm.cpp
+++ b/src/core/hle/service/sm/sm.cpp
@@ -38,14 +38,13 @@ static ResultCode ValidateServiceName(const std::string& name) {
38 return RESULT_SUCCESS; 38 return RESULT_SUCCESS;
39} 39}
40 40
41void ServiceManager::InstallInterfaces(std::shared_ptr<ServiceManager> self, 41void ServiceManager::InstallInterfaces(std::shared_ptr<ServiceManager> self, Core::System& system) {
42 Kernel::KernelCore& kernel) {
43 ASSERT(self->sm_interface.expired()); 42 ASSERT(self->sm_interface.expired());
44 43
45 auto sm = std::make_shared<SM>(self, kernel); 44 auto sm = std::make_shared<SM>(self, system);
46 sm->InstallAsNamedPort(kernel); 45 sm->InstallAsNamedPort(system.Kernel());
47 self->sm_interface = sm; 46 self->sm_interface = sm;
48 self->controller_interface = std::make_unique<Controller>(); 47 self->controller_interface = std::make_unique<Controller>(system);
49} 48}
50 49
51ResultVal<std::shared_ptr<Kernel::ServerPort>> ServiceManager::RegisterService(std::string name, 50ResultVal<std::shared_ptr<Kernel::ServerPort>> ServiceManager::RegisterService(std::string name,
@@ -190,8 +189,9 @@ void SM::UnregisterService(Kernel::HLERequestContext& ctx) {
190 rb.Push(service_manager->UnregisterService(name)); 189 rb.Push(service_manager->UnregisterService(name));
191} 190}
192 191
193SM::SM(std::shared_ptr<ServiceManager> service_manager, Kernel::KernelCore& kernel) 192SM::SM(std::shared_ptr<ServiceManager> service_manager_, Core::System& system_)
194 : ServiceFramework{"sm:", 4}, service_manager{std::move(service_manager)}, kernel{kernel} { 193 : ServiceFramework{system_, "sm:", 4},
194 service_manager{std::move(service_manager_)}, kernel{system_.Kernel()} {
195 static const FunctionInfo functions[] = { 195 static const FunctionInfo functions[] = {
196 {0x00000000, &SM::Initialize, "Initialize"}, 196 {0x00000000, &SM::Initialize, "Initialize"},
197 {0x00000001, &SM::GetService, "GetService"}, 197 {0x00000001, &SM::GetService, "GetService"},
diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h
index 6790c86f0..3f46ae44f 100644
--- a/src/core/hle/service/sm/sm.h
+++ b/src/core/hle/service/sm/sm.h
@@ -16,6 +16,10 @@
16#include "core/hle/result.h" 16#include "core/hle/result.h"
17#include "core/hle/service/service.h" 17#include "core/hle/service/service.h"
18 18
19namespace Core {
20class System;
21}
22
19namespace Kernel { 23namespace Kernel {
20class ClientPort; 24class ClientPort;
21class ClientSession; 25class ClientSession;
@@ -31,7 +35,7 @@ class Controller;
31/// Interface to "sm:" service 35/// Interface to "sm:" service
32class SM final : public ServiceFramework<SM> { 36class SM final : public ServiceFramework<SM> {
33public: 37public:
34 explicit SM(std::shared_ptr<ServiceManager> service_manager, Kernel::KernelCore& kernel); 38 explicit SM(std::shared_ptr<ServiceManager> service_manager_, Core::System& system_);
35 ~SM() override; 39 ~SM() override;
36 40
37private: 41private:
@@ -46,7 +50,7 @@ private:
46 50
47class ServiceManager { 51class ServiceManager {
48public: 52public:
49 static void InstallInterfaces(std::shared_ptr<ServiceManager> self, Kernel::KernelCore& kernel); 53 static void InstallInterfaces(std::shared_ptr<ServiceManager> self, Core::System& system);
50 54
51 explicit ServiceManager(Kernel::KernelCore& kernel_); 55 explicit ServiceManager(Kernel::KernelCore& kernel_);
52 ~ServiceManager(); 56 ~ServiceManager();
diff --git a/src/core/hle/service/sockets/blocking_worker.h b/src/core/hle/service/sockets/blocking_worker.h
deleted file mode 100644
index 2d53e52b6..000000000
--- a/src/core/hle/service/sockets/blocking_worker.h
+++ /dev/null
@@ -1,161 +0,0 @@
1// Copyright 2020 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <atomic>
8#include <memory>
9#include <string>
10#include <string_view>
11#include <thread>
12#include <variant>
13#include <vector>
14
15#include <fmt/format.h>
16
17#include "common/assert.h"
18#include "common/microprofile.h"
19#include "common/thread.h"
20#include "core/core.h"
21#include "core/hle/kernel/hle_ipc.h"
22#include "core/hle/kernel/kernel.h"
23#include "core/hle/kernel/thread.h"
24#include "core/hle/kernel/writable_event.h"
25
26namespace Service::Sockets {
27
28/**
29 * Worker abstraction to execute blocking calls on host without blocking the guest thread
30 *
31 * @tparam Service Service where the work is executed
32 * @tparam Types Types of work to execute
33 */
34template <class Service, class... Types>
35class BlockingWorker {
36 using This = BlockingWorker<Service, Types...>;
37 using WorkVariant = std::variant<std::monostate, Types...>;
38
39public:
40 /// Create a new worker
41 static std::unique_ptr<This> Create(Core::System& system, Service* service,
42 std::string_view name) {
43 return std::unique_ptr<This>(new This(system, service, name));
44 }
45
46 ~BlockingWorker() {
47 while (!is_available.load(std::memory_order_relaxed)) {
48 // Busy wait until work is finished
49 std::this_thread::yield();
50 }
51 // Monostate means to exit the thread
52 work = std::monostate{};
53 work_event.Set();
54 thread.join();
55 }
56
57 /**
58 * Try to capture the worker to send work after a success
59 * @returns True when the worker has been successfully captured
60 */
61 bool TryCapture() {
62 bool expected = true;
63 return is_available.compare_exchange_weak(expected, false, std::memory_order_relaxed,
64 std::memory_order_relaxed);
65 }
66
67 /**
68 * Send work to this worker abstraction
69 * @see TryCapture must be called before attempting to call this function
70 */
71 template <class Work>
72 void SendWork(Work new_work) {
73 ASSERT_MSG(!is_available, "Trying to send work on a worker that's not captured");
74 work = std::move(new_work);
75 work_event.Set();
76 }
77
78 /// Generate a callback for @see SleepClientThread
79 template <class Work>
80 auto Callback() {
81 return [this](std::shared_ptr<Kernel::Thread>, Kernel::HLERequestContext& ctx,
82 Kernel::ThreadWakeupReason reason) {
83 ASSERT(reason == Kernel::ThreadWakeupReason::Signal);
84 std::get<Work>(work).Response(ctx);
85 is_available.store(true);
86 };
87 }
88
89 /// Get kernel event that will be signalled by the worker when the host operation finishes
90 std::shared_ptr<Kernel::WritableEvent> KernelEvent() const {
91 return kernel_event;
92 }
93
94private:
95 explicit BlockingWorker(Core::System& system, Service* service, std::string_view name) {
96 auto pair = Kernel::WritableEvent::CreateEventPair(system.Kernel(), std::string(name));
97 kernel_event = std::move(pair.writable);
98 thread = std::thread([this, &system, service, name] { Run(system, service, name); });
99 }
100
101 void Run(Core::System& system, Service* service, std::string_view name) {
102 system.RegisterHostThread();
103
104 const std::string thread_name = fmt::format("yuzu:{}", name);
105 MicroProfileOnThreadCreate(thread_name.c_str());
106 Common::SetCurrentThreadName(thread_name.c_str());
107
108 bool keep_running = true;
109 while (keep_running) {
110 work_event.Wait();
111
112 const auto visit_fn = [service, &keep_running]<typename T>(T&& w) {
113 if constexpr (std::is_same_v<std::decay_t<T>, std::monostate>) {
114 keep_running = false;
115 } else {
116 w.Execute(service);
117 }
118 };
119 std::visit(visit_fn, work);
120
121 kernel_event->Signal();
122 }
123 }
124
125 std::thread thread;
126 WorkVariant work;
127 Common::Event work_event;
128 std::shared_ptr<Kernel::WritableEvent> kernel_event;
129 std::atomic_bool is_available{true};
130};
131
132template <class Service, class... Types>
133class BlockingWorkerPool {
134 using Worker = BlockingWorker<Service, Types...>;
135
136public:
137 explicit BlockingWorkerPool(Core::System& system_, Service* service_)
138 : system{system_}, service{service_} {}
139
140 /// Returns a captured worker thread, creating new ones if necessary
141 Worker* CaptureWorker() {
142 for (auto& worker : workers) {
143 if (worker->TryCapture()) {
144 return worker.get();
145 }
146 }
147 auto new_worker = Worker::Create(system, service, fmt::format("BSD:{}", workers.size()));
148 [[maybe_unused]] const bool success = new_worker->TryCapture();
149 ASSERT(success);
150
151 return workers.emplace_back(std::move(new_worker)).get();
152 }
153
154private:
155 Core::System& system;
156 Service* const service;
157
158 std::vector<std::unique_ptr<Worker>> workers;
159};
160
161} // namespace Service::Sockets
diff --git a/src/core/hle/service/sockets/bsd.cpp b/src/core/hle/service/sockets/bsd.cpp
index a74be9370..2b824059d 100644
--- a/src/core/hle/service/sockets/bsd.cpp
+++ b/src/core/hle/service/sockets/bsd.cpp
@@ -30,7 +30,7 @@ bool IsConnectionBased(Type type) {
30 case Type::DGRAM: 30 case Type::DGRAM:
31 return false; 31 return false;
32 default: 32 default:
33 UNIMPLEMENTED_MSG("Unimplemented type={}", static_cast<int>(type)); 33 UNIMPLEMENTED_MSG("Unimplemented type={}", type);
34 return false; 34 return false;
35 } 35 }
36} 36}
@@ -178,13 +178,12 @@ void BSD::Poll(Kernel::HLERequestContext& ctx) {
178 178
179 LOG_DEBUG(Service, "called. nfds={} timeout={}", nfds, timeout); 179 LOG_DEBUG(Service, "called. nfds={} timeout={}", nfds, timeout);
180 180
181 ExecuteWork(ctx, "BSD:Poll", timeout != 0, 181 ExecuteWork(ctx, PollWork{
182 PollWork{ 182 .nfds = nfds,
183 .nfds = nfds, 183 .timeout = timeout,
184 .timeout = timeout, 184 .read_buffer = ctx.ReadBuffer(),
185 .read_buffer = ctx.ReadBuffer(), 185 .write_buffer = std::vector<u8>(ctx.GetWriteBufferSize()),
186 .write_buffer = std::vector<u8>(ctx.GetWriteBufferSize()), 186 });
187 });
188} 187}
189 188
190void BSD::Accept(Kernel::HLERequestContext& ctx) { 189void BSD::Accept(Kernel::HLERequestContext& ctx) {
@@ -193,11 +192,10 @@ void BSD::Accept(Kernel::HLERequestContext& ctx) {
193 192
194 LOG_DEBUG(Service, "called. fd={}", fd); 193 LOG_DEBUG(Service, "called. fd={}", fd);
195 194
196 ExecuteWork(ctx, "BSD:Accept", IsBlockingSocket(fd), 195 ExecuteWork(ctx, AcceptWork{
197 AcceptWork{ 196 .fd = fd,
198 .fd = fd, 197 .write_buffer = std::vector<u8>(ctx.GetWriteBufferSize()),
199 .write_buffer = std::vector<u8>(ctx.GetWriteBufferSize()), 198 });
200 });
201} 199}
202 200
203void BSD::Bind(Kernel::HLERequestContext& ctx) { 201void BSD::Bind(Kernel::HLERequestContext& ctx) {
@@ -215,11 +213,10 @@ void BSD::Connect(Kernel::HLERequestContext& ctx) {
215 213
216 LOG_DEBUG(Service, "called. fd={} addrlen={}", fd, ctx.GetReadBufferSize()); 214 LOG_DEBUG(Service, "called. fd={} addrlen={}", fd, ctx.GetReadBufferSize());
217 215
218 ExecuteWork(ctx, "BSD:Connect", IsBlockingSocket(fd), 216 ExecuteWork(ctx, ConnectWork{
219 ConnectWork{ 217 .fd = fd,
220 .fd = fd, 218 .addr = ctx.ReadBuffer(),
221 .addr = ctx.ReadBuffer(), 219 });
222 });
223} 220}
224 221
225void BSD::GetPeerName(Kernel::HLERequestContext& ctx) { 222void BSD::GetPeerName(Kernel::HLERequestContext& ctx) {
@@ -327,12 +324,11 @@ void BSD::Recv(Kernel::HLERequestContext& ctx) {
327 324
328 LOG_DEBUG(Service, "called. fd={} flags=0x{:x} len={}", fd, flags, ctx.GetWriteBufferSize()); 325 LOG_DEBUG(Service, "called. fd={} flags=0x{:x} len={}", fd, flags, ctx.GetWriteBufferSize());
329 326
330 ExecuteWork(ctx, "BSD:Recv", IsBlockingSocket(fd), 327 ExecuteWork(ctx, RecvWork{
331 RecvWork{ 328 .fd = fd,
332 .fd = fd, 329 .flags = flags,
333 .flags = flags, 330 .message = std::vector<u8>(ctx.GetWriteBufferSize()),
334 .message = std::vector<u8>(ctx.GetWriteBufferSize()), 331 });
335 });
336} 332}
337 333
338void BSD::RecvFrom(Kernel::HLERequestContext& ctx) { 334void BSD::RecvFrom(Kernel::HLERequestContext& ctx) {
@@ -344,13 +340,12 @@ void BSD::RecvFrom(Kernel::HLERequestContext& ctx) {
344 LOG_DEBUG(Service, "called. fd={} flags=0x{:x} len={} addrlen={}", fd, flags, 340 LOG_DEBUG(Service, "called. fd={} flags=0x{:x} len={} addrlen={}", fd, flags,
345 ctx.GetWriteBufferSize(0), ctx.GetWriteBufferSize(1)); 341 ctx.GetWriteBufferSize(0), ctx.GetWriteBufferSize(1));
346 342
347 ExecuteWork(ctx, "BSD:RecvFrom", IsBlockingSocket(fd), 343 ExecuteWork(ctx, RecvFromWork{
348 RecvFromWork{ 344 .fd = fd,
349 .fd = fd, 345 .flags = flags,
350 .flags = flags, 346 .message = std::vector<u8>(ctx.GetWriteBufferSize(0)),
351 .message = std::vector<u8>(ctx.GetWriteBufferSize(0)), 347 .addr = std::vector<u8>(ctx.GetWriteBufferSize(1)),
352 .addr = std::vector<u8>(ctx.GetWriteBufferSize(1)), 348 });
353 });
354} 349}
355 350
356void BSD::Send(Kernel::HLERequestContext& ctx) { 351void BSD::Send(Kernel::HLERequestContext& ctx) {
@@ -361,12 +356,11 @@ void BSD::Send(Kernel::HLERequestContext& ctx) {
361 356
362 LOG_DEBUG(Service, "called. fd={} flags=0x{:x} len={}", fd, flags, ctx.GetReadBufferSize()); 357 LOG_DEBUG(Service, "called. fd={} flags=0x{:x} len={}", fd, flags, ctx.GetReadBufferSize());
363 358
364 ExecuteWork(ctx, "BSD:Send", IsBlockingSocket(fd), 359 ExecuteWork(ctx, SendWork{
365 SendWork{ 360 .fd = fd,
366 .fd = fd, 361 .flags = flags,
367 .flags = flags, 362 .message = ctx.ReadBuffer(),
368 .message = ctx.ReadBuffer(), 363 });
369 });
370} 364}
371 365
372void BSD::SendTo(Kernel::HLERequestContext& ctx) { 366void BSD::SendTo(Kernel::HLERequestContext& ctx) {
@@ -377,13 +371,12 @@ void BSD::SendTo(Kernel::HLERequestContext& ctx) {
377 LOG_DEBUG(Service, "called. fd={} flags=0x{} len={} addrlen={}", fd, flags, 371 LOG_DEBUG(Service, "called. fd={} flags=0x{} len={} addrlen={}", fd, flags,
378 ctx.GetReadBufferSize(0), ctx.GetReadBufferSize(1)); 372 ctx.GetReadBufferSize(0), ctx.GetReadBufferSize(1));
379 373
380 ExecuteWork(ctx, "BSD:SendTo", IsBlockingSocket(fd), 374 ExecuteWork(ctx, SendToWork{
381 SendToWork{ 375 .fd = fd,
382 .fd = fd, 376 .flags = flags,
383 .flags = flags, 377 .message = ctx.ReadBuffer(0),
384 .message = ctx.ReadBuffer(0), 378 .addr = ctx.ReadBuffer(1),
385 .addr = ctx.ReadBuffer(1), 379 });
386 });
387} 380}
388 381
389void BSD::Write(Kernel::HLERequestContext& ctx) { 382void BSD::Write(Kernel::HLERequestContext& ctx) {
@@ -392,12 +385,11 @@ void BSD::Write(Kernel::HLERequestContext& ctx) {
392 385
393 LOG_DEBUG(Service, "called. fd={} len={}", fd, ctx.GetReadBufferSize()); 386 LOG_DEBUG(Service, "called. fd={} len={}", fd, ctx.GetReadBufferSize());
394 387
395 ExecuteWork(ctx, "BSD:Write", IsBlockingSocket(fd), 388 ExecuteWork(ctx, SendWork{
396 SendWork{ 389 .fd = fd,
397 .fd = fd, 390 .flags = 0,
398 .flags = 0, 391 .message = ctx.ReadBuffer(),
399 .message = ctx.ReadBuffer(), 392 });
400 });
401} 393}
402 394
403void BSD::Close(Kernel::HLERequestContext& ctx) { 395void BSD::Close(Kernel::HLERequestContext& ctx) {
@@ -410,24 +402,9 @@ void BSD::Close(Kernel::HLERequestContext& ctx) {
410} 402}
411 403
412template <typename Work> 404template <typename Work>
413void BSD::ExecuteWork(Kernel::HLERequestContext& ctx, std::string_view sleep_reason, 405void BSD::ExecuteWork(Kernel::HLERequestContext& ctx, Work work) {
414 bool is_blocking, Work work) { 406 work.Execute(this);
415 if (!is_blocking) {
416 work.Execute(this);
417 work.Response(ctx);
418 return;
419 }
420
421 // Signal a dummy response to make IPC validation happy
422 // This will be overwritten by the SleepClientThread callback
423 work.Response(ctx); 407 work.Response(ctx);
424
425 auto worker = worker_pool.CaptureWorker();
426
427 ctx.SleepClientThread(std::string(sleep_reason), std::numeric_limits<u64>::max(),
428 worker->Callback<Work>(), worker->KernelEvent());
429
430 worker->SendWork(std::move(work));
431} 408}
432 409
433std::pair<s32, Errno> BSD::SocketImpl(Domain domain, Type type, Protocol protocol) { 410std::pair<s32, Errno> BSD::SocketImpl(Domain domain, Type type, Protocol protocol) {
@@ -489,18 +466,18 @@ std::pair<s32, Errno> BSD::PollImpl(std::vector<u8>& write_buffer, std::vector<u
489 } 466 }
490 467
491 for (PollFD& pollfd : fds) { 468 for (PollFD& pollfd : fds) {
492 ASSERT(pollfd.revents == 0); 469 ASSERT(False(pollfd.revents));
493 470
494 if (pollfd.fd > static_cast<s32>(MAX_FD) || pollfd.fd < 0) { 471 if (pollfd.fd > static_cast<s32>(MAX_FD) || pollfd.fd < 0) {
495 LOG_ERROR(Service, "File descriptor handle={} is invalid", pollfd.fd); 472 LOG_ERROR(Service, "File descriptor handle={} is invalid", pollfd.fd);
496 pollfd.revents = 0; 473 pollfd.revents = PollEvents{};
497 return {0, Errno::SUCCESS}; 474 return {0, Errno::SUCCESS};
498 } 475 }
499 476
500 const std::optional<FileDescriptor>& descriptor = file_descriptors[pollfd.fd]; 477 const std::optional<FileDescriptor>& descriptor = file_descriptors[pollfd.fd];
501 if (!descriptor) { 478 if (!descriptor) {
502 LOG_ERROR(Service, "File descriptor handle={} is not allocated", pollfd.fd); 479 LOG_ERROR(Service, "File descriptor handle={} is not allocated", pollfd.fd);
503 pollfd.revents = POLL_NVAL; 480 pollfd.revents = PollEvents::Nval;
504 return {0, Errno::SUCCESS}; 481 return {0, Errno::SUCCESS};
505 } 482 }
506 } 483 }
@@ -510,7 +487,7 @@ std::pair<s32, Errno> BSD::PollImpl(std::vector<u8>& write_buffer, std::vector<u
510 Network::PollFD result; 487 Network::PollFD result;
511 result.socket = file_descriptors[pollfd.fd]->socket.get(); 488 result.socket = file_descriptors[pollfd.fd]->socket.get();
512 result.events = TranslatePollEventsToHost(pollfd.events); 489 result.events = TranslatePollEventsToHost(pollfd.events);
513 result.revents = 0; 490 result.revents = Network::PollEvents{};
514 return result; 491 return result;
515 }); 492 });
516 493
@@ -636,7 +613,7 @@ std::pair<s32, Errno> BSD::FcntlImpl(s32 fd, FcntlCmd cmd, s32 arg) {
636 return {0, Errno::SUCCESS}; 613 return {0, Errno::SUCCESS};
637 } 614 }
638 default: 615 default:
639 UNIMPLEMENTED_MSG("Unimplemented cmd={}", static_cast<int>(cmd)); 616 UNIMPLEMENTED_MSG("Unimplemented cmd={}", cmd);
640 return {-1, Errno::SUCCESS}; 617 return {-1, Errno::SUCCESS};
641 } 618 }
642} 619}
@@ -679,7 +656,7 @@ Errno BSD::SetSockOptImpl(s32 fd, u32 level, OptName optname, size_t optlen, con
679 case OptName::RCVTIMEO: 656 case OptName::RCVTIMEO:
680 return Translate(socket->SetRcvTimeo(value)); 657 return Translate(socket->SetRcvTimeo(value));
681 default: 658 default:
682 UNIMPLEMENTED_MSG("Unimplemented optname={}", static_cast<int>(optname)); 659 UNIMPLEMENTED_MSG("Unimplemented optname={}", optname);
683 return Errno::SUCCESS; 660 return Errno::SUCCESS;
684 } 661 }
685} 662}
@@ -807,18 +784,6 @@ bool BSD::IsFileDescriptorValid(s32 fd) const noexcept {
807 return true; 784 return true;
808} 785}
809 786
810bool BSD::IsBlockingSocket(s32 fd) const noexcept {
811 // Inform invalid sockets as non-blocking
812 // This way we avoid using a worker thread as it will fail without blocking host
813 if (fd > static_cast<s32>(MAX_FD) || fd < 0) {
814 return false;
815 }
816 if (!file_descriptors[fd]) {
817 return false;
818 }
819 return (file_descriptors[fd]->flags & FLAG_O_NONBLOCK) != 0;
820}
821
822void BSD::BuildErrnoResponse(Kernel::HLERequestContext& ctx, Errno bsd_errno) const noexcept { 787void BSD::BuildErrnoResponse(Kernel::HLERequestContext& ctx, Errno bsd_errno) const noexcept {
823 IPC::ResponseBuilder rb{ctx, 4}; 788 IPC::ResponseBuilder rb{ctx, 4};
824 789
@@ -827,8 +792,7 @@ void BSD::BuildErrnoResponse(Kernel::HLERequestContext& ctx, Errno bsd_errno) co
827 rb.PushEnum(bsd_errno); 792 rb.PushEnum(bsd_errno);
828} 793}
829 794
830BSD::BSD(Core::System& system, const char* name) 795BSD::BSD(Core::System& system_, const char* name) : ServiceFramework{system_, name} {
831 : ServiceFramework(name), worker_pool{system, this} {
832 // clang-format off 796 // clang-format off
833 static const FunctionInfo functions[] = { 797 static const FunctionInfo functions[] = {
834 {0, &BSD::RegisterClient, "RegisterClient"}, 798 {0, &BSD::RegisterClient, "RegisterClient"},
@@ -873,7 +837,7 @@ BSD::BSD(Core::System& system, const char* name)
873 837
874BSD::~BSD() = default; 838BSD::~BSD() = default;
875 839
876BSDCFG::BSDCFG() : ServiceFramework{"bsdcfg"} { 840BSDCFG::BSDCFG(Core::System& system_) : ServiceFramework{system_, "bsdcfg"} {
877 // clang-format off 841 // clang-format off
878 static const FunctionInfo functions[] = { 842 static const FunctionInfo functions[] = {
879 {0, nullptr, "SetIfUp"}, 843 {0, nullptr, "SetIfUp"},
diff --git a/src/core/hle/service/sockets/bsd.h b/src/core/hle/service/sockets/bsd.h
index 357531951..6da0bfeb2 100644
--- a/src/core/hle/service/sockets/bsd.h
+++ b/src/core/hle/service/sockets/bsd.h
@@ -11,7 +11,6 @@
11#include "common/common_types.h" 11#include "common/common_types.h"
12#include "core/hle/kernel/hle_ipc.h" 12#include "core/hle/kernel/hle_ipc.h"
13#include "core/hle/service/service.h" 13#include "core/hle/service/service.h"
14#include "core/hle/service/sockets/blocking_worker.h"
15#include "core/hle/service/sockets/sockets.h" 14#include "core/hle/service/sockets/sockets.h"
16 15
17namespace Core { 16namespace Core {
@@ -26,7 +25,7 @@ namespace Service::Sockets {
26 25
27class BSD final : public ServiceFramework<BSD> { 26class BSD final : public ServiceFramework<BSD> {
28public: 27public:
29 explicit BSD(Core::System& system, const char* name); 28 explicit BSD(Core::System& system_, const char* name);
30 ~BSD() override; 29 ~BSD() override;
31 30
32private: 31private:
@@ -138,8 +137,7 @@ private:
138 void Close(Kernel::HLERequestContext& ctx); 137 void Close(Kernel::HLERequestContext& ctx);
139 138
140 template <typename Work> 139 template <typename Work>
141 void ExecuteWork(Kernel::HLERequestContext& ctx, std::string_view sleep_reason, 140 void ExecuteWork(Kernel::HLERequestContext& ctx, Work work);
142 bool is_blocking, Work work);
143 141
144 std::pair<s32, Errno> SocketImpl(Domain domain, Type type, Protocol protocol); 142 std::pair<s32, Errno> SocketImpl(Domain domain, Type type, Protocol protocol);
145 std::pair<s32, Errno> PollImpl(std::vector<u8>& write_buffer, std::vector<u8> read_buffer, 143 std::pair<s32, Errno> PollImpl(std::vector<u8>& write_buffer, std::vector<u8> read_buffer,
@@ -163,20 +161,15 @@ private:
163 161
164 s32 FindFreeFileDescriptorHandle() noexcept; 162 s32 FindFreeFileDescriptorHandle() noexcept;
165 bool IsFileDescriptorValid(s32 fd) const noexcept; 163 bool IsFileDescriptorValid(s32 fd) const noexcept;
166 bool IsBlockingSocket(s32 fd) const noexcept;
167 164
168 void BuildErrnoResponse(Kernel::HLERequestContext& ctx, Errno bsd_errno) const noexcept; 165 void BuildErrnoResponse(Kernel::HLERequestContext& ctx, Errno bsd_errno) const noexcept;
169 166
170 std::array<std::optional<FileDescriptor>, MAX_FD> file_descriptors; 167 std::array<std::optional<FileDescriptor>, MAX_FD> file_descriptors;
171
172 BlockingWorkerPool<BSD, PollWork, AcceptWork, ConnectWork, RecvWork, RecvFromWork, SendWork,
173 SendToWork>
174 worker_pool;
175}; 168};
176 169
177class BSDCFG final : public ServiceFramework<BSDCFG> { 170class BSDCFG final : public ServiceFramework<BSDCFG> {
178public: 171public:
179 explicit BSDCFG(); 172 explicit BSDCFG(Core::System& system_);
180 ~BSDCFG() override; 173 ~BSDCFG() override;
181}; 174};
182 175
diff --git a/src/core/hle/service/sockets/ethc.cpp b/src/core/hle/service/sockets/ethc.cpp
index abbeb4c50..05681ca2d 100644
--- a/src/core/hle/service/sockets/ethc.cpp
+++ b/src/core/hle/service/sockets/ethc.cpp
@@ -6,7 +6,7 @@
6 6
7namespace Service::Sockets { 7namespace Service::Sockets {
8 8
9ETHC_C::ETHC_C() : ServiceFramework{"ethc:c"} { 9ETHC_C::ETHC_C(Core::System& system_) : ServiceFramework{system_, "ethc:c"} {
10 // clang-format off 10 // clang-format off
11 static const FunctionInfo functions[] = { 11 static const FunctionInfo functions[] = {
12 {0, nullptr, "Initialize"}, 12 {0, nullptr, "Initialize"},
@@ -23,7 +23,7 @@ ETHC_C::ETHC_C() : ServiceFramework{"ethc:c"} {
23 23
24ETHC_C::~ETHC_C() = default; 24ETHC_C::~ETHC_C() = default;
25 25
26ETHC_I::ETHC_I() : ServiceFramework{"ethc:i"} { 26ETHC_I::ETHC_I(Core::System& system_) : ServiceFramework{system_, "ethc:i"} {
27 // clang-format off 27 // clang-format off
28 static const FunctionInfo functions[] = { 28 static const FunctionInfo functions[] = {
29 {0, nullptr, "GetReadableHandle"}, 29 {0, nullptr, "GetReadableHandle"},
diff --git a/src/core/hle/service/sockets/ethc.h b/src/core/hle/service/sockets/ethc.h
index da2c7f741..71884182e 100644
--- a/src/core/hle/service/sockets/ethc.h
+++ b/src/core/hle/service/sockets/ethc.h
@@ -6,17 +6,21 @@
6 6
7#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
8 8
9namespace Core {
10class System;
11}
12
9namespace Service::Sockets { 13namespace Service::Sockets {
10 14
11class ETHC_C final : public ServiceFramework<ETHC_C> { 15class ETHC_C final : public ServiceFramework<ETHC_C> {
12public: 16public:
13 explicit ETHC_C(); 17 explicit ETHC_C(Core::System& system_);
14 ~ETHC_C() override; 18 ~ETHC_C() override;
15}; 19};
16 20
17class ETHC_I final : public ServiceFramework<ETHC_I> { 21class ETHC_I final : public ServiceFramework<ETHC_I> {
18public: 22public:
19 explicit ETHC_I(); 23 explicit ETHC_I(Core::System& system_);
20 ~ETHC_I() override; 24 ~ETHC_I() override;
21}; 25};
22 26
diff --git a/src/core/hle/service/sockets/nsd.cpp b/src/core/hle/service/sockets/nsd.cpp
index 40d781124..51c3739bb 100644
--- a/src/core/hle/service/sockets/nsd.cpp
+++ b/src/core/hle/service/sockets/nsd.cpp
@@ -6,7 +6,7 @@
6 6
7namespace Service::Sockets { 7namespace Service::Sockets {
8 8
9NSD::NSD(const char* name) : ServiceFramework(name) { 9NSD::NSD(Core::System& system_, const char* name) : ServiceFramework{system_, name} {
10 // clang-format off 10 // clang-format off
11 static const FunctionInfo functions[] = { 11 static const FunctionInfo functions[] = {
12 {10, nullptr, "GetSettingName"}, 12 {10, nullptr, "GetSettingName"},
diff --git a/src/core/hle/service/sockets/nsd.h b/src/core/hle/service/sockets/nsd.h
index d842e3232..becf93125 100644
--- a/src/core/hle/service/sockets/nsd.h
+++ b/src/core/hle/service/sockets/nsd.h
@@ -4,14 +4,17 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "core/hle/kernel/hle_ipc.h"
8#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
9 8
9namespace Core {
10class System;
11}
12
10namespace Service::Sockets { 13namespace Service::Sockets {
11 14
12class NSD final : public ServiceFramework<NSD> { 15class NSD final : public ServiceFramework<NSD> {
13public: 16public:
14 explicit NSD(const char* name); 17 explicit NSD(Core::System& system_, const char* name);
15 ~NSD() override; 18 ~NSD() override;
16}; 19};
17 20
diff --git a/src/core/hle/service/sockets/sfdnsres.cpp b/src/core/hle/service/sockets/sfdnsres.cpp
index e3017451f..3a6329f56 100644
--- a/src/core/hle/service/sockets/sfdnsres.cpp
+++ b/src/core/hle/service/sockets/sfdnsres.cpp
@@ -7,25 +7,7 @@
7 7
8namespace Service::Sockets { 8namespace Service::Sockets {
9 9
10void SFDNSRES::GetAddrInfoRequest(Kernel::HLERequestContext& ctx) { 10SFDNSRES::SFDNSRES(Core::System& system_) : ServiceFramework{system_, "sfdnsres"} {
11 struct Parameters {
12 u8 use_nsd_resolve;
13 u32 unknown;
14 u64 process_id;
15 };
16
17 IPC::RequestParser rp{ctx};
18 const auto parameters = rp.PopRaw<Parameters>();
19
20 LOG_WARNING(Service,
21 "(STUBBED) called. use_nsd_resolve={}, unknown=0x{:08X}, process_id=0x{:016X}",
22 parameters.use_nsd_resolve, parameters.unknown, parameters.process_id);
23
24 IPC::ResponseBuilder rb{ctx, 2};
25 rb.Push(RESULT_SUCCESS);
26}
27
28SFDNSRES::SFDNSRES() : ServiceFramework("sfdnsres") {
29 static const FunctionInfo functions[] = { 11 static const FunctionInfo functions[] = {
30 {0, nullptr, "SetDnsAddressesPrivate"}, 12 {0, nullptr, "SetDnsAddressesPrivate"},
31 {1, nullptr, "GetDnsAddressPrivate"}, 13 {1, nullptr, "GetDnsAddressPrivate"},
@@ -49,4 +31,22 @@ SFDNSRES::SFDNSRES() : ServiceFramework("sfdnsres") {
49 31
50SFDNSRES::~SFDNSRES() = default; 32SFDNSRES::~SFDNSRES() = default;
51 33
34void SFDNSRES::GetAddrInfoRequest(Kernel::HLERequestContext& ctx) {
35 struct Parameters {
36 u8 use_nsd_resolve;
37 u32 unknown;
38 u64 process_id;
39 };
40
41 IPC::RequestParser rp{ctx};
42 const auto parameters = rp.PopRaw<Parameters>();
43
44 LOG_WARNING(Service,
45 "(STUBBED) called. use_nsd_resolve={}, unknown=0x{:08X}, process_id=0x{:016X}",
46 parameters.use_nsd_resolve, parameters.unknown, parameters.process_id);
47
48 IPC::ResponseBuilder rb{ctx, 2};
49 rb.Push(RESULT_SUCCESS);
50}
51
52} // namespace Service::Sockets 52} // namespace Service::Sockets
diff --git a/src/core/hle/service/sockets/sfdnsres.h b/src/core/hle/service/sockets/sfdnsres.h
index acd3647bb..faa6b7d0d 100644
--- a/src/core/hle/service/sockets/sfdnsres.h
+++ b/src/core/hle/service/sockets/sfdnsres.h
@@ -7,11 +7,15 @@
7#include "core/hle/kernel/hle_ipc.h" 7#include "core/hle/kernel/hle_ipc.h"
8#include "core/hle/service/service.h" 8#include "core/hle/service/service.h"
9 9
10namespace Core {
11class System;
12}
13
10namespace Service::Sockets { 14namespace Service::Sockets {
11 15
12class SFDNSRES final : public ServiceFramework<SFDNSRES> { 16class SFDNSRES final : public ServiceFramework<SFDNSRES> {
13public: 17public:
14 explicit SFDNSRES(); 18 explicit SFDNSRES(Core::System& system_);
15 ~SFDNSRES() override; 19 ~SFDNSRES() override;
16 20
17private: 21private:
diff --git a/src/core/hle/service/sockets/sockets.cpp b/src/core/hle/service/sockets/sockets.cpp
index 1d27f7906..96f73bce3 100644
--- a/src/core/hle/service/sockets/sockets.cpp
+++ b/src/core/hle/service/sockets/sockets.cpp
@@ -13,15 +13,15 @@ namespace Service::Sockets {
13void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { 13void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
14 std::make_shared<BSD>(system, "bsd:s")->InstallAsService(service_manager); 14 std::make_shared<BSD>(system, "bsd:s")->InstallAsService(service_manager);
15 std::make_shared<BSD>(system, "bsd:u")->InstallAsService(service_manager); 15 std::make_shared<BSD>(system, "bsd:u")->InstallAsService(service_manager);
16 std::make_shared<BSDCFG>()->InstallAsService(service_manager); 16 std::make_shared<BSDCFG>(system)->InstallAsService(service_manager);
17 17
18 std::make_shared<ETHC_C>()->InstallAsService(service_manager); 18 std::make_shared<ETHC_C>(system)->InstallAsService(service_manager);
19 std::make_shared<ETHC_I>()->InstallAsService(service_manager); 19 std::make_shared<ETHC_I>(system)->InstallAsService(service_manager);
20 20
21 std::make_shared<NSD>("nsd:a")->InstallAsService(service_manager); 21 std::make_shared<NSD>(system, "nsd:a")->InstallAsService(service_manager);
22 std::make_shared<NSD>("nsd:u")->InstallAsService(service_manager); 22 std::make_shared<NSD>(system, "nsd:u")->InstallAsService(service_manager);
23 23
24 std::make_shared<SFDNSRES>()->InstallAsService(service_manager); 24 std::make_shared<SFDNSRES>(system)->InstallAsService(service_manager);
25} 25}
26 26
27} // namespace Service::Sockets 27} // namespace Service::Sockets
diff --git a/src/core/hle/service/sockets/sockets.h b/src/core/hle/service/sockets/sockets.h
index 89a410076..5a65ed2a9 100644
--- a/src/core/hle/service/sockets/sockets.h
+++ b/src/core/hle/service/sockets/sockets.h
@@ -69,10 +69,22 @@ struct SockAddrIn {
69 std::array<u8, 8> zeroes; 69 std::array<u8, 8> zeroes;
70}; 70};
71 71
72enum class PollEvents : u16 {
73 // Using Pascal case because IN is a macro on Windows.
74 In = 1 << 0,
75 Pri = 1 << 1,
76 Out = 1 << 2,
77 Err = 1 << 3,
78 Hup = 1 << 4,
79 Nval = 1 << 5,
80};
81
82DECLARE_ENUM_FLAG_OPERATORS(PollEvents);
83
72struct PollFD { 84struct PollFD {
73 s32 fd; 85 s32 fd;
74 u16 events; 86 PollEvents events;
75 u16 revents; 87 PollEvents revents;
76}; 88};
77 89
78struct Linger { 90struct Linger {
@@ -80,13 +92,6 @@ struct Linger {
80 u32 linger; 92 u32 linger;
81}; 93};
82 94
83constexpr u16 POLL_IN = 0x01;
84constexpr u16 POLL_PRI = 0x02;
85constexpr u16 POLL_OUT = 0x04;
86constexpr u16 POLL_ERR = 0x08;
87constexpr u16 POLL_HUP = 0x10;
88constexpr u16 POLL_NVAL = 0x20;
89
90constexpr u32 FLAG_MSG_DONTWAIT = 0x80; 95constexpr u32 FLAG_MSG_DONTWAIT = 0x80;
91 96
92constexpr u32 FLAG_O_NONBLOCK = 0x800; 97constexpr u32 FLAG_O_NONBLOCK = 0x800;
diff --git a/src/core/hle/service/sockets/sockets_translate.cpp b/src/core/hle/service/sockets/sockets_translate.cpp
index 139743e1d..ca61d72ca 100644
--- a/src/core/hle/service/sockets/sockets_translate.cpp
+++ b/src/core/hle/service/sockets/sockets_translate.cpp
@@ -27,7 +27,7 @@ Errno Translate(Network::Errno value) {
27 case Network::Errno::NOTCONN: 27 case Network::Errno::NOTCONN:
28 return Errno::NOTCONN; 28 return Errno::NOTCONN;
29 default: 29 default:
30 UNIMPLEMENTED_MSG("Unimplemented errno={}", static_cast<int>(value)); 30 UNIMPLEMENTED_MSG("Unimplemented errno={}", value);
31 return Errno::SUCCESS; 31 return Errno::SUCCESS;
32 } 32 }
33} 33}
@@ -41,7 +41,7 @@ Network::Domain Translate(Domain domain) {
41 case Domain::INET: 41 case Domain::INET:
42 return Network::Domain::INET; 42 return Network::Domain::INET;
43 default: 43 default:
44 UNIMPLEMENTED_MSG("Unimplemented domain={}", static_cast<int>(domain)); 44 UNIMPLEMENTED_MSG("Unimplemented domain={}", domain);
45 return {}; 45 return {};
46 } 46 }
47} 47}
@@ -51,7 +51,7 @@ Domain Translate(Network::Domain domain) {
51 case Network::Domain::INET: 51 case Network::Domain::INET:
52 return Domain::INET; 52 return Domain::INET;
53 default: 53 default:
54 UNIMPLEMENTED_MSG("Unimplemented domain={}", static_cast<int>(domain)); 54 UNIMPLEMENTED_MSG("Unimplemented domain={}", domain);
55 return {}; 55 return {};
56 } 56 }
57} 57}
@@ -63,7 +63,8 @@ Network::Type Translate(Type type) {
63 case Type::DGRAM: 63 case Type::DGRAM:
64 return Network::Type::DGRAM; 64 return Network::Type::DGRAM;
65 default: 65 default:
66 UNIMPLEMENTED_MSG("Unimplemented type={}", static_cast<int>(type)); 66 UNIMPLEMENTED_MSG("Unimplemented type={}", type);
67 return Network::Type{};
67 } 68 }
68} 69}
69 70
@@ -84,47 +85,47 @@ Network::Protocol Translate(Type type, Protocol protocol) {
84 case Protocol::UDP: 85 case Protocol::UDP:
85 return Network::Protocol::UDP; 86 return Network::Protocol::UDP;
86 default: 87 default:
87 UNIMPLEMENTED_MSG("Unimplemented protocol={}", static_cast<int>(protocol)); 88 UNIMPLEMENTED_MSG("Unimplemented protocol={}", protocol);
88 return Network::Protocol::TCP; 89 return Network::Protocol::TCP;
89 } 90 }
90} 91}
91 92
92u16 TranslatePollEventsToHost(u16 flags) { 93Network::PollEvents TranslatePollEventsToHost(PollEvents flags) {
93 u16 result = 0; 94 Network::PollEvents result{};
94 const auto translate = [&result, &flags](u16 from, u16 to) { 95 const auto translate = [&result, &flags](PollEvents from, Network::PollEvents to) {
95 if ((flags & from) != 0) { 96 if (True(flags & from)) {
96 flags &= ~from; 97 flags &= ~from;
97 result |= to; 98 result |= to;
98 } 99 }
99 }; 100 };
100 translate(POLL_IN, Network::POLL_IN); 101 translate(PollEvents::In, Network::PollEvents::In);
101 translate(POLL_PRI, Network::POLL_PRI); 102 translate(PollEvents::Pri, Network::PollEvents::Pri);
102 translate(POLL_OUT, Network::POLL_OUT); 103 translate(PollEvents::Out, Network::PollEvents::Out);
103 translate(POLL_ERR, Network::POLL_ERR); 104 translate(PollEvents::Err, Network::PollEvents::Err);
104 translate(POLL_HUP, Network::POLL_HUP); 105 translate(PollEvents::Hup, Network::PollEvents::Hup);
105 translate(POLL_NVAL, Network::POLL_NVAL); 106 translate(PollEvents::Nval, Network::PollEvents::Nval);
106 107
107 UNIMPLEMENTED_IF_MSG(flags != 0, "Unimplemented flags={}", flags); 108 UNIMPLEMENTED_IF_MSG((u16)flags != 0, "Unimplemented flags={}", (u16)flags);
108 return result; 109 return result;
109} 110}
110 111
111u16 TranslatePollEventsToGuest(u16 flags) { 112PollEvents TranslatePollEventsToGuest(Network::PollEvents flags) {
112 u16 result = 0; 113 PollEvents result{};
113 const auto translate = [&result, &flags](u16 from, u16 to) { 114 const auto translate = [&result, &flags](Network::PollEvents from, PollEvents to) {
114 if ((flags & from) != 0) { 115 if (True(flags & from)) {
115 flags &= ~from; 116 flags &= ~from;
116 result |= to; 117 result |= to;
117 } 118 }
118 }; 119 };
119 120
120 translate(Network::POLL_IN, POLL_IN); 121 translate(Network::PollEvents::In, PollEvents::In);
121 translate(Network::POLL_PRI, POLL_PRI); 122 translate(Network::PollEvents::Pri, PollEvents::Pri);
122 translate(Network::POLL_OUT, POLL_OUT); 123 translate(Network::PollEvents::Out, PollEvents::Out);
123 translate(Network::POLL_ERR, POLL_ERR); 124 translate(Network::PollEvents::Err, PollEvents::Err);
124 translate(Network::POLL_HUP, POLL_HUP); 125 translate(Network::PollEvents::Hup, PollEvents::Hup);
125 translate(Network::POLL_NVAL, POLL_NVAL); 126 translate(Network::PollEvents::Nval, PollEvents::Nval);
126 127
127 UNIMPLEMENTED_IF_MSG(flags != 0, "Unimplemented flags={}", flags); 128 UNIMPLEMENTED_IF_MSG((u16)flags != 0, "Unimplemented flags={}", (u16)flags);
128 return result; 129 return result;
129} 130}
130 131
@@ -157,7 +158,7 @@ Network::ShutdownHow Translate(ShutdownHow how) {
157 case ShutdownHow::RDWR: 158 case ShutdownHow::RDWR:
158 return Network::ShutdownHow::RDWR; 159 return Network::ShutdownHow::RDWR;
159 default: 160 default:
160 UNIMPLEMENTED_MSG("Unimplemented how={}", static_cast<int>(how)); 161 UNIMPLEMENTED_MSG("Unimplemented how={}", how);
161 return {}; 162 return {};
162 } 163 }
163} 164}
diff --git a/src/core/hle/service/sockets/sockets_translate.h b/src/core/hle/service/sockets/sockets_translate.h
index 8ed041e31..057d1ff22 100644
--- a/src/core/hle/service/sockets/sockets_translate.h
+++ b/src/core/hle/service/sockets/sockets_translate.h
@@ -31,10 +31,10 @@ Network::Type Translate(Type type);
31Network::Protocol Translate(Type type, Protocol protocol); 31Network::Protocol Translate(Type type, Protocol protocol);
32 32
33/// Translate abstract poll event flags to guest poll event flags 33/// Translate abstract poll event flags to guest poll event flags
34u16 TranslatePollEventsToHost(u16 flags); 34Network::PollEvents TranslatePollEventsToHost(PollEvents flags);
35 35
36/// Translate guest poll event flags to abstract poll event flags 36/// Translate guest poll event flags to abstract poll event flags
37u16 TranslatePollEventsToGuest(u16 flags); 37PollEvents TranslatePollEventsToGuest(Network::PollEvents flags);
38 38
39/// Translate guest socket address structure to abstract socket address structure 39/// Translate guest socket address structure to abstract socket address structure
40Network::SockAddrIn Translate(SockAddrIn value); 40Network::SockAddrIn Translate(SockAddrIn value);
diff --git a/src/core/hle/service/spl/csrng.cpp b/src/core/hle/service/spl/csrng.cpp
index 674928798..1beca417c 100644
--- a/src/core/hle/service/spl/csrng.cpp
+++ b/src/core/hle/service/spl/csrng.cpp
@@ -6,7 +6,8 @@
6 6
7namespace Service::SPL { 7namespace Service::SPL {
8 8
9CSRNG::CSRNG(std::shared_ptr<Module> module) : Module::Interface(std::move(module), "csrng") { 9CSRNG::CSRNG(Core::System& system_, std::shared_ptr<Module> module_)
10 : Interface(system_, std::move(module_), "csrng") {
10 static const FunctionInfo functions[] = { 11 static const FunctionInfo functions[] = {
11 {0, &CSRNG::GetRandomBytes, "GetRandomBytes"}, 12 {0, &CSRNG::GetRandomBytes, "GetRandomBytes"},
12 }; 13 };
diff --git a/src/core/hle/service/spl/csrng.h b/src/core/hle/service/spl/csrng.h
index 764d5ceb0..5c0bd2199 100644
--- a/src/core/hle/service/spl/csrng.h
+++ b/src/core/hle/service/spl/csrng.h
@@ -6,11 +6,15 @@
6 6
7#include "core/hle/service/spl/module.h" 7#include "core/hle/service/spl/module.h"
8 8
9namespace Core {
10class System;
11}
12
9namespace Service::SPL { 13namespace Service::SPL {
10 14
11class CSRNG final : public Module::Interface { 15class CSRNG final : public Module::Interface {
12public: 16public:
13 explicit CSRNG(std::shared_ptr<Module> module); 17 explicit CSRNG(Core::System& system_, std::shared_ptr<Module> module_);
14 ~CSRNG() override; 18 ~CSRNG() override;
15}; 19};
16 20
diff --git a/src/core/hle/service/spl/module.cpp b/src/core/hle/service/spl/module.cpp
index 865ed3b91..dea6b0fe0 100644
--- a/src/core/hle/service/spl/module.cpp
+++ b/src/core/hle/service/spl/module.cpp
@@ -17,8 +17,9 @@
17 17
18namespace Service::SPL { 18namespace Service::SPL {
19 19
20Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) 20Module::Interface::Interface(Core::System& system_, std::shared_ptr<Module> module_,
21 : ServiceFramework(name), module(std::move(module)), 21 const char* name)
22 : ServiceFramework{system_, name}, module{std::move(module_)},
22 rng(Settings::values.rng_seed.GetValue().value_or(std::time(nullptr))) {} 23 rng(Settings::values.rng_seed.GetValue().value_or(std::time(nullptr))) {}
23 24
24Module::Interface::~Interface() = default; 25Module::Interface::~Interface() = default;
@@ -38,10 +39,10 @@ void Module::Interface::GetRandomBytes(Kernel::HLERequestContext& ctx) {
38 rb.Push(RESULT_SUCCESS); 39 rb.Push(RESULT_SUCCESS);
39} 40}
40 41
41void InstallInterfaces(SM::ServiceManager& service_manager) { 42void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
42 auto module = std::make_shared<Module>(); 43 auto module = std::make_shared<Module>();
43 std::make_shared<CSRNG>(module)->InstallAsService(service_manager); 44 std::make_shared<CSRNG>(system, module)->InstallAsService(service_manager);
44 std::make_shared<SPL>(module)->InstallAsService(service_manager); 45 std::make_shared<SPL>(system, module)->InstallAsService(service_manager);
45} 46}
46 47
47} // namespace Service::SPL 48} // namespace Service::SPL
diff --git a/src/core/hle/service/spl/module.h b/src/core/hle/service/spl/module.h
index afa1f0295..71855c1bf 100644
--- a/src/core/hle/service/spl/module.h
+++ b/src/core/hle/service/spl/module.h
@@ -7,13 +7,18 @@
7#include <random> 7#include <random>
8#include "core/hle/service/service.h" 8#include "core/hle/service/service.h"
9 9
10namespace Core {
11class System;
12}
13
10namespace Service::SPL { 14namespace Service::SPL {
11 15
12class Module final { 16class Module final {
13public: 17public:
14 class Interface : public ServiceFramework<Interface> { 18 class Interface : public ServiceFramework<Interface> {
15 public: 19 public:
16 explicit Interface(std::shared_ptr<Module> module, const char* name); 20 explicit Interface(Core::System& system_, std::shared_ptr<Module> module_,
21 const char* name);
17 ~Interface() override; 22 ~Interface() override;
18 23
19 void GetRandomBytes(Kernel::HLERequestContext& ctx); 24 void GetRandomBytes(Kernel::HLERequestContext& ctx);
@@ -27,6 +32,6 @@ public:
27}; 32};
28 33
29/// Registers all SPL services with the specified service manager. 34/// Registers all SPL services with the specified service manager.
30void InstallInterfaces(SM::ServiceManager& service_manager); 35void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system);
31 36
32} // namespace Service::SPL 37} // namespace Service::SPL
diff --git a/src/core/hle/service/spl/spl.cpp b/src/core/hle/service/spl/spl.cpp
index 773551464..3fabc2c79 100644
--- a/src/core/hle/service/spl/spl.cpp
+++ b/src/core/hle/service/spl/spl.cpp
@@ -6,7 +6,8 @@
6 6
7namespace Service::SPL { 7namespace Service::SPL {
8 8
9SPL::SPL(std::shared_ptr<Module> module) : Module::Interface(std::move(module), "spl:") { 9SPL::SPL(Core::System& system_, std::shared_ptr<Module> module_)
10 : Interface(system_, std::move(module_), "spl:") {
10 static const FunctionInfo functions[] = { 11 static const FunctionInfo functions[] = {
11 {0, nullptr, "GetConfig"}, 12 {0, nullptr, "GetConfig"},
12 {1, nullptr, "ModularExponentiate"}, 13 {1, nullptr, "ModularExponentiate"},
diff --git a/src/core/hle/service/spl/spl.h b/src/core/hle/service/spl/spl.h
index 3637d1623..d27d16b86 100644
--- a/src/core/hle/service/spl/spl.h
+++ b/src/core/hle/service/spl/spl.h
@@ -6,11 +6,15 @@
6 6
7#include "core/hle/service/spl/module.h" 7#include "core/hle/service/spl/module.h"
8 8
9namespace Core {
10class System;
11}
12
9namespace Service::SPL { 13namespace Service::SPL {
10 14
11class SPL final : public Module::Interface { 15class SPL final : public Module::Interface {
12public: 16public:
13 explicit SPL(std::shared_ptr<Module> module); 17 explicit SPL(Core::System& system_, std::shared_ptr<Module> module_);
14 ~SPL() override; 18 ~SPL() override;
15}; 19};
16 20
diff --git a/src/core/hle/service/ssl/ssl.cpp b/src/core/hle/service/ssl/ssl.cpp
index 1ba8c19a0..dc2baca4a 100644
--- a/src/core/hle/service/ssl/ssl.cpp
+++ b/src/core/hle/service/ssl/ssl.cpp
@@ -12,7 +12,7 @@ namespace Service::SSL {
12 12
13class ISslConnection final : public ServiceFramework<ISslConnection> { 13class ISslConnection final : public ServiceFramework<ISslConnection> {
14public: 14public:
15 ISslConnection() : ServiceFramework("ISslConnection") { 15 explicit ISslConnection(Core::System& system_) : ServiceFramework{system_, "ISslConnection"} {
16 // clang-format off 16 // clang-format off
17 static const FunctionInfo functions[] = { 17 static const FunctionInfo functions[] = {
18 {0, nullptr, "SetSocketDescriptor"}, 18 {0, nullptr, "SetSocketDescriptor"},
@@ -52,7 +52,7 @@ public:
52 52
53class ISslContext final : public ServiceFramework<ISslContext> { 53class ISslContext final : public ServiceFramework<ISslContext> {
54public: 54public:
55 ISslContext() : ServiceFramework("ISslContext") { 55 explicit ISslContext(Core::System& system_) : ServiceFramework{system_, "ISslContext"} {
56 static const FunctionInfo functions[] = { 56 static const FunctionInfo functions[] = {
57 {0, &ISslContext::SetOption, "SetOption"}, 57 {0, &ISslContext::SetOption, "SetOption"},
58 {1, nullptr, "GetOption"}, 58 {1, nullptr, "GetOption"},
@@ -92,13 +92,13 @@ private:
92 92
93 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 93 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
94 rb.Push(RESULT_SUCCESS); 94 rb.Push(RESULT_SUCCESS);
95 rb.PushIpcInterface<ISslConnection>(); 95 rb.PushIpcInterface<ISslConnection>(system);
96 } 96 }
97}; 97};
98 98
99class SSL final : public ServiceFramework<SSL> { 99class SSL final : public ServiceFramework<SSL> {
100public: 100public:
101 explicit SSL() : ServiceFramework{"ssl"} { 101 explicit SSL(Core::System& system_) : ServiceFramework{system_, "ssl"} {
102 // clang-format off 102 // clang-format off
103 static const FunctionInfo functions[] = { 103 static const FunctionInfo functions[] = {
104 {0, &SSL::CreateContext, "CreateContext"}, 104 {0, &SSL::CreateContext, "CreateContext"},
@@ -123,7 +123,7 @@ private:
123 123
124 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 124 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
125 rb.Push(RESULT_SUCCESS); 125 rb.Push(RESULT_SUCCESS);
126 rb.PushIpcInterface<ISslContext>(); 126 rb.PushIpcInterface<ISslContext>(system);
127 } 127 }
128 128
129 void SetInterfaceVersion(Kernel::HLERequestContext& ctx) { 129 void SetInterfaceVersion(Kernel::HLERequestContext& ctx) {
@@ -137,8 +137,8 @@ private:
137 } 137 }
138}; 138};
139 139
140void InstallInterfaces(SM::ServiceManager& service_manager) { 140void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
141 std::make_shared<SSL>()->InstallAsService(service_manager); 141 std::make_shared<SSL>(system)->InstallAsService(service_manager);
142} 142}
143 143
144} // namespace Service::SSL 144} // namespace Service::SSL
diff --git a/src/core/hle/service/ssl/ssl.h b/src/core/hle/service/ssl/ssl.h
index 5cb04c3b9..a3aa4b4b5 100644
--- a/src/core/hle/service/ssl/ssl.h
+++ b/src/core/hle/service/ssl/ssl.h
@@ -4,6 +4,10 @@
4 4
5#pragma once 5#pragma once
6 6
7namespace Core {
8class System;
9}
10
7namespace Service::SM { 11namespace Service::SM {
8class ServiceManager; 12class ServiceManager;
9} 13}
@@ -11,6 +15,6 @@ class ServiceManager;
11namespace Service::SSL { 15namespace Service::SSL {
12 16
13/// Registers all SSL services with the specified service manager. 17/// Registers all SSL services with the specified service manager.
14void InstallInterfaces(SM::ServiceManager& service_manager); 18void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system);
15 19
16} // namespace Service::SSL 20} // namespace Service::SSL
diff --git a/src/core/hle/service/time/interface.cpp b/src/core/hle/service/time/interface.cpp
index ba8fd6152..a01d9e0ff 100644
--- a/src/core/hle/service/time/interface.cpp
+++ b/src/core/hle/service/time/interface.cpp
@@ -7,7 +7,7 @@
7namespace Service::Time { 7namespace Service::Time {
8 8
9Time::Time(std::shared_ptr<Module> module, Core::System& system, const char* name) 9Time::Time(std::shared_ptr<Module> module, Core::System& system, const char* name)
10 : Module::Interface(std::move(module), system, name) { 10 : Interface(std::move(module), system, name) {
11 // clang-format off 11 // clang-format off
12 static const FunctionInfo functions[] = { 12 static const FunctionInfo functions[] = {
13 {0, &Time::GetStandardUserSystemClock, "GetStandardUserSystemClock"}, 13 {0, &Time::GetStandardUserSystemClock, "GetStandardUserSystemClock"},
diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp
index ee4fa4b48..abc753d5d 100644
--- a/src/core/hle/service/time/time.cpp
+++ b/src/core/hle/service/time/time.cpp
@@ -10,7 +10,8 @@
10#include "core/hle/ipc_helpers.h" 10#include "core/hle/ipc_helpers.h"
11#include "core/hle/kernel/client_port.h" 11#include "core/hle/kernel/client_port.h"
12#include "core/hle/kernel/client_session.h" 12#include "core/hle/kernel/client_session.h"
13#include "core/hle/kernel/scheduler.h" 13#include "core/hle/kernel/k_scheduler.h"
14#include "core/hle/kernel/kernel.h"
14#include "core/hle/service/time/interface.h" 15#include "core/hle/service/time/interface.h"
15#include "core/hle/service/time/time.h" 16#include "core/hle/service/time/time.h"
16#include "core/hle/service/time/time_sharedmemory.h" 17#include "core/hle/service/time/time_sharedmemory.h"
@@ -20,8 +21,8 @@ namespace Service::Time {
20 21
21class ISystemClock final : public ServiceFramework<ISystemClock> { 22class ISystemClock final : public ServiceFramework<ISystemClock> {
22public: 23public:
23 explicit ISystemClock(Clock::SystemClockCore& clock_core, Core::System& system) 24 explicit ISystemClock(Clock::SystemClockCore& clock_core_, Core::System& system_)
24 : ServiceFramework("ISystemClock"), clock_core{clock_core}, system{system} { 25 : ServiceFramework{system_, "ISystemClock"}, clock_core{clock_core_} {
25 // clang-format off 26 // clang-format off
26 static const FunctionInfo functions[] = { 27 static const FunctionInfo functions[] = {
27 {0, &ISystemClock::GetCurrentTime, "GetCurrentTime"}, 28 {0, &ISystemClock::GetCurrentTime, "GetCurrentTime"},
@@ -81,13 +82,12 @@ private:
81 } 82 }
82 83
83 Clock::SystemClockCore& clock_core; 84 Clock::SystemClockCore& clock_core;
84 Core::System& system;
85}; 85};
86 86
87class ISteadyClock final : public ServiceFramework<ISteadyClock> { 87class ISteadyClock final : public ServiceFramework<ISteadyClock> {
88public: 88public:
89 explicit ISteadyClock(Clock::SteadyClockCore& clock_core, Core::System& system) 89 explicit ISteadyClock(Clock::SteadyClockCore& clock_core_, Core::System& system_)
90 : ServiceFramework("ISteadyClock"), clock_core{clock_core}, system{system} { 90 : ServiceFramework{system_, "ISteadyClock"}, clock_core{clock_core_} {
91 static const FunctionInfo functions[] = { 91 static const FunctionInfo functions[] = {
92 {0, &ISteadyClock::GetCurrentTimePoint, "GetCurrentTimePoint"}, 92 {0, &ISteadyClock::GetCurrentTimePoint, "GetCurrentTimePoint"},
93 {2, nullptr, "GetTestOffset"}, 93 {2, nullptr, "GetTestOffset"},
@@ -118,14 +118,13 @@ private:
118 } 118 }
119 119
120 Clock::SteadyClockCore& clock_core; 120 Clock::SteadyClockCore& clock_core;
121 Core::System& system;
122}; 121};
123 122
124ResultCode Module::Interface::GetClockSnapshotFromSystemClockContextInternal( 123ResultCode Module::Interface::GetClockSnapshotFromSystemClockContextInternal(
125 Kernel::Thread* thread, Clock::SystemClockContext user_context, 124 Kernel::Thread* thread, Clock::SystemClockContext user_context,
126 Clock::SystemClockContext network_context, u8 type, Clock::ClockSnapshot& clock_snapshot) { 125 Clock::SystemClockContext network_context, u8 type, Clock::ClockSnapshot& clock_snapshot) {
127 126
128 auto& time_manager{module->GetTimeManager()}; 127 auto& time_manager{system.GetTimeManager()};
129 128
130 clock_snapshot.is_automatic_correction_enabled = 129 clock_snapshot.is_automatic_correction_enabled =
131 time_manager.GetStandardUserSystemClockCore().IsAutomaticCorrectionEnabled(); 130 time_manager.GetStandardUserSystemClockCore().IsAutomaticCorrectionEnabled();
@@ -182,7 +181,7 @@ void Module::Interface::GetStandardUserSystemClock(Kernel::HLERequestContext& ct
182 LOG_DEBUG(Service_Time, "called"); 181 LOG_DEBUG(Service_Time, "called");
183 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 182 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
184 rb.Push(RESULT_SUCCESS); 183 rb.Push(RESULT_SUCCESS);
185 rb.PushIpcInterface<ISystemClock>(module->GetTimeManager().GetStandardUserSystemClockCore(), 184 rb.PushIpcInterface<ISystemClock>(system.GetTimeManager().GetStandardUserSystemClockCore(),
186 system); 185 system);
187} 186}
188 187
@@ -190,7 +189,7 @@ void Module::Interface::GetStandardNetworkSystemClock(Kernel::HLERequestContext&
190 LOG_DEBUG(Service_Time, "called"); 189 LOG_DEBUG(Service_Time, "called");
191 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 190 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
192 rb.Push(RESULT_SUCCESS); 191 rb.Push(RESULT_SUCCESS);
193 rb.PushIpcInterface<ISystemClock>(module->GetTimeManager().GetStandardNetworkSystemClockCore(), 192 rb.PushIpcInterface<ISystemClock>(system.GetTimeManager().GetStandardNetworkSystemClockCore(),
194 system); 193 system);
195} 194}
196 195
@@ -198,29 +197,29 @@ void Module::Interface::GetStandardSteadyClock(Kernel::HLERequestContext& ctx) {
198 LOG_DEBUG(Service_Time, "called"); 197 LOG_DEBUG(Service_Time, "called");
199 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 198 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
200 rb.Push(RESULT_SUCCESS); 199 rb.Push(RESULT_SUCCESS);
201 rb.PushIpcInterface<ISteadyClock>(module->GetTimeManager().GetStandardSteadyClockCore(), 200 rb.PushIpcInterface<ISteadyClock>(system.GetTimeManager().GetStandardSteadyClockCore(), system);
202 system);
203} 201}
204 202
205void Module::Interface::GetTimeZoneService(Kernel::HLERequestContext& ctx) { 203void Module::Interface::GetTimeZoneService(Kernel::HLERequestContext& ctx) {
206 LOG_DEBUG(Service_Time, "called"); 204 LOG_DEBUG(Service_Time, "called");
207 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 205 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
208 rb.Push(RESULT_SUCCESS); 206 rb.Push(RESULT_SUCCESS);
209 rb.PushIpcInterface<ITimeZoneService>(module->GetTimeManager().GetTimeZoneContentManager()); 207 rb.PushIpcInterface<ITimeZoneService>(system,
208 system.GetTimeManager().GetTimeZoneContentManager());
210} 209}
211 210
212void Module::Interface::GetStandardLocalSystemClock(Kernel::HLERequestContext& ctx) { 211void Module::Interface::GetStandardLocalSystemClock(Kernel::HLERequestContext& ctx) {
213 LOG_DEBUG(Service_Time, "called"); 212 LOG_DEBUG(Service_Time, "called");
214 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 213 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
215 rb.Push(RESULT_SUCCESS); 214 rb.Push(RESULT_SUCCESS);
216 rb.PushIpcInterface<ISystemClock>(module->GetTimeManager().GetStandardLocalSystemClockCore(), 215 rb.PushIpcInterface<ISystemClock>(system.GetTimeManager().GetStandardLocalSystemClockCore(),
217 system); 216 system);
218} 217}
219 218
220void Module::Interface::IsStandardNetworkSystemClockAccuracySufficient( 219void Module::Interface::IsStandardNetworkSystemClockAccuracySufficient(
221 Kernel::HLERequestContext& ctx) { 220 Kernel::HLERequestContext& ctx) {
222 LOG_DEBUG(Service_Time, "called"); 221 LOG_DEBUG(Service_Time, "called");
223 auto& clock_core{module->GetTimeManager().GetStandardNetworkSystemClockCore()}; 222 auto& clock_core{system.GetTimeManager().GetStandardNetworkSystemClockCore()};
224 IPC::ResponseBuilder rb{ctx, 3}; 223 IPC::ResponseBuilder rb{ctx, 3};
225 rb.Push(RESULT_SUCCESS); 224 rb.Push(RESULT_SUCCESS);
226 rb.Push<u32>(clock_core.IsStandardNetworkSystemClockAccuracySufficient(system)); 225 rb.Push<u32>(clock_core.IsStandardNetworkSystemClockAccuracySufficient(system));
@@ -229,7 +228,7 @@ void Module::Interface::IsStandardNetworkSystemClockAccuracySufficient(
229void Module::Interface::CalculateMonotonicSystemClockBaseTimePoint(Kernel::HLERequestContext& ctx) { 228void Module::Interface::CalculateMonotonicSystemClockBaseTimePoint(Kernel::HLERequestContext& ctx) {
230 LOG_DEBUG(Service_Time, "called"); 229 LOG_DEBUG(Service_Time, "called");
231 230
232 auto& steady_clock_core{module->GetTimeManager().GetStandardSteadyClockCore()}; 231 auto& steady_clock_core{system.GetTimeManager().GetStandardSteadyClockCore()};
233 if (!steady_clock_core.IsInitialized()) { 232 if (!steady_clock_core.IsInitialized()) {
234 IPC::ResponseBuilder rb{ctx, 2}; 233 IPC::ResponseBuilder rb{ctx, 2};
235 rb.Push(ERROR_UNINITIALIZED_CLOCK); 234 rb.Push(ERROR_UNINITIALIZED_CLOCK);
@@ -262,8 +261,8 @@ void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) {
262 261
263 Clock::SystemClockContext user_context{}; 262 Clock::SystemClockContext user_context{};
264 if (const ResultCode result{ 263 if (const ResultCode result{
265 module->GetTimeManager().GetStandardUserSystemClockCore().GetClockContext( 264 system.GetTimeManager().GetStandardUserSystemClockCore().GetClockContext(system,
266 system, user_context)}; 265 user_context)};
267 result.IsError()) { 266 result.IsError()) {
268 IPC::ResponseBuilder rb{ctx, 2}; 267 IPC::ResponseBuilder rb{ctx, 2};
269 rb.Push(result); 268 rb.Push(result);
@@ -271,7 +270,7 @@ void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) {
271 } 270 }
272 Clock::SystemClockContext network_context{}; 271 Clock::SystemClockContext network_context{};
273 if (const ResultCode result{ 272 if (const ResultCode result{
274 module->GetTimeManager().GetStandardNetworkSystemClockCore().GetClockContext( 273 system.GetTimeManager().GetStandardNetworkSystemClockCore().GetClockContext(
275 system, network_context)}; 274 system, network_context)};
276 result.IsError()) { 275 result.IsError()) {
277 IPC::ResponseBuilder rb{ctx, 2}; 276 IPC::ResponseBuilder rb{ctx, 2};
@@ -372,16 +371,17 @@ void Module::Interface::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& c
372 LOG_DEBUG(Service_Time, "called"); 371 LOG_DEBUG(Service_Time, "called");
373 IPC::ResponseBuilder rb{ctx, 2, 1}; 372 IPC::ResponseBuilder rb{ctx, 2, 1};
374 rb.Push(RESULT_SUCCESS); 373 rb.Push(RESULT_SUCCESS);
375 rb.PushCopyObjects(module->GetTimeManager().GetSharedMemory().GetSharedMemoryHolder()); 374 rb.PushCopyObjects(SharedFrom(&system.Kernel().GetTimeSharedMem()));
376} 375}
377 376
378Module::Interface::Interface(std::shared_ptr<Module> module, Core::System& system, const char* name) 377Module::Interface::Interface(std::shared_ptr<Module> module_, Core::System& system_,
379 : ServiceFramework(name), module{std::move(module)}, system{system} {} 378 const char* name)
379 : ServiceFramework{system_, name}, module{std::move(module_)} {}
380 380
381Module::Interface::~Interface() = default; 381Module::Interface::~Interface() = default;
382 382
383void InstallInterfaces(Core::System& system) { 383void InstallInterfaces(Core::System& system) {
384 auto module{std::make_shared<Module>(system)}; 384 auto module{std::make_shared<Module>()};
385 std::make_shared<Time>(module, system, "time:a")->InstallAsService(system.ServiceManager()); 385 std::make_shared<Time>(module, system, "time:a")->InstallAsService(system.ServiceManager());
386 std::make_shared<Time>(module, system, "time:s")->InstallAsService(system.ServiceManager()); 386 std::make_shared<Time>(module, system, "time:s")->InstallAsService(system.ServiceManager());
387 std::make_shared<Time>(module, system, "time:u")->InstallAsService(system.ServiceManager()); 387 std::make_shared<Time>(module, system, "time:u")->InstallAsService(system.ServiceManager());
diff --git a/src/core/hle/service/time/time.h b/src/core/hle/service/time/time.h
index 41f3002e9..975a8ae5b 100644
--- a/src/core/hle/service/time/time.h
+++ b/src/core/hle/service/time/time.h
@@ -16,11 +16,12 @@ namespace Service::Time {
16 16
17class Module final { 17class Module final {
18public: 18public:
19 Module(Core::System& system) : time_manager{system} {} 19 Module() = default;
20 20
21 class Interface : public ServiceFramework<Interface> { 21 class Interface : public ServiceFramework<Interface> {
22 public: 22 public:
23 explicit Interface(std::shared_ptr<Module> module, Core::System& system, const char* name); 23 explicit Interface(std::shared_ptr<Module> module_, Core::System& system_,
24 const char* name);
24 ~Interface() override; 25 ~Interface() override;
25 26
26 void GetStandardUserSystemClock(Kernel::HLERequestContext& ctx); 27 void GetStandardUserSystemClock(Kernel::HLERequestContext& ctx);
@@ -44,15 +45,7 @@ public:
44 45
45 protected: 46 protected:
46 std::shared_ptr<Module> module; 47 std::shared_ptr<Module> module;
47 Core::System& system;
48 }; 48 };
49
50 TimeManager& GetTimeManager() {
51 return time_manager;
52 }
53
54private:
55 TimeManager time_manager;
56}; 49};
57 50
58/// Registers all Time services with the specified service manager. 51/// Registers all Time services with the specified service manager.
diff --git a/src/core/hle/service/time/time_manager.cpp b/src/core/hle/service/time/time_manager.cpp
index b4dfe45e5..858623e2b 100644
--- a/src/core/hle/service/time/time_manager.cpp
+++ b/src/core/hle/service/time/time_manager.cpp
@@ -22,125 +22,282 @@ static std::chrono::seconds GetSecondsSinceEpoch() {
22 Settings::values.custom_rtc_differential; 22 Settings::values.custom_rtc_differential;
23} 23}
24 24
25static s64 GetExternalTimeZoneOffset() {
26 // With "auto" timezone setting, we use the external system's timezone offset
27 if (Settings::GetTimeZoneString() == "auto") {
28 return Common::TimeZone::GetCurrentOffsetSeconds().count();
29 }
30 return 0;
31}
32
33static s64 GetExternalRtcValue() { 25static s64 GetExternalRtcValue() {
34 return GetSecondsSinceEpoch().count() + GetExternalTimeZoneOffset(); 26 return GetSecondsSinceEpoch().count() + TimeManager::GetExternalTimeZoneOffset();
35}
36
37TimeManager::TimeManager(Core::System& system)
38 : shared_memory{system}, standard_local_system_clock_core{standard_steady_clock_core},
39 standard_network_system_clock_core{standard_steady_clock_core},
40 standard_user_system_clock_core{standard_local_system_clock_core,
41 standard_network_system_clock_core, system},
42 ephemeral_network_system_clock_core{tick_based_steady_clock_core},
43 local_system_clock_context_writer{
44 std::make_shared<Clock::LocalSystemClockContextWriter>(shared_memory)},
45 network_system_clock_context_writer{
46 std::make_shared<Clock::NetworkSystemClockContextWriter>(shared_memory)},
47 ephemeral_network_system_clock_context_writer{
48 std::make_shared<Clock::EphemeralNetworkSystemClockContextWriter>()},
49 time_zone_content_manager{*this, system} {
50
51 const auto system_time{Clock::TimeSpanType::FromSeconds(GetExternalRtcValue())};
52 SetupStandardSteadyClock(system, Common::UUID::Generate(), system_time, {}, {});
53 SetupStandardLocalSystemClock(system, {}, system_time.ToSeconds());
54 SetupStandardNetworkSystemClock({}, standard_network_clock_accuracy);
55 SetupStandardUserSystemClock(system, {}, Clock::SteadyClockTimePoint::GetRandom());
56 SetupEphemeralNetworkSystemClock();
57} 27}
58 28
59TimeManager::~TimeManager() = default; 29struct TimeManager::Impl final {
30 explicit Impl(Core::System& system)
31 : shared_memory{system}, standard_local_system_clock_core{standard_steady_clock_core},
32 standard_network_system_clock_core{standard_steady_clock_core},
33 standard_user_system_clock_core{standard_local_system_clock_core,
34 standard_network_system_clock_core, system},
35 ephemeral_network_system_clock_core{tick_based_steady_clock_core},
36 local_system_clock_context_writer{
37 std::make_shared<Clock::LocalSystemClockContextWriter>(shared_memory)},
38 network_system_clock_context_writer{
39 std::make_shared<Clock::NetworkSystemClockContextWriter>(shared_memory)},
40 ephemeral_network_system_clock_context_writer{
41 std::make_shared<Clock::EphemeralNetworkSystemClockContextWriter>()},
42 time_zone_content_manager{system} {
60 43
61void TimeManager::SetupTimeZoneManager(std::string location_name, 44 const auto system_time{Clock::TimeSpanType::FromSeconds(GetExternalRtcValue())};
62 Clock::SteadyClockTimePoint time_zone_updated_time_point, 45 SetupStandardSteadyClock(system, Common::UUID::Generate(), system_time, {}, {});
63 std::size_t total_location_name_count, 46 SetupStandardLocalSystemClock(system, {}, system_time.ToSeconds());
64 u128 time_zone_rule_version, 47 SetupStandardNetworkSystemClock({}, standard_network_clock_accuracy);
65 FileSys::VirtualFile& vfs_file) { 48 SetupStandardUserSystemClock(system, {}, Clock::SteadyClockTimePoint::GetRandom());
66 if (time_zone_content_manager.GetTimeZoneManager().SetDeviceLocationNameWithTimeZoneRule( 49 SetupEphemeralNetworkSystemClock();
67 location_name, vfs_file) != RESULT_SUCCESS) { 50 }
68 UNREACHABLE(); 51
69 return; 52 ~Impl() = default;
70 } 53
71 54 Clock::StandardSteadyClockCore& GetStandardSteadyClockCore() {
72 time_zone_content_manager.GetTimeZoneManager().SetUpdatedTime(time_zone_updated_time_point); 55 return standard_steady_clock_core;
73 time_zone_content_manager.GetTimeZoneManager().SetTotalLocationNameCount( 56 }
74 total_location_name_count); 57
75 time_zone_content_manager.GetTimeZoneManager().SetTimeZoneRuleVersion(time_zone_rule_version); 58 const Clock::StandardSteadyClockCore& GetStandardSteadyClockCore() const {
76 time_zone_content_manager.GetTimeZoneManager().MarkAsInitialized(); 59 return standard_steady_clock_core;
77} 60 }
78 61
79void TimeManager::SetupStandardSteadyClock(Core::System& system, Common::UUID clock_source_id, 62 Clock::StandardLocalSystemClockCore& GetStandardLocalSystemClockCore() {
80 Clock::TimeSpanType setup_value, 63 return standard_local_system_clock_core;
81 Clock::TimeSpanType internal_offset, 64 }
82 bool is_rtc_reset_detected) { 65
83 standard_steady_clock_core.SetClockSourceId(clock_source_id); 66 const Clock::StandardLocalSystemClockCore& GetStandardLocalSystemClockCore() const {
84 standard_steady_clock_core.SetSetupValue(setup_value); 67 return standard_local_system_clock_core;
85 standard_steady_clock_core.SetInternalOffset(internal_offset); 68 }
86 standard_steady_clock_core.MarkAsInitialized(); 69
87 70 Clock::StandardNetworkSystemClockCore& GetStandardNetworkSystemClockCore() {
88 const auto current_time_point{standard_steady_clock_core.GetCurrentRawTimePoint(system)}; 71 return standard_network_system_clock_core;
89 shared_memory.SetupStandardSteadyClock(system, clock_source_id, current_time_point); 72 }
90} 73
91 74 const Clock::StandardNetworkSystemClockCore& GetStandardNetworkSystemClockCore() const {
92void TimeManager::SetupStandardLocalSystemClock(Core::System& system, 75 return standard_network_system_clock_core;
93 Clock::SystemClockContext clock_context, 76 }
94 s64 posix_time) { 77
95 standard_local_system_clock_core.SetUpdateCallbackInstance(local_system_clock_context_writer); 78 Clock::StandardUserSystemClockCore& GetStandardUserSystemClockCore() {
96 79 return standard_user_system_clock_core;
97 const auto current_time_point{ 80 }
98 standard_local_system_clock_core.GetSteadyClockCore().GetCurrentTimePoint(system)}; 81
99 if (current_time_point.clock_source_id == clock_context.steady_time_point.clock_source_id) { 82 const Clock::StandardUserSystemClockCore& GetStandardUserSystemClockCore() const {
100 standard_local_system_clock_core.SetSystemClockContext(clock_context); 83 return standard_user_system_clock_core;
101 } else { 84 }
102 if (standard_local_system_clock_core.SetCurrentTime(system, posix_time) != RESULT_SUCCESS) { 85
86 TimeZone::TimeZoneContentManager& GetTimeZoneContentManager() {
87 return time_zone_content_manager;
88 }
89
90 const TimeZone::TimeZoneContentManager& GetTimeZoneContentManager() const {
91 return time_zone_content_manager;
92 }
93
94 SharedMemory& GetSharedMemory() {
95 return shared_memory;
96 }
97
98 const SharedMemory& GetSharedMemory() const {
99 return shared_memory;
100 }
101
102 void SetupTimeZoneManager(std::string location_name,
103 Clock::SteadyClockTimePoint time_zone_updated_time_point,
104 std::size_t total_location_name_count, u128 time_zone_rule_version,
105 FileSys::VirtualFile& vfs_file) {
106 if (time_zone_content_manager.GetTimeZoneManager().SetDeviceLocationNameWithTimeZoneRule(
107 location_name, vfs_file) != RESULT_SUCCESS) {
103 UNREACHABLE(); 108 UNREACHABLE();
104 return; 109 return;
105 } 110 }
111
112 time_zone_content_manager.GetTimeZoneManager().SetUpdatedTime(time_zone_updated_time_point);
113 time_zone_content_manager.GetTimeZoneManager().SetTotalLocationNameCount(
114 total_location_name_count);
115 time_zone_content_manager.GetTimeZoneManager().SetTimeZoneRuleVersion(
116 time_zone_rule_version);
117 time_zone_content_manager.GetTimeZoneManager().MarkAsInitialized();
106 } 118 }
107 119
108 standard_local_system_clock_core.MarkAsInitialized(); 120 static s64 GetExternalTimeZoneOffset() {
109} 121 // With "auto" timezone setting, we use the external system's timezone offset
122 if (Settings::GetTimeZoneString() == "auto") {
123 return Common::TimeZone::GetCurrentOffsetSeconds().count();
124 }
125 return 0;
126 }
110 127
111void TimeManager::SetupStandardNetworkSystemClock(Clock::SystemClockContext clock_context, 128 void SetupStandardSteadyClock(Core::System& system, Common::UUID clock_source_id,
112 Clock::TimeSpanType sufficient_accuracy) { 129 Clock::TimeSpanType setup_value,
113 standard_network_system_clock_core.SetUpdateCallbackInstance( 130 Clock::TimeSpanType internal_offset, bool is_rtc_reset_detected) {
114 network_system_clock_context_writer); 131 standard_steady_clock_core.SetClockSourceId(clock_source_id);
132 standard_steady_clock_core.SetSetupValue(setup_value);
133 standard_steady_clock_core.SetInternalOffset(internal_offset);
134 standard_steady_clock_core.MarkAsInitialized();
115 135
116 if (standard_network_system_clock_core.SetSystemClockContext(clock_context) != RESULT_SUCCESS) { 136 const auto current_time_point{standard_steady_clock_core.GetCurrentRawTimePoint(system)};
117 UNREACHABLE(); 137 shared_memory.SetupStandardSteadyClock(system, clock_source_id, current_time_point);
118 return;
119 } 138 }
120 139
121 standard_network_system_clock_core.SetStandardNetworkClockSufficientAccuracy( 140 void SetupStandardLocalSystemClock(Core::System& system,
122 sufficient_accuracy); 141 Clock::SystemClockContext clock_context, s64 posix_time) {
123 standard_network_system_clock_core.MarkAsInitialized(); 142 standard_local_system_clock_core.SetUpdateCallbackInstance(
124} 143 local_system_clock_context_writer);
144
145 const auto current_time_point{
146 standard_local_system_clock_core.GetSteadyClockCore().GetCurrentTimePoint(system)};
147 if (current_time_point.clock_source_id == clock_context.steady_time_point.clock_source_id) {
148 standard_local_system_clock_core.SetSystemClockContext(clock_context);
149 } else {
150 if (standard_local_system_clock_core.SetCurrentTime(system, posix_time) !=
151 RESULT_SUCCESS) {
152 UNREACHABLE();
153 return;
154 }
155 }
156
157 standard_local_system_clock_core.MarkAsInitialized();
158 }
159
160 void SetupStandardNetworkSystemClock(Clock::SystemClockContext clock_context,
161 Clock::TimeSpanType sufficient_accuracy) {
162 standard_network_system_clock_core.SetUpdateCallbackInstance(
163 network_system_clock_context_writer);
125 164
126void TimeManager::SetupStandardUserSystemClock( 165 if (standard_network_system_clock_core.SetSystemClockContext(clock_context) !=
127 Core::System& system, bool is_automatic_correction_enabled, 166 RESULT_SUCCESS) {
128 Clock::SteadyClockTimePoint steady_clock_time_point) { 167 UNREACHABLE();
129 if (standard_user_system_clock_core.SetAutomaticCorrectionEnabled( 168 return;
130 system, is_automatic_correction_enabled) != RESULT_SUCCESS) { 169 }
131 UNREACHABLE(); 170
132 return; 171 standard_network_system_clock_core.SetStandardNetworkClockSufficientAccuracy(
172 sufficient_accuracy);
173 standard_network_system_clock_core.MarkAsInitialized();
133 } 174 }
134 175
135 standard_user_system_clock_core.SetAutomaticCorrectionUpdatedTime(steady_clock_time_point); 176 void SetupStandardUserSystemClock(Core::System& system, bool is_automatic_correction_enabled,
136 standard_user_system_clock_core.MarkAsInitialized(); 177 Clock::SteadyClockTimePoint steady_clock_time_point) {
137 shared_memory.SetAutomaticCorrectionEnabled(is_automatic_correction_enabled); 178 if (standard_user_system_clock_core.SetAutomaticCorrectionEnabled(
179 system, is_automatic_correction_enabled) != RESULT_SUCCESS) {
180 UNREACHABLE();
181 return;
182 }
183
184 standard_user_system_clock_core.SetAutomaticCorrectionUpdatedTime(steady_clock_time_point);
185 standard_user_system_clock_core.MarkAsInitialized();
186 shared_memory.SetAutomaticCorrectionEnabled(is_automatic_correction_enabled);
187 }
188
189 void SetupEphemeralNetworkSystemClock() {
190 ephemeral_network_system_clock_core.SetUpdateCallbackInstance(
191 ephemeral_network_system_clock_context_writer);
192 ephemeral_network_system_clock_core.MarkAsInitialized();
193 }
194
195 void UpdateLocalSystemClockTime(Core::System& system, s64 posix_time) {
196 const auto timespan{Service::Time::Clock::TimeSpanType::FromSeconds(posix_time)};
197 if (GetStandardLocalSystemClockCore()
198 .SetCurrentTime(system, timespan.ToSeconds())
199 .IsError()) {
200 UNREACHABLE();
201 return;
202 }
203 }
204
205 SharedMemory shared_memory;
206
207 Clock::StandardSteadyClockCore standard_steady_clock_core;
208 Clock::TickBasedSteadyClockCore tick_based_steady_clock_core;
209 Clock::StandardLocalSystemClockCore standard_local_system_clock_core;
210 Clock::StandardNetworkSystemClockCore standard_network_system_clock_core;
211 Clock::StandardUserSystemClockCore standard_user_system_clock_core;
212 Clock::EphemeralNetworkSystemClockCore ephemeral_network_system_clock_core;
213
214 std::shared_ptr<Clock::LocalSystemClockContextWriter> local_system_clock_context_writer;
215 std::shared_ptr<Clock::NetworkSystemClockContextWriter> network_system_clock_context_writer;
216 std::shared_ptr<Clock::EphemeralNetworkSystemClockContextWriter>
217 ephemeral_network_system_clock_context_writer;
218
219 TimeZone::TimeZoneContentManager time_zone_content_manager;
220};
221
222TimeManager::TimeManager(Core::System& system) : system{system} {}
223
224TimeManager::~TimeManager() = default;
225
226void TimeManager::Initialize() {
227 impl = std::make_unique<Impl>(system);
228
229 // Time zones can only be initialized after impl is valid
230 impl->time_zone_content_manager.Initialize(*this);
231}
232
233Clock::StandardSteadyClockCore& TimeManager::GetStandardSteadyClockCore() {
234 return impl->standard_steady_clock_core;
235}
236
237const Clock::StandardSteadyClockCore& TimeManager::GetStandardSteadyClockCore() const {
238 return impl->standard_steady_clock_core;
239}
240
241Clock::StandardLocalSystemClockCore& TimeManager::GetStandardLocalSystemClockCore() {
242 return impl->standard_local_system_clock_core;
243}
244
245const Clock::StandardLocalSystemClockCore& TimeManager::GetStandardLocalSystemClockCore() const {
246 return impl->standard_local_system_clock_core;
247}
248
249Clock::StandardNetworkSystemClockCore& TimeManager::GetStandardNetworkSystemClockCore() {
250 return impl->standard_network_system_clock_core;
138} 251}
139 252
140void TimeManager::SetupEphemeralNetworkSystemClock() { 253const Clock::StandardNetworkSystemClockCore& TimeManager::GetStandardNetworkSystemClockCore()
141 ephemeral_network_system_clock_core.SetUpdateCallbackInstance( 254 const {
142 ephemeral_network_system_clock_context_writer); 255 return impl->standard_network_system_clock_core;
143 ephemeral_network_system_clock_core.MarkAsInitialized(); 256}
257
258Clock::StandardUserSystemClockCore& TimeManager::GetStandardUserSystemClockCore() {
259 return impl->standard_user_system_clock_core;
260}
261
262const Clock::StandardUserSystemClockCore& TimeManager::GetStandardUserSystemClockCore() const {
263 return impl->standard_user_system_clock_core;
264}
265
266TimeZone::TimeZoneContentManager& TimeManager::GetTimeZoneContentManager() {
267 return impl->time_zone_content_manager;
268}
269
270const TimeZone::TimeZoneContentManager& TimeManager::GetTimeZoneContentManager() const {
271 return impl->time_zone_content_manager;
272}
273
274SharedMemory& TimeManager::GetSharedMemory() {
275 return impl->shared_memory;
276}
277
278const SharedMemory& TimeManager::GetSharedMemory() const {
279 return impl->shared_memory;
280}
281
282void TimeManager::UpdateLocalSystemClockTime(s64 posix_time) {
283 impl->UpdateLocalSystemClockTime(system, posix_time);
284}
285
286void TimeManager::SetupTimeZoneManager(std::string location_name,
287 Clock::SteadyClockTimePoint time_zone_updated_time_point,
288 std::size_t total_location_name_count,
289 u128 time_zone_rule_version,
290 FileSys::VirtualFile& vfs_file) {
291 impl->SetupTimeZoneManager(location_name, time_zone_updated_time_point,
292 total_location_name_count, time_zone_rule_version, vfs_file);
293}
294
295/*static*/ s64 TimeManager::GetExternalTimeZoneOffset() {
296 // With "auto" timezone setting, we use the external system's timezone offset
297 if (Settings::GetTimeZoneString() == "auto") {
298 return Common::TimeZone::GetCurrentOffsetSeconds().count();
299 }
300 return 0;
144} 301}
145 302
146} // namespace Service::Time 303} // namespace Service::Time
diff --git a/src/core/hle/service/time/time_manager.h b/src/core/hle/service/time/time_manager.h
index 8e65f0d22..993c7c288 100644
--- a/src/core/hle/service/time/time_manager.h
+++ b/src/core/hle/service/time/time_manager.h
@@ -5,6 +5,7 @@
5#pragma once 5#pragma once
6 6
7#include "common/common_types.h" 7#include "common/common_types.h"
8#include "common/time_zone.h"
8#include "core/file_sys/vfs_types.h" 9#include "core/file_sys/vfs_types.h"
9#include "core/hle/service/time/clock_types.h" 10#include "core/hle/service/time/clock_types.h"
10#include "core/hle/service/time/ephemeral_network_system_clock_core.h" 11#include "core/hle/service/time/ephemeral_network_system_clock_core.h"
@@ -32,86 +33,46 @@ public:
32 explicit TimeManager(Core::System& system); 33 explicit TimeManager(Core::System& system);
33 ~TimeManager(); 34 ~TimeManager();
34 35
35 Clock::StandardSteadyClockCore& GetStandardSteadyClockCore() { 36 void Initialize();
36 return standard_steady_clock_core;
37 }
38 37
39 const Clock::StandardSteadyClockCore& GetStandardSteadyClockCore() const { 38 Clock::StandardSteadyClockCore& GetStandardSteadyClockCore();
40 return standard_steady_clock_core;
41 }
42 39
43 Clock::StandardLocalSystemClockCore& GetStandardLocalSystemClockCore() { 40 const Clock::StandardSteadyClockCore& GetStandardSteadyClockCore() const;
44 return standard_local_system_clock_core;
45 }
46 41
47 const Clock::StandardLocalSystemClockCore& GetStandardLocalSystemClockCore() const { 42 Clock::StandardLocalSystemClockCore& GetStandardLocalSystemClockCore();
48 return standard_local_system_clock_core;
49 }
50 43
51 Clock::StandardNetworkSystemClockCore& GetStandardNetworkSystemClockCore() { 44 const Clock::StandardLocalSystemClockCore& GetStandardLocalSystemClockCore() const;
52 return standard_network_system_clock_core;
53 }
54 45
55 const Clock::StandardNetworkSystemClockCore& GetStandardNetworkSystemClockCore() const { 46 Clock::StandardNetworkSystemClockCore& GetStandardNetworkSystemClockCore();
56 return standard_network_system_clock_core;
57 }
58 47
59 Clock::StandardUserSystemClockCore& GetStandardUserSystemClockCore() { 48 const Clock::StandardNetworkSystemClockCore& GetStandardNetworkSystemClockCore() const;
60 return standard_user_system_clock_core;
61 }
62 49
63 const Clock::StandardUserSystemClockCore& GetStandardUserSystemClockCore() const { 50 Clock::StandardUserSystemClockCore& GetStandardUserSystemClockCore();
64 return standard_user_system_clock_core;
65 }
66 51
67 TimeZone::TimeZoneContentManager& GetTimeZoneContentManager() { 52 const Clock::StandardUserSystemClockCore& GetStandardUserSystemClockCore() const;
68 return time_zone_content_manager;
69 }
70 53
71 const TimeZone::TimeZoneContentManager& GetTimeZoneContentManager() const { 54 TimeZone::TimeZoneContentManager& GetTimeZoneContentManager();
72 return time_zone_content_manager;
73 }
74 55
75 SharedMemory& GetSharedMemory() { 56 const TimeZone::TimeZoneContentManager& GetTimeZoneContentManager() const;
76 return shared_memory;
77 }
78 57
79 const SharedMemory& GetSharedMemory() const { 58 void UpdateLocalSystemClockTime(s64 posix_time);
80 return shared_memory; 59
81 } 60 SharedMemory& GetSharedMemory();
61
62 const SharedMemory& GetSharedMemory() const;
82 63
83 void SetupTimeZoneManager(std::string location_name, 64 void SetupTimeZoneManager(std::string location_name,
84 Clock::SteadyClockTimePoint time_zone_updated_time_point, 65 Clock::SteadyClockTimePoint time_zone_updated_time_point,
85 std::size_t total_location_name_count, u128 time_zone_rule_version, 66 std::size_t total_location_name_count, u128 time_zone_rule_version,
86 FileSys::VirtualFile& vfs_file); 67 FileSys::VirtualFile& vfs_file);
87 68
69 static s64 GetExternalTimeZoneOffset();
70
88private: 71private:
89 void SetupStandardSteadyClock(Core::System& system, Common::UUID clock_source_id, 72 Core::System& system;
90 Clock::TimeSpanType setup_value, 73
91 Clock::TimeSpanType internal_offset, bool is_rtc_reset_detected); 74 struct Impl;
92 void SetupStandardLocalSystemClock(Core::System& system, 75 std::unique_ptr<Impl> impl;
93 Clock::SystemClockContext clock_context, s64 posix_time);
94 void SetupStandardNetworkSystemClock(Clock::SystemClockContext clock_context,
95 Clock::TimeSpanType sufficient_accuracy);
96 void SetupStandardUserSystemClock(Core::System& system, bool is_automatic_correction_enabled,
97 Clock::SteadyClockTimePoint steady_clock_time_point);
98 void SetupEphemeralNetworkSystemClock();
99
100 SharedMemory shared_memory;
101
102 Clock::StandardSteadyClockCore standard_steady_clock_core;
103 Clock::TickBasedSteadyClockCore tick_based_steady_clock_core;
104 Clock::StandardLocalSystemClockCore standard_local_system_clock_core;
105 Clock::StandardNetworkSystemClockCore standard_network_system_clock_core;
106 Clock::StandardUserSystemClockCore standard_user_system_clock_core;
107 Clock::EphemeralNetworkSystemClockCore ephemeral_network_system_clock_core;
108
109 std::shared_ptr<Clock::LocalSystemClockContextWriter> local_system_clock_context_writer;
110 std::shared_ptr<Clock::NetworkSystemClockContextWriter> network_system_clock_context_writer;
111 std::shared_ptr<Clock::EphemeralNetworkSystemClockContextWriter>
112 ephemeral_network_system_clock_context_writer;
113
114 TimeZone::TimeZoneContentManager time_zone_content_manager;
115}; 76};
116 77
117} // namespace Service::Time 78} // namespace Service::Time
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 320672add..4177d0a41 100644
--- a/src/core/hle/service/time/time_zone_content_manager.cpp
+++ b/src/core/hle/service/time/time_zone_content_manager.cpp
@@ -68,9 +68,10 @@ static std::vector<std::string> BuildLocationNameCache(Core::System& system) {
68 return location_name_cache; 68 return location_name_cache;
69} 69}
70 70
71TimeZoneContentManager::TimeZoneContentManager(TimeManager& time_manager, Core::System& system) 71TimeZoneContentManager::TimeZoneContentManager(Core::System& system)
72 : system{system}, location_name_cache{BuildLocationNameCache(system)} { 72 : system{system}, location_name_cache{BuildLocationNameCache(system)} {}
73 73
74void TimeZoneContentManager::Initialize(TimeManager& time_manager) {
74 std::string location_name; 75 std::string location_name;
75 const auto timezone_setting = Settings::GetTimeZoneString(); 76 const auto timezone_setting = Settings::GetTimeZoneString();
76 if (timezone_setting == "auto" || timezone_setting == "default") { 77 if (timezone_setting == "auto" || timezone_setting == "default") {
diff --git a/src/core/hle/service/time/time_zone_content_manager.h b/src/core/hle/service/time/time_zone_content_manager.h
index 4f302c3b9..52dd1a020 100644
--- a/src/core/hle/service/time/time_zone_content_manager.h
+++ b/src/core/hle/service/time/time_zone_content_manager.h
@@ -21,7 +21,9 @@ namespace Service::Time::TimeZone {
21 21
22class TimeZoneContentManager final { 22class TimeZoneContentManager final {
23public: 23public:
24 TimeZoneContentManager(TimeManager& time_manager, Core::System& system); 24 explicit TimeZoneContentManager(Core::System& system);
25
26 void Initialize(TimeManager& time_manager);
25 27
26 TimeZoneManager& GetTimeZoneManager() { 28 TimeZoneManager& GetTimeZoneManager() {
27 return time_zone_manager; 29 return time_zone_manager;
diff --git a/src/core/hle/service/time/time_zone_manager.cpp b/src/core/hle/service/time/time_zone_manager.cpp
index 69152d0ac..bdf0439f2 100644
--- a/src/core/hle/service/time/time_zone_manager.cpp
+++ b/src/core/hle/service/time/time_zone_manager.cpp
@@ -820,7 +820,10 @@ static ResultCode ToCalendarTimeImpl(const TimeZoneRule& rules, s64 time, Calend
820 const ResultCode result{ 820 const ResultCode result{
821 ToCalendarTimeInternal(rules, time, calendar_time, calendar.additiona_info)}; 821 ToCalendarTimeInternal(rules, time, calendar_time, calendar.additiona_info)};
822 calendar.time.year = static_cast<s16>(calendar_time.year); 822 calendar.time.year = static_cast<s16>(calendar_time.year);
823 calendar.time.month = calendar_time.month + 1; // Internal impl. uses 0-indexed month 823
824 // Internal impl. uses 0-indexed month
825 calendar.time.month = static_cast<s8>(calendar_time.month + 1);
826
824 calendar.time.day = calendar_time.day; 827 calendar.time.day = calendar_time.day;
825 calendar.time.hour = calendar_time.hour; 828 calendar.time.hour = calendar_time.hour;
826 calendar.time.minute = calendar_time.minute; 829 calendar.time.minute = calendar_time.minute;
@@ -872,13 +875,15 @@ ResultCode TimeZoneManager::ToPosixTime(const TimeZoneRule& rules,
872 const CalendarTime& calendar_time, s64& posix_time) const { 875 const CalendarTime& calendar_time, s64& posix_time) const {
873 posix_time = 0; 876 posix_time = 0;
874 877
875 CalendarTimeInternal internal_time{}; 878 CalendarTimeInternal internal_time{
876 internal_time.year = calendar_time.year; 879 .year = calendar_time.year,
877 internal_time.month = calendar_time.month - 1; // Internal impl. uses 0-indexed month 880 // Internal impl. uses 0-indexed month
878 internal_time.day = calendar_time.day; 881 .month = static_cast<s8>(calendar_time.month - 1),
879 internal_time.hour = calendar_time.hour; 882 .day = calendar_time.day,
880 internal_time.minute = calendar_time.minute; 883 .hour = calendar_time.hour,
881 internal_time.second = calendar_time.second; 884 .minute = calendar_time.minute,
885 .second = calendar_time.second,
886 };
882 887
883 s32 hour{internal_time.hour}; 888 s32 hour{internal_time.hour};
884 s32 minute{internal_time.minute}; 889 s32 minute{internal_time.minute};
diff --git a/src/core/hle/service/time/time_zone_service.cpp b/src/core/hle/service/time/time_zone_service.cpp
index ff3a10b3e..25cecbc83 100644
--- a/src/core/hle/service/time/time_zone_service.cpp
+++ b/src/core/hle/service/time/time_zone_service.cpp
@@ -10,8 +10,9 @@
10 10
11namespace Service::Time { 11namespace Service::Time {
12 12
13ITimeZoneService ::ITimeZoneService(TimeZone::TimeZoneContentManager& time_zone_content_manager) 13ITimeZoneService ::ITimeZoneService(Core::System& system_,
14 : ServiceFramework("ITimeZoneService"), time_zone_content_manager{time_zone_content_manager} { 14 TimeZone::TimeZoneContentManager& time_zone_manager_)
15 : ServiceFramework{system_, "ITimeZoneService"}, time_zone_content_manager{time_zone_manager_} {
15 static const FunctionInfo functions[] = { 16 static const FunctionInfo functions[] = {
16 {0, &ITimeZoneService::GetDeviceLocationName, "GetDeviceLocationName"}, 17 {0, &ITimeZoneService::GetDeviceLocationName, "GetDeviceLocationName"},
17 {1, nullptr, "SetDeviceLocationName"}, 18 {1, nullptr, "SetDeviceLocationName"},
diff --git a/src/core/hle/service/time/time_zone_service.h b/src/core/hle/service/time/time_zone_service.h
index cb495748b..2c9b97603 100644
--- a/src/core/hle/service/time/time_zone_service.h
+++ b/src/core/hle/service/time/time_zone_service.h
@@ -6,6 +6,10 @@
6 6
7#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
8 8
9namespace Core {
10class System;
11}
12
9namespace Service::Time { 13namespace Service::Time {
10 14
11namespace TimeZone { 15namespace TimeZone {
@@ -14,7 +18,8 @@ class TimeZoneContentManager;
14 18
15class ITimeZoneService final : public ServiceFramework<ITimeZoneService> { 19class ITimeZoneService final : public ServiceFramework<ITimeZoneService> {
16public: 20public:
17 explicit ITimeZoneService(TimeZone::TimeZoneContentManager& time_zone_manager); 21 explicit ITimeZoneService(Core::System& system_,
22 TimeZone::TimeZoneContentManager& time_zone_manager_);
18 23
19private: 24private:
20 void GetDeviceLocationName(Kernel::HLERequestContext& ctx); 25 void GetDeviceLocationName(Kernel::HLERequestContext& ctx);
diff --git a/src/core/hle/service/usb/usb.cpp b/src/core/hle/service/usb/usb.cpp
index d033f8603..579de83e4 100644
--- a/src/core/hle/service/usb/usb.cpp
+++ b/src/core/hle/service/usb/usb.cpp
@@ -15,7 +15,7 @@ namespace Service::USB {
15 15
16class IDsInterface final : public ServiceFramework<IDsInterface> { 16class IDsInterface final : public ServiceFramework<IDsInterface> {
17public: 17public:
18 explicit IDsInterface() : ServiceFramework{"IDsInterface"} { 18 explicit IDsInterface(Core::System& system_) : ServiceFramework{system_, "IDsInterface"} {
19 // clang-format off 19 // clang-format off
20 static const FunctionInfo functions[] = { 20 static const FunctionInfo functions[] = {
21 {0, nullptr, "GetDsEndpoint"}, 21 {0, nullptr, "GetDsEndpoint"},
@@ -40,7 +40,7 @@ public:
40 40
41class USB_DS final : public ServiceFramework<USB_DS> { 41class USB_DS final : public ServiceFramework<USB_DS> {
42public: 42public:
43 explicit USB_DS() : ServiceFramework{"usb:ds"} { 43 explicit USB_DS(Core::System& system_) : ServiceFramework{system_, "usb:ds"} {
44 // clang-format off 44 // clang-format off
45 static const FunctionInfo functions[] = { 45 static const FunctionInfo functions[] = {
46 {0, nullptr, "BindDevice"}, 46 {0, nullptr, "BindDevice"},
@@ -65,7 +65,8 @@ public:
65 65
66class IClientEpSession final : public ServiceFramework<IClientEpSession> { 66class IClientEpSession final : public ServiceFramework<IClientEpSession> {
67public: 67public:
68 explicit IClientEpSession() : ServiceFramework{"IClientEpSession"} { 68 explicit IClientEpSession(Core::System& system_)
69 : ServiceFramework{system_, "IClientEpSession"} {
69 // clang-format off 70 // clang-format off
70 static const FunctionInfo functions[] = { 71 static const FunctionInfo functions[] = {
71 {0, nullptr, "Open"}, 72 {0, nullptr, "Open"},
@@ -86,7 +87,8 @@ public:
86 87
87class IClientIfSession final : public ServiceFramework<IClientIfSession> { 88class IClientIfSession final : public ServiceFramework<IClientIfSession> {
88public: 89public:
89 explicit IClientIfSession() : ServiceFramework{"IClientIfSession"} { 90 explicit IClientIfSession(Core::System& system_)
91 : ServiceFramework{system_, "IClientIfSession"} {
90 // clang-format off 92 // clang-format off
91 static const FunctionInfo functions[] = { 93 static const FunctionInfo functions[] = {
92 {0, nullptr, "Unknown0"}, 94 {0, nullptr, "Unknown0"},
@@ -108,7 +110,7 @@ public:
108 110
109class USB_HS final : public ServiceFramework<USB_HS> { 111class USB_HS final : public ServiceFramework<USB_HS> {
110public: 112public:
111 explicit USB_HS() : ServiceFramework{"usb:hs"} { 113 explicit USB_HS(Core::System& system_) : ServiceFramework{system_, "usb:hs"} {
112 // clang-format off 114 // clang-format off
113 static const FunctionInfo functions[] = { 115 static const FunctionInfo functions[] = {
114 {0, nullptr, "BindClientProcess"}, 116 {0, nullptr, "BindClientProcess"},
@@ -129,7 +131,7 @@ public:
129 131
130class IPdSession final : public ServiceFramework<IPdSession> { 132class IPdSession final : public ServiceFramework<IPdSession> {
131public: 133public:
132 explicit IPdSession() : ServiceFramework{"IPdSession"} { 134 explicit IPdSession(Core::System& system_) : ServiceFramework{system_, "IPdSession"} {
133 // clang-format off 135 // clang-format off
134 static const FunctionInfo functions[] = { 136 static const FunctionInfo functions[] = {
135 {0, nullptr, "BindNoticeEvent"}, 137 {0, nullptr, "BindNoticeEvent"},
@@ -148,7 +150,7 @@ public:
148 150
149class USB_PD final : public ServiceFramework<USB_PD> { 151class USB_PD final : public ServiceFramework<USB_PD> {
150public: 152public:
151 explicit USB_PD() : ServiceFramework{"usb:pd"} { 153 explicit USB_PD(Core::System& system_) : ServiceFramework{system_, "usb:pd"} {
152 // clang-format off 154 // clang-format off
153 static const FunctionInfo functions[] = { 155 static const FunctionInfo functions[] = {
154 {0, &USB_PD::GetPdSession, "GetPdSession"}, 156 {0, &USB_PD::GetPdSession, "GetPdSession"},
@@ -164,13 +166,14 @@ private:
164 166
165 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 167 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
166 rb.Push(RESULT_SUCCESS); 168 rb.Push(RESULT_SUCCESS);
167 rb.PushIpcInterface<IPdSession>(); 169 rb.PushIpcInterface<IPdSession>(system);
168 } 170 }
169}; 171};
170 172
171class IPdCradleSession final : public ServiceFramework<IPdCradleSession> { 173class IPdCradleSession final : public ServiceFramework<IPdCradleSession> {
172public: 174public:
173 explicit IPdCradleSession() : ServiceFramework{"IPdCradleSession"} { 175 explicit IPdCradleSession(Core::System& system_)
176 : ServiceFramework{system_, "IPdCradleSession"} {
174 // clang-format off 177 // clang-format off
175 static const FunctionInfo functions[] = { 178 static const FunctionInfo functions[] = {
176 {0, nullptr, "VdmUserWrite"}, 179 {0, nullptr, "VdmUserWrite"},
@@ -191,7 +194,7 @@ public:
191 194
192class USB_PD_C final : public ServiceFramework<USB_PD_C> { 195class USB_PD_C final : public ServiceFramework<USB_PD_C> {
193public: 196public:
194 explicit USB_PD_C() : ServiceFramework{"usb:pd:c"} { 197 explicit USB_PD_C(Core::System& system_) : ServiceFramework{system_, "usb:pd:c"} {
195 // clang-format off 198 // clang-format off
196 static const FunctionInfo functions[] = { 199 static const FunctionInfo functions[] = {
197 {0, &USB_PD_C::GetPdCradleSession, "GetPdCradleSession"}, 200 {0, &USB_PD_C::GetPdCradleSession, "GetPdCradleSession"},
@@ -205,7 +208,7 @@ private:
205 void GetPdCradleSession(Kernel::HLERequestContext& ctx) { 208 void GetPdCradleSession(Kernel::HLERequestContext& ctx) {
206 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 209 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
207 rb.Push(RESULT_SUCCESS); 210 rb.Push(RESULT_SUCCESS);
208 rb.PushIpcInterface<IPdCradleSession>(); 211 rb.PushIpcInterface<IPdCradleSession>(system);
209 212
210 LOG_DEBUG(Service_USB, "called"); 213 LOG_DEBUG(Service_USB, "called");
211 } 214 }
@@ -213,7 +216,7 @@ private:
213 216
214class USB_PM final : public ServiceFramework<USB_PM> { 217class USB_PM final : public ServiceFramework<USB_PM> {
215public: 218public:
216 explicit USB_PM() : ServiceFramework{"usb:pm"} { 219 explicit USB_PM(Core::System& system_) : ServiceFramework{system_, "usb:pm"} {
217 // clang-format off 220 // clang-format off
218 static const FunctionInfo functions[] = { 221 static const FunctionInfo functions[] = {
219 {0, nullptr, "Unknown0"}, 222 {0, nullptr, "Unknown0"},
@@ -229,12 +232,12 @@ public:
229 } 232 }
230}; 233};
231 234
232void InstallInterfaces(SM::ServiceManager& sm) { 235void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
233 std::make_shared<USB_DS>()->InstallAsService(sm); 236 std::make_shared<USB_DS>(system)->InstallAsService(sm);
234 std::make_shared<USB_HS>()->InstallAsService(sm); 237 std::make_shared<USB_HS>(system)->InstallAsService(sm);
235 std::make_shared<USB_PD>()->InstallAsService(sm); 238 std::make_shared<USB_PD>(system)->InstallAsService(sm);
236 std::make_shared<USB_PD_C>()->InstallAsService(sm); 239 std::make_shared<USB_PD_C>(system)->InstallAsService(sm);
237 std::make_shared<USB_PM>()->InstallAsService(sm); 240 std::make_shared<USB_PM>(system)->InstallAsService(sm);
238} 241}
239 242
240} // namespace Service::USB 243} // namespace Service::USB
diff --git a/src/core/hle/service/usb/usb.h b/src/core/hle/service/usb/usb.h
index 970a11fe8..fc366df34 100644
--- a/src/core/hle/service/usb/usb.h
+++ b/src/core/hle/service/usb/usb.h
@@ -4,12 +4,16 @@
4 4
5#pragma once 5#pragma once
6 6
7namespace Core {
8class System;
9}
10
7namespace Service::SM { 11namespace Service::SM {
8class ServiceManager; 12class ServiceManager;
9} 13}
10 14
11namespace Service::USB { 15namespace Service::USB {
12 16
13void InstallInterfaces(SM::ServiceManager& sm); 17void InstallInterfaces(SM::ServiceManager& sm, Core::System& system);
14 18
15} // namespace Service::USB 19} // namespace Service::USB
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index 480d34725..968cd16b6 100644
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -159,7 +159,7 @@ public:
159 header.data_size = static_cast<u32_le>(write_index - sizeof(Header)); 159 header.data_size = static_cast<u32_le>(write_index - sizeof(Header));
160 header.data_offset = sizeof(Header); 160 header.data_offset = sizeof(Header);
161 header.objects_size = 4; 161 header.objects_size = 4;
162 header.objects_offset = sizeof(Header) + header.data_size; 162 header.objects_offset = static_cast<u32>(sizeof(Header) + header.data_size);
163 std::memcpy(buffer.data(), &header, sizeof(Header)); 163 std::memcpy(buffer.data(), &header, sizeof(Header));
164 164
165 return buffer; 165 return buffer;
@@ -215,10 +215,9 @@ public:
215 explicit IGBPConnectRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) { 215 explicit IGBPConnectRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) {
216 Deserialize(); 216 Deserialize();
217 } 217 }
218 ~IGBPConnectRequestParcel() override = default;
219 218
220 void DeserializeData() override { 219 void DeserializeData() override {
221 std::u16string token = ReadInterfaceToken(); 220 [[maybe_unused]] const std::u16string token = ReadInterfaceToken();
222 data = Read<Data>(); 221 data = Read<Data>();
223 } 222 }
224 223
@@ -279,23 +278,28 @@ public:
279 : Parcel(std::move(buffer)) { 278 : Parcel(std::move(buffer)) {
280 Deserialize(); 279 Deserialize();
281 } 280 }
282 ~IGBPSetPreallocatedBufferRequestParcel() override = default;
283 281
284 void DeserializeData() override { 282 void DeserializeData() override {
285 std::u16string token = ReadInterfaceToken(); 283 [[maybe_unused]] const std::u16string token = ReadInterfaceToken();
286 data = Read<Data>(); 284 data = Read<Data>();
287 buffer = Read<NVFlinger::IGBPBuffer>(); 285 if (data.contains_object != 0) {
286 buffer_container = Read<BufferContainer>();
287 }
288 } 288 }
289 289
290 struct Data { 290 struct Data {
291 u32_le slot; 291 u32_le slot;
292 INSERT_PADDING_WORDS(1); 292 u32_le contains_object;
293 };
294
295 struct BufferContainer {
293 u32_le graphic_buffer_length; 296 u32_le graphic_buffer_length;
294 INSERT_PADDING_WORDS(1); 297 INSERT_PADDING_WORDS(1);
298 NVFlinger::IGBPBuffer buffer{};
295 }; 299 };
296 300
297 Data data; 301 Data data{};
298 NVFlinger::IGBPBuffer buffer; 302 BufferContainer buffer_container{};
299}; 303};
300 304
301class IGBPSetPreallocatedBufferResponseParcel : public Parcel { 305class IGBPSetPreallocatedBufferResponseParcel : public Parcel {
@@ -306,15 +310,40 @@ protected:
306 } 310 }
307}; 311};
308 312
313class IGBPCancelBufferRequestParcel : public Parcel {
314public:
315 explicit IGBPCancelBufferRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) {
316 Deserialize();
317 }
318
319 void DeserializeData() override {
320 [[maybe_unused]] const std::u16string token = ReadInterfaceToken();
321 data = Read<Data>();
322 }
323
324 struct Data {
325 u32_le slot;
326 Service::Nvidia::MultiFence multi_fence;
327 };
328
329 Data data;
330};
331
332class IGBPCancelBufferResponseParcel : public Parcel {
333protected:
334 void SerializeData() override {
335 Write<u32>(0); // Success
336 }
337};
338
309class IGBPDequeueBufferRequestParcel : public Parcel { 339class IGBPDequeueBufferRequestParcel : public Parcel {
310public: 340public:
311 explicit IGBPDequeueBufferRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) { 341 explicit IGBPDequeueBufferRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) {
312 Deserialize(); 342 Deserialize();
313 } 343 }
314 ~IGBPDequeueBufferRequestParcel() override = default;
315 344
316 void DeserializeData() override { 345 void DeserializeData() override {
317 std::u16string token = ReadInterfaceToken(); 346 [[maybe_unused]] const std::u16string token = ReadInterfaceToken();
318 data = Read<Data>(); 347 data = Read<Data>();
319 } 348 }
320 349
@@ -333,7 +362,6 @@ class IGBPDequeueBufferResponseParcel : public Parcel {
333public: 362public:
334 explicit IGBPDequeueBufferResponseParcel(u32 slot, Service::Nvidia::MultiFence& multi_fence) 363 explicit IGBPDequeueBufferResponseParcel(u32 slot, Service::Nvidia::MultiFence& multi_fence)
335 : slot(slot), multi_fence(multi_fence) {} 364 : slot(slot), multi_fence(multi_fence) {}
336 ~IGBPDequeueBufferResponseParcel() override = default;
337 365
338protected: 366protected:
339 void SerializeData() override { 367 void SerializeData() override {
@@ -352,10 +380,9 @@ public:
352 explicit IGBPRequestBufferRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) { 380 explicit IGBPRequestBufferRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) {
353 Deserialize(); 381 Deserialize();
354 } 382 }
355 ~IGBPRequestBufferRequestParcel() override = default;
356 383
357 void DeserializeData() override { 384 void DeserializeData() override {
358 std::u16string token = ReadInterfaceToken(); 385 [[maybe_unused]] const std::u16string token = ReadInterfaceToken();
359 slot = Read<u32_le>(); 386 slot = Read<u32_le>();
360 } 387 }
361 388
@@ -384,10 +411,9 @@ public:
384 explicit IGBPQueueBufferRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) { 411 explicit IGBPQueueBufferRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) {
385 Deserialize(); 412 Deserialize();
386 } 413 }
387 ~IGBPQueueBufferRequestParcel() override = default;
388 414
389 void DeserializeData() override { 415 void DeserializeData() override {
390 std::u16string token = ReadInterfaceToken(); 416 [[maybe_unused]] const std::u16string token = ReadInterfaceToken();
391 data = Read<Data>(); 417 data = Read<Data>();
392 } 418 }
393 419
@@ -447,10 +473,9 @@ public:
447 explicit IGBPQueryRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) { 473 explicit IGBPQueryRequestParcel(std::vector<u8> buffer) : Parcel(std::move(buffer)) {
448 Deserialize(); 474 Deserialize();
449 } 475 }
450 ~IGBPQueryRequestParcel() override = default;
451 476
452 void DeserializeData() override { 477 void DeserializeData() override {
453 std::u16string token = ReadInterfaceToken(); 478 [[maybe_unused]] const std::u16string token = ReadInterfaceToken();
454 type = Read<u32_le>(); 479 type = Read<u32_le>();
455 } 480 }
456 481
@@ -473,8 +498,8 @@ private:
473 498
474class IHOSBinderDriver final : public ServiceFramework<IHOSBinderDriver> { 499class IHOSBinderDriver final : public ServiceFramework<IHOSBinderDriver> {
475public: 500public:
476 explicit IHOSBinderDriver(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) 501 explicit IHOSBinderDriver(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_)
477 : ServiceFramework("IHOSBinderDriver"), nv_flinger(std::move(nv_flinger)) { 502 : ServiceFramework{system_, "IHOSBinderDriver"}, nv_flinger(nv_flinger_) {
478 static const FunctionInfo functions[] = { 503 static const FunctionInfo functions[] = {
479 {0, &IHOSBinderDriver::TransactParcel, "TransactParcel"}, 504 {0, &IHOSBinderDriver::TransactParcel, "TransactParcel"},
480 {1, &IHOSBinderDriver::AdjustRefcount, "AdjustRefcount"}, 505 {1, &IHOSBinderDriver::AdjustRefcount, "AdjustRefcount"},
@@ -509,10 +534,9 @@ private:
509 const u32 flags = rp.Pop<u32>(); 534 const u32 flags = rp.Pop<u32>();
510 535
511 LOG_DEBUG(Service_VI, "called. id=0x{:08X} transaction={:X}, flags=0x{:08X}", id, 536 LOG_DEBUG(Service_VI, "called. id=0x{:08X} transaction={:X}, flags=0x{:08X}", id,
512 static_cast<u32>(transaction), flags); 537 transaction, flags);
513 538
514 const auto guard = nv_flinger->Lock(); 539 auto& buffer_queue = *nv_flinger.FindBufferQueue(id);
515 auto& buffer_queue = nv_flinger->FindBufferQueue(id);
516 540
517 switch (transaction) { 541 switch (transaction) {
518 case TransactionId::Connect: { 542 case TransactionId::Connect: {
@@ -522,13 +546,16 @@ private:
522 Settings::values.resolution_factor.GetValue()), 546 Settings::values.resolution_factor.GetValue()),
523 static_cast<u32>(static_cast<u32>(DisplayResolution::UndockedHeight) * 547 static_cast<u32>(static_cast<u32>(DisplayResolution::UndockedHeight) *
524 Settings::values.resolution_factor.GetValue())}; 548 Settings::values.resolution_factor.GetValue())};
549
550 buffer_queue.Connect();
551
525 ctx.WriteBuffer(response.Serialize()); 552 ctx.WriteBuffer(response.Serialize());
526 break; 553 break;
527 } 554 }
528 case TransactionId::SetPreallocatedBuffer: { 555 case TransactionId::SetPreallocatedBuffer: {
529 IGBPSetPreallocatedBufferRequestParcel request{ctx.ReadBuffer()}; 556 IGBPSetPreallocatedBufferRequestParcel request{ctx.ReadBuffer()};
530 557
531 buffer_queue.SetPreallocatedBuffer(request.data.slot, request.buffer); 558 buffer_queue.SetPreallocatedBuffer(request.data.slot, request.buffer_container.buffer);
532 559
533 IGBPSetPreallocatedBufferResponseParcel response{}; 560 IGBPSetPreallocatedBufferResponseParcel response{};
534 ctx.WriteBuffer(response.Serialize()); 561 ctx.WriteBuffer(response.Serialize());
@@ -538,40 +565,25 @@ private:
538 IGBPDequeueBufferRequestParcel request{ctx.ReadBuffer()}; 565 IGBPDequeueBufferRequestParcel request{ctx.ReadBuffer()};
539 const u32 width{request.data.width}; 566 const u32 width{request.data.width};
540 const u32 height{request.data.height}; 567 const u32 height{request.data.height};
541 auto result = buffer_queue.DequeueBuffer(width, height); 568
542 569 do {
543 if (result) { 570 if (auto result = buffer_queue.DequeueBuffer(width, height); result) {
544 // Buffer is available 571 // Buffer is available
545 IGBPDequeueBufferResponseParcel response{result->first, *result->second}; 572 IGBPDequeueBufferResponseParcel response{result->first, *result->second};
546 ctx.WriteBuffer(response.Serialize()); 573 ctx.WriteBuffer(response.Serialize());
547 } else { 574 break;
548 // Wait the current thread until a buffer becomes available 575 }
549 ctx.SleepClientThread( 576 } while (buffer_queue.IsConnected());
550 "IHOSBinderDriver::DequeueBuffer", UINT64_MAX, 577
551 [=, this](std::shared_ptr<Kernel::Thread> thread,
552 Kernel::HLERequestContext& ctx, Kernel::ThreadWakeupReason reason) {
553 // Repeat TransactParcel DequeueBuffer when a buffer is available
554 const auto guard = nv_flinger->Lock();
555 auto& buffer_queue = nv_flinger->FindBufferQueue(id);
556 auto result = buffer_queue.DequeueBuffer(width, height);
557 ASSERT_MSG(result != std::nullopt, "Could not dequeue buffer.");
558
559 IGBPDequeueBufferResponseParcel response{result->first, *result->second};
560 ctx.WriteBuffer(response.Serialize());
561 IPC::ResponseBuilder rb{ctx, 2};
562 rb.Push(RESULT_SUCCESS);
563 },
564 buffer_queue.GetWritableBufferWaitEvent());
565 }
566 break; 578 break;
567 } 579 }
568 case TransactionId::RequestBuffer: { 580 case TransactionId::RequestBuffer: {
569 IGBPRequestBufferRequestParcel request{ctx.ReadBuffer()}; 581 IGBPRequestBufferRequestParcel request{ctx.ReadBuffer()};
570 582
571 auto& buffer = buffer_queue.RequestBuffer(request.slot); 583 auto& buffer = buffer_queue.RequestBuffer(request.slot);
572
573 IGBPRequestBufferResponseParcel response{buffer}; 584 IGBPRequestBufferResponseParcel response{buffer};
574 ctx.WriteBuffer(response.Serialize()); 585 ctx.WriteBuffer(response.Serialize());
586
575 break; 587 break;
576 } 588 }
577 case TransactionId::QueueBuffer: { 589 case TransactionId::QueueBuffer: {
@@ -596,7 +608,12 @@ private:
596 break; 608 break;
597 } 609 }
598 case TransactionId::CancelBuffer: { 610 case TransactionId::CancelBuffer: {
599 LOG_CRITICAL(Service_VI, "(STUBBED) called, transaction=CancelBuffer"); 611 IGBPCancelBufferRequestParcel request{ctx.ReadBuffer()};
612
613 buffer_queue.CancelBuffer(request.data.slot, request.data.multi_fence);
614
615 IGBPCancelBufferResponseParcel response{};
616 ctx.WriteBuffer(response.Serialize());
600 break; 617 break;
601 } 618 }
602 case TransactionId::Disconnect: { 619 case TransactionId::Disconnect: {
@@ -652,7 +669,7 @@ private:
652 669
653 LOG_WARNING(Service_VI, "(STUBBED) called id={}, unknown={:08X}", id, unknown); 670 LOG_WARNING(Service_VI, "(STUBBED) called id={}, unknown={:08X}", id, unknown);
654 671
655 const auto& buffer_queue = nv_flinger->FindBufferQueue(id); 672 const auto& buffer_queue = *nv_flinger.FindBufferQueue(id);
656 673
657 // TODO(Subv): Find out what this actually is. 674 // TODO(Subv): Find out what this actually is.
658 IPC::ResponseBuilder rb{ctx, 2, 1}; 675 IPC::ResponseBuilder rb{ctx, 2, 1};
@@ -660,12 +677,13 @@ private:
660 rb.PushCopyObjects(buffer_queue.GetBufferWaitEvent()); 677 rb.PushCopyObjects(buffer_queue.GetBufferWaitEvent());
661 } 678 }
662 679
663 std::shared_ptr<NVFlinger::NVFlinger> nv_flinger; 680 NVFlinger::NVFlinger& nv_flinger;
664}; // namespace VI 681};
665 682
666class ISystemDisplayService final : public ServiceFramework<ISystemDisplayService> { 683class ISystemDisplayService final : public ServiceFramework<ISystemDisplayService> {
667public: 684public:
668 explicit ISystemDisplayService() : ServiceFramework("ISystemDisplayService") { 685 explicit ISystemDisplayService(Core::System& system_)
686 : ServiceFramework{system_, "ISystemDisplayService"} {
669 static const FunctionInfo functions[] = { 687 static const FunctionInfo functions[] = {
670 {1200, nullptr, "GetZOrderCountMin"}, 688 {1200, nullptr, "GetZOrderCountMin"},
671 {1202, nullptr, "GetZOrderCountMax"}, 689 {1202, nullptr, "GetZOrderCountMax"},
@@ -747,7 +765,7 @@ private:
747 IPC::ResponseBuilder rb{ctx, 6}; 765 IPC::ResponseBuilder rb{ctx, 6};
748 rb.Push(RESULT_SUCCESS); 766 rb.Push(RESULT_SUCCESS);
749 767
750 if (Settings::values.use_docked_mode) { 768 if (Settings::values.use_docked_mode.GetValue()) {
751 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth) * 769 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth) *
752 static_cast<u32>(Settings::values.resolution_factor.GetValue())); 770 static_cast<u32>(Settings::values.resolution_factor.GetValue()));
753 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight) * 771 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight) *
@@ -766,8 +784,8 @@ private:
766 784
767class IManagerDisplayService final : public ServiceFramework<IManagerDisplayService> { 785class IManagerDisplayService final : public ServiceFramework<IManagerDisplayService> {
768public: 786public:
769 explicit IManagerDisplayService(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) 787 explicit IManagerDisplayService(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_)
770 : ServiceFramework("IManagerDisplayService"), nv_flinger(std::move(nv_flinger)) { 788 : ServiceFramework{system_, "IManagerDisplayService"}, nv_flinger{nv_flinger_} {
771 // clang-format off 789 // clang-format off
772 static const FunctionInfo functions[] = { 790 static const FunctionInfo functions[] = {
773 {200, nullptr, "AllocateProcessHeapBlock"}, 791 {200, nullptr, "AllocateProcessHeapBlock"},
@@ -869,7 +887,7 @@ private:
869 "(STUBBED) called. unknown=0x{:08X}, display=0x{:016X}, aruid=0x{:016X}", 887 "(STUBBED) called. unknown=0x{:08X}, display=0x{:016X}, aruid=0x{:016X}",
870 unknown, display, aruid); 888 unknown, display, aruid);
871 889
872 const auto layer_id = nv_flinger->CreateLayer(display); 890 const auto layer_id = nv_flinger.CreateLayer(display);
873 if (!layer_id) { 891 if (!layer_id) {
874 LOG_ERROR(Service_VI, "Layer not found! display=0x{:016X}", display); 892 LOG_ERROR(Service_VI, "Layer not found! display=0x{:016X}", display);
875 IPC::ResponseBuilder rb{ctx, 2}; 893 IPC::ResponseBuilder rb{ctx, 2};
@@ -906,12 +924,12 @@ private:
906 rb.Push(RESULT_SUCCESS); 924 rb.Push(RESULT_SUCCESS);
907 } 925 }
908 926
909 std::shared_ptr<NVFlinger::NVFlinger> nv_flinger; 927 NVFlinger::NVFlinger& nv_flinger;
910}; 928};
911 929
912class IApplicationDisplayService final : public ServiceFramework<IApplicationDisplayService> { 930class IApplicationDisplayService final : public ServiceFramework<IApplicationDisplayService> {
913public: 931public:
914 explicit IApplicationDisplayService(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger); 932 explicit IApplicationDisplayService(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_);
915 933
916private: 934private:
917 enum class ConvertedScaleMode : u64 { 935 enum class ConvertedScaleMode : u64 {
@@ -935,7 +953,7 @@ private:
935 953
936 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 954 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
937 rb.Push(RESULT_SUCCESS); 955 rb.Push(RESULT_SUCCESS);
938 rb.PushIpcInterface<IHOSBinderDriver>(nv_flinger); 956 rb.PushIpcInterface<IHOSBinderDriver>(system, nv_flinger);
939 } 957 }
940 958
941 void GetSystemDisplayService(Kernel::HLERequestContext& ctx) { 959 void GetSystemDisplayService(Kernel::HLERequestContext& ctx) {
@@ -943,7 +961,7 @@ private:
943 961
944 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 962 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
945 rb.Push(RESULT_SUCCESS); 963 rb.Push(RESULT_SUCCESS);
946 rb.PushIpcInterface<ISystemDisplayService>(); 964 rb.PushIpcInterface<ISystemDisplayService>(system);
947 } 965 }
948 966
949 void GetManagerDisplayService(Kernel::HLERequestContext& ctx) { 967 void GetManagerDisplayService(Kernel::HLERequestContext& ctx) {
@@ -951,7 +969,7 @@ private:
951 969
952 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 970 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
953 rb.Push(RESULT_SUCCESS); 971 rb.Push(RESULT_SUCCESS);
954 rb.PushIpcInterface<IManagerDisplayService>(nv_flinger); 972 rb.PushIpcInterface<IManagerDisplayService>(system, nv_flinger);
955 } 973 }
956 974
957 void GetIndirectDisplayTransactionService(Kernel::HLERequestContext& ctx) { 975 void GetIndirectDisplayTransactionService(Kernel::HLERequestContext& ctx) {
@@ -959,7 +977,7 @@ private:
959 977
960 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 978 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
961 rb.Push(RESULT_SUCCESS); 979 rb.Push(RESULT_SUCCESS);
962 rb.PushIpcInterface<IHOSBinderDriver>(nv_flinger); 980 rb.PushIpcInterface<IHOSBinderDriver>(system, nv_flinger);
963 } 981 }
964 982
965 void OpenDisplay(Kernel::HLERequestContext& ctx) { 983 void OpenDisplay(Kernel::HLERequestContext& ctx) {
@@ -986,7 +1004,7 @@ private:
986 1004
987 ASSERT_MSG(name == "Default", "Non-default displays aren't supported yet"); 1005 ASSERT_MSG(name == "Default", "Non-default displays aren't supported yet");
988 1006
989 const auto display_id = nv_flinger->OpenDisplay(name); 1007 const auto display_id = nv_flinger.OpenDisplay(name);
990 if (!display_id) { 1008 if (!display_id) {
991 LOG_ERROR(Service_VI, "Display not found! display_name={}", name); 1009 LOG_ERROR(Service_VI, "Display not found! display_name={}", name);
992 IPC::ResponseBuilder rb{ctx, 2}; 1010 IPC::ResponseBuilder rb{ctx, 2};
@@ -1041,8 +1059,8 @@ private:
1041 const auto scaling_mode = rp.PopEnum<NintendoScaleMode>(); 1059 const auto scaling_mode = rp.PopEnum<NintendoScaleMode>();
1042 const u64 unknown = rp.Pop<u64>(); 1060 const u64 unknown = rp.Pop<u64>();
1043 1061
1044 LOG_DEBUG(Service_VI, "called. scaling_mode=0x{:08X}, unknown=0x{:016X}", 1062 LOG_DEBUG(Service_VI, "called. scaling_mode=0x{:08X}, unknown=0x{:016X}", scaling_mode,
1045 static_cast<u32>(scaling_mode), unknown); 1063 unknown);
1046 1064
1047 IPC::ResponseBuilder rb{ctx, 2}; 1065 IPC::ResponseBuilder rb{ctx, 2};
1048 1066
@@ -1086,7 +1104,7 @@ private:
1086 1104
1087 LOG_DEBUG(Service_VI, "called. layer_id=0x{:016X}, aruid=0x{:016X}", layer_id, aruid); 1105 LOG_DEBUG(Service_VI, "called. layer_id=0x{:016X}, aruid=0x{:016X}", layer_id, aruid);
1088 1106
1089 const auto display_id = nv_flinger->OpenDisplay(display_name); 1107 const auto display_id = nv_flinger.OpenDisplay(display_name);
1090 if (!display_id) { 1108 if (!display_id) {
1091 LOG_ERROR(Service_VI, "Layer not found! layer_id={}", layer_id); 1109 LOG_ERROR(Service_VI, "Layer not found! layer_id={}", layer_id);
1092 IPC::ResponseBuilder rb{ctx, 2}; 1110 IPC::ResponseBuilder rb{ctx, 2};
@@ -1094,7 +1112,7 @@ private:
1094 return; 1112 return;
1095 } 1113 }
1096 1114
1097 const auto buffer_queue_id = nv_flinger->FindBufferQueueId(*display_id, layer_id); 1115 const auto buffer_queue_id = nv_flinger.FindBufferQueueId(*display_id, layer_id);
1098 if (!buffer_queue_id) { 1116 if (!buffer_queue_id) {
1099 LOG_ERROR(Service_VI, "Buffer queue id not found! display_id={}", *display_id); 1117 LOG_ERROR(Service_VI, "Buffer queue id not found! display_id={}", *display_id);
1100 IPC::ResponseBuilder rb{ctx, 2}; 1118 IPC::ResponseBuilder rb{ctx, 2};
@@ -1114,7 +1132,7 @@ private:
1114 1132
1115 LOG_DEBUG(Service_VI, "called. layer_id=0x{:016X}", layer_id); 1133 LOG_DEBUG(Service_VI, "called. layer_id=0x{:016X}", layer_id);
1116 1134
1117 nv_flinger->CloseLayer(layer_id); 1135 nv_flinger.CloseLayer(layer_id);
1118 1136
1119 IPC::ResponseBuilder rb{ctx, 2}; 1137 IPC::ResponseBuilder rb{ctx, 2};
1120 rb.Push(RESULT_SUCCESS); 1138 rb.Push(RESULT_SUCCESS);
@@ -1130,7 +1148,7 @@ private:
1130 1148
1131 // TODO(Subv): What's the difference between a Stray and a Managed layer? 1149 // TODO(Subv): What's the difference between a Stray and a Managed layer?
1132 1150
1133 const auto layer_id = nv_flinger->CreateLayer(display_id); 1151 const auto layer_id = nv_flinger.CreateLayer(display_id);
1134 if (!layer_id) { 1152 if (!layer_id) {
1135 LOG_ERROR(Service_VI, "Layer not found! layer_id={}", *layer_id); 1153 LOG_ERROR(Service_VI, "Layer not found! layer_id={}", *layer_id);
1136 IPC::ResponseBuilder rb{ctx, 2}; 1154 IPC::ResponseBuilder rb{ctx, 2};
@@ -1138,7 +1156,7 @@ private:
1138 return; 1156 return;
1139 } 1157 }
1140 1158
1141 const auto buffer_queue_id = nv_flinger->FindBufferQueueId(display_id, *layer_id); 1159 const auto buffer_queue_id = nv_flinger.FindBufferQueueId(display_id, *layer_id);
1142 if (!buffer_queue_id) { 1160 if (!buffer_queue_id) {
1143 LOG_ERROR(Service_VI, "Buffer queue id not found! display_id={}", display_id); 1161 LOG_ERROR(Service_VI, "Buffer queue id not found! display_id={}", display_id);
1144 IPC::ResponseBuilder rb{ctx, 2}; 1162 IPC::ResponseBuilder rb{ctx, 2};
@@ -1169,7 +1187,7 @@ private:
1169 1187
1170 LOG_WARNING(Service_VI, "(STUBBED) called. display_id=0x{:016X}", display_id); 1188 LOG_WARNING(Service_VI, "(STUBBED) called. display_id=0x{:016X}", display_id);
1171 1189
1172 const auto vsync_event = nv_flinger->FindVsyncEvent(display_id); 1190 const auto vsync_event = nv_flinger.FindVsyncEvent(display_id);
1173 if (!vsync_event) { 1191 if (!vsync_event) {
1174 LOG_ERROR(Service_VI, "Vsync event was not found for display_id={}", display_id); 1192 LOG_ERROR(Service_VI, "Vsync event was not found for display_id={}", display_id);
1175 IPC::ResponseBuilder rb{ctx, 2}; 1193 IPC::ResponseBuilder rb{ctx, 2};
@@ -1185,7 +1203,7 @@ private:
1185 void ConvertScalingMode(Kernel::HLERequestContext& ctx) { 1203 void ConvertScalingMode(Kernel::HLERequestContext& ctx) {
1186 IPC::RequestParser rp{ctx}; 1204 IPC::RequestParser rp{ctx};
1187 const auto mode = rp.PopEnum<NintendoScaleMode>(); 1205 const auto mode = rp.PopEnum<NintendoScaleMode>();
1188 LOG_DEBUG(Service_VI, "called mode={}", static_cast<u32>(mode)); 1206 LOG_DEBUG(Service_VI, "called mode={}", mode);
1189 1207
1190 const auto converted_mode = ConvertScalingModeImpl(mode); 1208 const auto converted_mode = ConvertScalingModeImpl(mode);
1191 1209
@@ -1205,8 +1223,8 @@ private:
1205 const auto height = rp.Pop<u64>(); 1223 const auto height = rp.Pop<u64>();
1206 LOG_DEBUG(Service_VI, "called width={}, height={}", width, height); 1224 LOG_DEBUG(Service_VI, "called width={}, height={}", width, height);
1207 1225
1208 constexpr std::size_t base_size = 0x20000; 1226 constexpr u64 base_size = 0x20000;
1209 constexpr std::size_t alignment = 0x1000; 1227 constexpr u64 alignment = 0x1000;
1210 const auto texture_size = width * height * 4; 1228 const auto texture_size = width * height * 4;
1211 const auto out_size = (texture_size + base_size - 1) / base_size * base_size; 1229 const auto out_size = (texture_size + base_size - 1) / base_size * base_size;
1212 1230
@@ -1234,12 +1252,12 @@ private:
1234 } 1252 }
1235 } 1253 }
1236 1254
1237 std::shared_ptr<NVFlinger::NVFlinger> nv_flinger; 1255 NVFlinger::NVFlinger& nv_flinger;
1238}; 1256};
1239 1257
1240IApplicationDisplayService::IApplicationDisplayService( 1258IApplicationDisplayService::IApplicationDisplayService(Core::System& system_,
1241 std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) 1259 NVFlinger::NVFlinger& nv_flinger_)
1242 : ServiceFramework("IApplicationDisplayService"), nv_flinger(std::move(nv_flinger)) { 1260 : ServiceFramework{system_, "IApplicationDisplayService"}, nv_flinger{nv_flinger_} {
1243 static const FunctionInfo functions[] = { 1261 static const FunctionInfo functions[] = {
1244 {100, &IApplicationDisplayService::GetRelayService, "GetRelayService"}, 1262 {100, &IApplicationDisplayService::GetRelayService, "GetRelayService"},
1245 {101, &IApplicationDisplayService::GetSystemDisplayService, "GetSystemDisplayService"}, 1263 {101, &IApplicationDisplayService::GetSystemDisplayService, "GetSystemDisplayService"},
@@ -1280,14 +1298,13 @@ static bool IsValidServiceAccess(Permission permission, Policy policy) {
1280 return false; 1298 return false;
1281} 1299}
1282 1300
1283void detail::GetDisplayServiceImpl(Kernel::HLERequestContext& ctx, 1301void detail::GetDisplayServiceImpl(Kernel::HLERequestContext& ctx, Core::System& system,
1284 std::shared_ptr<NVFlinger::NVFlinger> nv_flinger, 1302 NVFlinger::NVFlinger& nv_flinger, Permission permission) {
1285 Permission permission) {
1286 IPC::RequestParser rp{ctx}; 1303 IPC::RequestParser rp{ctx};
1287 const auto policy = rp.PopEnum<Policy>(); 1304 const auto policy = rp.PopEnum<Policy>();
1288 1305
1289 if (!IsValidServiceAccess(permission, policy)) { 1306 if (!IsValidServiceAccess(permission, policy)) {
1290 LOG_ERROR(Service_VI, "Permission denied for policy {}", static_cast<u32>(policy)); 1307 LOG_ERROR(Service_VI, "Permission denied for policy {}", policy);
1291 IPC::ResponseBuilder rb{ctx, 2}; 1308 IPC::ResponseBuilder rb{ctx, 2};
1292 rb.Push(ERR_PERMISSION_DENIED); 1309 rb.Push(ERR_PERMISSION_DENIED);
1293 return; 1310 return;
@@ -1295,14 +1312,14 @@ void detail::GetDisplayServiceImpl(Kernel::HLERequestContext& ctx,
1295 1312
1296 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 1313 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
1297 rb.Push(RESULT_SUCCESS); 1314 rb.Push(RESULT_SUCCESS);
1298 rb.PushIpcInterface<IApplicationDisplayService>(std::move(nv_flinger)); 1315 rb.PushIpcInterface<IApplicationDisplayService>(system, nv_flinger);
1299} 1316}
1300 1317
1301void InstallInterfaces(SM::ServiceManager& service_manager, 1318void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system,
1302 std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) { 1319 NVFlinger::NVFlinger& nv_flinger) {
1303 std::make_shared<VI_M>(nv_flinger)->InstallAsService(service_manager); 1320 std::make_shared<VI_M>(system, nv_flinger)->InstallAsService(service_manager);
1304 std::make_shared<VI_S>(nv_flinger)->InstallAsService(service_manager); 1321 std::make_shared<VI_S>(system, nv_flinger)->InstallAsService(service_manager);
1305 std::make_shared<VI_U>(nv_flinger)->InstallAsService(service_manager); 1322 std::make_shared<VI_U>(system, nv_flinger)->InstallAsService(service_manager);
1306} 1323}
1307 1324
1308} // namespace Service::VI 1325} // namespace Service::VI
diff --git a/src/core/hle/service/vi/vi.h b/src/core/hle/service/vi/vi.h
index 6b66f8b81..eec531d54 100644
--- a/src/core/hle/service/vi/vi.h
+++ b/src/core/hle/service/vi/vi.h
@@ -7,6 +7,10 @@
7#include <memory> 7#include <memory>
8#include "common/common_types.h" 8#include "common/common_types.h"
9 9
10namespace Core {
11class System;
12}
13
10namespace Kernel { 14namespace Kernel {
11class HLERequestContext; 15class HLERequestContext;
12} 16}
@@ -43,12 +47,12 @@ enum class Policy {
43}; 47};
44 48
45namespace detail { 49namespace detail {
46void GetDisplayServiceImpl(Kernel::HLERequestContext& ctx, 50void GetDisplayServiceImpl(Kernel::HLERequestContext& ctx, Core::System& system,
47 std::shared_ptr<NVFlinger::NVFlinger> nv_flinger, Permission permission); 51 NVFlinger::NVFlinger& nv_flinger, Permission permission);
48} // namespace detail 52} // namespace detail
49 53
50/// Registers all VI services with the specified service manager. 54/// Registers all VI services with the specified service manager.
51void InstallInterfaces(SM::ServiceManager& service_manager, 55void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system,
52 std::shared_ptr<NVFlinger::NVFlinger> nv_flinger); 56 NVFlinger::NVFlinger& nv_flinger);
53 57
54} // namespace Service::VI 58} // namespace Service::VI
diff --git a/src/core/hle/service/vi/vi_m.cpp b/src/core/hle/service/vi/vi_m.cpp
index 06070087f..87db1c416 100644
--- a/src/core/hle/service/vi/vi_m.cpp
+++ b/src/core/hle/service/vi/vi_m.cpp
@@ -8,8 +8,8 @@
8 8
9namespace Service::VI { 9namespace Service::VI {
10 10
11VI_M::VI_M(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) 11VI_M::VI_M(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_)
12 : ServiceFramework{"vi:m"}, nv_flinger{std::move(nv_flinger)} { 12 : ServiceFramework{system_, "vi:m"}, nv_flinger{nv_flinger_} {
13 static const FunctionInfo functions[] = { 13 static const FunctionInfo functions[] = {
14 {2, &VI_M::GetDisplayService, "GetDisplayService"}, 14 {2, &VI_M::GetDisplayService, "GetDisplayService"},
15 {3, nullptr, "GetDisplayServiceWithProxyNameExchange"}, 15 {3, nullptr, "GetDisplayServiceWithProxyNameExchange"},
@@ -22,7 +22,7 @@ VI_M::~VI_M() = default;
22void VI_M::GetDisplayService(Kernel::HLERequestContext& ctx) { 22void VI_M::GetDisplayService(Kernel::HLERequestContext& ctx) {
23 LOG_DEBUG(Service_VI, "called"); 23 LOG_DEBUG(Service_VI, "called");
24 24
25 detail::GetDisplayServiceImpl(ctx, nv_flinger, Permission::Manager); 25 detail::GetDisplayServiceImpl(ctx, system, nv_flinger, Permission::Manager);
26} 26}
27 27
28} // namespace Service::VI 28} // namespace Service::VI
diff --git a/src/core/hle/service/vi/vi_m.h b/src/core/hle/service/vi/vi_m.h
index 290e06689..d79c41beb 100644
--- a/src/core/hle/service/vi/vi_m.h
+++ b/src/core/hle/service/vi/vi_m.h
@@ -6,6 +6,10 @@
6 6
7#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
8 8
9namespace Core {
10class System;
11}
12
9namespace Kernel { 13namespace Kernel {
10class HLERequestContext; 14class HLERequestContext;
11} 15}
@@ -18,13 +22,13 @@ namespace Service::VI {
18 22
19class VI_M final : public ServiceFramework<VI_M> { 23class VI_M final : public ServiceFramework<VI_M> {
20public: 24public:
21 explicit VI_M(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger); 25 explicit VI_M(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_);
22 ~VI_M() override; 26 ~VI_M() override;
23 27
24private: 28private:
25 void GetDisplayService(Kernel::HLERequestContext& ctx); 29 void GetDisplayService(Kernel::HLERequestContext& ctx);
26 30
27 std::shared_ptr<NVFlinger::NVFlinger> nv_flinger; 31 NVFlinger::NVFlinger& nv_flinger;
28}; 32};
29 33
30} // namespace Service::VI 34} // namespace Service::VI
diff --git a/src/core/hle/service/vi/vi_s.cpp b/src/core/hle/service/vi/vi_s.cpp
index 57c596cc4..5cd22f7df 100644
--- a/src/core/hle/service/vi/vi_s.cpp
+++ b/src/core/hle/service/vi/vi_s.cpp
@@ -8,8 +8,8 @@
8 8
9namespace Service::VI { 9namespace Service::VI {
10 10
11VI_S::VI_S(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) 11VI_S::VI_S(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_)
12 : ServiceFramework{"vi:s"}, nv_flinger{std::move(nv_flinger)} { 12 : ServiceFramework{system_, "vi:s"}, nv_flinger{nv_flinger_} {
13 static const FunctionInfo functions[] = { 13 static const FunctionInfo functions[] = {
14 {1, &VI_S::GetDisplayService, "GetDisplayService"}, 14 {1, &VI_S::GetDisplayService, "GetDisplayService"},
15 {3, nullptr, "GetDisplayServiceWithProxyNameExchange"}, 15 {3, nullptr, "GetDisplayServiceWithProxyNameExchange"},
@@ -22,7 +22,7 @@ VI_S::~VI_S() = default;
22void VI_S::GetDisplayService(Kernel::HLERequestContext& ctx) { 22void VI_S::GetDisplayService(Kernel::HLERequestContext& ctx) {
23 LOG_DEBUG(Service_VI, "called"); 23 LOG_DEBUG(Service_VI, "called");
24 24
25 detail::GetDisplayServiceImpl(ctx, nv_flinger, Permission::System); 25 detail::GetDisplayServiceImpl(ctx, system, nv_flinger, Permission::System);
26} 26}
27 27
28} // namespace Service::VI 28} // namespace Service::VI
diff --git a/src/core/hle/service/vi/vi_s.h b/src/core/hle/service/vi/vi_s.h
index 47804dc0b..5f1f8f290 100644
--- a/src/core/hle/service/vi/vi_s.h
+++ b/src/core/hle/service/vi/vi_s.h
@@ -6,6 +6,10 @@
6 6
7#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
8 8
9namespace Core {
10class System;
11}
12
9namespace Kernel { 13namespace Kernel {
10class HLERequestContext; 14class HLERequestContext;
11} 15}
@@ -18,13 +22,13 @@ namespace Service::VI {
18 22
19class VI_S final : public ServiceFramework<VI_S> { 23class VI_S final : public ServiceFramework<VI_S> {
20public: 24public:
21 explicit VI_S(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger); 25 explicit VI_S(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_);
22 ~VI_S() override; 26 ~VI_S() override;
23 27
24private: 28private:
25 void GetDisplayService(Kernel::HLERequestContext& ctx); 29 void GetDisplayService(Kernel::HLERequestContext& ctx);
26 30
27 std::shared_ptr<NVFlinger::NVFlinger> nv_flinger; 31 NVFlinger::NVFlinger& nv_flinger;
28}; 32};
29 33
30} // namespace Service::VI 34} // namespace Service::VI
diff --git a/src/core/hle/service/vi/vi_u.cpp b/src/core/hle/service/vi/vi_u.cpp
index 6b7329345..0079d51f0 100644
--- a/src/core/hle/service/vi/vi_u.cpp
+++ b/src/core/hle/service/vi/vi_u.cpp
@@ -8,8 +8,8 @@
8 8
9namespace Service::VI { 9namespace Service::VI {
10 10
11VI_U::VI_U(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger) 11VI_U::VI_U(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_)
12 : ServiceFramework{"vi:u"}, nv_flinger{std::move(nv_flinger)} { 12 : ServiceFramework{system_, "vi:u"}, nv_flinger{nv_flinger_} {
13 static const FunctionInfo functions[] = { 13 static const FunctionInfo functions[] = {
14 {0, &VI_U::GetDisplayService, "GetDisplayService"}, 14 {0, &VI_U::GetDisplayService, "GetDisplayService"},
15 {1, nullptr, "GetDisplayServiceWithProxyNameExchange"}, 15 {1, nullptr, "GetDisplayServiceWithProxyNameExchange"},
@@ -22,7 +22,7 @@ VI_U::~VI_U() = default;
22void VI_U::GetDisplayService(Kernel::HLERequestContext& ctx) { 22void VI_U::GetDisplayService(Kernel::HLERequestContext& ctx) {
23 LOG_DEBUG(Service_VI, "called"); 23 LOG_DEBUG(Service_VI, "called");
24 24
25 detail::GetDisplayServiceImpl(ctx, nv_flinger, Permission::User); 25 detail::GetDisplayServiceImpl(ctx, system, nv_flinger, Permission::User);
26} 26}
27 27
28} // namespace Service::VI 28} // namespace Service::VI
diff --git a/src/core/hle/service/vi/vi_u.h b/src/core/hle/service/vi/vi_u.h
index 19bdb73b0..8e3885c73 100644
--- a/src/core/hle/service/vi/vi_u.h
+++ b/src/core/hle/service/vi/vi_u.h
@@ -6,6 +6,10 @@
6 6
7#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
8 8
9namespace Core {
10class System;
11}
12
9namespace Kernel { 13namespace Kernel {
10class HLERequestContext; 14class HLERequestContext;
11} 15}
@@ -18,13 +22,13 @@ namespace Service::VI {
18 22
19class VI_U final : public ServiceFramework<VI_U> { 23class VI_U final : public ServiceFramework<VI_U> {
20public: 24public:
21 explicit VI_U(std::shared_ptr<NVFlinger::NVFlinger> nv_flinger); 25 explicit VI_U(Core::System& system_, NVFlinger::NVFlinger& nv_flinger_);
22 ~VI_U() override; 26 ~VI_U() override;
23 27
24private: 28private:
25 void GetDisplayService(Kernel::HLERequestContext& ctx); 29 void GetDisplayService(Kernel::HLERequestContext& ctx);
26 30
27 std::shared_ptr<NVFlinger::NVFlinger> nv_flinger; 31 NVFlinger::NVFlinger& nv_flinger;
28}; 32};
29 33
30} // namespace Service::VI 34} // namespace Service::VI
diff --git a/src/core/hle/service/wlan/wlan.cpp b/src/core/hle/service/wlan/wlan.cpp
index 0260d7dcf..ddbf04069 100644
--- a/src/core/hle/service/wlan/wlan.cpp
+++ b/src/core/hle/service/wlan/wlan.cpp
@@ -12,7 +12,7 @@ namespace Service::WLAN {
12 12
13class WLANInfra final : public ServiceFramework<WLANInfra> { 13class WLANInfra final : public ServiceFramework<WLANInfra> {
14public: 14public:
15 explicit WLANInfra() : ServiceFramework{"wlan:inf"} { 15 explicit WLANInfra(Core::System& system_) : ServiceFramework{system_, "wlan:inf"} {
16 // clang-format off 16 // clang-format off
17 static const FunctionInfo functions[] = { 17 static const FunctionInfo functions[] = {
18 {0, nullptr, "OpenMode"}, 18 {0, nullptr, "OpenMode"},
@@ -55,7 +55,7 @@ public:
55 55
56class WLANLocal final : public ServiceFramework<WLANLocal> { 56class WLANLocal final : public ServiceFramework<WLANLocal> {
57public: 57public:
58 explicit WLANLocal() : ServiceFramework{"wlan:lcl"} { 58 explicit WLANLocal(Core::System& system_) : ServiceFramework{system_, "wlan:lcl"} {
59 // clang-format off 59 // clang-format off
60 static const FunctionInfo functions[] = { 60 static const FunctionInfo functions[] = {
61 {0, nullptr, "Unknown0"}, 61 {0, nullptr, "Unknown0"},
@@ -120,7 +120,7 @@ public:
120 120
121class WLANLocalGetFrame final : public ServiceFramework<WLANLocalGetFrame> { 121class WLANLocalGetFrame final : public ServiceFramework<WLANLocalGetFrame> {
122public: 122public:
123 explicit WLANLocalGetFrame() : ServiceFramework{"wlan:lg"} { 123 explicit WLANLocalGetFrame(Core::System& system_) : ServiceFramework{system_, "wlan:lg"} {
124 // clang-format off 124 // clang-format off
125 static const FunctionInfo functions[] = { 125 static const FunctionInfo functions[] = {
126 {0, nullptr, "Unknown"}, 126 {0, nullptr, "Unknown"},
@@ -133,7 +133,7 @@ public:
133 133
134class WLANSocketGetFrame final : public ServiceFramework<WLANSocketGetFrame> { 134class WLANSocketGetFrame final : public ServiceFramework<WLANSocketGetFrame> {
135public: 135public:
136 explicit WLANSocketGetFrame() : ServiceFramework{"wlan:sg"} { 136 explicit WLANSocketGetFrame(Core::System& system_) : ServiceFramework{system_, "wlan:sg"} {
137 // clang-format off 137 // clang-format off
138 static const FunctionInfo functions[] = { 138 static const FunctionInfo functions[] = {
139 {0, nullptr, "Unknown"}, 139 {0, nullptr, "Unknown"},
@@ -146,7 +146,7 @@ public:
146 146
147class WLANSocketManager final : public ServiceFramework<WLANSocketManager> { 147class WLANSocketManager final : public ServiceFramework<WLANSocketManager> {
148public: 148public:
149 explicit WLANSocketManager() : ServiceFramework{"wlan:soc"} { 149 explicit WLANSocketManager(Core::System& system_) : ServiceFramework{system_, "wlan:soc"} {
150 // clang-format off 150 // clang-format off
151 static const FunctionInfo functions[] = { 151 static const FunctionInfo functions[] = {
152 {0, nullptr, "Unknown0"}, 152 {0, nullptr, "Unknown0"},
@@ -169,12 +169,12 @@ public:
169 } 169 }
170}; 170};
171 171
172void InstallInterfaces(SM::ServiceManager& sm) { 172void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
173 std::make_shared<WLANInfra>()->InstallAsService(sm); 173 std::make_shared<WLANInfra>(system)->InstallAsService(sm);
174 std::make_shared<WLANLocal>()->InstallAsService(sm); 174 std::make_shared<WLANLocal>(system)->InstallAsService(sm);
175 std::make_shared<WLANLocalGetFrame>()->InstallAsService(sm); 175 std::make_shared<WLANLocalGetFrame>(system)->InstallAsService(sm);
176 std::make_shared<WLANSocketGetFrame>()->InstallAsService(sm); 176 std::make_shared<WLANSocketGetFrame>(system)->InstallAsService(sm);
177 std::make_shared<WLANSocketManager>()->InstallAsService(sm); 177 std::make_shared<WLANSocketManager>(system)->InstallAsService(sm);
178} 178}
179 179
180} // namespace Service::WLAN 180} // namespace Service::WLAN
diff --git a/src/core/hle/service/wlan/wlan.h b/src/core/hle/service/wlan/wlan.h
index 054ea928a..3899eedbb 100644
--- a/src/core/hle/service/wlan/wlan.h
+++ b/src/core/hle/service/wlan/wlan.h
@@ -4,12 +4,16 @@
4 4
5#pragma once 5#pragma once
6 6
7namespace Core {
8class System;
9}
10
7namespace Service::SM { 11namespace Service::SM {
8class ServiceManager; 12class ServiceManager;
9} 13}
10 14
11namespace Service::WLAN { 15namespace Service::WLAN {
12 16
13void InstallInterfaces(SM::ServiceManager& sm); 17void InstallInterfaces(SM::ServiceManager& sm, Core::System& system);
14 18
15} // namespace Service::WLAN 19} // namespace Service::WLAN
diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp
index 394a1bf26..79ebf11de 100644
--- a/src/core/loader/deconstructed_rom_directory.cpp
+++ b/src/core/loader/deconstructed_rom_directory.cpp
@@ -12,7 +12,6 @@
12#include "core/file_sys/control_metadata.h" 12#include "core/file_sys/control_metadata.h"
13#include "core/file_sys/patch_manager.h" 13#include "core/file_sys/patch_manager.h"
14#include "core/file_sys/romfs_factory.h" 14#include "core/file_sys/romfs_factory.h"
15#include "core/gdbstub/gdbstub.h"
16#include "core/hle/kernel/kernel.h" 15#include "core/hle/kernel/kernel.h"
17#include "core/hle/kernel/memory/page_table.h" 16#include "core/hle/kernel/memory/page_table.h"
18#include "core/hle/kernel/process.h" 17#include "core/hle/kernel/process.h"
@@ -114,7 +113,8 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect
114 } 113 }
115 114
116 if (override_update) { 115 if (override_update) {
117 const FileSys::PatchManager patch_manager(metadata.GetTitleID()); 116 const FileSys::PatchManager patch_manager(
117 metadata.GetTitleID(), system.GetFileSystemController(), system.GetContentProvider());
118 dir = patch_manager.PatchExeFS(dir); 118 dir = patch_manager.PatchExeFS(dir);
119 } 119 }
120 120
@@ -160,7 +160,8 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect
160 modules.clear(); 160 modules.clear();
161 const VAddr base_address{process.PageTable().GetCodeRegionStart()}; 161 const VAddr base_address{process.PageTable().GetCodeRegionStart()};
162 VAddr next_load_addr{base_address}; 162 VAddr next_load_addr{base_address};
163 const FileSys::PatchManager pm{metadata.GetTitleID()}; 163 const FileSys::PatchManager pm{metadata.GetTitleID(), system.GetFileSystemController(),
164 system.GetContentProvider()};
164 for (const auto& module : static_modules) { 165 for (const auto& module : static_modules) {
165 const FileSys::VirtualFile module_file{dir->GetFile(module)}; 166 const FileSys::VirtualFile module_file{dir->GetFile(module)};
166 if (!module_file) { 167 if (!module_file) {
@@ -178,8 +179,6 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect
178 next_load_addr = *tentative_next_load_addr; 179 next_load_addr = *tentative_next_load_addr;
179 modules.insert_or_assign(load_addr, module); 180 modules.insert_or_assign(load_addr, module);
180 LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", module, load_addr); 181 LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", module, load_addr);
181 // Register module with GDBStub
182 GDBStub::RegisterModule(module, load_addr, next_load_addr - 1, false);
183 } 182 }
184 183
185 // Find the RomFS by searching for a ".romfs" file in this directory 184 // Find the RomFS by searching for a ".romfs" file in this directory
diff --git a/src/core/loader/deconstructed_rom_directory.h b/src/core/loader/deconstructed_rom_directory.h
index 35d340317..3c968580f 100644
--- a/src/core/loader/deconstructed_rom_directory.h
+++ b/src/core/loader/deconstructed_rom_directory.h
@@ -32,7 +32,7 @@ public:
32 32
33 /** 33 /**
34 * Returns the type of the file 34 * Returns the type of the file
35 * @param file std::shared_ptr<VfsFile> open file 35 * @param file open file
36 * @return FileType found, or FileType::Error if this loader doesn't know it 36 * @return FileType found, or FileType::Error if this loader doesn't know it
37 */ 37 */
38 static FileType IdentifyType(const FileSys::VirtualFile& file); 38 static FileType IdentifyType(const FileSys::VirtualFile& file);
diff --git a/src/core/loader/elf.h b/src/core/loader/elf.h
index 3527933ad..2067932c7 100644
--- a/src/core/loader/elf.h
+++ b/src/core/loader/elf.h
@@ -21,7 +21,7 @@ public:
21 21
22 /** 22 /**
23 * Returns the type of the file 23 * Returns the type of the file
24 * @param file std::shared_ptr<VfsFile> open file 24 * @param file open file
25 * @return FileType found, or FileType::Error if this loader doesn't know it 25 * @return FileType found, or FileType::Error if this loader doesn't know it
26 */ 26 */
27 static FileType IdentifyType(const FileSys::VirtualFile& file); 27 static FileType IdentifyType(const FileSys::VirtualFile& file);
diff --git a/src/core/loader/kip.cpp b/src/core/loader/kip.cpp
index 5981bcd21..e162c4ff0 100644
--- a/src/core/loader/kip.cpp
+++ b/src/core/loader/kip.cpp
@@ -5,7 +5,6 @@
5#include <cstring> 5#include <cstring>
6#include "core/file_sys/kernel_executable.h" 6#include "core/file_sys/kernel_executable.h"
7#include "core/file_sys/program_metadata.h" 7#include "core/file_sys/program_metadata.h"
8#include "core/gdbstub/gdbstub.h"
9#include "core/hle/kernel/code_set.h" 8#include "core/hle/kernel/code_set.h"
10#include "core/hle/kernel/memory/page_table.h" 9#include "core/hle/kernel/memory/page_table.h"
11#include "core/hle/kernel/process.h" 10#include "core/hle/kernel/process.h"
@@ -16,7 +15,7 @@ namespace Loader {
16 15
17namespace { 16namespace {
18constexpr u32 PageAlignSize(u32 size) { 17constexpr u32 PageAlignSize(u32 size) {
19 return (size + Core::Memory::PAGE_MASK) & ~Core::Memory::PAGE_MASK; 18 return static_cast<u32>((size + Core::Memory::PAGE_MASK) & ~Core::Memory::PAGE_MASK);
20} 19}
21} // Anonymous namespace 20} // Anonymous namespace
22 21
@@ -91,8 +90,6 @@ AppLoader::LoadResult AppLoader_KIP::Load(Kernel::Process& process,
91 program_image.resize(PageAlignSize(kip->GetBSSOffset()) + kip->GetBSSSize()); 90 program_image.resize(PageAlignSize(kip->GetBSSOffset()) + kip->GetBSSSize());
92 codeset.DataSegment().size += kip->GetBSSSize(); 91 codeset.DataSegment().size += kip->GetBSSSize();
93 92
94 GDBStub::RegisterModule(kip->GetName(), base_address, base_address + program_image.size());
95
96 codeset.memory = std::move(program_image); 93 codeset.memory = std::move(program_image);
97 process.LoadModule(std::move(codeset), base_address); 94 process.LoadModule(std::move(codeset), base_address);
98 95
diff --git a/src/core/loader/kip.h b/src/core/loader/kip.h
index dee05a7b5..14a85e295 100644
--- a/src/core/loader/kip.h
+++ b/src/core/loader/kip.h
@@ -23,7 +23,7 @@ public:
23 23
24 /** 24 /**
25 * Returns the type of the file 25 * Returns the type of the file
26 * @param file std::shared_ptr<VfsFile> open file 26 * @param file open file
27 * @return FileType found, or FileType::Error if this loader doesn't know it 27 * @return FileType found, or FileType::Error if this loader doesn't know it
28 */ 28 */
29 static FileType IdentifyType(const FileSys::VirtualFile& file); 29 static FileType IdentifyType(const FileSys::VirtualFile& file);
diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp
index 9bc3a8840..e4f5fd40c 100644
--- a/src/core/loader/loader.cpp
+++ b/src/core/loader/loader.cpp
@@ -10,6 +10,7 @@
10#include "common/file_util.h" 10#include "common/file_util.h"
11#include "common/logging/log.h" 11#include "common/logging/log.h"
12#include "common/string_util.h" 12#include "common/string_util.h"
13#include "core/core.h"
13#include "core/hle/kernel/process.h" 14#include "core/hle/kernel/process.h"
14#include "core/loader/deconstructed_rom_directory.h" 15#include "core/loader/deconstructed_rom_directory.h"
15#include "core/loader/elf.h" 16#include "core/loader/elf.h"
@@ -184,6 +185,10 @@ constexpr std::array<const char*, 66> RESULT_MESSAGES{
184 "The INI file contains more than the maximum allowable number of KIP files.", 185 "The INI file contains more than the maximum allowable number of KIP files.",
185}; 186};
186 187
188std::string GetResultStatusString(ResultStatus status) {
189 return RESULT_MESSAGES.at(static_cast<std::size_t>(status));
190}
191
187std::ostream& operator<<(std::ostream& os, ResultStatus status) { 192std::ostream& operator<<(std::ostream& os, ResultStatus status) {
188 os << RESULT_MESSAGES.at(static_cast<std::size_t>(status)); 193 os << RESULT_MESSAGES.at(static_cast<std::size_t>(status));
189 return os; 194 return os;
@@ -194,15 +199,15 @@ AppLoader::~AppLoader() = default;
194 199
195/** 200/**
196 * Get a loader for a file with a specific type 201 * Get a loader for a file with a specific type
197 * @param file The file to load 202 * @param system The system context to use.
198 * @param type The type of the file 203 * @param file The file to retrieve the loader for
199 * @param file the file to retrieve the loader for 204 * @param type The file type
200 * @param type the file type 205 * @param program_index Specifies the index within the container of the program to launch.
201 * @return std::unique_ptr<AppLoader> a pointer to a loader object; nullptr for unsupported type 206 * @return std::unique_ptr<AppLoader> a pointer to a loader object; nullptr for unsupported type
202 */ 207 */
203static std::unique_ptr<AppLoader> GetFileLoader(FileSys::VirtualFile file, FileType type) { 208static std::unique_ptr<AppLoader> GetFileLoader(Core::System& system, FileSys::VirtualFile file,
209 FileType type, std::size_t program_index) {
204 switch (type) { 210 switch (type) {
205
206 // Standard ELF file format. 211 // Standard ELF file format.
207 case FileType::ELF: 212 case FileType::ELF:
208 return std::make_unique<AppLoader_ELF>(std::move(file)); 213 return std::make_unique<AppLoader_ELF>(std::move(file));
@@ -221,7 +226,8 @@ static std::unique_ptr<AppLoader> GetFileLoader(FileSys::VirtualFile file, FileT
221 226
222 // NX XCI (nX Card Image) file format. 227 // NX XCI (nX Card Image) file format.
223 case FileType::XCI: 228 case FileType::XCI:
224 return std::make_unique<AppLoader_XCI>(std::move(file)); 229 return std::make_unique<AppLoader_XCI>(std::move(file), system.GetFileSystemController(),
230 system.GetContentProvider(), program_index);
225 231
226 // NX NAX (NintendoAesXts) file format. 232 // NX NAX (NintendoAesXts) file format.
227 case FileType::NAX: 233 case FileType::NAX:
@@ -229,7 +235,8 @@ static std::unique_ptr<AppLoader> GetFileLoader(FileSys::VirtualFile file, FileT
229 235
230 // NX NSP (Nintendo Submission Package) file format 236 // NX NSP (Nintendo Submission Package) file format
231 case FileType::NSP: 237 case FileType::NSP:
232 return std::make_unique<AppLoader_NSP>(std::move(file)); 238 return std::make_unique<AppLoader_NSP>(std::move(file), system.GetFileSystemController(),
239 system.GetContentProvider(), program_index);
233 240
234 // NX KIP (Kernel Internal Process) file format 241 // NX KIP (Kernel Internal Process) file format
235 case FileType::KIP: 242 case FileType::KIP:
@@ -244,20 +251,22 @@ static std::unique_ptr<AppLoader> GetFileLoader(FileSys::VirtualFile file, FileT
244 } 251 }
245} 252}
246 253
247std::unique_ptr<AppLoader> GetLoader(FileSys::VirtualFile file) { 254std::unique_ptr<AppLoader> GetLoader(Core::System& system, FileSys::VirtualFile file,
255 std::size_t program_index) {
248 FileType type = IdentifyFile(file); 256 FileType type = IdentifyFile(file);
249 FileType filename_type = GuessFromFilename(file->GetName()); 257 const FileType filename_type = GuessFromFilename(file->GetName());
250 258
251 // Special case: 00 is either a NCA or NAX. 259 // Special case: 00 is either a NCA or NAX.
252 if (type != filename_type && !(file->GetName() == "00" && type == FileType::NAX)) { 260 if (type != filename_type && !(file->GetName() == "00" && type == FileType::NAX)) {
253 LOG_WARNING(Loader, "File {} has a different type than its extension.", file->GetName()); 261 LOG_WARNING(Loader, "File {} has a different type than its extension.", file->GetName());
254 if (FileType::Unknown == type) 262 if (FileType::Unknown == type) {
255 type = filename_type; 263 type = filename_type;
264 }
256 } 265 }
257 266
258 LOG_DEBUG(Loader, "Loading file {} as {}...", file->GetName(), GetFileTypeString(type)); 267 LOG_DEBUG(Loader, "Loading file {} as {}...", file->GetName(), GetFileTypeString(type));
259 268
260 return GetFileLoader(std::move(file), type); 269 return GetFileLoader(system, std::move(file), type, program_index);
261} 270}
262 271
263} // namespace Loader 272} // namespace Loader
diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h
index ac60b097a..b2e5b13de 100644
--- a/src/core/loader/loader.h
+++ b/src/core/loader/loader.h
@@ -135,6 +135,7 @@ enum class ResultStatus : u16 {
135 ErrorINITooManyKIPs, 135 ErrorINITooManyKIPs,
136}; 136};
137 137
138std::string GetResultStatusString(ResultStatus status);
138std::ostream& operator<<(std::ostream& os, ResultStatus status); 139std::ostream& operator<<(std::ostream& os, ResultStatus status);
139 140
140/// Interface for loading an application 141/// Interface for loading an application
@@ -290,9 +291,14 @@ protected:
290 291
291/** 292/**
292 * Identifies a bootable file and return a suitable loader 293 * Identifies a bootable file and return a suitable loader
293 * @param file The bootable file 294 *
294 * @return the best loader for this file 295 * @param system The system context.
296 * @param file The bootable file.
297 * @param program_index Specifies the index within the container of the program to launch.
298 *
299 * @return the best loader for this file.
295 */ 300 */
296std::unique_ptr<AppLoader> GetLoader(FileSys::VirtualFile file); 301std::unique_ptr<AppLoader> GetLoader(Core::System& system, FileSys::VirtualFile file,
302 std::size_t program_index = 0);
297 303
298} // namespace Loader 304} // namespace Loader
diff --git a/src/core/loader/nax.h b/src/core/loader/nax.h
index c2b7722b5..a5b5e2ae1 100644
--- a/src/core/loader/nax.h
+++ b/src/core/loader/nax.h
@@ -28,7 +28,7 @@ public:
28 28
29 /** 29 /**
30 * Returns the type of the file 30 * Returns the type of the file
31 * @param file std::shared_ptr<VfsFile> open file 31 * @param file open file
32 * @return FileType found, or FileType::Error if this loader doesn't know it 32 * @return FileType found, or FileType::Error if this loader doesn't know it
33 */ 33 */
34 static FileType IdentifyType(const FileSys::VirtualFile& file); 34 static FileType IdentifyType(const FileSys::VirtualFile& file);
diff --git a/src/core/loader/nca.h b/src/core/loader/nca.h
index 711070294..918792800 100644
--- a/src/core/loader/nca.h
+++ b/src/core/loader/nca.h
@@ -28,7 +28,7 @@ public:
28 28
29 /** 29 /**
30 * Returns the type of the file 30 * Returns the type of the file
31 * @param file std::shared_ptr<VfsFile> open file 31 * @param file open file
32 * @return FileType found, or FileType::Error if this loader doesn't know it 32 * @return FileType found, or FileType::Error if this loader doesn't know it
33 */ 33 */
34 static FileType IdentifyType(const FileSys::VirtualFile& file); 34 static FileType IdentifyType(const FileSys::VirtualFile& file);
diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp
index 9fb5eddad..ccf8cc153 100644
--- a/src/core/loader/nro.cpp
+++ b/src/core/loader/nro.cpp
@@ -14,10 +14,10 @@
14#include "core/file_sys/control_metadata.h" 14#include "core/file_sys/control_metadata.h"
15#include "core/file_sys/romfs_factory.h" 15#include "core/file_sys/romfs_factory.h"
16#include "core/file_sys/vfs_offset.h" 16#include "core/file_sys/vfs_offset.h"
17#include "core/gdbstub/gdbstub.h"
18#include "core/hle/kernel/code_set.h" 17#include "core/hle/kernel/code_set.h"
19#include "core/hle/kernel/memory/page_table.h" 18#include "core/hle/kernel/memory/page_table.h"
20#include "core/hle/kernel/process.h" 19#include "core/hle/kernel/process.h"
20#include "core/hle/kernel/thread.h"
21#include "core/hle/service/filesystem/filesystem.h" 21#include "core/hle/service/filesystem/filesystem.h"
22#include "core/loader/nro.h" 22#include "core/loader/nro.h"
23#include "core/loader/nso.h" 23#include "core/loader/nso.h"
@@ -127,7 +127,7 @@ FileType AppLoader_NRO::IdentifyType(const FileSys::VirtualFile& file) {
127} 127}
128 128
129static constexpr u32 PageAlignSize(u32 size) { 129static constexpr u32 PageAlignSize(u32 size) {
130 return (size + Core::Memory::PAGE_MASK) & ~Core::Memory::PAGE_MASK; 130 return static_cast<u32>((size + Core::Memory::PAGE_MASK) & ~Core::Memory::PAGE_MASK);
131} 131}
132 132
133static bool LoadNroImpl(Kernel::Process& process, const std::vector<u8>& data, 133static bool LoadNroImpl(Kernel::Process& process, const std::vector<u8>& data,
@@ -197,10 +197,6 @@ static bool LoadNroImpl(Kernel::Process& process, const std::vector<u8>& data,
197 codeset.memory = std::move(program_image); 197 codeset.memory = std::move(program_image);
198 process.LoadModule(std::move(codeset), process.PageTable().GetCodeRegionStart()); 198 process.LoadModule(std::move(codeset), process.PageTable().GetCodeRegionStart());
199 199
200 // Register module with GDBStub
201 GDBStub::RegisterModule(name, process.PageTable().GetCodeRegionStart(),
202 process.PageTable().GetCodeRegionEnd());
203
204 return true; 200 return true;
205} 201}
206 202
diff --git a/src/core/loader/nro.h b/src/core/loader/nro.h
index a2aab2ecc..a82b66221 100644
--- a/src/core/loader/nro.h
+++ b/src/core/loader/nro.h
@@ -32,7 +32,7 @@ public:
32 32
33 /** 33 /**
34 * Returns the type of the file 34 * Returns the type of the file
35 * @param file std::shared_ptr<VfsFile> open file 35 * @param file open file
36 * @return FileType found, or FileType::Error if this loader doesn't know it 36 * @return FileType found, or FileType::Error if this loader doesn't know it
37 */ 37 */
38 static FileType IdentifyType(const FileSys::VirtualFile& file); 38 static FileType IdentifyType(const FileSys::VirtualFile& file);
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp
index 1e70f6e11..95b6f339a 100644
--- a/src/core/loader/nso.cpp
+++ b/src/core/loader/nso.cpp
@@ -14,10 +14,10 @@
14#include "common/swap.h" 14#include "common/swap.h"
15#include "core/core.h" 15#include "core/core.h"
16#include "core/file_sys/patch_manager.h" 16#include "core/file_sys/patch_manager.h"
17#include "core/gdbstub/gdbstub.h"
18#include "core/hle/kernel/code_set.h" 17#include "core/hle/kernel/code_set.h"
19#include "core/hle/kernel/memory/page_table.h" 18#include "core/hle/kernel/memory/page_table.h"
20#include "core/hle/kernel/process.h" 19#include "core/hle/kernel/process.h"
20#include "core/hle/kernel/thread.h"
21#include "core/loader/nso.h" 21#include "core/loader/nso.h"
22#include "core/memory.h" 22#include "core/memory.h"
23#include "core/settings.h" 23#include "core/settings.h"
@@ -47,7 +47,7 @@ std::vector<u8> DecompressSegment(const std::vector<u8>& compressed_data,
47} 47}
48 48
49constexpr u32 PageAlignSize(u32 size) { 49constexpr u32 PageAlignSize(u32 size) {
50 return (size + Core::Memory::PAGE_MASK) & ~Core::Memory::PAGE_MASK; 50 return static_cast<u32>((size + Core::Memory::PAGE_MASK) & ~Core::Memory::PAGE_MASK);
51} 51}
52} // Anonymous namespace 52} // Anonymous namespace
53 53
@@ -149,7 +149,7 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::Process& process, Core::S
149 // Apply cheats if they exist and the program has a valid title ID 149 // Apply cheats if they exist and the program has a valid title ID
150 if (pm) { 150 if (pm) {
151 system.SetCurrentProcessBuildID(nso_header.build_id); 151 system.SetCurrentProcessBuildID(nso_header.build_id);
152 const auto cheats = pm->CreateCheatList(system, nso_header.build_id); 152 const auto cheats = pm->CreateCheatList(nso_header.build_id);
153 if (!cheats.empty()) { 153 if (!cheats.empty()) {
154 system.RegisterCheatList(cheats, nso_header.build_id, load_base, image_size); 154 system.RegisterCheatList(cheats, nso_header.build_id, load_base, image_size);
155 } 155 }
@@ -159,9 +159,6 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::Process& process, Core::S
159 codeset.memory = std::move(program_image); 159 codeset.memory = std::move(program_image);
160 process.LoadModule(std::move(codeset), load_base); 160 process.LoadModule(std::move(codeset), load_base);
161 161
162 // Register module with GDBStub
163 GDBStub::RegisterModule(file.GetName(), load_base, load_base);
164
165 return load_base + image_size; 162 return load_base + image_size;
166} 163}
167 164
diff --git a/src/core/loader/nso.h b/src/core/loader/nso.h
index 4bd47787d..3af461b5f 100644
--- a/src/core/loader/nso.h
+++ b/src/core/loader/nso.h
@@ -59,7 +59,7 @@ struct NSOHeader {
59static_assert(sizeof(NSOHeader) == 0x100, "NSOHeader has incorrect size."); 59static_assert(sizeof(NSOHeader) == 0x100, "NSOHeader has incorrect size.");
60static_assert(std::is_trivially_copyable_v<NSOHeader>, "NSOHeader must be trivially copyable."); 60static_assert(std::is_trivially_copyable_v<NSOHeader>, "NSOHeader must be trivially copyable.");
61 61
62constexpr u64 NSO_ARGUMENT_DATA_ALLOCATION_SIZE = 0x9000; 62constexpr u32 NSO_ARGUMENT_DATA_ALLOCATION_SIZE = 0x9000;
63 63
64struct NSOArgumentHeader { 64struct NSOArgumentHeader {
65 u32_le allocated_size; 65 u32_le allocated_size;
@@ -75,7 +75,7 @@ public:
75 75
76 /** 76 /**
77 * Returns the type of the file 77 * Returns the type of the file
78 * @param file std::shared_ptr<VfsFile> open file 78 * @param file open file
79 * @return FileType found, or FileType::Error if this loader doesn't know it 79 * @return FileType found, or FileType::Error if this loader doesn't know it
80 */ 80 */
81 static FileType IdentifyType(const FileSys::VirtualFile& file); 81 static FileType IdentifyType(const FileSys::VirtualFile& file);
diff --git a/src/core/loader/nsp.cpp b/src/core/loader/nsp.cpp
index 15e528fa8..928f64c8c 100644
--- a/src/core/loader/nsp.cpp
+++ b/src/core/loader/nsp.cpp
@@ -21,26 +21,34 @@
21 21
22namespace Loader { 22namespace Loader {
23 23
24AppLoader_NSP::AppLoader_NSP(FileSys::VirtualFile file) 24AppLoader_NSP::AppLoader_NSP(FileSys::VirtualFile file,
25 : AppLoader(file), nsp(std::make_unique<FileSys::NSP>(file)), 25 const Service::FileSystem::FileSystemController& fsc,
26 const FileSys::ContentProvider& content_provider,
27 std::size_t program_index)
28 : AppLoader(file), nsp(std::make_unique<FileSys::NSP>(file, program_index)),
26 title_id(nsp->GetProgramTitleID()) { 29 title_id(nsp->GetProgramTitleID()) {
27 30
28 if (nsp->GetStatus() != ResultStatus::Success) 31 if (nsp->GetStatus() != ResultStatus::Success) {
29 return; 32 return;
33 }
30 34
31 if (nsp->IsExtractedType()) { 35 if (nsp->IsExtractedType()) {
32 secondary_loader = std::make_unique<AppLoader_DeconstructedRomDirectory>(nsp->GetExeFS()); 36 secondary_loader = std::make_unique<AppLoader_DeconstructedRomDirectory>(nsp->GetExeFS());
33 } else { 37 } else {
34 const auto control_nca = 38 const auto control_nca =
35 nsp->GetNCA(nsp->GetProgramTitleID(), FileSys::ContentRecordType::Control); 39 nsp->GetNCA(nsp->GetProgramTitleID(), FileSys::ContentRecordType::Control);
36 if (control_nca == nullptr || control_nca->GetStatus() != ResultStatus::Success) 40 if (control_nca == nullptr || control_nca->GetStatus() != ResultStatus::Success) {
37 return; 41 return;
42 }
38 43
39 std::tie(nacp_file, icon_file) = 44 std::tie(nacp_file, icon_file) = [this, &content_provider, &control_nca, &fsc] {
40 FileSys::PatchManager(nsp->GetProgramTitleID()).ParseControlNCA(*control_nca); 45 const FileSys::PatchManager pm{nsp->GetProgramTitleID(), fsc, content_provider};
46 return pm.ParseControlNCA(*control_nca);
47 }();
41 48
42 if (title_id == 0) 49 if (title_id == 0) {
43 return; 50 return;
51 }
44 52
45 secondary_loader = std::make_unique<AppLoader_NCA>( 53 secondary_loader = std::make_unique<AppLoader_NCA>(
46 nsp->GetNCAFile(title_id, FileSys::ContentRecordType::Program)); 54 nsp->GetNCAFile(title_id, FileSys::ContentRecordType::Program));
diff --git a/src/core/loader/nsp.h b/src/core/loader/nsp.h
index b27deb686..d48d87f2c 100644
--- a/src/core/loader/nsp.h
+++ b/src/core/loader/nsp.h
@@ -9,15 +9,16 @@
9#include "core/file_sys/vfs.h" 9#include "core/file_sys/vfs.h"
10#include "core/loader/loader.h" 10#include "core/loader/loader.h"
11 11
12namespace Core {
13class System;
14}
15
16namespace FileSys { 12namespace FileSys {
13class ContentProvider;
17class NACP; 14class NACP;
18class NSP; 15class NSP;
19} // namespace FileSys 16} // namespace FileSys
20 17
18namespace Service::FileSystem {
19class FileSystemController;
20}
21
21namespace Loader { 22namespace Loader {
22 23
23class AppLoader_NCA; 24class AppLoader_NCA;
@@ -25,12 +26,15 @@ class AppLoader_NCA;
25/// Loads an XCI file 26/// Loads an XCI file
26class AppLoader_NSP final : public AppLoader { 27class AppLoader_NSP final : public AppLoader {
27public: 28public:
28 explicit AppLoader_NSP(FileSys::VirtualFile file); 29 explicit AppLoader_NSP(FileSys::VirtualFile file,
30 const Service::FileSystem::FileSystemController& fsc,
31 const FileSys::ContentProvider& content_provider,
32 std::size_t program_index);
29 ~AppLoader_NSP() override; 33 ~AppLoader_NSP() override;
30 34
31 /** 35 /**
32 * Returns the type of the file 36 * Returns the type of the file
33 * @param file std::shared_ptr<VfsFile> open file 37 * @param file open file
34 * @return FileType found, or FileType::Error if this loader doesn't know it 38 * @return FileType found, or FileType::Error if this loader doesn't know it
35 */ 39 */
36 static FileType IdentifyType(const FileSys::VirtualFile& file); 40 static FileType IdentifyType(const FileSys::VirtualFile& file);
diff --git a/src/core/loader/xci.cpp b/src/core/loader/xci.cpp
index 25e83af0f..aaa250cea 100644
--- a/src/core/loader/xci.cpp
+++ b/src/core/loader/xci.cpp
@@ -20,18 +20,25 @@
20 20
21namespace Loader { 21namespace Loader {
22 22
23AppLoader_XCI::AppLoader_XCI(FileSys::VirtualFile file) 23AppLoader_XCI::AppLoader_XCI(FileSys::VirtualFile file,
24 : AppLoader(file), xci(std::make_unique<FileSys::XCI>(file)), 24 const Service::FileSystem::FileSystemController& fsc,
25 const FileSys::ContentProvider& content_provider,
26 std::size_t program_index)
27 : AppLoader(file), xci(std::make_unique<FileSys::XCI>(file, program_index)),
25 nca_loader(std::make_unique<AppLoader_NCA>(xci->GetProgramNCAFile())) { 28 nca_loader(std::make_unique<AppLoader_NCA>(xci->GetProgramNCAFile())) {
26 if (xci->GetStatus() != ResultStatus::Success) 29 if (xci->GetStatus() != ResultStatus::Success) {
27 return; 30 return;
31 }
28 32
29 const auto control_nca = xci->GetNCAByType(FileSys::NCAContentType::Control); 33 const auto control_nca = xci->GetNCAByType(FileSys::NCAContentType::Control);
30 if (control_nca == nullptr || control_nca->GetStatus() != ResultStatus::Success) 34 if (control_nca == nullptr || control_nca->GetStatus() != ResultStatus::Success) {
31 return; 35 return;
36 }
32 37
33 std::tie(nacp_file, icon_file) = 38 std::tie(nacp_file, icon_file) = [this, &content_provider, &control_nca, &fsc] {
34 FileSys::PatchManager(xci->GetProgramTitleID()).ParseControlNCA(*control_nca); 39 const FileSys::PatchManager pm{xci->GetProgramTitleID(), fsc, content_provider};
40 return pm.ParseControlNCA(*control_nca);
41 }();
35} 42}
36 43
37AppLoader_XCI::~AppLoader_XCI() = default; 44AppLoader_XCI::~AppLoader_XCI() = default;
diff --git a/src/core/loader/xci.h b/src/core/loader/xci.h
index 04aea286f..9f0ceb5ef 100644
--- a/src/core/loader/xci.h
+++ b/src/core/loader/xci.h
@@ -9,15 +9,16 @@
9#include "core/file_sys/vfs.h" 9#include "core/file_sys/vfs.h"
10#include "core/loader/loader.h" 10#include "core/loader/loader.h"
11 11
12namespace Core {
13class System;
14}
15
16namespace FileSys { 12namespace FileSys {
13class ContentProvider;
17class NACP; 14class NACP;
18class XCI; 15class XCI;
19} // namespace FileSys 16} // namespace FileSys
20 17
18namespace Service::FileSystem {
19class FileSystemController;
20}
21
21namespace Loader { 22namespace Loader {
22 23
23class AppLoader_NCA; 24class AppLoader_NCA;
@@ -25,12 +26,15 @@ class AppLoader_NCA;
25/// Loads an XCI file 26/// Loads an XCI file
26class AppLoader_XCI final : public AppLoader { 27class AppLoader_XCI final : public AppLoader {
27public: 28public:
28 explicit AppLoader_XCI(FileSys::VirtualFile file); 29 explicit AppLoader_XCI(FileSys::VirtualFile file,
30 const Service::FileSystem::FileSystemController& fsc,
31 const FileSys::ContentProvider& content_provider,
32 std::size_t program_index);
29 ~AppLoader_XCI() override; 33 ~AppLoader_XCI() override;
30 34
31 /** 35 /**
32 * Returns the type of the file 36 * Returns the type of the file
33 * @param file std::shared_ptr<VfsFile> open file 37 * @param file open file
34 * @return FileType found, or FileType::Error if this loader doesn't know it 38 * @return FileType found, or FileType::Error if this loader doesn't know it
35 */ 39 */
36 static FileType IdentifyType(const FileSys::VirtualFile& file); 40 static FileType IdentifyType(const FileSys::VirtualFile& file);
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index c3f4829d7..11609682a 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -44,44 +44,16 @@ struct Memory::Impl {
44 MapPages(page_table, base / PAGE_SIZE, size / PAGE_SIZE, target, Common::PageType::Memory); 44 MapPages(page_table, base / PAGE_SIZE, size / PAGE_SIZE, target, Common::PageType::Memory);
45 } 45 }
46 46
47 void MapIoRegion(Common::PageTable& page_table, VAddr base, u64 size,
48 Common::MemoryHookPointer mmio_handler) {
49 UNIMPLEMENTED();
50 }
51
52 void UnmapRegion(Common::PageTable& page_table, VAddr base, u64 size) { 47 void UnmapRegion(Common::PageTable& page_table, VAddr base, u64 size) {
53 ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: {:016X}", size); 48 ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: {:016X}", size);
54 ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: {:016X}", base); 49 ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: {:016X}", base);
55 MapPages(page_table, base / PAGE_SIZE, size / PAGE_SIZE, 0, Common::PageType::Unmapped); 50 MapPages(page_table, base / PAGE_SIZE, size / PAGE_SIZE, 0, Common::PageType::Unmapped);
56 } 51 }
57 52
58 void AddDebugHook(Common::PageTable& page_table, VAddr base, u64 size,
59 Common::MemoryHookPointer hook) {
60 UNIMPLEMENTED();
61 }
62
63 void RemoveDebugHook(Common::PageTable& page_table, VAddr base, u64 size,
64 Common::MemoryHookPointer hook) {
65 UNIMPLEMENTED();
66 }
67
68 bool IsValidVirtualAddress(const Kernel::Process& process, const VAddr vaddr) const { 53 bool IsValidVirtualAddress(const Kernel::Process& process, const VAddr vaddr) const {
69 const auto& page_table = process.PageTable().PageTableImpl(); 54 const auto& page_table = process.PageTable().PageTableImpl();
70 55 const auto [pointer, type] = page_table.pointers[vaddr >> PAGE_BITS].PointerType();
71 const u8* const page_pointer = page_table.pointers[vaddr >> PAGE_BITS]; 56 return pointer != nullptr || type == Common::PageType::RasterizerCachedMemory;
72 if (page_pointer != nullptr) {
73 return true;
74 }
75
76 if (page_table.attributes[vaddr >> PAGE_BITS] == Common::PageType::RasterizerCachedMemory) {
77 return true;
78 }
79
80 if (page_table.attributes[vaddr >> PAGE_BITS] != Common::PageType::Special) {
81 return false;
82 }
83
84 return false;
85 } 57 }
86 58
87 bool IsValidVirtualAddress(VAddr vaddr) const { 59 bool IsValidVirtualAddress(VAddr vaddr) const {
@@ -99,17 +71,15 @@ struct Memory::Impl {
99 } 71 }
100 72
101 u8* GetPointer(const VAddr vaddr) const { 73 u8* GetPointer(const VAddr vaddr) const {
102 u8* const page_pointer{current_page_table->pointers[vaddr >> PAGE_BITS]}; 74 const uintptr_t raw_pointer = current_page_table->pointers[vaddr >> PAGE_BITS].Raw();
103 if (page_pointer) { 75 if (u8* const pointer = Common::PageTable::PageInfo::ExtractPointer(raw_pointer)) {
104 return page_pointer + vaddr; 76 return pointer + vaddr;
105 } 77 }
106 78 const auto type = Common::PageTable::PageInfo::ExtractType(raw_pointer);
107 if (current_page_table->attributes[vaddr >> PAGE_BITS] == 79 if (type == Common::PageType::RasterizerCachedMemory) {
108 Common::PageType::RasterizerCachedMemory) {
109 return GetPointerFromRasterizerCachedMemory(vaddr); 80 return GetPointerFromRasterizerCachedMemory(vaddr);
110 } 81 }
111 82 return nullptr;
112 return {};
113 } 83 }
114 84
115 u8 Read8(const VAddr addr) { 85 u8 Read8(const VAddr addr) {
@@ -120,9 +90,9 @@ struct Memory::Impl {
120 if ((addr & 1) == 0) { 90 if ((addr & 1) == 0) {
121 return Read<u16_le>(addr); 91 return Read<u16_le>(addr);
122 } else { 92 } else {
123 const u8 a{Read<u8>(addr)}; 93 const u32 a{Read<u8>(addr)};
124 const u8 b{Read<u8>(addr + sizeof(u8))}; 94 const u32 b{Read<u8>(addr + sizeof(u8))};
125 return (static_cast<u16>(b) << 8) | a; 95 return static_cast<u16>((b << 8) | a);
126 } 96 }
127 } 97 }
128 98
@@ -130,9 +100,9 @@ struct Memory::Impl {
130 if ((addr & 3) == 0) { 100 if ((addr & 3) == 0) {
131 return Read<u32_le>(addr); 101 return Read<u32_le>(addr);
132 } else { 102 } else {
133 const u16 a{Read16(addr)}; 103 const u32 a{Read16(addr)};
134 const u16 b{Read16(addr + sizeof(u16))}; 104 const u32 b{Read16(addr + sizeof(u16))};
135 return (static_cast<u32>(b) << 16) | a; 105 return (b << 16) | a;
136 } 106 }
137 } 107 }
138 108
@@ -221,7 +191,8 @@ struct Memory::Impl {
221 std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size); 191 std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size);
222 const auto current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset); 192 const auto current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset);
223 193
224 switch (page_table.attributes[page_index]) { 194 const auto [pointer, type] = page_table.pointers[page_index].PointerType();
195 switch (type) {
225 case Common::PageType::Unmapped: { 196 case Common::PageType::Unmapped: {
226 LOG_ERROR(HW_Memory, 197 LOG_ERROR(HW_Memory,
227 "Unmapped ReadBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})", 198 "Unmapped ReadBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})",
@@ -230,10 +201,8 @@ struct Memory::Impl {
230 break; 201 break;
231 } 202 }
232 case Common::PageType::Memory: { 203 case Common::PageType::Memory: {
233 DEBUG_ASSERT(page_table.pointers[page_index]); 204 DEBUG_ASSERT(pointer);
234 205 const u8* const src_ptr = pointer + page_offset + (page_index << PAGE_BITS);
235 const u8* const src_ptr =
236 page_table.pointers[page_index] + page_offset + (page_index << PAGE_BITS);
237 std::memcpy(dest_buffer, src_ptr, copy_amount); 206 std::memcpy(dest_buffer, src_ptr, copy_amount);
238 break; 207 break;
239 } 208 }
@@ -267,7 +236,8 @@ struct Memory::Impl {
267 std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size); 236 std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size);
268 const auto current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset); 237 const auto current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset);
269 238
270 switch (page_table.attributes[page_index]) { 239 const auto [pointer, type] = page_table.pointers[page_index].PointerType();
240 switch (type) {
271 case Common::PageType::Unmapped: { 241 case Common::PageType::Unmapped: {
272 LOG_ERROR(HW_Memory, 242 LOG_ERROR(HW_Memory,
273 "Unmapped ReadBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})", 243 "Unmapped ReadBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})",
@@ -276,10 +246,8 @@ struct Memory::Impl {
276 break; 246 break;
277 } 247 }
278 case Common::PageType::Memory: { 248 case Common::PageType::Memory: {
279 DEBUG_ASSERT(page_table.pointers[page_index]); 249 DEBUG_ASSERT(pointer);
280 250 const u8* const src_ptr = pointer + page_offset + (page_index << PAGE_BITS);
281 const u8* const src_ptr =
282 page_table.pointers[page_index] + page_offset + (page_index << PAGE_BITS);
283 std::memcpy(dest_buffer, src_ptr, copy_amount); 251 std::memcpy(dest_buffer, src_ptr, copy_amount);
284 break; 252 break;
285 } 253 }
@@ -319,7 +287,8 @@ struct Memory::Impl {
319 std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size); 287 std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size);
320 const auto current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset); 288 const auto current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset);
321 289
322 switch (page_table.attributes[page_index]) { 290 const auto [pointer, type] = page_table.pointers[page_index].PointerType();
291 switch (type) {
323 case Common::PageType::Unmapped: { 292 case Common::PageType::Unmapped: {
324 LOG_ERROR(HW_Memory, 293 LOG_ERROR(HW_Memory,
325 "Unmapped WriteBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})", 294 "Unmapped WriteBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})",
@@ -327,10 +296,8 @@ struct Memory::Impl {
327 break; 296 break;
328 } 297 }
329 case Common::PageType::Memory: { 298 case Common::PageType::Memory: {
330 DEBUG_ASSERT(page_table.pointers[page_index]); 299 DEBUG_ASSERT(pointer);
331 300 u8* const dest_ptr = pointer + page_offset + (page_index << PAGE_BITS);
332 u8* const dest_ptr =
333 page_table.pointers[page_index] + page_offset + (page_index << PAGE_BITS);
334 std::memcpy(dest_ptr, src_buffer, copy_amount); 301 std::memcpy(dest_ptr, src_buffer, copy_amount);
335 break; 302 break;
336 } 303 }
@@ -363,7 +330,8 @@ struct Memory::Impl {
363 std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size); 330 std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size);
364 const auto current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset); 331 const auto current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset);
365 332
366 switch (page_table.attributes[page_index]) { 333 const auto [pointer, type] = page_table.pointers[page_index].PointerType();
334 switch (type) {
367 case Common::PageType::Unmapped: { 335 case Common::PageType::Unmapped: {
368 LOG_ERROR(HW_Memory, 336 LOG_ERROR(HW_Memory,
369 "Unmapped WriteBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})", 337 "Unmapped WriteBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})",
@@ -371,10 +339,8 @@ struct Memory::Impl {
371 break; 339 break;
372 } 340 }
373 case Common::PageType::Memory: { 341 case Common::PageType::Memory: {
374 DEBUG_ASSERT(page_table.pointers[page_index]); 342 DEBUG_ASSERT(pointer);
375 343 u8* const dest_ptr = pointer + page_offset + (page_index << PAGE_BITS);
376 u8* const dest_ptr =
377 page_table.pointers[page_index] + page_offset + (page_index << PAGE_BITS);
378 std::memcpy(dest_ptr, src_buffer, copy_amount); 344 std::memcpy(dest_ptr, src_buffer, copy_amount);
379 break; 345 break;
380 } 346 }
@@ -413,7 +379,8 @@ struct Memory::Impl {
413 std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size); 379 std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size);
414 const auto current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset); 380 const auto current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset);
415 381
416 switch (page_table.attributes[page_index]) { 382 const auto [pointer, type] = page_table.pointers[page_index].PointerType();
383 switch (type) {
417 case Common::PageType::Unmapped: { 384 case Common::PageType::Unmapped: {
418 LOG_ERROR(HW_Memory, 385 LOG_ERROR(HW_Memory,
419 "Unmapped ZeroBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})", 386 "Unmapped ZeroBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})",
@@ -421,10 +388,8 @@ struct Memory::Impl {
421 break; 388 break;
422 } 389 }
423 case Common::PageType::Memory: { 390 case Common::PageType::Memory: {
424 DEBUG_ASSERT(page_table.pointers[page_index]); 391 DEBUG_ASSERT(pointer);
425 392 u8* const dest_ptr = pointer + page_offset + (page_index << PAGE_BITS);
426 u8* dest_ptr =
427 page_table.pointers[page_index] + page_offset + (page_index << PAGE_BITS);
428 std::memset(dest_ptr, 0, copy_amount); 393 std::memset(dest_ptr, 0, copy_amount);
429 break; 394 break;
430 } 395 }
@@ -460,7 +425,8 @@ struct Memory::Impl {
460 std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size); 425 std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size);
461 const auto current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset); 426 const auto current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset);
462 427
463 switch (page_table.attributes[page_index]) { 428 const auto [pointer, type] = page_table.pointers[page_index].PointerType();
429 switch (type) {
464 case Common::PageType::Unmapped: { 430 case Common::PageType::Unmapped: {
465 LOG_ERROR(HW_Memory, 431 LOG_ERROR(HW_Memory,
466 "Unmapped CopyBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})", 432 "Unmapped CopyBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})",
@@ -469,9 +435,8 @@ struct Memory::Impl {
469 break; 435 break;
470 } 436 }
471 case Common::PageType::Memory: { 437 case Common::PageType::Memory: {
472 DEBUG_ASSERT(page_table.pointers[page_index]); 438 DEBUG_ASSERT(pointer);
473 const u8* src_ptr = 439 const u8* src_ptr = pointer + page_offset + (page_index << PAGE_BITS);
474 page_table.pointers[page_index] + page_offset + (page_index << PAGE_BITS);
475 WriteBlock(process, dest_addr, src_ptr, copy_amount); 440 WriteBlock(process, dest_addr, src_ptr, copy_amount);
476 break; 441 break;
477 } 442 }
@@ -501,16 +466,15 @@ struct Memory::Impl {
501 if (vaddr == 0) { 466 if (vaddr == 0) {
502 return; 467 return;
503 } 468 }
504
505 // Iterate over a contiguous CPU address space, which corresponds to the specified GPU 469 // Iterate over a contiguous CPU address space, which corresponds to the specified GPU
506 // address space, marking the region as un/cached. The region is marked un/cached at a 470 // address space, marking the region as un/cached. The region is marked un/cached at a
507 // granularity of CPU pages, hence why we iterate on a CPU page basis (note: GPU page size 471 // granularity of CPU pages, hence why we iterate on a CPU page basis (note: GPU page size
508 // is different). This assumes the specified GPU address region is contiguous as well. 472 // is different). This assumes the specified GPU address region is contiguous as well.
509 473
510 u64 num_pages = ((vaddr + size - 1) >> PAGE_BITS) - (vaddr >> PAGE_BITS) + 1; 474 const u64 num_pages = ((vaddr + size - 1) >> PAGE_BITS) - (vaddr >> PAGE_BITS) + 1;
511 for (unsigned i = 0; i < num_pages; ++i, vaddr += PAGE_SIZE) { 475 for (u64 i = 0; i < num_pages; ++i, vaddr += PAGE_SIZE) {
512 Common::PageType& page_type{current_page_table->attributes[vaddr >> PAGE_BITS]}; 476 const Common::PageType page_type{
513 477 current_page_table->pointers[vaddr >> PAGE_BITS].Type()};
514 if (cached) { 478 if (cached) {
515 // Switch page type to cached if now cached 479 // Switch page type to cached if now cached
516 switch (page_type) { 480 switch (page_type) {
@@ -519,8 +483,8 @@ struct Memory::Impl {
519 // space, for example, a system module need not have a VRAM mapping. 483 // space, for example, a system module need not have a VRAM mapping.
520 break; 484 break;
521 case Common::PageType::Memory: 485 case Common::PageType::Memory:
522 page_type = Common::PageType::RasterizerCachedMemory; 486 current_page_table->pointers[vaddr >> PAGE_BITS].Store(
523 current_page_table->pointers[vaddr >> PAGE_BITS] = nullptr; 487 nullptr, Common::PageType::RasterizerCachedMemory);
524 break; 488 break;
525 case Common::PageType::RasterizerCachedMemory: 489 case Common::PageType::RasterizerCachedMemory:
526 // There can be more than one GPU region mapped per CPU region, so it's common 490 // There can be more than one GPU region mapped per CPU region, so it's common
@@ -541,16 +505,16 @@ struct Memory::Impl {
541 // that this area is already unmarked as cached. 505 // that this area is already unmarked as cached.
542 break; 506 break;
543 case Common::PageType::RasterizerCachedMemory: { 507 case Common::PageType::RasterizerCachedMemory: {
544 u8* pointer{GetPointerFromRasterizerCachedMemory(vaddr & ~PAGE_MASK)}; 508 u8* const pointer{GetPointerFromRasterizerCachedMemory(vaddr & ~PAGE_MASK)};
545 if (pointer == nullptr) { 509 if (pointer == nullptr) {
546 // It's possible that this function has been called while updating the 510 // It's possible that this function has been called while updating the
547 // pagetable after unmapping a VMA. In that case the underlying VMA will no 511 // pagetable after unmapping a VMA. In that case the underlying VMA will no
548 // longer exist, and we should just leave the pagetable entry blank. 512 // longer exist, and we should just leave the pagetable entry blank.
549 page_type = Common::PageType::Unmapped; 513 current_page_table->pointers[vaddr >> PAGE_BITS].Store(
514 nullptr, Common::PageType::Unmapped);
550 } else { 515 } else {
551 current_page_table->pointers[vaddr >> PAGE_BITS] = 516 current_page_table->pointers[vaddr >> PAGE_BITS].Store(
552 pointer - (vaddr & ~PAGE_MASK); 517 pointer - (vaddr & ~PAGE_MASK), Common::PageType::Memory);
553 page_type = Common::PageType::Memory;
554 } 518 }
555 break; 519 break;
556 } 520 }
@@ -580,7 +544,7 @@ struct Memory::Impl {
580 auto& gpu = system.GPU(); 544 auto& gpu = system.GPU();
581 for (u64 i = 0; i < size; i++) { 545 for (u64 i = 0; i < size; i++) {
582 const auto page = base + i; 546 const auto page = base + i;
583 if (page_table.attributes[page] == Common::PageType::RasterizerCachedMemory) { 547 if (page_table.pointers[page].Type() == Common::PageType::RasterizerCachedMemory) {
584 gpu.FlushAndInvalidateRegion(page << PAGE_BITS, PAGE_SIZE); 548 gpu.FlushAndInvalidateRegion(page << PAGE_BITS, PAGE_SIZE);
585 } 549 }
586 } 550 }
@@ -595,20 +559,18 @@ struct Memory::Impl {
595 "Mapping memory page without a pointer @ {:016x}", base * PAGE_SIZE); 559 "Mapping memory page without a pointer @ {:016x}", base * PAGE_SIZE);
596 560
597 while (base != end) { 561 while (base != end) {
598 page_table.attributes[base] = type; 562 page_table.pointers[base].Store(nullptr, type);
599 page_table.pointers[base] = nullptr;
600 page_table.backing_addr[base] = 0; 563 page_table.backing_addr[base] = 0;
601 564
602 base += 1; 565 base += 1;
603 } 566 }
604 } else { 567 } else {
605 while (base != end) { 568 while (base != end) {
606 page_table.pointers[base] = 569 page_table.pointers[base].Store(
607 system.DeviceMemory().GetPointer(target) - (base << PAGE_BITS); 570 system.DeviceMemory().GetPointer(target) - (base << PAGE_BITS), type);
608 page_table.attributes[base] = type;
609 page_table.backing_addr[base] = target - (base << PAGE_BITS); 571 page_table.backing_addr[base] = target - (base << PAGE_BITS);
610 572
611 ASSERT_MSG(page_table.pointers[base], 573 ASSERT_MSG(page_table.pointers[base].Pointer(),
612 "memory mapping base yield a nullptr within the table"); 574 "memory mapping base yield a nullptr within the table");
613 575
614 base += 1; 576 base += 1;
@@ -630,16 +592,14 @@ struct Memory::Impl {
630 */ 592 */
631 template <typename T> 593 template <typename T>
632 T Read(const VAddr vaddr) { 594 T Read(const VAddr vaddr) {
633 const u8* const page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS]; 595 // Avoid adding any extra logic to this fast-path block
634 if (page_pointer != nullptr) { 596 const uintptr_t raw_pointer = current_page_table->pointers[vaddr >> PAGE_BITS].Raw();
635 // NOTE: Avoid adding any extra logic to this fast-path block 597 if (const u8* const pointer = Common::PageTable::PageInfo::ExtractPointer(raw_pointer)) {
636 T value; 598 T value;
637 std::memcpy(&value, &page_pointer[vaddr], sizeof(T)); 599 std::memcpy(&value, &pointer[vaddr], sizeof(T));
638 return value; 600 return value;
639 } 601 }
640 602 switch (Common::PageTable::PageInfo::ExtractType(raw_pointer)) {
641 const Common::PageType type = current_page_table->attributes[vaddr >> PAGE_BITS];
642 switch (type) {
643 case Common::PageType::Unmapped: 603 case Common::PageType::Unmapped:
644 LOG_ERROR(HW_Memory, "Unmapped Read{} @ 0x{:08X}", sizeof(T) * 8, vaddr); 604 LOG_ERROR(HW_Memory, "Unmapped Read{} @ 0x{:08X}", sizeof(T) * 8, vaddr);
645 return 0; 605 return 0;
@@ -667,20 +627,16 @@ struct Memory::Impl {
667 * @tparam T The data type to write to memory. This type *must* be 627 * @tparam T The data type to write to memory. This type *must* be
668 * trivially copyable, otherwise the behavior of this function 628 * trivially copyable, otherwise the behavior of this function
669 * is undefined. 629 * is undefined.
670 *
671 * @returns The instance of T write to the specified virtual address.
672 */ 630 */
673 template <typename T> 631 template <typename T>
674 void Write(const VAddr vaddr, const T data) { 632 void Write(const VAddr vaddr, const T data) {
675 u8* const page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS]; 633 // Avoid adding any extra logic to this fast-path block
676 if (page_pointer != nullptr) { 634 const uintptr_t raw_pointer = current_page_table->pointers[vaddr >> PAGE_BITS].Raw();
677 // NOTE: Avoid adding any extra logic to this fast-path block 635 if (u8* const pointer = Common::PageTable::PageInfo::ExtractPointer(raw_pointer)) {
678 std::memcpy(&page_pointer[vaddr], &data, sizeof(T)); 636 std::memcpy(&pointer[vaddr], &data, sizeof(T));
679 return; 637 return;
680 } 638 }
681 639 switch (Common::PageTable::PageInfo::ExtractType(raw_pointer)) {
682 const Common::PageType type = current_page_table->attributes[vaddr >> PAGE_BITS];
683 switch (type) {
684 case Common::PageType::Unmapped: 640 case Common::PageType::Unmapped:
685 LOG_ERROR(HW_Memory, "Unmapped Write{} 0x{:08X} @ 0x{:016X}", sizeof(data) * 8, 641 LOG_ERROR(HW_Memory, "Unmapped Write{} 0x{:08X} @ 0x{:016X}", sizeof(data) * 8,
686 static_cast<u32>(data), vaddr); 642 static_cast<u32>(data), vaddr);
@@ -701,15 +657,13 @@ struct Memory::Impl {
701 657
702 template <typename T> 658 template <typename T>
703 bool WriteExclusive(const VAddr vaddr, const T data, const T expected) { 659 bool WriteExclusive(const VAddr vaddr, const T data, const T expected) {
704 u8* page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS]; 660 const uintptr_t raw_pointer = current_page_table->pointers[vaddr >> PAGE_BITS].Raw();
705 if (page_pointer != nullptr) { 661 if (u8* const pointer = Common::PageTable::PageInfo::ExtractPointer(raw_pointer)) {
706 // NOTE: Avoid adding any extra logic to this fast-path block 662 // NOTE: Avoid adding any extra logic to this fast-path block
707 auto* pointer = reinterpret_cast<volatile T*>(&page_pointer[vaddr]); 663 const auto volatile_pointer = reinterpret_cast<volatile T*>(&pointer[vaddr]);
708 return Common::AtomicCompareAndSwap(pointer, data, expected); 664 return Common::AtomicCompareAndSwap(volatile_pointer, data, expected);
709 } 665 }
710 666 switch (Common::PageTable::PageInfo::ExtractType(raw_pointer)) {
711 const Common::PageType type = current_page_table->attributes[vaddr >> PAGE_BITS];
712 switch (type) {
713 case Common::PageType::Unmapped: 667 case Common::PageType::Unmapped:
714 LOG_ERROR(HW_Memory, "Unmapped Write{} 0x{:08X} @ 0x{:016X}", sizeof(data) * 8, 668 LOG_ERROR(HW_Memory, "Unmapped Write{} 0x{:08X} @ 0x{:016X}", sizeof(data) * 8,
715 static_cast<u32>(data), vaddr); 669 static_cast<u32>(data), vaddr);
@@ -730,15 +684,13 @@ struct Memory::Impl {
730 } 684 }
731 685
732 bool WriteExclusive128(const VAddr vaddr, const u128 data, const u128 expected) { 686 bool WriteExclusive128(const VAddr vaddr, const u128 data, const u128 expected) {
733 u8* const page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS]; 687 const uintptr_t raw_pointer = current_page_table->pointers[vaddr >> PAGE_BITS].Raw();
734 if (page_pointer != nullptr) { 688 if (u8* const pointer = Common::PageTable::PageInfo::ExtractPointer(raw_pointer)) {
735 // NOTE: Avoid adding any extra logic to this fast-path block 689 // NOTE: Avoid adding any extra logic to this fast-path block
736 auto* pointer = reinterpret_cast<volatile u64*>(&page_pointer[vaddr]); 690 const auto volatile_pointer = reinterpret_cast<volatile u64*>(&pointer[vaddr]);
737 return Common::AtomicCompareAndSwap(pointer, data, expected); 691 return Common::AtomicCompareAndSwap(volatile_pointer, data, expected);
738 } 692 }
739 693 switch (Common::PageTable::PageInfo::ExtractType(raw_pointer)) {
740 const Common::PageType type = current_page_table->attributes[vaddr >> PAGE_BITS];
741 switch (type) {
742 case Common::PageType::Unmapped: 694 case Common::PageType::Unmapped:
743 LOG_ERROR(HW_Memory, "Unmapped Write{} 0x{:08X} @ 0x{:016X}{:016X}", sizeof(data) * 8, 695 LOG_ERROR(HW_Memory, "Unmapped Write{} 0x{:08X} @ 0x{:016X}{:016X}", sizeof(data) * 8,
744 static_cast<u64>(data[1]), static_cast<u64>(data[0]), vaddr); 696 static_cast<u64>(data[1]), static_cast<u64>(data[0]), vaddr);
@@ -773,25 +725,10 @@ void Memory::MapMemoryRegion(Common::PageTable& page_table, VAddr base, u64 size
773 impl->MapMemoryRegion(page_table, base, size, target); 725 impl->MapMemoryRegion(page_table, base, size, target);
774} 726}
775 727
776void Memory::MapIoRegion(Common::PageTable& page_table, VAddr base, u64 size,
777 Common::MemoryHookPointer mmio_handler) {
778 impl->MapIoRegion(page_table, base, size, std::move(mmio_handler));
779}
780
781void Memory::UnmapRegion(Common::PageTable& page_table, VAddr base, u64 size) { 728void Memory::UnmapRegion(Common::PageTable& page_table, VAddr base, u64 size) {
782 impl->UnmapRegion(page_table, base, size); 729 impl->UnmapRegion(page_table, base, size);
783} 730}
784 731
785void Memory::AddDebugHook(Common::PageTable& page_table, VAddr base, u64 size,
786 Common::MemoryHookPointer hook) {
787 impl->AddDebugHook(page_table, base, size, std::move(hook));
788}
789
790void Memory::RemoveDebugHook(Common::PageTable& page_table, VAddr base, u64 size,
791 Common::MemoryHookPointer hook) {
792 impl->RemoveDebugHook(page_table, base, size, std::move(hook));
793}
794
795bool Memory::IsValidVirtualAddress(const Kernel::Process& process, const VAddr vaddr) const { 732bool Memory::IsValidVirtualAddress(const Kernel::Process& process, const VAddr vaddr) const {
796 return impl->IsValidVirtualAddress(process, vaddr); 733 return impl->IsValidVirtualAddress(process, vaddr);
797} 734}
diff --git a/src/core/memory.h b/src/core/memory.h
index 4a1cc63f4..705ebb23d 100644
--- a/src/core/memory.h
+++ b/src/core/memory.h
@@ -8,7 +8,6 @@
8#include <memory> 8#include <memory>
9#include <string> 9#include <string>
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "common/memory_hook.h"
12 11
13namespace Common { 12namespace Common {
14struct PageTable; 13struct PageTable;
@@ -78,17 +77,6 @@ public:
78 void MapMemoryRegion(Common::PageTable& page_table, VAddr base, u64 size, PAddr target); 77 void MapMemoryRegion(Common::PageTable& page_table, VAddr base, u64 size, PAddr target);
79 78
80 /** 79 /**
81 * Maps a region of the emulated process address space as a IO region.
82 *
83 * @param page_table The page table of the emulated process.
84 * @param base The address to start mapping at. Must be page-aligned.
85 * @param size The amount of bytes to map. Must be page-aligned.
86 * @param mmio_handler The handler that backs the mapping.
87 */
88 void MapIoRegion(Common::PageTable& page_table, VAddr base, u64 size,
89 Common::MemoryHookPointer mmio_handler);
90
91 /**
92 * Unmaps a region of the emulated process address space. 80 * Unmaps a region of the emulated process address space.
93 * 81 *
94 * @param page_table The page table of the emulated process. 82 * @param page_table The page table of the emulated process.
@@ -98,28 +86,6 @@ public:
98 void UnmapRegion(Common::PageTable& page_table, VAddr base, u64 size); 86 void UnmapRegion(Common::PageTable& page_table, VAddr base, u64 size);
99 87
100 /** 88 /**
101 * Adds a memory hook to intercept reads and writes to given region of memory.
102 *
103 * @param page_table The page table of the emulated process
104 * @param base The starting address to apply the hook to.
105 * @param size The size of the memory region to apply the hook to, in bytes.
106 * @param hook The hook to apply to the region of memory.
107 */
108 void AddDebugHook(Common::PageTable& page_table, VAddr base, u64 size,
109 Common::MemoryHookPointer hook);
110
111 /**
112 * Removes a memory hook from a given range of memory.
113 *
114 * @param page_table The page table of the emulated process.
115 * @param base The starting address to remove the hook from.
116 * @param size The size of the memory region to remove the hook from, in bytes.
117 * @param hook The hook to remove from the specified region of memory.
118 */
119 void RemoveDebugHook(Common::PageTable& page_table, VAddr base, u64 size,
120 Common::MemoryHookPointer hook);
121
122 /**
123 * Checks whether or not the supplied address is a valid virtual 89 * Checks whether or not the supplied address is a valid virtual
124 * address for the given process. 90 * address for the given process.
125 * 91 *
diff --git a/src/core/memory/cheat_engine.cpp b/src/core/memory/cheat_engine.cpp
index 29284a42d..2dd0eb0f8 100644
--- a/src/core/memory/cheat_engine.cpp
+++ b/src/core/memory/cheat_engine.cpp
@@ -153,8 +153,9 @@ std::vector<CheatEntry> TextCheatParser::Parse(std::string_view data) const {
153 return {}; 153 return {};
154 } 154 }
155 155
156 const auto value = static_cast<u32>(std::stoul(hex, nullptr, 0x10));
156 out[*current_entry].definition.opcodes[out[*current_entry].definition.num_opcodes++] = 157 out[*current_entry].definition.opcodes[out[*current_entry].definition.num_opcodes++] =
157 std::stoul(hex, nullptr, 0x10); 158 value;
158 159
159 i += 8; 160 i += 8;
160 } else { 161 } else {
diff --git a/src/core/network/network.cpp b/src/core/network/network.cpp
index 56d173b5e..681e93468 100644
--- a/src/core/network/network.cpp
+++ b/src/core/network/network.cpp
@@ -11,7 +11,7 @@
11#ifdef _WIN32 11#ifdef _WIN32
12#define _WINSOCK_DEPRECATED_NO_WARNINGS // gethostname 12#define _WINSOCK_DEPRECATED_NO_WARNINGS // gethostname
13#include <winsock2.h> 13#include <winsock2.h>
14#elif __unix__ 14#elif YUZU_UNIX
15#include <errno.h> 15#include <errno.h>
16#include <fcntl.h> 16#include <fcntl.h>
17#include <netdb.h> 17#include <netdb.h>
@@ -54,7 +54,7 @@ constexpr IPv4Address TranslateIPv4(in_addr addr) {
54sockaddr TranslateFromSockAddrIn(SockAddrIn input) { 54sockaddr TranslateFromSockAddrIn(SockAddrIn input) {
55 sockaddr_in result; 55 sockaddr_in result;
56 56
57#ifdef __unix__ 57#if YUZU_UNIX
58 result.sin_len = sizeof(result); 58 result.sin_len = sizeof(result);
59#endif 59#endif
60 60
@@ -63,7 +63,7 @@ sockaddr TranslateFromSockAddrIn(SockAddrIn input) {
63 result.sin_family = AF_INET; 63 result.sin_family = AF_INET;
64 break; 64 break;
65 default: 65 default:
66 UNIMPLEMENTED_MSG("Unhandled sockaddr family={}", static_cast<int>(input.family)); 66 UNIMPLEMENTED_MSG("Unhandled sockaddr family={}", input.family);
67 result.sin_family = AF_INET; 67 result.sin_family = AF_INET;
68 break; 68 break;
69 } 69 }
@@ -99,7 +99,7 @@ bool EnableNonBlock(SOCKET fd, bool enable) {
99 return ioctlsocket(fd, FIONBIO, &value) != SOCKET_ERROR; 99 return ioctlsocket(fd, FIONBIO, &value) != SOCKET_ERROR;
100} 100}
101 101
102#elif __unix__ // ^ _WIN32 v __unix__ 102#elif YUZU_UNIX // ^ _WIN32 v YUZU_UNIX
103 103
104using SOCKET = int; 104using SOCKET = int;
105using WSAPOLLFD = pollfd; 105using WSAPOLLFD = pollfd;
@@ -133,7 +133,7 @@ sockaddr TranslateFromSockAddrIn(SockAddrIn input) {
133 result.sin_family = AF_INET; 133 result.sin_family = AF_INET;
134 break; 134 break;
135 default: 135 default:
136 UNIMPLEMENTED_MSG("Unhandled sockaddr family={}", static_cast<int>(input.family)); 136 UNIMPLEMENTED_MSG("Unhandled sockaddr family={}", input.family);
137 result.sin_family = AF_INET; 137 result.sin_family = AF_INET;
138 break; 138 break;
139 } 139 }
@@ -148,7 +148,7 @@ sockaddr TranslateFromSockAddrIn(SockAddrIn input) {
148} 148}
149 149
150int WSAPoll(WSAPOLLFD* fds, ULONG nfds, int timeout) { 150int WSAPoll(WSAPOLLFD* fds, ULONG nfds, int timeout) {
151 return poll(fds, nfds, timeout); 151 return poll(fds, static_cast<nfds_t>(nfds), timeout);
152} 152}
153 153
154int closesocket(SOCKET fd) { 154int closesocket(SOCKET fd) {
@@ -186,7 +186,7 @@ int TranslateDomain(Domain domain) {
186 case Domain::INET: 186 case Domain::INET:
187 return AF_INET; 187 return AF_INET;
188 default: 188 default:
189 UNIMPLEMENTED_MSG("Unimplemented domain={}", static_cast<int>(domain)); 189 UNIMPLEMENTED_MSG("Unimplemented domain={}", domain);
190 return 0; 190 return 0;
191 } 191 }
192} 192}
@@ -198,7 +198,7 @@ int TranslateType(Type type) {
198 case Type::DGRAM: 198 case Type::DGRAM:
199 return SOCK_DGRAM; 199 return SOCK_DGRAM;
200 default: 200 default:
201 UNIMPLEMENTED_MSG("Unimplemented type={}", static_cast<int>(type)); 201 UNIMPLEMENTED_MSG("Unimplemented type={}", type);
202 return 0; 202 return 0;
203 } 203 }
204} 204}
@@ -210,7 +210,7 @@ int TranslateProtocol(Protocol protocol) {
210 case Protocol::UDP: 210 case Protocol::UDP:
211 return IPPROTO_UDP; 211 return IPPROTO_UDP;
212 default: 212 default:
213 UNIMPLEMENTED_MSG("Unimplemented protocol={}", static_cast<int>(protocol)); 213 UNIMPLEMENTED_MSG("Unimplemented protocol={}", protocol);
214 return 0; 214 return 0;
215 } 215 }
216} 216}
@@ -238,45 +238,45 @@ SockAddrIn TranslateToSockAddrIn(sockaddr input_) {
238 return result; 238 return result;
239} 239}
240 240
241u16 TranslatePollEvents(u16 events) { 241short TranslatePollEvents(PollEvents events) {
242 u16 result = 0; 242 short result = 0;
243 243
244 if (events & POLL_IN) { 244 if (True(events & PollEvents::In)) {
245 events &= ~POLL_IN; 245 events &= ~PollEvents::In;
246 result |= POLLIN; 246 result |= POLLIN;
247 } 247 }
248 if (events & POLL_PRI) { 248 if (True(events & PollEvents::Pri)) {
249 events &= ~POLL_PRI; 249 events &= ~PollEvents::Pri;
250#ifdef _WIN32 250#ifdef _WIN32
251 LOG_WARNING(Service, "Winsock doesn't support POLLPRI"); 251 LOG_WARNING(Service, "Winsock doesn't support POLLPRI");
252#else 252#else
253 result |= POLL_PRI; 253 result |= POLLPRI;
254#endif 254#endif
255 } 255 }
256 if (events & POLL_OUT) { 256 if (True(events & PollEvents::Out)) {
257 events &= ~POLL_OUT; 257 events &= ~PollEvents::Out;
258 result |= POLLOUT; 258 result |= POLLOUT;
259 } 259 }
260 260
261 UNIMPLEMENTED_IF_MSG(events != 0, "Unhandled guest events=0x{:x}", events); 261 UNIMPLEMENTED_IF_MSG((u16)events != 0, "Unhandled guest events=0x{:x}", (u16)events);
262 262
263 return result; 263 return result;
264} 264}
265 265
266u16 TranslatePollRevents(u16 revents) { 266PollEvents TranslatePollRevents(short revents) {
267 u16 result = 0; 267 PollEvents result{};
268 const auto translate = [&result, &revents](int host, unsigned guest) { 268 const auto translate = [&result, &revents](short host, PollEvents guest) {
269 if (revents & host) { 269 if ((revents & host) != 0) {
270 revents &= ~host; 270 revents &= static_cast<short>(~host);
271 result |= guest; 271 result |= guest;
272 } 272 }
273 }; 273 };
274 274
275 translate(POLLIN, POLL_IN); 275 translate(POLLIN, PollEvents::In);
276 translate(POLLPRI, POLL_PRI); 276 translate(POLLPRI, PollEvents::Pri);
277 translate(POLLOUT, POLL_OUT); 277 translate(POLLOUT, PollEvents::Out);
278 translate(POLLERR, POLL_ERR); 278 translate(POLLERR, PollEvents::Err);
279 translate(POLLHUP, POLL_HUP); 279 translate(POLLHUP, PollEvents::Hup);
280 280
281 UNIMPLEMENTED_IF_MSG(revents != 0, "Unhandled host revents=0x{:x}", revents); 281 UNIMPLEMENTED_IF_MSG(revents != 0, "Unhandled host revents=0x{:x}", revents);
282 282
@@ -408,7 +408,7 @@ std::pair<Socket::AcceptResult, Errno> Socket::Accept() {
408 408
409Errno Socket::Connect(SockAddrIn addr_in) { 409Errno Socket::Connect(SockAddrIn addr_in) {
410 const sockaddr host_addr_in = TranslateFromSockAddrIn(addr_in); 410 const sockaddr host_addr_in = TranslateFromSockAddrIn(addr_in);
411 if (connect(fd, &host_addr_in, sizeof(host_addr_in)) != INVALID_SOCKET) { 411 if (connect(fd, &host_addr_in, sizeof(host_addr_in)) != SOCKET_ERROR) {
412 return Errno::SUCCESS; 412 return Errno::SUCCESS;
413 } 413 }
414 414
@@ -482,7 +482,7 @@ Errno Socket::Shutdown(ShutdownHow how) {
482 host_how = SD_BOTH; 482 host_how = SD_BOTH;
483 break; 483 break;
484 default: 484 default:
485 UNIMPLEMENTED_MSG("Unimplemented flag how={}", static_cast<int>(how)); 485 UNIMPLEMENTED_MSG("Unimplemented flag how={}", how);
486 return Errno::SUCCESS; 486 return Errno::SUCCESS;
487 } 487 }
488 if (shutdown(fd, host_how) != SOCKET_ERROR) { 488 if (shutdown(fd, host_how) != SOCKET_ERROR) {
@@ -503,10 +503,10 @@ std::pair<s32, Errno> Socket::Recv(int flags, std::vector<u8>& message) {
503 ASSERT(flags == 0); 503 ASSERT(flags == 0);
504 ASSERT(message.size() < static_cast<size_t>(std::numeric_limits<int>::max())); 504 ASSERT(message.size() < static_cast<size_t>(std::numeric_limits<int>::max()));
505 505
506 const int result = 506 const auto result =
507 recv(fd, reinterpret_cast<char*>(message.data()), static_cast<int>(message.size()), 0); 507 recv(fd, reinterpret_cast<char*>(message.data()), static_cast<int>(message.size()), 0);
508 if (result != SOCKET_ERROR) { 508 if (result != SOCKET_ERROR) {
509 return {result, Errno::SUCCESS}; 509 return {static_cast<s32>(result), Errno::SUCCESS};
510 } 510 }
511 511
512 switch (const int ec = LastError()) { 512 switch (const int ec = LastError()) {
@@ -531,14 +531,14 @@ std::pair<s32, Errno> Socket::RecvFrom(int flags, std::vector<u8>& message, Sock
531 socklen_t* const p_addrlen = addr ? &addrlen : nullptr; 531 socklen_t* const p_addrlen = addr ? &addrlen : nullptr;
532 sockaddr* const p_addr_in = addr ? &addr_in : nullptr; 532 sockaddr* const p_addr_in = addr ? &addr_in : nullptr;
533 533
534 const int result = recvfrom(fd, reinterpret_cast<char*>(message.data()), 534 const auto result = recvfrom(fd, reinterpret_cast<char*>(message.data()),
535 static_cast<int>(message.size()), 0, p_addr_in, p_addrlen); 535 static_cast<int>(message.size()), 0, p_addr_in, p_addrlen);
536 if (result != SOCKET_ERROR) { 536 if (result != SOCKET_ERROR) {
537 if (addr) { 537 if (addr) {
538 ASSERT(addrlen == sizeof(addr_in)); 538 ASSERT(addrlen == sizeof(addr_in));
539 *addr = TranslateToSockAddrIn(addr_in); 539 *addr = TranslateToSockAddrIn(addr_in);
540 } 540 }
541 return {result, Errno::SUCCESS}; 541 return {static_cast<s32>(result), Errno::SUCCESS};
542 } 542 }
543 543
544 switch (const int ec = LastError()) { 544 switch (const int ec = LastError()) {
@@ -558,10 +558,10 @@ std::pair<s32, Errno> Socket::Send(const std::vector<u8>& message, int flags) {
558 ASSERT(message.size() < static_cast<size_t>(std::numeric_limits<int>::max())); 558 ASSERT(message.size() < static_cast<size_t>(std::numeric_limits<int>::max()));
559 ASSERT(flags == 0); 559 ASSERT(flags == 0);
560 560
561 const int result = send(fd, reinterpret_cast<const char*>(message.data()), 561 const auto result = send(fd, reinterpret_cast<const char*>(message.data()),
562 static_cast<int>(message.size()), 0); 562 static_cast<int>(message.size()), 0);
563 if (result != SOCKET_ERROR) { 563 if (result != SOCKET_ERROR) {
564 return {result, Errno::SUCCESS}; 564 return {static_cast<s32>(result), Errno::SUCCESS};
565 } 565 }
566 566
567 const int ec = LastError(); 567 const int ec = LastError();
@@ -591,10 +591,10 @@ std::pair<s32, Errno> Socket::SendTo(u32 flags, const std::vector<u8>& message,
591 to = &host_addr_in; 591 to = &host_addr_in;
592 } 592 }
593 593
594 const int result = sendto(fd, reinterpret_cast<const char*>(message.data()), 594 const auto result = sendto(fd, reinterpret_cast<const char*>(message.data()),
595 static_cast<int>(message.size()), 0, to, tolen); 595 static_cast<int>(message.size()), 0, to, tolen);
596 if (result != SOCKET_ERROR) { 596 if (result != SOCKET_ERROR) {
597 return {result, Errno::SUCCESS}; 597 return {static_cast<s32>(result), Errno::SUCCESS};
598 } 598 }
599 599
600 const int ec = LastError(); 600 const int ec = LastError();
diff --git a/src/core/network/network.h b/src/core/network/network.h
index 0622e4593..76b2821f2 100644
--- a/src/core/network/network.h
+++ b/src/core/network/network.h
@@ -61,19 +61,25 @@ struct SockAddrIn {
61}; 61};
62 62
63/// Cross-platform poll fd structure 63/// Cross-platform poll fd structure
64
65enum class PollEvents : u16 {
66 // Using Pascal case because IN is a macro on Windows.
67 In = 1 << 0,
68 Pri = 1 << 1,
69 Out = 1 << 2,
70 Err = 1 << 3,
71 Hup = 1 << 4,
72 Nval = 1 << 5,
73};
74
75DECLARE_ENUM_FLAG_OPERATORS(PollEvents);
76
64struct PollFD { 77struct PollFD {
65 Socket* socket; 78 Socket* socket;
66 u16 events; 79 PollEvents events;
67 u16 revents; 80 PollEvents revents;
68}; 81};
69 82
70constexpr u16 POLL_IN = 1 << 0;
71constexpr u16 POLL_PRI = 1 << 1;
72constexpr u16 POLL_OUT = 1 << 2;
73constexpr u16 POLL_ERR = 1 << 3;
74constexpr u16 POLL_HUP = 1 << 4;
75constexpr u16 POLL_NVAL = 1 << 5;
76
77class NetworkInstance { 83class NetworkInstance {
78public: 84public:
79 explicit NetworkInstance(); 85 explicit NetworkInstance();
diff --git a/src/core/network/sockets.h b/src/core/network/sockets.h
index 7bdff0fe4..a44393325 100644
--- a/src/core/network/sockets.h
+++ b/src/core/network/sockets.h
@@ -9,7 +9,7 @@
9 9
10#if defined(_WIN32) 10#if defined(_WIN32)
11#include <winsock.h> 11#include <winsock.h>
12#elif !defined(__unix__) 12#elif !YUZU_UNIX
13#error "Platform not implemented" 13#error "Platform not implemented"
14#endif 14#endif
15 15
@@ -84,7 +84,7 @@ public:
84 84
85#if defined(_WIN32) 85#if defined(_WIN32)
86 SOCKET fd = INVALID_SOCKET; 86 SOCKET fd = INVALID_SOCKET;
87#elif defined(__unix__) 87#elif YUZU_UNIX
88 int fd = -1; 88 int fd = -1;
89#endif 89#endif
90}; 90};
diff --git a/src/core/settings.cpp b/src/core/settings.cpp
index 28d3f9099..39306509a 100644
--- a/src/core/settings.cpp
+++ b/src/core/settings.cpp
@@ -4,9 +4,10 @@
4 4
5#include <string_view> 5#include <string_view>
6 6
7#include "common/assert.h"
7#include "common/file_util.h" 8#include "common/file_util.h"
9#include "common/logging/log.h"
8#include "core/core.h" 10#include "core/core.h"
9#include "core/gdbstub/gdbstub.h"
10#include "core/hle/service/hid/hid.h" 11#include "core/hle/service/hid/hid.h"
11#include "core/settings.h" 12#include "core/settings.h"
12#include "video_core/renderer_base.h" 13#include "video_core/renderer_base.h"
@@ -14,7 +15,7 @@
14namespace Settings { 15namespace Settings {
15 16
16Values values = {}; 17Values values = {};
17bool configuring_global = true; 18static bool configuring_global = true;
18 19
19std::string GetTimeZoneString() { 20std::string GetTimeZoneString() {
20 static constexpr std::array timezones{ 21 static constexpr std::array timezones{
@@ -31,13 +32,9 @@ std::string GetTimeZoneString() {
31 return timezones[time_zone_index]; 32 return timezones[time_zone_index];
32} 33}
33 34
34void Apply() { 35void Apply(Core::System& system) {
35 GDBStub::SetServerPort(values.gdbstub_port); 36 if (system.IsPoweredOn()) {
36 GDBStub::ToggleServer(values.use_gdbstub); 37 system.Renderer().RefreshBaseSettings();
37
38 auto& system_instance = Core::System::GetInstance();
39 if (system_instance.IsPoweredOn()) {
40 system_instance.Renderer().RefreshBaseSettings();
41 } 38 }
42 39
43 Service::HID::ReloadInputDevices(); 40 Service::HID::ReloadInputDevices();
@@ -49,13 +46,14 @@ void LogSettings() {
49 }; 46 };
50 47
51 LOG_INFO(Config, "yuzu Configuration:"); 48 LOG_INFO(Config, "yuzu Configuration:");
52 log_setting("Controls_UseDockedMode", values.use_docked_mode); 49 log_setting("Controls_UseDockedMode", values.use_docked_mode.GetValue());
53 log_setting("System_RngSeed", values.rng_seed.GetValue().value_or(0)); 50 log_setting("System_RngSeed", values.rng_seed.GetValue().value_or(0));
54 log_setting("System_CurrentUser", values.current_user); 51 log_setting("System_CurrentUser", values.current_user);
55 log_setting("System_LanguageIndex", values.language_index.GetValue()); 52 log_setting("System_LanguageIndex", values.language_index.GetValue());
56 log_setting("System_RegionIndex", values.region_index.GetValue()); 53 log_setting("System_RegionIndex", values.region_index.GetValue());
57 log_setting("System_TimeZoneIndex", values.time_zone_index.GetValue()); 54 log_setting("System_TimeZoneIndex", values.time_zone_index.GetValue());
58 log_setting("Core_UseMultiCore", values.use_multi_core.GetValue()); 55 log_setting("Core_UseMultiCore", values.use_multi_core.GetValue());
56 log_setting("CPU_Accuracy", values.cpu_accuracy);
59 log_setting("Renderer_UseResolutionFactor", values.resolution_factor.GetValue()); 57 log_setting("Renderer_UseResolutionFactor", values.resolution_factor.GetValue());
60 log_setting("Renderer_UseFrameLimit", values.use_frame_limit.GetValue()); 58 log_setting("Renderer_UseFrameLimit", values.use_frame_limit.GetValue());
61 log_setting("Renderer_FrameLimit", values.frame_limit.GetValue()); 59 log_setting("Renderer_FrameLimit", values.frame_limit.GetValue());
@@ -63,6 +61,7 @@ void LogSettings() {
63 log_setting("Renderer_GPUAccuracyLevel", values.gpu_accuracy.GetValue()); 61 log_setting("Renderer_GPUAccuracyLevel", values.gpu_accuracy.GetValue());
64 log_setting("Renderer_UseAsynchronousGpuEmulation", 62 log_setting("Renderer_UseAsynchronousGpuEmulation",
65 values.use_asynchronous_gpu_emulation.GetValue()); 63 values.use_asynchronous_gpu_emulation.GetValue());
64 log_setting("Renderer_UseNvdecEmulation", values.use_nvdec_emulation.GetValue());
66 log_setting("Renderer_UseVsync", values.use_vsync.GetValue()); 65 log_setting("Renderer_UseVsync", values.use_vsync.GetValue());
67 log_setting("Renderer_UseAssemblyShaders", values.use_assembly_shaders.GetValue()); 66 log_setting("Renderer_UseAssemblyShaders", values.use_assembly_shaders.GetValue());
68 log_setting("Renderer_UseAsynchronousShaders", values.use_asynchronous_shaders.GetValue()); 67 log_setting("Renderer_UseAsynchronousShaders", values.use_asynchronous_shaders.GetValue());
@@ -73,18 +72,17 @@ void LogSettings() {
73 log_setting("DataStorage_UseVirtualSd", values.use_virtual_sd); 72 log_setting("DataStorage_UseVirtualSd", values.use_virtual_sd);
74 log_setting("DataStorage_NandDir", Common::FS::GetUserPath(Common::FS::UserPath::NANDDir)); 73 log_setting("DataStorage_NandDir", Common::FS::GetUserPath(Common::FS::UserPath::NANDDir));
75 log_setting("DataStorage_SdmcDir", Common::FS::GetUserPath(Common::FS::UserPath::SDMCDir)); 74 log_setting("DataStorage_SdmcDir", Common::FS::GetUserPath(Common::FS::UserPath::SDMCDir));
76 log_setting("Debugging_UseGdbstub", values.use_gdbstub);
77 log_setting("Debugging_GdbstubPort", values.gdbstub_port);
78 log_setting("Debugging_ProgramArgs", values.program_args); 75 log_setting("Debugging_ProgramArgs", values.program_args);
79 log_setting("Services_BCATBackend", values.bcat_backend); 76 log_setting("Services_BCATBackend", values.bcat_backend);
80 log_setting("Services_BCATBoxcatLocal", values.bcat_boxcat_local); 77 log_setting("Services_BCATBoxcatLocal", values.bcat_boxcat_local);
81} 78}
82 79
83float Volume() { 80bool IsConfiguringGlobal() {
84 if (values.audio_muted) { 81 return configuring_global;
85 return 0.0f; 82}
86 } 83
87 return values.volume.GetValue(); 84void SetConfiguringGlobal(bool is_global) {
85 configuring_global = is_global;
88} 86}
89 87
90bool IsGPULevelExtreme() { 88bool IsGPULevelExtreme() {
@@ -96,9 +94,16 @@ bool IsGPULevelHigh() {
96 values.gpu_accuracy.GetValue() == GPUAccuracy::High; 94 values.gpu_accuracy.GetValue() == GPUAccuracy::High;
97} 95}
98 96
99void RestoreGlobalState() { 97float Volume() {
98 if (values.audio_muted) {
99 return 0.0f;
100 }
101 return values.volume.GetValue();
102}
103
104void RestoreGlobalState(bool is_powered_on) {
100 // If a game is running, DO NOT restore the global settings state 105 // If a game is running, DO NOT restore the global settings state
101 if (Core::System::GetInstance().IsPoweredOn()) { 106 if (is_powered_on) {
102 return; 107 return;
103 } 108 }
104 109
@@ -119,6 +124,7 @@ void RestoreGlobalState() {
119 values.use_disk_shader_cache.SetGlobal(true); 124 values.use_disk_shader_cache.SetGlobal(true);
120 values.gpu_accuracy.SetGlobal(true); 125 values.gpu_accuracy.SetGlobal(true);
121 values.use_asynchronous_gpu_emulation.SetGlobal(true); 126 values.use_asynchronous_gpu_emulation.SetGlobal(true);
127 values.use_nvdec_emulation.SetGlobal(true);
122 values.use_vsync.SetGlobal(true); 128 values.use_vsync.SetGlobal(true);
123 values.use_assembly_shaders.SetGlobal(true); 129 values.use_assembly_shaders.SetGlobal(true);
124 values.use_asynchronous_shaders.SetGlobal(true); 130 values.use_asynchronous_shaders.SetGlobal(true);
@@ -134,11 +140,12 @@ void RestoreGlobalState() {
134 values.rng_seed.SetGlobal(true); 140 values.rng_seed.SetGlobal(true);
135 values.custom_rtc.SetGlobal(true); 141 values.custom_rtc.SetGlobal(true);
136 values.sound_index.SetGlobal(true); 142 values.sound_index.SetGlobal(true);
137}
138 143
139void Sanitize() { 144 // Controls
140 values.use_asynchronous_gpu_emulation.SetValue( 145 values.players.SetGlobal(true);
141 values.use_asynchronous_gpu_emulation.GetValue() || values.use_multi_core.GetValue()); 146 values.use_docked_mode.SetGlobal(true);
147 values.vibration_enabled.SetGlobal(true);
148 values.motion_enabled.SetGlobal(true);
142} 149}
143 150
144} // namespace Settings 151} // namespace Settings
diff --git a/src/core/settings.h b/src/core/settings.h
index 9834f44bb..a324530bd 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -14,6 +14,10 @@
14#include "common/common_types.h" 14#include "common/common_types.h"
15#include "input_common/settings.h" 15#include "input_common/settings.h"
16 16
17namespace Core {
18class System;
19}
20
17namespace Settings { 21namespace Settings {
18 22
19enum class RendererBackend { 23enum class RendererBackend {
@@ -33,8 +37,6 @@ enum class CPUAccuracy {
33 DebugMode = 2, 37 DebugMode = 2,
34}; 38};
35 39
36extern bool configuring_global;
37
38template <typename Type> 40template <typename Type>
39class Setting final { 41class Setting final {
40public: 42public:
@@ -67,6 +69,38 @@ private:
67 Type local{}; 69 Type local{};
68}; 70};
69 71
72/**
73 * The InputSetting class allows for getting a reference to either the global or local members.
74 * This is required as we cannot easily modify the values of user-defined types within containers
75 * using the SetValue() member function found in the Setting class. The primary purpose of this
76 * class is to store an array of 10 PlayerInput structs for both the global and local (per-game)
77 * setting and allows for easily accessing and modifying both settings.
78 */
79template <typename Type>
80class InputSetting final {
81public:
82 InputSetting() = default;
83 explicit InputSetting(Type val) : global{val} {}
84 ~InputSetting() = default;
85 void SetGlobal(bool to_global) {
86 use_global = to_global;
87 }
88 bool UsingGlobal() const {
89 return use_global;
90 }
91 Type& GetValue(bool need_global = false) {
92 if (use_global || need_global) {
93 return global;
94 }
95 return local;
96 }
97
98private:
99 bool use_global = true;
100 Type global{};
101 Type local{};
102};
103
70struct TouchFromButtonMap { 104struct TouchFromButtonMap {
71 std::string name; 105 std::string name;
72 std::vector<std::string> buttons; 106 std::vector<std::string> buttons;
@@ -97,13 +131,14 @@ struct Values {
97 131
98 bool cpuopt_unsafe_unfuse_fma; 132 bool cpuopt_unsafe_unfuse_fma;
99 bool cpuopt_unsafe_reduce_fp_error; 133 bool cpuopt_unsafe_reduce_fp_error;
134 bool cpuopt_unsafe_inaccurate_nan;
100 135
101 // Renderer 136 // Renderer
102 Setting<RendererBackend> renderer_backend; 137 Setting<RendererBackend> renderer_backend;
103 bool renderer_debug; 138 bool renderer_debug;
104 Setting<int> vulkan_device; 139 Setting<int> vulkan_device;
105 140
106 Setting<u16> resolution_factor = Setting(static_cast<u16>(1)); 141 Setting<u16> resolution_factor{1};
107 Setting<int> aspect_ratio; 142 Setting<int> aspect_ratio;
108 Setting<int> max_anisotropy; 143 Setting<int> max_anisotropy;
109 Setting<bool> use_frame_limit; 144 Setting<bool> use_frame_limit;
@@ -111,6 +146,7 @@ struct Values {
111 Setting<bool> use_disk_shader_cache; 146 Setting<bool> use_disk_shader_cache;
112 Setting<GPUAccuracy> gpu_accuracy; 147 Setting<GPUAccuracy> gpu_accuracy;
113 Setting<bool> use_asynchronous_gpu_emulation; 148 Setting<bool> use_asynchronous_gpu_emulation;
149 Setting<bool> use_nvdec_emulation;
114 Setting<bool> use_vsync; 150 Setting<bool> use_vsync;
115 Setting<bool> use_assembly_shaders; 151 Setting<bool> use_assembly_shaders;
116 Setting<bool> use_asynchronous_shaders; 152 Setting<bool> use_asynchronous_shaders;
@@ -134,9 +170,18 @@ struct Values {
134 Setting<s32> sound_index; 170 Setting<s32> sound_index;
135 171
136 // Controls 172 // Controls
137 std::array<PlayerInput, 10> players; 173 InputSetting<std::array<PlayerInput, 10>> players;
174
175 Setting<bool> use_docked_mode;
176
177 Setting<bool> vibration_enabled;
178 Setting<bool> enable_accurate_vibrations;
179
180 Setting<bool> motion_enabled;
181 std::string motion_device;
182 std::string udp_input_servers;
138 183
139 bool use_docked_mode; 184 bool emulate_analog_keyboard;
140 185
141 bool mouse_enabled; 186 bool mouse_enabled;
142 std::string mouse_device; 187 std::string mouse_device;
@@ -150,20 +195,15 @@ struct Values {
150 ButtonsRaw debug_pad_buttons; 195 ButtonsRaw debug_pad_buttons;
151 AnalogsRaw debug_pad_analogs; 196 AnalogsRaw debug_pad_analogs;
152 197
153 bool vibration_enabled;
154
155 bool motion_enabled;
156 std::string motion_device;
157 std::string touch_device;
158 TouchscreenInput touchscreen; 198 TouchscreenInput touchscreen;
159 std::atomic_bool is_device_reload_pending{true}; 199
160 bool use_touch_from_button; 200 bool use_touch_from_button;
201 std::string touch_device;
161 int touch_from_button_map_index; 202 int touch_from_button_map_index;
162 std::string udp_input_address;
163 u16 udp_input_port;
164 u8 udp_pad_index;
165 std::vector<TouchFromButtonMap> touch_from_button_maps; 203 std::vector<TouchFromButtonMap> touch_from_button_maps;
166 204
205 std::atomic_bool is_device_reload_pending{true};
206
167 // Data Storage 207 // Data Storage
168 bool use_virtual_sd; 208 bool use_virtual_sd;
169 bool gamecard_inserted; 209 bool gamecard_inserted;
@@ -180,8 +220,9 @@ struct Values {
180 bool reporting_services; 220 bool reporting_services;
181 bool quest_flag; 221 bool quest_flag;
182 bool disable_macro_jit; 222 bool disable_macro_jit;
223 bool extended_logging;
183 224
184 // Misceallaneous 225 // Miscellaneous
185 std::string log_filter; 226 std::string log_filter;
186 bool use_dev_keys; 227 bool use_dev_keys;
187 228
@@ -197,22 +238,24 @@ struct Values {
197 238
198 // Add-Ons 239 // Add-Ons
199 std::map<u64, std::vector<std::string>> disabled_addons; 240 std::map<u64, std::vector<std::string>> disabled_addons;
200} extern values; 241};
201 242
202float Volume(); 243extern Values values;
244
245bool IsConfiguringGlobal();
246void SetConfiguringGlobal(bool is_global);
203 247
204bool IsGPULevelExtreme(); 248bool IsGPULevelExtreme();
205bool IsGPULevelHigh(); 249bool IsGPULevelHigh();
206 250
251float Volume();
252
207std::string GetTimeZoneString(); 253std::string GetTimeZoneString();
208 254
209void Apply(); 255void Apply(Core::System& system);
210void LogSettings(); 256void LogSettings();
211 257
212// Restore the global state of all applicable settings in the Values struct 258// Restore the global state of all applicable settings in the Values struct
213void RestoreGlobalState(); 259void RestoreGlobalState(bool is_powered_on);
214
215// Fixes settings that are known to cause issues with the emulator
216void Sanitize();
217 260
218} // namespace Settings 261} // namespace Settings
diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp
index da09c0dbc..d11b15f38 100644
--- a/src/core/telemetry_session.cpp
+++ b/src/core/telemetry_session.cpp
@@ -147,7 +147,9 @@ TelemetrySession::~TelemetrySession() {
147 } 147 }
148} 148}
149 149
150void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader) { 150void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader,
151 const Service::FileSystem::FileSystemController& fsc,
152 const FileSys::ContentProvider& content_provider) {
151 // Log one-time top-level information 153 // Log one-time top-level information
152 AddField(Telemetry::FieldType::None, "TelemetryId", GetTelemetryId()); 154 AddField(Telemetry::FieldType::None, "TelemetryId", GetTelemetryId());
153 155
@@ -167,7 +169,10 @@ void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader) {
167 app_loader.ReadTitle(name); 169 app_loader.ReadTitle(name);
168 170
169 if (name.empty()) { 171 if (name.empty()) {
170 const auto metadata = FileSys::PatchManager(program_id).GetControlMetadata(); 172 const auto metadata = [&content_provider, &fsc, program_id] {
173 const FileSys::PatchManager pm{program_id, fsc, content_provider};
174 return pm.GetControlMetadata();
175 }();
171 if (metadata.first != nullptr) { 176 if (metadata.first != nullptr) {
172 name = metadata.first->GetApplicationName(); 177 name = metadata.first->GetApplicationName();
173 } 178 }
@@ -206,12 +211,14 @@ void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader) {
206 TranslateGPUAccuracyLevel(Settings::values.gpu_accuracy.GetValue())); 211 TranslateGPUAccuracyLevel(Settings::values.gpu_accuracy.GetValue()));
207 AddField(field_type, "Renderer_UseAsynchronousGpuEmulation", 212 AddField(field_type, "Renderer_UseAsynchronousGpuEmulation",
208 Settings::values.use_asynchronous_gpu_emulation.GetValue()); 213 Settings::values.use_asynchronous_gpu_emulation.GetValue());
214 AddField(field_type, "Renderer_UseNvdecEmulation",
215 Settings::values.use_nvdec_emulation.GetValue());
209 AddField(field_type, "Renderer_UseVsync", Settings::values.use_vsync.GetValue()); 216 AddField(field_type, "Renderer_UseVsync", Settings::values.use_vsync.GetValue());
210 AddField(field_type, "Renderer_UseAssemblyShaders", 217 AddField(field_type, "Renderer_UseAssemblyShaders",
211 Settings::values.use_assembly_shaders.GetValue()); 218 Settings::values.use_assembly_shaders.GetValue());
212 AddField(field_type, "Renderer_UseAsynchronousShaders", 219 AddField(field_type, "Renderer_UseAsynchronousShaders",
213 Settings::values.use_asynchronous_shaders.GetValue()); 220 Settings::values.use_asynchronous_shaders.GetValue());
214 AddField(field_type, "System_UseDockedMode", Settings::values.use_docked_mode); 221 AddField(field_type, "System_UseDockedMode", Settings::values.use_docked_mode.GetValue());
215} 222}
216 223
217bool TelemetrySession::SubmitTestcase() { 224bool TelemetrySession::SubmitTestcase() {
diff --git a/src/core/telemetry_session.h b/src/core/telemetry_session.h
index 66789d4bd..6f3d45bea 100644
--- a/src/core/telemetry_session.h
+++ b/src/core/telemetry_session.h
@@ -7,10 +7,18 @@
7#include <string> 7#include <string>
8#include "common/telemetry.h" 8#include "common/telemetry.h"
9 9
10namespace FileSys {
11class ContentProvider;
12}
13
10namespace Loader { 14namespace Loader {
11class AppLoader; 15class AppLoader;
12} 16}
13 17
18namespace Service::FileSystem {
19class FileSystemController;
20}
21
14namespace Core { 22namespace Core {
15 23
16/** 24/**
@@ -40,10 +48,14 @@ public:
40 * - Title file format 48 * - Title file format
41 * - Miscellaneous settings values. 49 * - Miscellaneous settings values.
42 * 50 *
43 * @param app_loader The application loader to use to retrieve 51 * @param app_loader The application loader to use to retrieve
44 * title-specific information. 52 * title-specific information.
53 * @param fsc Filesystem controller to use to retrieve info.
54 * @param content_provider Content provider to use to retrieve info.
45 */ 55 */
46 void AddInitialInfo(Loader::AppLoader& app_loader); 56 void AddInitialInfo(Loader::AppLoader& app_loader,
57 const Service::FileSystem::FileSystemController& fsc,
58 const FileSys::ContentProvider& content_provider);
47 59
48 /** 60 /**
49 * Wrapper around the Telemetry::FieldCollection::AddField method. 61 * Wrapper around the Telemetry::FieldCollection::AddField method.