summaryrefslogtreecommitdiff
path: root/src/core/hle
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/hle
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/hle')
-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
313 files changed, 8691 insertions, 5357 deletions
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