From 0c16e294d4559f3ebe9d36293c59eda6136baee8 Mon Sep 17 00:00:00 2001 From: DH Date: Sat, 12 Oct 2024 05:24:58 +0300 Subject: [PATCH] merge rpcsx-gpu and rpcsx-os initial watchdog implementation implement gpu -> os events implement main gfx queue --- .github/BUILDING.md | 19 +- .github/USAGE.md | 6 +- CMakeLists.txt | 4 +- hw/amdgpu/CMakeLists.txt | 7 - hw/amdgpu/bridge/CMakeLists.txt | 17 - .../bridge/include/amdgpu/bridge/bridge.hpp | 402 --- hw/amdgpu/bridge/src/bridge.cpp | 87 - orbis-kernel/include/orbis/KernelContext.hpp | 4 + .../include/orbis/error/SysResult.hpp | 9 + orbis-kernel/include/orbis/note.hpp | 8 +- orbis-kernel/include/orbis/thread/Process.hpp | 1 + orbis-kernel/include/orbis/thread/types.hpp | 2 +- orbis-kernel/include/orbis/utils/Rc.hpp | 35 +- orbis-kernel/src/KernelContext.cpp | 31 +- orbis-kernel/src/event.cpp | 33 +- orbis-kernel/src/ipmi.cpp | 15 +- orbis-kernel/src/sys/sys_event.cpp | 27 +- orbis-kernel/src/sys/sys_sysctl.cpp | 4 +- orbis-kernel/src/umtx.cpp | 2 +- rpcsx-gpu/Device.cpp | 437 ---- rpcsx-gpu/Device.hpp | 98 - rpcsx-gpu/main.cpp | 646 ----- rpcsx-os/bridge.cpp | 3 - rpcsx-os/bridge.hpp | 7 - rpcsx-os/main.cpp | 2277 ----------------- {rpcsx-os => rpcsx}/AudioOut.cpp | 38 +- {rpcsx-os => rpcsx}/AudioOut.hpp | 0 {rpcsx-os => rpcsx}/CMakeLists.txt | 31 +- {rpcsx-os => rpcsx}/audio/AlsaDevice.cpp | 0 {rpcsx-os => rpcsx}/audio/AlsaDevice.hpp | 0 {rpcsx-os => rpcsx}/audio/AudioDevice.cpp | 0 {rpcsx-os => rpcsx}/audio/AudioDevice.hpp | 0 {rpcsx-os => rpcsx}/backtrace.cpp | 0 {rpcsx-os => rpcsx}/backtrace.hpp | 0 rpcsx/core/CMakeLists.txt | 13 + rpcsx/core/include/rx/Config.hpp | 11 + rpcsx/core/include/rx/watchdog.hpp | 12 + rpcsx/core/src/Config.cpp | 3 + rpcsx/core/src/watchdog.cpp | 194 ++ {rpcsx-gpu => rpcsx/gpu}/CMakeLists.txt | 10 +- {rpcsx-gpu => rpcsx/gpu}/Cache.cpp | 144 +- {rpcsx-gpu => rpcsx/gpu}/Cache.hpp | 0 rpcsx/gpu/Device.cpp | 1070 ++++++++ rpcsx/gpu/Device.hpp | 224 ++ {rpcsx-gpu => rpcsx/gpu}/FlipPipeline.cpp | 0 {rpcsx-gpu => rpcsx/gpu}/FlipPipeline.hpp | 0 {rpcsx-gpu => rpcsx/gpu}/Pipe.cpp | 202 +- {rpcsx-gpu => rpcsx/gpu}/Pipe.hpp | 13 +- {rpcsx-gpu => rpcsx/gpu}/Registers.cpp | 0 {rpcsx-gpu => rpcsx/gpu}/Registers.hpp | 0 {rpcsx-gpu => rpcsx/gpu}/Renderer.cpp | 0 {rpcsx-gpu => rpcsx/gpu}/Renderer.hpp | 0 {rpcsx-gpu => rpcsx/gpu}/lib/CMakeLists.txt | 0 .../gpu}/lib/amdgpu-tiler/CMakeLists.txt | 0 .../lib/amdgpu-tiler/include/amdgpu/tiler.hpp | 0 .../amdgpu-tiler/include/amdgpu/tiler_cpu.hpp | 0 .../include/amdgpu/tiler_vulkan.hpp | 0 .../amdgpu-tiler/shaders/detiler1d.comp.glsl | 0 .../amdgpu-tiler/shaders/detiler2d.comp.glsl | 0 .../shaders/detilerLinear.comp.glsl | 0 .../gpu}/lib/amdgpu-tiler/shaders/tiler.glsl | 0 .../amdgpu-tiler/shaders/tiler1d.comp.glsl | 0 .../amdgpu-tiler/shaders/tiler2d.comp.glsl | 0 .../shaders/tilerLinear.comp.glsl | 0 .../gpu}/lib/amdgpu-tiler/src/tiler.cpp | 0 .../gpu}/lib/amdgpu-tiler/src/tiler_cpu.cpp | 0 .../lib/amdgpu-tiler/src/tiler_vulkan.cpp | 0 .../gpu}/lib/gcn-shader/CMakeLists.txt | 0 .../lib/gcn-shader/include/shader/Access.hpp | 0 .../gcn-shader/include/shader/Evaluator.hpp | 0 .../include/shader/GcnConverter.hpp | 0 .../include/shader/GcnInstruction.hpp | 0 .../gcn-shader/include/shader/ModuleInfo.hpp | 0 .../include/shader/SemanticInfo.hpp | 0 .../include/shader/SpvConverter.hpp | 0 .../gcn-shader/include/shader/SpvTypeInfo.hpp | 0 .../lib/gcn-shader/include/shader/Vector.hpp | 0 .../lib/gcn-shader/include/shader/analyze.hpp | 0 .../lib/gcn-shader/include/shader/dialect.hpp | 0 .../include/shader/dialect/amdgpu.hpp | 0 .../include/shader/dialect/builtin.hpp | 0 .../gcn-shader/include/shader/dialect/ds.hpp | 0 .../gcn-shader/include/shader/dialect/exp.hpp | 0 .../include/shader/dialect/memssa.hpp | 0 .../include/shader/dialect/mimg.hpp | 0 .../include/shader/dialect/mtbuf.hpp | 0 .../include/shader/dialect/mubuf.hpp | 0 .../include/shader/dialect/smrd.hpp | 0 .../include/shader/dialect/sop1.hpp | 0 .../include/shader/dialect/sop2.hpp | 0 .../include/shader/dialect/sopc.hpp | 0 .../include/shader/dialect/sopk.hpp | 0 .../include/shader/dialect/sopp.hpp | 0 .../include/shader/dialect/vintrp.hpp | 0 .../include/shader/dialect/vop1.hpp | 0 .../include/shader/dialect/vop2.hpp | 0 .../include/shader/dialect/vop3.hpp | 0 .../include/shader/dialect/vopc.hpp | 0 .../lib/gcn-shader/include/shader/eval.hpp | 0 .../lib/gcn-shader/include/shader/gcn.hpp | 0 .../lib/gcn-shader/include/shader/glsl.hpp | 0 .../lib/gcn-shader/include/shader/graph.hpp | 0 .../gpu}/lib/gcn-shader/include/shader/ir.hpp | 0 .../gcn-shader/include/shader/ir/Block.hpp | 0 .../gcn-shader/include/shader/ir/Builder.hpp | 0 .../gcn-shader/include/shader/ir/Context.hpp | 0 .../lib/gcn-shader/include/shader/ir/Impl.hpp | 0 .../include/shader/ir/Instruction.hpp | 0 .../include/shader/ir/InstructionImpl.hpp | 0 .../lib/gcn-shader/include/shader/ir/Kind.hpp | 0 .../gcn-shader/include/shader/ir/Location.hpp | 0 .../include/shader/ir/NameStorage.hpp | 0 .../lib/gcn-shader/include/shader/ir/Node.hpp | 0 .../gcn-shader/include/shader/ir/NodeImpl.hpp | 0 .../gcn-shader/include/shader/ir/Operand.hpp | 0 .../include/shader/ir/OperandPrint.hpp | 0 .../include/shader/ir/PointerWrapper.hpp | 0 .../include/shader/ir/PreincNodeIterable.hpp | 0 .../include/shader/ir/PrintableWrapper.hpp | 0 .../gcn-shader/include/shader/ir/Region.hpp | 0 .../include/shader/ir/RegionImpl.hpp | 0 .../include/shader/ir/RegionLike.hpp | 0 .../include/shader/ir/RegionLikeImpl.hpp | 0 .../gcn-shader/include/shader/ir/Value.hpp | 0 .../include/shader/ir/ValueImpl.hpp | 0 .../lib/gcn-shader/include/shader/opt.hpp | 0 .../lib/gcn-shader/include/shader/spv.hpp | 0 .../gcn-shader/include/shader/transform.hpp | 0 .../lib/gcn-shader/shaders/CMakeLists.txt | 0 .../gpu}/lib/gcn-shader/shaders/rdna.glsl | 0 .../gpu}/lib/gcn-shader/src/Evaluator.cpp | 0 .../gpu}/lib/gcn-shader/src/GcnConverter.cpp | 7 + .../lib/gcn-shader/src/GcnInstruction.cpp | 3 +- .../gpu}/lib/gcn-shader/src/ModuleInfo.cpp | 0 .../lib/gcn-shader/src/SemanticModuleInfo.cpp | 0 .../gpu}/lib/gcn-shader/src/SpvConverter.cpp | 0 .../gpu}/lib/gcn-shader/src/SpvTypeInfo.cpp | 0 .../gpu}/lib/gcn-shader/src/analyze.cpp | 0 .../gpu}/lib/gcn-shader/src/eval.cpp | 0 .../gpu}/lib/gcn-shader/src/gcn.cpp | 0 .../gpu}/lib/gcn-shader/src/glsl.cpp | 0 .../gpu}/lib/gcn-shader/src/opt.cpp | 0 .../gpu}/lib/gcn-shader/src/spv.cpp | 0 .../gpu}/lib/gcn-shader/src/transform.cpp | 0 .../gpu}/lib/gnm/CMakeLists.txt | 0 .../gpu}/lib/gnm/include/gnm/constants.hpp | 0 .../gpu}/lib/gnm/include/gnm/descriptors.hpp | 0 .../gpu}/lib/gnm/include/gnm/gnm.hpp | 0 .../gpu}/lib/gnm/include/gnm/mmio.hpp | 0 .../gpu}/lib/gnm/include/gnm/pm4.hpp | 0 .../gpu}/lib/gnm/lib/CMakeLists.txt | 0 .../lib/gnm/lib/gnm-vulkan/CMakeLists.txt | 0 .../gnm/lib/gnm-vulkan/include/gnm/vulkan.hpp | 0 .../lib/gnm/lib/gnm-vulkan/src/vulkan.cpp | 4 +- {rpcsx-gpu => rpcsx/gpu}/lib/gnm/src/mmio.cpp | 0 {rpcsx-gpu => rpcsx/gpu}/lib/gnm/src/pm4.cpp | 0 .../gpu}/lib/vk/CMakeLists.txt | 0 .../gpu}/lib/vk/include/Scheduler.hpp | 0 .../gpu}/lib/vk/include/vk.hpp | 110 +- {rpcsx-gpu => rpcsx/gpu}/lib/vk/src/vk.cpp | 0 .../gpu}/shaders/fill_red.frag.glsl | 0 .../gpu}/shaders/flip.vert.glsl | 0 .../gpu}/shaders/flip_alt.frag.glsl | 0 .../gpu}/shaders/flip_std.frag.glsl | 0 .../gpu}/shaders/rect_list.geom.glsl | 0 {rpcsx-os => rpcsx}/io-device.cpp | 20 +- {rpcsx-os => rpcsx}/io-device.hpp | 2 + {rpcsx-os => rpcsx}/io-devices.hpp | 0 {rpcsx-os => rpcsx}/iodev/MBusEvent.hpp | 0 {rpcsx-os => rpcsx}/iodev/ajm.cpp | 0 {rpcsx-os => rpcsx}/iodev/aout.cpp | 0 {rpcsx-os => rpcsx}/iodev/av_control.cpp | 0 {rpcsx-os => rpcsx}/iodev/blockpool.cpp | 6 +- {rpcsx-os => rpcsx}/iodev/blockpool.hpp | 0 {rpcsx-os => rpcsx}/iodev/bt.cpp | 0 {rpcsx-os => rpcsx}/iodev/camera.cpp | 0 {rpcsx-os => rpcsx}/iodev/cayman_reg.cpp | 0 {rpcsx-os => rpcsx}/iodev/cd.cpp | 0 {rpcsx-os => rpcsx}/iodev/console.cpp | 0 {rpcsx-os => rpcsx}/iodev/dce.cpp | 111 +- {rpcsx-os => rpcsx}/iodev/devact.cpp | 0 {rpcsx-os => rpcsx}/iodev/devctl.cpp | 0 {rpcsx-os => rpcsx}/iodev/devstat.cpp | 0 {rpcsx-os => rpcsx}/iodev/dipsw.cpp | 0 {rpcsx-os => rpcsx}/iodev/dmem.cpp | 39 +- {rpcsx-os => rpcsx}/iodev/dmem.hpp | 0 {rpcsx-os => rpcsx}/iodev/evlg.cpp | 0 {rpcsx-os => rpcsx}/iodev/gbase.cpp | 0 {rpcsx-os => rpcsx}/iodev/gc.cpp | 173 +- {rpcsx-os => rpcsx}/iodev/hdd.cpp | 0 {rpcsx-os => rpcsx}/iodev/hdmi.cpp | 0 {rpcsx-os => rpcsx}/iodev/hid.cpp | 51 +- {rpcsx-os => rpcsx}/iodev/hmd_3da.cpp | 0 {rpcsx-os => rpcsx}/iodev/hmd_cmd.cpp | 0 {rpcsx-os => rpcsx}/iodev/hmd_mmap.cpp | 2 +- {rpcsx-os => rpcsx}/iodev/hmd_snsr.cpp | 0 .../iodev/icc_configuration.cpp | 0 {rpcsx-os => rpcsx}/iodev/icc_power.cpp | 0 {rpcsx-os => rpcsx}/iodev/lvdctl.cpp | 0 {rpcsx-os => rpcsx}/iodev/mbus.cpp | 0 {rpcsx-os => rpcsx}/iodev/mbus.hpp | 0 {rpcsx-os => rpcsx}/iodev/mbus_av.cpp | 0 {rpcsx-os => rpcsx}/iodev/mbus_av.hpp | 0 {rpcsx-os => rpcsx}/iodev/metadbg.cpp | 0 {rpcsx-os => rpcsx}/iodev/notification.cpp | 0 {rpcsx-os => rpcsx}/iodev/npdrm.cpp | 0 {rpcsx-os => rpcsx}/iodev/null.cpp | 0 {rpcsx-os => rpcsx}/iodev/rng.cpp | 2 +- {rpcsx-os => rpcsx}/iodev/s3da.cpp | 0 {rpcsx-os => rpcsx}/iodev/sbl_srv.cpp | 2 +- {rpcsx-os => rpcsx}/iodev/scanin.cpp | 0 {rpcsx-os => rpcsx}/iodev/shm.cpp | 39 +- {rpcsx-os => rpcsx}/iodev/srtc.cpp | 0 {rpcsx-os => rpcsx}/iodev/sshot.cpp | 0 {rpcsx-os => rpcsx}/iodev/urandom.cpp | 0 {rpcsx-os => rpcsx}/iodev/uvd.cpp | 0 {rpcsx-os => rpcsx}/iodev/vce.cpp | 0 {rpcsx-os => rpcsx}/iodev/xpt.cpp | 0 {rpcsx-os => rpcsx}/iodev/zero.cpp | 0 rpcsx/ipmi.cpp | 841 ++++++ rpcsx/ipmi.hpp | 275 ++ {rpcsx-os => rpcsx}/linker.cpp | 10 +- {rpcsx-os => rpcsx}/linker.hpp | 0 rpcsx/main.cpp | 1155 +++++++++ {rpcsx-os => rpcsx}/ops.cpp | 38 +- {rpcsx-os => rpcsx}/ops.hpp | 0 .../orbis-kernel-config/orbis-config.hpp | 0 {rpcsx-os => rpcsx}/scheduler.hpp | 0 {rpcsx-os => rpcsx}/thread.cpp | 0 {rpcsx-os => rpcsx}/thread.hpp | 0 {rpcsx-os => rpcsx}/vfs.cpp | 43 +- {rpcsx-os => rpcsx}/vfs.hpp | 4 +- {rpcsx-os => rpcsx}/vm.cpp | 205 +- {rpcsx-os => rpcsx}/vm.hpp | 6 +- rx/include/rx/mem.hpp | 1 + rx/src/mem.cpp | 23 +- 236 files changed, 4649 insertions(+), 4669 deletions(-) delete mode 100644 hw/amdgpu/CMakeLists.txt delete mode 100644 hw/amdgpu/bridge/CMakeLists.txt delete mode 100644 hw/amdgpu/bridge/include/amdgpu/bridge/bridge.hpp delete mode 100644 hw/amdgpu/bridge/src/bridge.cpp delete mode 100644 rpcsx-gpu/Device.cpp delete mode 100644 rpcsx-gpu/Device.hpp delete mode 100644 rpcsx-gpu/main.cpp delete mode 100644 rpcsx-os/bridge.cpp delete mode 100644 rpcsx-os/bridge.hpp delete mode 100644 rpcsx-os/main.cpp rename {rpcsx-os => rpcsx}/AudioOut.cpp (86%) rename {rpcsx-os => rpcsx}/AudioOut.hpp (100%) rename {rpcsx-os => rpcsx}/CMakeLists.txt (70%) rename {rpcsx-os => rpcsx}/audio/AlsaDevice.cpp (100%) rename {rpcsx-os => rpcsx}/audio/AlsaDevice.hpp (100%) rename {rpcsx-os => rpcsx}/audio/AudioDevice.cpp (100%) rename {rpcsx-os => rpcsx}/audio/AudioDevice.hpp (100%) rename {rpcsx-os => rpcsx}/backtrace.cpp (100%) rename {rpcsx-os => rpcsx}/backtrace.hpp (100%) create mode 100644 rpcsx/core/CMakeLists.txt create mode 100644 rpcsx/core/include/rx/Config.hpp create mode 100644 rpcsx/core/include/rx/watchdog.hpp create mode 100644 rpcsx/core/src/Config.cpp create mode 100644 rpcsx/core/src/watchdog.cpp rename {rpcsx-gpu => rpcsx/gpu}/CMakeLists.txt (68%) rename {rpcsx-gpu => rpcsx/gpu}/Cache.cpp (94%) rename {rpcsx-gpu => rpcsx/gpu}/Cache.hpp (100%) create mode 100644 rpcsx/gpu/Device.cpp create mode 100644 rpcsx/gpu/Device.hpp rename {rpcsx-gpu => rpcsx/gpu}/FlipPipeline.cpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/FlipPipeline.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/Pipe.cpp (86%) rename {rpcsx-gpu => rpcsx/gpu}/Pipe.hpp (89%) rename {rpcsx-gpu => rpcsx/gpu}/Registers.cpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/Registers.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/Renderer.cpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/Renderer.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/CMakeLists.txt (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/amdgpu-tiler/CMakeLists.txt (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/amdgpu-tiler/include/amdgpu/tiler.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/amdgpu-tiler/include/amdgpu/tiler_cpu.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/amdgpu-tiler/include/amdgpu/tiler_vulkan.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/amdgpu-tiler/shaders/detiler1d.comp.glsl (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/amdgpu-tiler/shaders/detiler2d.comp.glsl (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/amdgpu-tiler/shaders/detilerLinear.comp.glsl (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/amdgpu-tiler/shaders/tiler.glsl (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/amdgpu-tiler/shaders/tiler1d.comp.glsl (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/amdgpu-tiler/shaders/tiler2d.comp.glsl (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/amdgpu-tiler/shaders/tilerLinear.comp.glsl (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/amdgpu-tiler/src/tiler.cpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/amdgpu-tiler/src/tiler_cpu.cpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/amdgpu-tiler/src/tiler_vulkan.cpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/CMakeLists.txt (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/include/shader/Access.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/include/shader/Evaluator.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/include/shader/GcnConverter.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/include/shader/GcnInstruction.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/include/shader/ModuleInfo.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/include/shader/SemanticInfo.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/include/shader/SpvConverter.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/include/shader/SpvTypeInfo.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/include/shader/Vector.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/include/shader/analyze.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/include/shader/dialect.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/include/shader/dialect/amdgpu.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/include/shader/dialect/builtin.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/include/shader/dialect/ds.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/include/shader/dialect/exp.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/include/shader/dialect/memssa.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/include/shader/dialect/mimg.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/include/shader/dialect/mtbuf.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/include/shader/dialect/mubuf.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/include/shader/dialect/smrd.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/include/shader/dialect/sop1.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/include/shader/dialect/sop2.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/include/shader/dialect/sopc.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/include/shader/dialect/sopk.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/include/shader/dialect/sopp.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/include/shader/dialect/vintrp.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/include/shader/dialect/vop1.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/include/shader/dialect/vop2.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/include/shader/dialect/vop3.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/include/shader/dialect/vopc.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/include/shader/eval.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/include/shader/gcn.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/include/shader/glsl.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/include/shader/graph.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/include/shader/ir.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/include/shader/ir/Block.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/include/shader/ir/Builder.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/include/shader/ir/Context.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/include/shader/ir/Impl.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/include/shader/ir/Instruction.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/include/shader/ir/InstructionImpl.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/include/shader/ir/Kind.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/include/shader/ir/Location.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/include/shader/ir/NameStorage.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/include/shader/ir/Node.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/include/shader/ir/NodeImpl.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/include/shader/ir/Operand.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/include/shader/ir/OperandPrint.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/include/shader/ir/PointerWrapper.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/include/shader/ir/PreincNodeIterable.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/include/shader/ir/PrintableWrapper.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/include/shader/ir/Region.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/include/shader/ir/RegionImpl.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/include/shader/ir/RegionLike.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/include/shader/ir/RegionLikeImpl.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/include/shader/ir/Value.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/include/shader/ir/ValueImpl.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/include/shader/opt.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/include/shader/spv.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/include/shader/transform.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/shaders/CMakeLists.txt (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/shaders/rdna.glsl (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/src/Evaluator.cpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/src/GcnConverter.cpp (99%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/src/GcnInstruction.cpp (99%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/src/ModuleInfo.cpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/src/SemanticModuleInfo.cpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/src/SpvConverter.cpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/src/SpvTypeInfo.cpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/src/analyze.cpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/src/eval.cpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/src/gcn.cpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/src/glsl.cpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/src/opt.cpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/src/spv.cpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gcn-shader/src/transform.cpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gnm/CMakeLists.txt (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gnm/include/gnm/constants.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gnm/include/gnm/descriptors.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gnm/include/gnm/gnm.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gnm/include/gnm/mmio.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gnm/include/gnm/pm4.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gnm/lib/CMakeLists.txt (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gnm/lib/gnm-vulkan/CMakeLists.txt (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gnm/lib/gnm-vulkan/include/gnm/vulkan.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gnm/lib/gnm-vulkan/src/vulkan.cpp (99%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gnm/src/mmio.cpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/gnm/src/pm4.cpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/vk/CMakeLists.txt (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/vk/include/Scheduler.hpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/lib/vk/include/vk.hpp (90%) rename {rpcsx-gpu => rpcsx/gpu}/lib/vk/src/vk.cpp (100%) rename {rpcsx-gpu => rpcsx/gpu}/shaders/fill_red.frag.glsl (100%) rename {rpcsx-gpu => rpcsx/gpu}/shaders/flip.vert.glsl (100%) rename {rpcsx-gpu => rpcsx/gpu}/shaders/flip_alt.frag.glsl (100%) rename {rpcsx-gpu => rpcsx/gpu}/shaders/flip_std.frag.glsl (100%) rename {rpcsx-gpu => rpcsx/gpu}/shaders/rect_list.geom.glsl (100%) rename {rpcsx-os => rpcsx}/io-device.cpp (97%) rename {rpcsx-os => rpcsx}/io-device.hpp (97%) rename {rpcsx-os => rpcsx}/io-devices.hpp (100%) rename {rpcsx-os => rpcsx}/iodev/MBusEvent.hpp (100%) rename {rpcsx-os => rpcsx}/iodev/ajm.cpp (100%) rename {rpcsx-os => rpcsx}/iodev/aout.cpp (100%) rename {rpcsx-os => rpcsx}/iodev/av_control.cpp (100%) rename {rpcsx-os => rpcsx}/iodev/blockpool.cpp (96%) rename {rpcsx-os => rpcsx}/iodev/blockpool.hpp (100%) rename {rpcsx-os => rpcsx}/iodev/bt.cpp (100%) rename {rpcsx-os => rpcsx}/iodev/camera.cpp (100%) rename {rpcsx-os => rpcsx}/iodev/cayman_reg.cpp (100%) rename {rpcsx-os => rpcsx}/iodev/cd.cpp (100%) rename {rpcsx-os => rpcsx}/iodev/console.cpp (100%) rename {rpcsx-os => rpcsx}/iodev/dce.cpp (81%) rename {rpcsx-os => rpcsx}/iodev/devact.cpp (100%) rename {rpcsx-os => rpcsx}/iodev/devctl.cpp (100%) rename {rpcsx-os => rpcsx}/iodev/devstat.cpp (100%) rename {rpcsx-os => rpcsx}/iodev/dipsw.cpp (100%) rename {rpcsx-os => rpcsx}/iodev/dmem.cpp (89%) rename {rpcsx-os => rpcsx}/iodev/dmem.hpp (100%) rename {rpcsx-os => rpcsx}/iodev/evlg.cpp (100%) rename {rpcsx-os => rpcsx}/iodev/gbase.cpp (100%) rename {rpcsx-os => rpcsx}/iodev/gc.cpp (62%) rename {rpcsx-os => rpcsx}/iodev/hdd.cpp (100%) rename {rpcsx-os => rpcsx}/iodev/hdmi.cpp (100%) rename {rpcsx-os => rpcsx}/iodev/hid.cpp (68%) rename {rpcsx-os => rpcsx}/iodev/hmd_3da.cpp (100%) rename {rpcsx-os => rpcsx}/iodev/hmd_cmd.cpp (100%) rename {rpcsx-os => rpcsx}/iodev/hmd_mmap.cpp (96%) rename {rpcsx-os => rpcsx}/iodev/hmd_snsr.cpp (100%) rename {rpcsx-os => rpcsx}/iodev/icc_configuration.cpp (100%) rename {rpcsx-os => rpcsx}/iodev/icc_power.cpp (100%) rename {rpcsx-os => rpcsx}/iodev/lvdctl.cpp (100%) rename {rpcsx-os => rpcsx}/iodev/mbus.cpp (100%) rename {rpcsx-os => rpcsx}/iodev/mbus.hpp (100%) rename {rpcsx-os => rpcsx}/iodev/mbus_av.cpp (100%) rename {rpcsx-os => rpcsx}/iodev/mbus_av.hpp (100%) rename {rpcsx-os => rpcsx}/iodev/metadbg.cpp (100%) rename {rpcsx-os => rpcsx}/iodev/notification.cpp (100%) rename {rpcsx-os => rpcsx}/iodev/npdrm.cpp (100%) rename {rpcsx-os => rpcsx}/iodev/null.cpp (100%) rename {rpcsx-os => rpcsx}/iodev/rng.cpp (96%) rename {rpcsx-os => rpcsx}/iodev/s3da.cpp (100%) rename {rpcsx-os => rpcsx}/iodev/sbl_srv.cpp (96%) rename {rpcsx-os => rpcsx}/iodev/scanin.cpp (100%) rename {rpcsx-os => rpcsx}/iodev/shm.cpp (69%) rename {rpcsx-os => rpcsx}/iodev/srtc.cpp (100%) rename {rpcsx-os => rpcsx}/iodev/sshot.cpp (100%) rename {rpcsx-os => rpcsx}/iodev/urandom.cpp (100%) rename {rpcsx-os => rpcsx}/iodev/uvd.cpp (100%) rename {rpcsx-os => rpcsx}/iodev/vce.cpp (100%) rename {rpcsx-os => rpcsx}/iodev/xpt.cpp (100%) rename {rpcsx-os => rpcsx}/iodev/zero.cpp (100%) create mode 100644 rpcsx/ipmi.cpp create mode 100644 rpcsx/ipmi.hpp rename {rpcsx-os => rpcsx}/linker.cpp (98%) rename {rpcsx-os => rpcsx}/linker.hpp (100%) create mode 100644 rpcsx/main.cpp rename {rpcsx-os => rpcsx}/ops.cpp (96%) rename {rpcsx-os => rpcsx}/ops.hpp (100%) rename {rpcsx-os => rpcsx}/orbis-kernel-config/orbis-config.hpp (100%) rename {rpcsx-os => rpcsx}/scheduler.hpp (100%) rename {rpcsx-os => rpcsx}/thread.cpp (100%) rename {rpcsx-os => rpcsx}/thread.hpp (100%) rename {rpcsx-os => rpcsx}/vfs.cpp (83%) rename {rpcsx-os => rpcsx}/vfs.hpp (96%) rename {rpcsx-os => rpcsx}/vm.cpp (85%) rename {rpcsx-os => rpcsx}/vm.hpp (96%) diff --git a/.github/BUILDING.md b/.github/BUILDING.md index c120a19..0e41995 100644 --- a/.github/BUILDING.md +++ b/.github/BUILDING.md @@ -39,25 +39,8 @@ git clone https://github.com/KhronosGroup/SPIRV-Cross && cd SPIRV-Cross && mkdir ``` git clone --recursive https://github.com/RPCSX/rpcsx && cd rpcsx ``` -``` -git submodule update --init --recursive -``` ## How to compile the emulator ``` -mkdir -p build && cd build && cmake .. && cmake --build . -``` - -## How to create a Virtual HDD - -> The PS4 has a case-insensitive filesystem. To create the Virtual HDD, do the following: - -``` -truncate -s 512M ps4-hdd.exfat - -mkfs.exfat -n PS4-HDD ./ps4-hdd.exfat - -mkdir ps4-fs - -sudo mount -t exfat -o uid=`id -u`,gid=`id -g` ./ps4-hdd.exfat ./ps4-fs +cmake -B build && cmake --build build -j$(nproc) ``` diff --git a/.github/USAGE.md b/.github/USAGE.md index 5a4ec7e..ee2d6a8 100644 --- a/.github/USAGE.md +++ b/.github/USAGE.md @@ -4,17 +4,17 @@ You will need firmware 5.05 dumped via PS4 FTP it must be fully decrypted and we do not provide the firmware -See the Commands of `rpcsx-os` (`-h` argument), or join the [Discord](https://discord.gg/t6dzA4wUdG) for help. +See the Commands of `rpcsx` (`-h` argument), or join the [Discord](https://discord.gg/t6dzA4wUdG) for help. You can run the emulator with some samples using this command: ```sh -rm -f /dev/shm/rpcsx-* && ./rpcsx-os --mount "/system" "/system" --mount "" /app0 /app0/some-test-sample.elf [...] +./rpcsx --mount "/system" "/system" --mount "" /app0 /app0/some-test-sample.elf [...] ``` ### You can now enter safe mode ```sh -./rpcsx-os --system --safemode --mount $PATH_TO_YOUR_FW_ROOT / /mini-syscore.elf +./rpcsx --system --safemode --mount $PATH_TO_YOUR_FW_ROOT / /mini-syscore.elf ``` drop ```--safemode``` to have normal mode (not expected to produce graphics yet) ## Creating a log diff --git a/CMakeLists.txt b/CMakeLists.txt index 1b3d339..53d4f97 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -57,9 +57,7 @@ endfunction() add_subdirectory(tools) add_subdirectory(orbis-kernel) -add_subdirectory(rpcsx-os) -add_subdirectory(rpcsx-gpu) -add_subdirectory(hw/amdgpu) +add_subdirectory(rpcsx) add_subdirectory(rx) target_compile_definitions(rx PRIVATE diff --git a/hw/amdgpu/CMakeLists.txt b/hw/amdgpu/CMakeLists.txt deleted file mode 100644 index b4d9065..0000000 --- a/hw/amdgpu/CMakeLists.txt +++ /dev/null @@ -1,7 +0,0 @@ -cmake_minimum_required(VERSION 3.10) - -set(CMAKE_CXX_STANDARD 23) -set(CMAKE_CXX_EXTENSIONS off) - -add_subdirectory(bridge) - diff --git a/hw/amdgpu/bridge/CMakeLists.txt b/hw/amdgpu/bridge/CMakeLists.txt deleted file mode 100644 index d711ecf..0000000 --- a/hw/amdgpu/bridge/CMakeLists.txt +++ /dev/null @@ -1,17 +0,0 @@ -project(libamdgpu-bridge) -set(PROJECT_PATH amdgpu/bridge) - -set(INCLUDE - include/${PROJECT_PATH}/bridge.hpp -) - -set(SRC - src/bridge.cpp -) - -add_library(${PROJECT_NAME} STATIC ${INCLUDE} ${SRC}) -target_include_directories(${PROJECT_NAME} PUBLIC include PRIVATE include/${PROJECT_PATH}) -target_link_libraries(${PROJECT_NAME} PUBLIC orbis::utils::ipc) -set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "") -add_library(amdgpu::bridge ALIAS ${PROJECT_NAME}) -set_property(TARGET ${PROJECT_NAME} PROPERTY POSITION_INDEPENDENT_CODE ON) diff --git a/hw/amdgpu/bridge/include/amdgpu/bridge/bridge.hpp b/hw/amdgpu/bridge/include/amdgpu/bridge/bridge.hpp deleted file mode 100644 index e1f9297..0000000 --- a/hw/amdgpu/bridge/include/amdgpu/bridge/bridge.hpp +++ /dev/null @@ -1,402 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -namespace amdgpu::bridge { -struct PadState { - std::uint64_t timestamp; - std::uint32_t unk; - std::uint32_t buttons; - std::uint8_t leftStickX; - std::uint8_t leftStickY; - std::uint8_t rightStickX; - std::uint8_t rightStickY; - std::uint8_t l2; - std::uint8_t r2; -}; - -enum { - kPadBtnL3 = 1 << 1, - kPadBtnR3 = 1 << 2, - kPadBtnOptions = 1 << 3, - kPadBtnUp = 1 << 4, - kPadBtnRight = 1 << 5, - kPadBtnDown = 1 << 6, - kPadBtnLeft = 1 << 7, - kPadBtnL2 = 1 << 8, - kPadBtnR2 = 1 << 9, - kPadBtnL1 = 1 << 10, - kPadBtnR1 = 1 << 11, - kPadBtnTriangle = 1 << 12, - kPadBtnCircle = 1 << 13, - kPadBtnCross = 1 << 14, - kPadBtnSquare = 1 << 15, - kPadBtnPs = 1 << 16, - kPadBtnTouchPad = 1 << 20, - kPadBtnIntercepted = 1 << 31, -}; - -enum class CommandId : std::uint32_t { - Nop, - ProtectMemory, - CommandBuffer, - Flip, - MapMemory, - MapProcess, - UnmapProcess, - RegisterBuffer, - RegisterBufferAttribute, -}; - -struct CmdMemoryProt { - std::uint64_t address; - std::uint64_t size; - std::uint32_t prot; - std::uint32_t pid; -}; - -struct CmdCommandBuffer { - std::uint64_t queue; - std::uint64_t address; - std::uint32_t size; - std::uint32_t pid; -}; - -struct CmdBufferAttribute { - std::uint32_t pid; - std::uint8_t attrId; - std::uint8_t submit; - std::uint64_t canary; - std::uint32_t pixelFormat; - std::uint32_t tilingMode; - std::uint32_t pitch; - std::uint32_t width; - std::uint32_t height; -}; - -struct CmdBuffer { - std::uint64_t canary; - std::uint32_t index; - std::uint32_t attrId; - std::uint64_t address; - std::uint64_t address2; - std::uint32_t pid; -}; - -struct CmdFlip { - std::uint32_t pid; - std::uint32_t bufferIndex; - std::uint64_t arg; -}; - -struct CmdMapMemory { - std::int64_t offset; - std::uint64_t address; - std::uint64_t size; - std::uint32_t prot; - std::uint32_t pid; - std::int32_t memoryType; - std::uint32_t dmemIndex; -}; - -struct CmdMapProcess { - std::uint64_t pid; - int vmId; -}; - -struct CmdUnmapProcess { - std::uint64_t pid; -}; - -enum { - kPageWriteWatch = 1 << 0, - kPageReadWriteLock = 1 << 1, - kPageInvalidated = 1 << 2, - kPageLazyLock = 1 << 3 -}; - -static constexpr auto kHostPageSize = 0x1000; - -struct BridgeHeader { - std::uint64_t size; - std::uint64_t info; - std::uint32_t pullerPid; - std::uint32_t pusherPid; - std::atomic lock; - volatile std::uint64_t flags; - std::uint64_t vmAddress; - std::uint64_t vmSize; - char vmName[32]; - PadState kbPadState; - volatile std::uint32_t flipBuffer[6]; - volatile std::uint64_t flipArg[6]; - volatile std::uint64_t flipCount[6]; - volatile std::uint64_t bufferInUseAddress[6]; - std::uint32_t commandBufferCount; - std::uint32_t bufferCount; - CmdCommandBuffer commandBuffers[32]; - // CmdBuffer buffers[10]; - // orbis::shared_mutex cacheCommandMtx; - // orbis::shared_cv cacheCommandCv; - std::atomic cacheCommands[6][4]; - std::atomic gpuCacheCommand[6]; - std::atomic cachePages[6][0x100'0000'0000 / kHostPageSize]; - - volatile std::uint64_t pull; - volatile std::uint64_t push; - std::uint64_t commands[]; -}; - -struct Command { - CommandId id; - - union { - CmdMemoryProt memoryProt; - CmdCommandBuffer commandBuffer; - CmdBuffer buffer; - CmdBufferAttribute bufferAttribute; - CmdFlip flip; - CmdMapMemory mapMemory; - CmdMapProcess mapProcess; - CmdUnmapProcess unmapProcess; - }; -}; - -enum class BridgeFlags { - VmConfigured = 1 << 0, - PushLock = 1 << 1, - PullLock = 1 << 2, -}; - -struct BridgePusher { - BridgeHeader *header = nullptr; - - void setVm(std::uint64_t address, std::uint64_t size, const char *name) { - header->vmAddress = address; - header->vmSize = size; - std::strncpy(header->vmName, name, sizeof(header->vmName)); - header->flags = - header->flags | static_cast(BridgeFlags::VmConfigured); - } - - void sendMemoryProtect(std::uint32_t pid, std::uint64_t address, - std::uint64_t size, std::uint32_t prot) { - sendCommand(CommandId::ProtectMemory, {pid, address, size, prot}); - } - - void sendMapMemory(std::uint32_t pid, std::uint32_t memoryType, - std::uint32_t dmemIndex, std::uint64_t address, - std::uint64_t size, std::uint32_t prot, - std::uint64_t offset) { - sendCommand(CommandId::MapMemory, - {pid, memoryType, dmemIndex, address, size, prot, offset}); - } - - void sendRegisterBuffer(std::uint32_t pid, std::uint64_t canary, - std::uint32_t index, std::uint32_t attrId, - std::uint64_t address, std::uint64_t address2) { - sendCommand(CommandId::RegisterBuffer, - {pid, canary, index, attrId, address, address2}); - } - void sendRegisterBufferAttribute(std::uint32_t pid, std::uint8_t attrId, - std::uint8_t submit, std::uint64_t canary, - std::uint32_t pixelFormat, - std::uint32_t tilingMode, - std::uint32_t pitch, std::uint32_t width, - std::uint32_t height) { - sendCommand(CommandId::RegisterBufferAttribute, - {pid, attrId, submit, canary, pixelFormat, tilingMode, pitch, - width, height}); - } - - void sendCommandBuffer(std::uint32_t pid, std::uint64_t queue, - std::uint64_t address, std::uint64_t size) { - sendCommand(CommandId::CommandBuffer, {pid, queue, address, size}); - } - - void sendFlip(std::uint32_t pid, std::uint32_t bufferIndex, - std::uint64_t arg) { - sendCommand(CommandId::Flip, {pid, bufferIndex, arg}); - } - - void sendMapProcess(std::uint32_t pid, unsigned vmId) { - sendCommand(CommandId::MapProcess, {pid, vmId}); - } - void sendUnmapProcess(std::uint32_t pid) { - sendCommand(CommandId::UnmapProcess, {pid}); - } - - void wait() { - while (header->pull != header->push) - ; - } - -private: - static std::uint64_t makeCommandHeader(CommandId id, std::size_t cmdSize) { - return static_cast(id) | - (static_cast(cmdSize - 1) << 32); - } - - void sendCommand(CommandId id, std::initializer_list args) { - std::uint64_t exp = 0; - while (!header->lock.compare_exchange_strong( - exp, 1, std::memory_order::acquire, std::memory_order::relaxed)) { - exp = 0; - } - - std::size_t cmdSize = args.size() + 1; - std::uint64_t pos = getPushPosition(cmdSize); - - header->commands[pos++] = makeCommandHeader(id, cmdSize); - for (auto arg : args) { - header->commands[pos++] = arg; - } - header->push = pos; - header->lock.store(0, std::memory_order::release); - } - - std::uint64_t getPushPosition(std::uint64_t cmdSize) { - std::uint64_t position = header->push; - - if (position + cmdSize > header->size) { - waitPuller(position); - - if (position < header->size) { - header->commands[position] = - static_cast(CommandId::Nop) | - ((header->size - position + cmdSize) << 32); - } - - position = 0; - header->push = position; - } - - return position; - } - void waitPuller(std::uint64_t pullValue) { - while (header->pull != pullValue) { - ; - } - } -}; - -struct BridgePuller { - BridgeHeader *header = nullptr; - - BridgePuller() = default; - BridgePuller(BridgeHeader *header) : header(header) {} - - std::size_t pullCommands(Command *commands, std::size_t maxCount) { - std::size_t processed = 0; - - while (processed < maxCount) { - if (header->pull == header->push) { - break; - } - - auto pos = header->pull; - - if (pos >= header->size) { - header->pull = 0; - continue; - } - - auto cmd = header->commands[pos]; - CommandId cmdId = static_cast(cmd); - std::uint32_t argsCount = cmd >> 32; - - if (cmdId != CommandId::Nop) { - commands[processed++] = - unpackCommand(cmdId, header->commands + pos + 1, argsCount); - } - - header->pull = pos + argsCount + 1; - } - - return processed; - } - -private: - Command unpackCommand(CommandId command, const std::uint64_t *args, - std::uint32_t argsCount) { - Command result; - result.id = command; - - switch (command) { - case CommandId::Nop: - return result; - - case CommandId::ProtectMemory: - result.memoryProt.pid = args[0]; - result.memoryProt.address = args[1]; - result.memoryProt.size = args[2]; - result.memoryProt.prot = args[3]; - return result; - - case CommandId::CommandBuffer: - result.commandBuffer.pid = args[0]; - result.commandBuffer.queue = args[1]; - result.commandBuffer.address = args[2]; - result.commandBuffer.size = args[3]; - return result; - - case CommandId::Flip: - result.flip.pid = args[0]; - result.flip.bufferIndex = args[1]; - result.flip.arg = args[2]; - return result; - - case CommandId::MapMemory: - result.mapMemory.pid = args[0]; - result.mapMemory.memoryType = args[1]; - result.mapMemory.dmemIndex = args[2]; - result.mapMemory.address = args[3]; - result.mapMemory.size = args[4]; - result.mapMemory.prot = args[5]; - result.mapMemory.offset = args[6]; - return result; - - case CommandId::MapProcess: - result.mapProcess.pid = args[0]; - result.mapProcess.vmId = args[1]; - return result; - - case CommandId::UnmapProcess: - result.unmapProcess.pid = args[0]; - return result; - - case CommandId::RegisterBufferAttribute: - result.bufferAttribute.pid = args[0]; - result.bufferAttribute.attrId = args[1]; - result.bufferAttribute.submit = args[2]; - result.bufferAttribute.canary = args[3]; - result.bufferAttribute.pixelFormat = args[4]; - result.bufferAttribute.tilingMode = args[5]; - result.bufferAttribute.pitch = args[6]; - result.bufferAttribute.width = args[7]; - result.bufferAttribute.height = args[8]; - return result; - - case CommandId::RegisterBuffer: - result.buffer.pid = args[0]; - result.buffer.canary = args[1]; - result.buffer.index = args[2]; - result.buffer.attrId = args[3]; - result.buffer.address = args[4]; - result.buffer.address2 = args[5]; - return result; - } - - __builtin_trap(); - } -}; - -BridgeHeader *createShmCommandBuffer(const char *name); -BridgeHeader *openShmCommandBuffer(const char *name); -void destroyShmCommandBuffer(BridgeHeader *buffer); -void unlinkShm(const char *name); -} // namespace amdgpu::bridge diff --git a/hw/amdgpu/bridge/src/bridge.cpp b/hw/amdgpu/bridge/src/bridge.cpp deleted file mode 100644 index e221f57..0000000 --- a/hw/amdgpu/bridge/src/bridge.cpp +++ /dev/null @@ -1,87 +0,0 @@ -#include "bridge.hpp" - -#include -#include -#include -#include - -static int gShmFd = -1; -static constexpr std::size_t kShmSize = sizeof(amdgpu::bridge::BridgeHeader) + - (sizeof(std::uint64_t) * 1024); -amdgpu::bridge::BridgeHeader * -amdgpu::bridge::createShmCommandBuffer(const char *name) { - if (gShmFd != -1) { - return nullptr; - } - - // unlinkShm(name); - - int fd = ::shm_open(name, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); - - if (fd == -1) { - return nullptr; - } - - if (ftruncate(fd, kShmSize) < 0) { - ::close(fd); - return nullptr; - } - - void *memory = - ::mmap(nullptr, kShmSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - - if (memory == MAP_FAILED) { - ::close(fd); - return nullptr; - } - - gShmFd = fd; - auto result = new (memory) amdgpu::bridge::BridgeHeader; - std::memset(result, 0, sizeof(*result)); - result->size = - (kShmSize - sizeof(amdgpu::bridge::BridgeHeader)) / sizeof(std::uint64_t); - return result; -} - -amdgpu::bridge::BridgeHeader * -amdgpu::bridge::openShmCommandBuffer(const char *name) { - if (gShmFd != -1) { - return nullptr; - } - - int fd = ::shm_open(name, O_RDWR, S_IRUSR | S_IWUSR); - - if (fd == -1) { - return nullptr; - } - - if (ftruncate(fd, kShmSize) < 0) { - ::close(fd); - return nullptr; - } - - void *memory = - ::mmap(nullptr, kShmSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - - if (memory == MAP_FAILED) { - ::close(fd); - return nullptr; - } - - gShmFd = fd; - return new (memory) amdgpu::bridge::BridgeHeader; -} - -void amdgpu::bridge::destroyShmCommandBuffer( - amdgpu::bridge::BridgeHeader *buffer) { - if (gShmFd == -1) { - __builtin_trap(); - } - - buffer->~BridgeHeader(); - ::close(gShmFd); - gShmFd = -1; - ::munmap(buffer, kShmSize); -} - -void amdgpu::bridge::unlinkShm(const char *name) { ::shm_unlink(name); } diff --git a/orbis-kernel/include/orbis/KernelContext.hpp b/orbis-kernel/include/orbis/KernelContext.hpp index 227e5d1..b6b8068 100644 --- a/orbis-kernel/include/orbis/KernelContext.hpp +++ b/orbis-kernel/include/orbis/KernelContext.hpp @@ -2,6 +2,7 @@ #include "KernelAllocator.hpp" #include "evf.hpp" #include "ipmi.hpp" +#include "orbis/note.hpp" #include "osem.hpp" #include "thread/types.hpp" #include "utils/IdMap.hpp" @@ -174,9 +175,12 @@ public: return getUmtxChainIndexed(1, t, flags, ptr); } + Ref deviceEventEmitter; Ref shmDevice; Ref dmemDevice; Ref blockpoolDevice; + shared_mutex gpuDeviceMtx; + Ref gpuDevice; uint sdkVersion{}; uint fwSdkVersion{}; uint safeMode{}; diff --git a/orbis-kernel/include/orbis/error/SysResult.hpp b/orbis-kernel/include/orbis/error/SysResult.hpp index 99308d6..8f5856b 100644 --- a/orbis-kernel/include/orbis/error/SysResult.hpp +++ b/orbis-kernel/include/orbis/error/SysResult.hpp @@ -1,4 +1,5 @@ #pragma once +#include namespace orbis { enum class ErrorCode : int; @@ -18,5 +19,13 @@ public: [[nodiscard]] int value() const { return mValue < 0 ? -mValue : mValue; } [[nodiscard]] bool isError() const { return mValue < 0; } + + [[nodiscard]] auto operator<=>(ErrorCode ec) const { + return static_cast(value()) <=> ec; + } + + [[nodiscard]] auto operator<=>(SysResult other) const { + return value() <=> other.value(); + } }; } // namespace orbis diff --git a/orbis-kernel/include/orbis/note.hpp b/orbis-kernel/include/orbis/note.hpp index f6212d5..eda954d 100644 --- a/orbis-kernel/include/orbis/note.hpp +++ b/orbis-kernel/include/orbis/note.hpp @@ -2,8 +2,8 @@ #include "KernelAllocator.hpp" #include "orbis-config.hpp" +#include "orbis/utils/Rc.hpp" #include "utils/SharedMutex.hpp" -#include #include namespace orbis { @@ -71,6 +71,7 @@ struct KEvent { ptr udata; }; +struct EventEmitter; struct KQueue; struct KNote { shared_mutex mutex; @@ -80,6 +81,7 @@ struct KNote { bool enabled = true; bool triggered = false; void *linked = nullptr; // TODO: use Ref<> + kvector> emitters; ~KNote(); }; @@ -88,6 +90,8 @@ struct EventEmitter : orbis::RcBase { shared_mutex mutex; std::set, kallocator> notes; - void emit(uint filter, uint fflags = 0, intptr_t data = 0); + void emit(sshort filter, uint fflags = 0, intptr_t data = 0); + void subscribe(KNote *note); + void unsubscribe(KNote *note); }; } // namespace orbis diff --git a/orbis-kernel/include/orbis/thread/Process.hpp b/orbis-kernel/include/orbis/thread/Process.hpp index 104308f..a6c9492 100644 --- a/orbis-kernel/include/orbis/thread/Process.hpp +++ b/orbis-kernel/include/orbis/thread/Process.hpp @@ -46,6 +46,7 @@ struct NamedMemoryRange { struct Process final { KernelContext *context = nullptr; pid_t pid = -1; + int gfxRing = 0; std::uint64_t hostPid = -1; sysentvec *sysent = nullptr; ProcessState state = ProcessState::NEW; diff --git a/orbis-kernel/include/orbis/thread/types.hpp b/orbis-kernel/include/orbis/thread/types.hpp index f867833..438b6fa 100644 --- a/orbis-kernel/include/orbis/thread/types.hpp +++ b/orbis-kernel/include/orbis/thread/types.hpp @@ -3,7 +3,7 @@ namespace orbis { using lwpid_t = int32_t; -using pid_t = int64_t; +using pid_t = int32_t; using uid_t = uint32_t; using gid_t = uint32_t; diff --git a/orbis-kernel/include/orbis/utils/Rc.hpp b/orbis-kernel/include/orbis/utils/Rc.hpp index 20ecb5d..b716803 100644 --- a/orbis-kernel/include/orbis/utils/Rc.hpp +++ b/orbis-kernel/include/orbis/utils/Rc.hpp @@ -49,11 +49,11 @@ template class Ref { public: Ref() = default; - Ref(std::nullptr_t) {} + Ref(std::nullptr_t) noexcept {} template requires(std::is_base_of_v) - Ref(OT *ref) : m_ref(ref) { + Ref(OT *ref) noexcept : m_ref(ref) { if (m_ref != nullptr) { ref->incRef(); } @@ -61,7 +61,7 @@ public: template requires(std::is_base_of_v) - Ref(const Ref &other) : m_ref(other.get()) { + Ref(const Ref &other) noexcept : m_ref(other.get()) { if (m_ref != nullptr) { m_ref->incRef(); } @@ -69,42 +69,42 @@ public: template requires(std::is_base_of_v) - Ref(Ref &&other) : m_ref(other.release()) {} + Ref(Ref &&other) noexcept : m_ref(other.release()) {} - Ref(const Ref &other) : m_ref(other.get()) { + Ref(const Ref &other) noexcept : m_ref(other.get()) { if (m_ref != nullptr) { m_ref->incRef(); } } - Ref(Ref &&other) : m_ref(other.release()) {} + Ref(Ref &&other) noexcept : m_ref(other.release()) {} template requires(std::is_base_of_v) - Ref &operator=(Ref &&other) { + Ref &operator=(Ref &&other) noexcept { other.template cast().swap(*this); return *this; } template requires(std::is_base_of_v) - Ref &operator=(OT *other) { + Ref &operator=(OT *other) noexcept { *this = Ref(other); return *this; } template requires(std::is_base_of_v) - Ref &operator=(const Ref &other) { + Ref &operator=(const Ref &other) noexcept { *this = Ref(other); return *this; } - Ref &operator=(const Ref &other) { + Ref &operator=(const Ref &other) noexcept { *this = Ref(other); return *this; } - Ref &operator=(Ref &&other) { + Ref &operator=(Ref &&other) noexcept { other.swap(*this); return *this; } @@ -115,7 +115,7 @@ public: } } - void swap(Ref &other) { std::swap(m_ref, other.m_ref); } + void swap(Ref &other) noexcept { std::swap(m_ref, other.m_ref); } T *get() const { return m_ref; } T *release() { return std::exchange(m_ref, nullptr); } T *operator->() const { return m_ref; } @@ -126,10 +126,17 @@ public: auto operator<=>(const Ref &other) const = default; template Ref cast() { - return Ref(dynamic_cast(m_ref)); + return dynamic_cast(m_ref); } template Ref staticCast() { - return Ref(static_cast(m_ref)); + return static_cast(m_ref); + } + + template OtherT *rawCast() { + return dynamic_cast(m_ref); + } + template OtherT *rawStaticCast() { + return static_cast(m_ref); } }; diff --git a/orbis-kernel/src/KernelContext.cpp b/orbis-kernel/src/KernelContext.cpp index ea3ef39..20ce6e5 100644 --- a/orbis-kernel/src/KernelContext.cpp +++ b/orbis-kernel/src/KernelContext.cpp @@ -9,6 +9,8 @@ #include static const std::uint64_t g_allocProtWord = 0xDEADBEAFBADCAFE1; +static constexpr auto kHeapBaseAddress = 0x600'0000'0000; +static constexpr auto kHeapSize = 0x2'0000'0000; namespace orbis { thread_local Thread *g_currentThread; @@ -16,7 +18,7 @@ thread_local Thread *g_currentThread; KernelContext &g_context = *[]() -> KernelContext * { // Allocate global shared kernel memory // TODO: randomize for hardening and reduce size - auto ptr = mmap(reinterpret_cast(0x200'0000'0000), 0x2'0000'0000, + auto ptr = mmap(reinterpret_cast(kHeapBaseAddress), kHeapSize, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS | MAP_FIXED, -1, 0); if (ptr == MAP_FAILED) @@ -166,15 +168,32 @@ void *KernelContext::kalloc(std::size_t size, std::size_t align) { align = std::max(align, __STDCPP_DEFAULT_NEW_ALIGNMENT__); auto heap = reinterpret_cast(m_heap_next); heap = (heap + (align - 1)) & ~(align - 1); + + if (heap + size > kHeapBaseAddress + kHeapSize) { + std::fprintf(stderr, "out of kernel memory"); + std::abort(); + } + // Check overflow + if (heap + size < heap) { + std::fprintf(stderr, "too big allocation"); + std::abort(); + } + auto result = reinterpret_cast(heap); std::memcpy(std::bit_cast(result) + size, &g_allocProtWord, sizeof(g_allocProtWord)); m_heap_next = reinterpret_cast(heap + size + sizeof(g_allocProtWord)); - // Check overflow - if (heap + size < heap) - std::abort(); - if (heap + size > (uintptr_t)&g_context + 0x1'0000'0000) - std::abort(); + + if (true) { + heap = reinterpret_cast(m_heap_next); + align = std::min(align, 4096); + heap = (heap + (align - 1)) & ~(align - 1); + size = 4096; + ::mmap(reinterpret_cast(heap), size, PROT_NONE, MAP_FIXED, -1, 0); + + m_heap_next = reinterpret_cast(heap + size); + } + return result; } diff --git a/orbis-kernel/src/event.cpp b/orbis-kernel/src/event.cpp index 407b095..689a5b6 100644 --- a/orbis-kernel/src/event.cpp +++ b/orbis-kernel/src/event.cpp @@ -1,7 +1,13 @@ #include "event.hpp" + #include "thread/Process.hpp" +#include orbis::KNote::~KNote() { + while (!emitters.empty()) { + emitters.back()->unsubscribe(this); + } + if (linked == nullptr) { return; } @@ -14,7 +20,7 @@ orbis::KNote::~KNote() { } } -void orbis::EventEmitter::emit(uint filter, uint fflags, intptr_t data) { +void orbis::EventEmitter::emit(sshort filter, uint fflags, intptr_t data) { std::lock_guard lock(mutex); for (auto note : notes) { @@ -40,3 +46,28 @@ void orbis::EventEmitter::emit(uint filter, uint fflags, intptr_t data) { note->queue->cv.notify_all(note->queue->mtx); } } + +void orbis::EventEmitter::subscribe(KNote *note) { + std::lock_guard lock(mutex); + notes.insert(note); + note->emitters.emplace_back(this); +} + +void orbis::EventEmitter::unsubscribe(KNote *note) { + std::lock_guard lock(mutex); + notes.erase(note); + + auto it = std::ranges::find(note->emitters, this); + if (it == note->emitters.end()) { + return; + } + + std::size_t index = it - note->emitters.begin(); + auto lastEmitter = note->emitters.size() - 1; + + if (index != lastEmitter) { + std::swap(note->emitters[index], note->emitters[lastEmitter]); + } + + note->emitters.pop_back(); +} \ No newline at end of file diff --git a/orbis-kernel/src/ipmi.cpp b/orbis-kernel/src/ipmi.cpp index 7742abe..177470a 100644 --- a/orbis-kernel/src/ipmi.cpp +++ b/orbis-kernel/src/ipmi.cpp @@ -223,6 +223,10 @@ orbis::SysResult orbis::sysIpmiServerReceivePacket(Thread *thread, ptr unk; }; + if (paramsSz != sizeof(IpmiServerReceivePacketParams)) { + return orbis::ErrorCode::INVAL; + } + IpmiServerReceivePacketParams _params; ORBIS_RET_ON_ERROR( @@ -265,9 +269,6 @@ orbis::SysResult orbis::sysIpmiServerReceivePacket(Thread *thread, auto asyncMessage = (IpmiAsyncMessageHeader *)_packet.message.data(); ORBIS_LOG_ERROR(__FUNCTION__, server->name, asyncMessage->methodId, asyncMessage->numInData, asyncMessage->pid); - - ORBIS_LOG_ERROR(__FUNCTION__, server->name, - *(std::uint64_t *)(*(long *)server->eventHandler + 0x18)); } if (_params.bufferSize < _packet.message.size()) { @@ -380,11 +381,13 @@ orbis::SysResult orbis::sysIpmiSessionRespondSync(Thread *thread, clientTid = session->server->tidToClientTid.at(thread->tid); } + ORBIS_LOG_ERROR(__FUNCTION__, session->client->name, _params.errorCode); + if (_params.errorCode != 0) { ORBIS_LOG_ERROR(__FUNCTION__, session->client->name, _params.errorCode); thread->where(); - // HACK: completely broken audio audio support should not be visible + // HACK: completely broken audio support should not be visible if (session->client->name == "SceSysAudioSystemIpc" && _params.errorCode == -1) { _params.errorCode = 0; @@ -1268,6 +1271,10 @@ orbis::SysResult orbis::sysIpmiClientWaitEventFlag(Thread *thread, static_assert(sizeof(IpmiWaitEventFlagParam) == 0x28); + if (paramsSz != sizeof(IpmiWaitEventFlagParam)) { + return ErrorCode::INVAL; + } + IpmiWaitEventFlagParam _params; ORBIS_RET_ON_ERROR(uread(_params, ptr(params))); diff --git a/orbis-kernel/src/sys/sys_event.cpp b/orbis-kernel/src/sys/sys_event.cpp index 8b9ca33..f204867 100644 --- a/orbis-kernel/src/sys/sys_event.cpp +++ b/orbis-kernel/src/sys/sys_event.cpp @@ -113,17 +113,15 @@ static SysResult keventChange(KQueue *kq, KEvent &change, Thread *thread) { nodeIt->file = fd; if (auto eventEmitter = fd->event) { - std::unique_lock lock(eventEmitter->mutex); - // if (change.filter == kEvFiltWrite) { - // nodeIt->triggered = true; - // kq->cv.notify_all(kq->mtx); - // } + eventEmitter->subscribe(&*nodeIt); nodeIt->triggered = true; - eventEmitter->notes.insert(&*nodeIt); kq->cv.notify_all(kq->mtx); } else if (note.file->hostFd < 0) { ORBIS_LOG_ERROR("Unimplemented event emitter", change.ident); } + } else if (change.filter == kEvFiltGraphicsCore || + change.filter == kEvFiltDisplay) { + g_context.deviceEventEmitter->subscribe(&*nodeIt); } } } @@ -172,19 +170,14 @@ static SysResult keventChange(KQueue *kq, KEvent &change, Thread *thread) { nodeIt->triggered = true; kq->cv.notify_all(kq->mtx); } - } else if (change.filter == kEvFiltGraphicsCore) { + } else if (change.filter == kEvFiltDisplay && change.ident >> 48 == 0x6301) { nodeIt->triggered = true; - - if (change.ident == 0x84) { - // clock change event - nodeIt->event.data |= 1000ull << 16; // clock - } kq->cv.notify_all(kq->mtx); - } else if (change.filter == kEvFiltDisplay) { - if (change.ident != 0x51000100000000 && change.ident != 0x63010100000000) { - nodeIt->triggered = true; - kq->cv.notify_all(kq->mtx); - } + } else if (change.filter == kEvFiltGraphicsCore && change.ident == 0x84) { + nodeIt->triggered = true; + nodeIt->event.data |= 1000ull << 16; // clock + + kq->cv.notify_all(kq->mtx); } return {}; diff --git a/orbis-kernel/src/sys/sys_sysctl.cpp b/orbis-kernel/src/sys/sys_sysctl.cpp index e3d3487..a220adc 100644 --- a/orbis-kernel/src/sys/sys_sysctl.cpp +++ b/orbis-kernel/src/sys/sys_sysctl.cpp @@ -307,8 +307,8 @@ SysResult kern_sysctl(Thread *thread, ptr name, uint namelen, case sysctl_ctl::unspec: { switch (name[1]) { case 3: { - std::fprintf(stderr, " unspec - get name of '%s'\n", - std::string((char *)new_, newlen).c_str()); + // std::fprintf(stderr, " unspec - get name of '%s'\n", + // std::string((char *)new_, newlen).c_str()); auto searchName = std::string_view((char *)new_, newlen); auto *dest = (std::uint32_t *)old; std::uint32_t count = 0; diff --git a/orbis-kernel/src/umtx.cpp b/orbis-kernel/src/umtx.cpp index bbf4b51..3a94170 100644 --- a/orbis-kernel/src/umtx.cpp +++ b/orbis-kernel/src/umtx.cpp @@ -305,7 +305,7 @@ orbis::ErrorCode orbis::umtx_cv_wait(Thread *thread, ptr cv, ORBIS_LOG_FATAL("umtx_cv_wait: UNKNOWN wflags", wflags); return ErrorCode::INVAL; } - if ((wflags & kCvWaitClockId) != 0 && ut + 1) { + if ((wflags & kCvWaitClockId) != 0 && ut + 1 && cv->clockid != 0) { ORBIS_LOG_WARNING("umtx_cv_wait: CLOCK_ID", wflags, cv->clockid); // std::abort(); return ErrorCode::NOSYS; diff --git a/rpcsx-gpu/Device.cpp b/rpcsx-gpu/Device.cpp deleted file mode 100644 index cc5780b..0000000 --- a/rpcsx-gpu/Device.cpp +++ /dev/null @@ -1,437 +0,0 @@ -#include "Device.hpp" -#include "FlipPipeline.hpp" -#include "Renderer.hpp" -#include "amdgpu/tiler.hpp" -#include "gnm/constants.hpp" -#include "gnm/pm4.hpp" -#include "rx/bits.hpp" -#include "rx/die.hpp" -#include "rx/mem.hpp" -#include "shader/spv.hpp" -#include "shaders/rdna-semantic-spirv.hpp" -#include "vk.hpp" -#include -#include -#include - -using namespace amdgpu; - -Device::Device() { - if (!shader::spv::validate(g_rdna_semantic_spirv)) { - shader::spv::dump(g_rdna_semantic_spirv, true); - rx::die("builtin semantic validation failed"); - } - - if (auto sem = shader::spv::deserialize( - shaderSemanticContext, g_rdna_semantic_spirv, - shaderSemanticContext.getUnknownLocation())) { - auto shaderSemantic = *sem; - shader::gcn::canonicalizeSemantic(shaderSemanticContext, shaderSemantic); - shader::gcn::collectSemanticModuleInfo(gcnSemanticModuleInfo, - shaderSemantic); - gcnSemantic = shader::gcn::collectSemanticInfo(gcnSemanticModuleInfo); - } else { - rx::die("failed to deserialize builtin semantics\n"); - } - - for (auto &pipe : graphicsPipes) { - pipe.device = this; - } - - // for (auto &pipe : computePipes) { - // pipe.device = this; - // } -} - -Device::~Device() { - for (auto fd : dmemFd) { - if (fd >= 0) { - ::close(fd); - } - } - - for (auto &[pid, info] : processInfo) { - if (info.vmFd >= 0) { - ::close(info.vmFd); - } - } -} - -void Device::mapProcess(std::int64_t pid, int vmId, const char *shmName) { - auto &process = processInfo[pid]; - process.vmId = vmId; - - auto memory = amdgpu::RemoteMemory{vmId}; - - std::string pidVmName = shmName; - pidVmName += '-'; - pidVmName += std::to_string(pid); - int memoryFd = ::shm_open(pidVmName.c_str(), O_RDWR, S_IRUSR | S_IWUSR); - process.vmFd = memoryFd; - - if (memoryFd < 0) { - std::println("failed to process {:x} shared memory", (int)pid); - std::abort(); - } - - for (auto [startAddress, endAddress, slot] : process.vmTable) { - auto gpuProt = slot.prot >> 4; - if (gpuProt == 0) { - continue; - } - - auto devOffset = slot.offset + startAddress - slot.baseAddress; - int mapFd = memoryFd; - - if (slot.memoryType >= 0) { - mapFd = dmemFd[slot.memoryType]; - } - - auto mmapResult = - ::mmap(memory.getPointer(startAddress), endAddress - startAddress, - gpuProt, MAP_FIXED | MAP_SHARED, mapFd, devOffset); - - if (mmapResult == MAP_FAILED) { - std::println("failed to map process {:x} memory, address {:x}-{:x}, type {:x}", - (int)pid, startAddress, endAddress, slot.memoryType); - std::abort(); - } - - handleProtectChange(vmId, startAddress, endAddress - startAddress, - slot.prot); - } -} - -void Device::unmapProcess(std::int64_t pid) { - auto &process = processInfo[pid]; - auto startAddress = static_cast(process.vmId) << 40; - auto size = static_cast(1) << 40; - rx::mem::reserve(reinterpret_cast(startAddress), size); - - ::close(process.vmFd); - process.vmFd = -1; - process.vmId = -1; -} - -void Device::protectMemory(int pid, std::uint64_t address, std::uint64_t size, - int prot) { - auto &process = processInfo[pid]; - - auto vmSlotIt = process.vmTable.queryArea(address); - if (vmSlotIt == process.vmTable.end()) { - std::abort(); - } - - auto vmSlot = (*vmSlotIt).payload; - - process.vmTable.map(address, address + size, - VmMapSlot{ - .memoryType = vmSlot.memoryType, - .prot = static_cast(prot), - .offset = vmSlot.offset, - .baseAddress = vmSlot.baseAddress, - }); - - if (process.vmId >= 0) { - auto memory = amdgpu::RemoteMemory{process.vmId}; - rx::mem::protect(memory.getPointer(address), size, prot >> 4); - handleProtectChange(process.vmId, address, size, prot); - } -} - -void Device::onCommandBuffer(std::int64_t pid, int cmdHeader, - std::uint64_t address, std::uint64_t size) { - auto &process = processInfo[pid]; - if (process.vmId < 0) { - return; - } - - auto memory = RemoteMemory{process.vmId}; - - auto op = rx::getBits(cmdHeader, 15, 8); - - if (op == gnm::IT_INDIRECT_BUFFER_CNST) { - graphicsPipes[0].setCeQueue(Queue::createFromRange( - process.vmId, memory.getPointer(address), - size / sizeof(std::uint32_t))); - } else if (op == gnm::IT_INDIRECT_BUFFER) { - graphicsPipes[0].setDeQueue( - Queue::createFromRange(process.vmId, - memory.getPointer(address), - size / sizeof(std::uint32_t)), - 1); - } else { - rx::die("unimplemented command buffer %x", cmdHeader); - } -} - -bool Device::processPipes() { - bool allProcessed = true; - - // for (auto &pipe : computePipes) { - // if (!pipe.processAllRings()) { - // allProcessed = false; - // } - // } - - for (auto &pipe : graphicsPipes) { - if (!pipe.processAllRings()) { - allProcessed = false; - } - } - - return allProcessed; -} - -static void -transitionImageLayout(VkCommandBuffer commandBuffer, VkImage image, - VkImageLayout oldLayout, VkImageLayout newLayout, - const VkImageSubresourceRange &subresourceRange) { - VkImageMemoryBarrier barrier{}; - barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - barrier.oldLayout = oldLayout; - barrier.newLayout = newLayout; - barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier.image = image; - barrier.subresourceRange = subresourceRange; - - auto layoutToStageAccess = [](VkImageLayout layout) - -> std::pair { - switch (layout) { - case VK_IMAGE_LAYOUT_UNDEFINED: - case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR: - case VK_IMAGE_LAYOUT_GENERAL: - return {VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0}; - - case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: - return {VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT}; - - case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: - return {VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_READ_BIT}; - - case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: - return {VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_ACCESS_SHADER_READ_BIT}; - - case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: - return {VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT, - VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | - VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT}; - - case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: - return {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | - VK_ACCESS_COLOR_ATTACHMENT_READ_BIT}; - - default: - std::abort(); - } - }; - - auto [sourceStage, sourceAccess] = layoutToStageAccess(oldLayout); - auto [destinationStage, destinationAccess] = layoutToStageAccess(newLayout); - - barrier.srcAccessMask = sourceAccess; - barrier.dstAccessMask = destinationAccess; - - vkCmdPipelineBarrier(commandBuffer, sourceStage, destinationStage, 0, 0, - nullptr, 0, nullptr, 1, &barrier); -} - -bool Device::flip(std::int64_t pid, int bufferIndex, std::uint64_t arg, - VkImage swapchainImage, VkImageView swapchainImageView) { - auto &pipe = graphicsPipes[0]; - auto &scheduler = pipe.scheduler; - auto &process = processInfo[pid]; - if (process.vmId < 0) { - return false; - } - - if (bufferIndex < 0) { - bridge->flipBuffer[process.vmId] = bufferIndex; - bridge->flipArg[process.vmId] = arg; - bridge->flipCount[process.vmId] = bridge->flipCount[process.vmId] + 1; - return false; - } - - auto &buffer = process.buffers[bufferIndex]; - auto &bufferAttr = process.bufferAttributes[buffer.attrId]; - - gnm::DataFormat dfmt; - gnm::NumericFormat nfmt; - auto flipType = FlipType::Alt; - switch (bufferAttr.pixelFormat) { - case 0x80000000: - dfmt = gnm::kDataFormat8_8_8_8; - nfmt = gnm::kNumericFormatSrgb; - break; - - case 0x80002200: - dfmt = gnm::kDataFormat8_8_8_8; - nfmt = gnm::kNumericFormatSrgb; - flipType = FlipType::Std; - break; - - case 0x88740000: - case 0x88060000: - dfmt = gnm::kDataFormat2_10_10_10; - nfmt = gnm::kNumericFormatSNorm; - break; - - case 0xc1060000: - dfmt = gnm::kDataFormat16_16_16_16; - nfmt = gnm::kNumericFormatFloat; - break; - - default: - rx::die("unimplemented color buffer format %x", bufferAttr.pixelFormat); - } - - // std::printf("displaying buffer %lx\n", buffer.address); - - auto cacheTag = getCacheTag(process.vmId, scheduler); - auto &sched = cacheTag.getScheduler(); - - transitionImageLayout(sched.getCommandBuffer(), swapchainImage, - VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - { - .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, - .levelCount = 1, - .layerCount = 1, - }); - - amdgpu::flip( - cacheTag, vk::context->swapchainExtent, buffer.address, - swapchainImageView, {bufferAttr.width, bufferAttr.height}, flipType, - getDefaultTileModes()[bufferAttr.tilingMode == 1 ? 10 : 8], dfmt, nfmt); - - transitionImageLayout(sched.getCommandBuffer(), swapchainImage, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, - { - .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, - .levelCount = 1, - .layerCount = 1, - }); - - sched.submit(); - - auto submitCompleteTask = scheduler.createExternalSubmit(); - - { - VkSemaphoreSubmitInfo waitSemSubmitInfos[] = { - { - .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, - .semaphore = vk::context->presentCompleteSemaphore, - .value = 1, - .stageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, - }, - { - .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, - .semaphore = scheduler.getSemaphoreHandle(), - .value = submitCompleteTask - 1, - .stageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, - }, - }; - - VkSemaphoreSubmitInfo signalSemSubmitInfos[] = { - { - .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, - .semaphore = vk::context->renderCompleteSemaphore, - .value = 1, - .stageMask = VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT, - }, - { - .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, - .semaphore = scheduler.getSemaphoreHandle(), - .value = submitCompleteTask, - .stageMask = VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT, - }, - }; - - VkSubmitInfo2 submitInfo{ - .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO_2, - .waitSemaphoreInfoCount = 2, - .pWaitSemaphoreInfos = waitSemSubmitInfos, - .signalSemaphoreInfoCount = 2, - .pSignalSemaphoreInfos = signalSemSubmitInfos, - }; - - vkQueueSubmit2(vk::context->presentQueue, 1, &submitInfo, VK_NULL_HANDLE); - } - - scheduler.then([=, this, cacheTag = std::move(cacheTag)] { - bridge->flipBuffer[process.vmId] = bufferIndex; - bridge->flipArg[process.vmId] = arg; - bridge->flipCount[process.vmId] = bridge->flipCount[process.vmId] + 1; - - auto mem = RemoteMemory{process.vmId}; - auto bufferInUse = - mem.getPointer(bridge->bufferInUseAddress[process.vmId]); - if (bufferInUse != nullptr) { - bufferInUse[bufferIndex] = 0; - } - }); - - return true; -} - -void Device::mapMemory(std::int64_t pid, std::uint64_t address, - std::uint64_t size, int memoryType, int dmemIndex, - int prot, std::int64_t offset) { - auto &process = processInfo[pid]; - - process.vmTable.map(address, address + size, - VmMapSlot{ - .memoryType = memoryType >= 0 ? dmemIndex : -1, - .prot = prot, - .offset = offset, - .baseAddress = address, - }); - - if (process.vmId < 0) { - return; - } - - auto memory = amdgpu::RemoteMemory{process.vmId}; - - int mapFd = process.vmFd; - - if (memoryType >= 0) { - mapFd = dmemFd[dmemIndex]; - } - - auto mmapResult = ::mmap(memory.getPointer(address), size, prot >> 4, - MAP_FIXED | MAP_SHARED, mapFd, offset); - - if (mmapResult == MAP_FAILED) { - rx::die("failed to map process %x memory, address %lx-%lx, type %x", - (int)pid, address, address + size, memoryType); - } - - handleProtectChange(process.vmId, address, size, prot); -} - -void Device::registerBuffer(std::int64_t pid, bridge::CmdBuffer buffer) { - auto &process = processInfo[pid]; - - if (buffer.attrId >= 10 || buffer.index >= 10) { - rx::die("out of buffers %u, %u", buffer.attrId, buffer.index); - } - - process.buffers[buffer.index] = buffer; -} - -void Device::registerBufferAttribute(std::int64_t pid, - bridge::CmdBufferAttribute attr) { - auto &process = processInfo[pid]; - if (attr.attrId >= 10) { - rx::die("out of buffer attributes %u", attr.attrId); - } - - process.bufferAttributes[attr.attrId] = attr; -} - -void Device::handleProtectChange(int vmId, std::uint64_t address, - std::uint64_t size, int prot) {} diff --git a/rpcsx-gpu/Device.hpp b/rpcsx-gpu/Device.hpp deleted file mode 100644 index bb14a06..0000000 --- a/rpcsx-gpu/Device.hpp +++ /dev/null @@ -1,98 +0,0 @@ -#pragma once -#include "Cache.hpp" -#include "FlipPipeline.hpp" -#include "Pipe.hpp" -#include "amdgpu/bridge/bridge.hpp" -#include "amdgpu/tiler_vulkan.hpp" -#include "rx/MemoryTable.hpp" -#include "shader/SemanticInfo.hpp" -#include "shader/SpvConverter.hpp" -#include "shader/gcn.hpp" -#include -#include - -namespace amdgpu { - -struct VmMapSlot { - int memoryType; - int prot; - std::int64_t offset; - std::uint64_t baseAddress; - - auto operator<=>(const VmMapSlot &) const = default; -}; - -struct ProcessInfo { - int vmId = -1; - int vmFd = -1; - amdgpu::bridge::CmdBufferAttribute bufferAttributes[10]; - amdgpu::bridge::CmdBuffer buffers[10]; - rx::MemoryTableWithPayload vmTable; -}; - -struct RemoteMemory { - int vmId; - - template T *getPointer(std::uint64_t address) const { - return address ? reinterpret_cast( - static_cast(vmId) << 40 | address) - : nullptr; - } -}; - -struct Device { - static constexpr auto kComputePipeCount = 8; - static constexpr auto kGfxPipeCount = 2; - - shader::SemanticInfo gcnSemantic; - shader::spv::Context shaderSemanticContext; - shader::gcn::SemanticModuleInfo gcnSemanticModuleInfo; - amdgpu::bridge::BridgeHeader *bridge; - - Registers::Config config; - - GpuTiler tiler; - GraphicsPipe graphicsPipes[kGfxPipeCount]{0, 1}; - // ComputePipe computePipes[kComputePipeCount]{0, 1, 2, 3, 4, 5, 6, 7}; - FlipPipeline flipPipeline; - - int dmemFd[3] = {-1, -1, -1}; - std::unordered_map processInfo; - - Cache caches[6]{ - {this, 0}, {this, 1}, {this, 2}, {this, 3}, {this, 4}, {this, 5}, - }; - - Device(); - ~Device(); - - Cache::Tag getCacheTag(int vmId, Scheduler &scheduler) { - return caches[vmId].createTag(scheduler); - } - - Cache::GraphicsTag getGraphicsTag(int vmId, Scheduler &scheduler) { - return caches[vmId].createGraphicsTag(scheduler); - } - - Cache::ComputeTag getComputeTag(int vmId, Scheduler &scheduler) { - return caches[vmId].createComputeTag(scheduler); - } - - void mapProcess(std::int64_t pid, int vmId, const char *shmName); - void unmapProcess(std::int64_t pid); - void protectMemory(int pid, std::uint64_t address, std::uint64_t size, - int prot); - void onCommandBuffer(std::int64_t pid, int cmdHeader, std::uint64_t address, - std::uint64_t size); - bool processPipes(); - bool flip(std::int64_t pid, int bufferIndex, std::uint64_t arg, - VkImage swapchainImage, VkImageView swapchainImageView); - void mapMemory(std::int64_t pid, std::uint64_t address, std::uint64_t size, - int memoryType, int dmemIndex, int prot, std::int64_t offset); - void registerBuffer(std::int64_t pid, bridge::CmdBuffer buffer); - void registerBufferAttribute(std::int64_t pid, - bridge::CmdBufferAttribute attr); - void handleProtectChange(int vmId, std::uint64_t address, std::uint64_t size, - int prot); -}; -} // namespace amdgpu diff --git a/rpcsx-gpu/main.cpp b/rpcsx-gpu/main.cpp deleted file mode 100644 index bd8afe9..0000000 --- a/rpcsx-gpu/main.cpp +++ /dev/null @@ -1,646 +0,0 @@ -#include "vk.hpp" - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -#include "Device.hpp" - -void transitionImageLayout(VkCommandBuffer commandBuffer, VkImage image, - VkImageLayout oldLayout, VkImageLayout newLayout, - const VkImageSubresourceRange &subresourceRange) { - VkImageMemoryBarrier barrier{}; - barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - barrier.oldLayout = oldLayout; - barrier.newLayout = newLayout; - barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier.image = image; - barrier.subresourceRange = subresourceRange; - - auto layoutToStageAccess = [](VkImageLayout layout) - -> std::pair { - switch (layout) { - case VK_IMAGE_LAYOUT_UNDEFINED: - case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR: - case VK_IMAGE_LAYOUT_GENERAL: - return {VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0}; - - case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: - return {VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT}; - - case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: - return {VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_READ_BIT}; - - case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: - return {VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_ACCESS_SHADER_READ_BIT}; - - case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: - return {VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT, - VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | - VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT}; - - case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: - return {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | - VK_ACCESS_COLOR_ATTACHMENT_READ_BIT}; - - default: - std::abort(); - } - }; - - auto [sourceStage, sourceAccess] = layoutToStageAccess(oldLayout); - auto [destinationStage, destinationAccess] = layoutToStageAccess(newLayout); - - barrier.srcAccessMask = sourceAccess; - barrier.dstAccessMask = destinationAccess; - - vkCmdPipelineBarrier(commandBuffer, sourceStage, destinationStage, 0, 0, - nullptr, 0, nullptr, 1, &barrier); -} - -void transitionImageLayout(VkCommandBuffer commandBuffer, VkImage image, - VkImageAspectFlags aspectFlags, - VkImageLayout oldLayout, VkImageLayout newLayout) { - transitionImageLayout(commandBuffer, image, oldLayout, newLayout, - VkImageSubresourceRange{ - .aspectMask = aspectFlags, - .levelCount = 1, - .layerCount = 1, - }); -} - -static void usage(std::FILE *out, const char *argv0) { - std::println(out, "usage: {} [options...]", argv0); - std::println(out, " options:"); - std::println(out, " --version, -v - print version"); - std::println(out, - " --cmd-bridge - setup command queue bridge name"); - std::println(out, " --shm - setup shared memory name"); - std::println( - out, - " --gpu - specify physical gpu index to use, default is 0"); - std::println(out, - " --presenter - set flip engine target"); - std::println(out, " --validate - enable validation layers"); - std::println(out, " -h, --help - show this message"); - std::println(out, ""); - std::println(out, " presenter mode:"); - std::println(out, " window - create and use native window (default)"); -} - -static VKAPI_ATTR VkBool32 VKAPI_CALL debugUtilsMessageCallback( - VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, - VkDebugUtilsMessageTypeFlagsEXT messageType, - const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData, - void *pUserData) { - if (pCallbackData->pMessage) { - std::println("{}", pCallbackData->pMessage); - } - return VK_FALSE; -} - -int main(int argc, const char *argv[]) { - const char *cmdBridgeName = "/rpcsx-gpu-cmds"; - const char *shmName = "/rpcsx-os-memory"; - - unsigned long gpuIndex = 0; - // auto presenter = PresenterMode::Window; - bool enableValidation = false; - - for (int i = 1; i < argc; ++i) { - if (argv[i] == std::string_view("--cmd-bridge")) { - if (argc <= i + 1) { - usage(stderr, argv[0]); - return 1; - } - - cmdBridgeName = argv[++i]; - continue; - } - - if (argv[i] == std::string_view("--shm")) { - if (argc <= i + 1) { - usage(stderr, argv[0]); - return 1; - } - shmName = argv[++i]; - continue; - } - - if (argv[i] == std::string_view("--presenter")) { - if (argc <= i + 1) { - usage(stderr, argv[0]); - return 1; - } - - auto presenterText = std::string_view(argv[++i]); - - if (presenterText == "window") { - // presenter = PresenterMode::Window; - } else { - usage(stderr, argv[0]); - return 1; - } - continue; - } - - if (argv[i] == std::string_view("--gpu")) { - if (argc <= i + 1) { - usage(stderr, argv[0]); - return 1; - } - - char *endPtr = nullptr; - gpuIndex = std::strtoul(argv[++i], &endPtr, 10); - if (endPtr == nullptr || *endPtr != '\0') { - usage(stderr, argv[0]); - return 1; - } - - continue; - } - - if (argv[i] == std::string_view("--validate")) { - enableValidation = true; - continue; - } - - usage(stderr, argv[0]); - return 1; - } - - if (!rx::mem::reserve((void *)0x40000, 0x60000000000 - 0x40000)) { - std::fprintf(stderr, "failed to reserve virtual memory\n"); - return 1; - } - - auto bridge = amdgpu::bridge::openShmCommandBuffer(cmdBridgeName); - if (bridge == nullptr) { - bridge = amdgpu::bridge::createShmCommandBuffer(cmdBridgeName); - } - - if (bridge->pullerPid > 0 && ::kill(bridge->pullerPid, 0) == 0) { - // another instance of rpcsx-gpu on the same bridge, kill self after that - - std::fprintf(stderr, "Another instance already exists\n"); - return 1; - } - - bridge->pullerPid = ::getpid(); - - int dmemFd[3]; - - for (std::size_t i = 0; i < std::size(dmemFd); ++i) { - auto path = "/dev/shm/rpcsx-dmem-" + std::to_string(i); - if (!std::filesystem::exists(path)) { - std::printf("Waiting for dmem %zu\n", i); - while (!std::filesystem::exists(path)) { - std::this_thread::sleep_for(std::chrono::milliseconds(300)); - } - } - - dmemFd[i] = ::shm_open(("/rpcsx-dmem-" + std::to_string(i)).c_str(), O_RDWR, - S_IRUSR | S_IWUSR); - - if (dmemFd[i] < 0) { - std::printf("failed to open dmem shared memory %zu\n", i); - return 1; - } - } - - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - auto window = glfwCreateWindow(1920, 1080, "RPCSX", nullptr, nullptr); - - rx::atScopeExit _{[window] { glfwDestroyWindow(window); }}; - - const char **glfwExtensions; - uint32_t glfwExtensionCount = 0; - glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount); - - std::vector requiredExtensions( - glfwExtensions, glfwExtensions + glfwExtensionCount); - - std::vector optionalLayers; - - if (enableValidation) { - optionalLayers.push_back("VK_LAYER_KHRONOS_validation"); - requiredExtensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); - } - - auto vkContext = - vk::Context::create({}, optionalLayers, requiredExtensions, {}); - vk::context = &vkContext; - - VkDebugUtilsMessengerEXT debugMessenger = VK_NULL_HANDLE; - - if (enableValidation) { - VkDebugUtilsMessengerCreateInfoEXT debugUtilsMessengerCreateInfo{ - .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, - .messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT, - .messageType = - VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_TYPE_DEVICE_ADDRESS_BINDING_BIT_EXT | - VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT, - .pfnUserCallback = debugUtilsMessageCallback, - }; - - VK_VERIFY(vk::CreateDebugUtilsMessengerEXT( - vkContext.instance, &debugUtilsMessengerCreateInfo, - vk::context->allocator, &debugMessenger)); - } - - rx::atScopeExit _debugMessenger{[=] { - if (debugMessenger != VK_NULL_HANDLE) { - vk::DestroyDebugUtilsMessengerEXT(vk::context->instance, debugMessenger, - vk::context->allocator); - } - }}; - - VkSurfaceKHR vkSurface; - glfwCreateWindowSurface(vkContext.instance, window, nullptr, &vkSurface); - - vkContext.createDevice(vkSurface, gpuIndex, - { - // VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME, - // VK_EXT_DEPTH_CLIP_ENABLE_EXTENSION_NAME, - // VK_EXT_INLINE_UNIFORM_BLOCK_EXTENSION_NAME, - // VK_EXT_DESCRIPTOR_BUFFER_EXTENSION_NAME, - // VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME, - // VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME, - VK_EXT_SEPARATE_STENCIL_USAGE_EXTENSION_NAME, - VK_KHR_SWAPCHAIN_EXTENSION_NAME, - VK_EXT_SHADER_OBJECT_EXTENSION_NAME, - VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME, - VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME, - }, - { - VK_KHR_FRAGMENT_SHADER_BARYCENTRIC_EXTENSION_NAME, - VK_KHR_SHADER_NON_SEMANTIC_INFO_EXTENSION_NAME, - }); - - auto getTotalMemorySize = [&](int memoryType) -> VkDeviceSize { - auto deviceLocalMemoryType = - vkContext.findPhysicalMemoryTypeIndex(~0, memoryType); - - if (deviceLocalMemoryType < 0) { - return 0; - } - - auto heapIndex = - vkContext.physicalMemoryProperties.memoryTypes[deviceLocalMemoryType] - .heapIndex; - - return vkContext.physicalMemoryProperties.memoryHeaps[heapIndex].size; - }; - - auto localMemoryTotalSize = - getTotalMemorySize(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - auto hostVisibleMemoryTotalSize = - getTotalMemorySize(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | - VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); - - vk::getHostVisibleMemory().initHostVisible( - std::min(hostVisibleMemoryTotalSize / 2, 1ul * 1024 * 1024 * 1024)); - vk::getDeviceLocalMemory().initDeviceLocal( - std::min(localMemoryTotalSize / 4, 4ul * 1024 * 1024 * 1024)); - - auto commandPool = - vk::CommandPool::Create(vkContext.presentQueueFamily, - VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT); - - vkContext.createSwapchain(); - - amdgpu::bridge::BridgePuller bridgePuller{bridge}; - amdgpu::bridge::Command commandsBuffer[1]; - - amdgpu::Device device; - device.bridge = bridge; - - for (int i = 0; i < std::size(device.dmemFd); ++i) { - device.dmemFd[i] = dmemFd[i]; - } - - uint32_t imageIndex = 0; - bool isImageAcquired = false; - uint32_t gpIndex = -1; - GLFWgamepadstate gpState; - - rx::atScopeExit __{[] { - vk::getHostVisibleMemory().free(); - vk::getDeviceLocalMemory().free(); - }}; - - while (!glfwWindowShouldClose(window)) { - glfwPollEvents(); - - while (true) { - bool allProcessed = false; - - for (int i = 0; i < 1000; ++i) { - if (device.processPipes()) { - allProcessed = true; - break; - } - } - - if (allProcessed) { - break; - } - - glfwPollEvents(); - - if (glfwWindowShouldClose(window)) { - break; - } - } - - std::size_t pulledCount = - bridgePuller.pullCommands(commandsBuffer, std::size(commandsBuffer)); - - if (gpIndex > GLFW_JOYSTICK_LAST) { - for (int i = 0; i <= GLFW_JOYSTICK_LAST; ++i) { - if (glfwJoystickIsGamepad(i) == GLFW_TRUE) { - std::print("Gamepad \"{}\" activated", glfwGetGamepadName(i)); - gpIndex = i; - break; - } - } - } else if (gpIndex <= GLFW_JOYSTICK_LAST) { - if (!glfwJoystickIsGamepad(gpIndex)) { - gpIndex = -1; - } - } - - if (gpIndex <= GLFW_JOYSTICK_LAST) { - if (glfwGetGamepadState(gpIndex, &gpState) == GLFW_TRUE) { - bridge->kbPadState.leftStickX = - gpState.axes[GLFW_GAMEPAD_AXIS_LEFT_X] * 127.5f + 127.5f; - bridge->kbPadState.leftStickY = - gpState.axes[GLFW_GAMEPAD_AXIS_LEFT_Y] * 127.5f + 127.5f; - bridge->kbPadState.rightStickX = - gpState.axes[GLFW_GAMEPAD_AXIS_RIGHT_X] * 127.5f + 127.5f; - bridge->kbPadState.rightStickY = - gpState.axes[GLFW_GAMEPAD_AXIS_RIGHT_Y] * 127.5f + 127.5f; - bridge->kbPadState.l2 = - (gpState.axes[GLFW_GAMEPAD_AXIS_LEFT_TRIGGER] + 1.0f) * 127.5f; - bridge->kbPadState.r2 = - (gpState.axes[GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER] + 1.0f) * 127.5f; - bridge->kbPadState.buttons = 0; - - if (bridge->kbPadState.l2 == 0xFF) { - bridge->kbPadState.buttons |= amdgpu::bridge::kPadBtnL2; - } - - if (bridge->kbPadState.r2 == 0xFF) { - bridge->kbPadState.buttons |= amdgpu::bridge::kPadBtnR2; - } - - static const uint32_t gpmap[GLFW_GAMEPAD_BUTTON_LAST + 1] = { - [GLFW_GAMEPAD_BUTTON_A] = amdgpu::bridge::kPadBtnCross, - [GLFW_GAMEPAD_BUTTON_B] = amdgpu::bridge::kPadBtnCircle, - [GLFW_GAMEPAD_BUTTON_X] = amdgpu::bridge::kPadBtnSquare, - [GLFW_GAMEPAD_BUTTON_Y] = amdgpu::bridge::kPadBtnTriangle, - [GLFW_GAMEPAD_BUTTON_LEFT_BUMPER] = amdgpu::bridge::kPadBtnL1, - [GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER] = amdgpu::bridge::kPadBtnR1, - [GLFW_GAMEPAD_BUTTON_BACK] = 0, - [GLFW_GAMEPAD_BUTTON_START] = amdgpu::bridge::kPadBtnOptions, - [GLFW_GAMEPAD_BUTTON_GUIDE] = 0, - [GLFW_GAMEPAD_BUTTON_LEFT_THUMB] = amdgpu::bridge::kPadBtnL3, - [GLFW_GAMEPAD_BUTTON_RIGHT_THUMB] = amdgpu::bridge::kPadBtnR3, - [GLFW_GAMEPAD_BUTTON_DPAD_UP] = amdgpu::bridge::kPadBtnUp, - [GLFW_GAMEPAD_BUTTON_DPAD_RIGHT] = amdgpu::bridge::kPadBtnRight, - [GLFW_GAMEPAD_BUTTON_DPAD_DOWN] = amdgpu::bridge::kPadBtnDown, - [GLFW_GAMEPAD_BUTTON_DPAD_LEFT] = amdgpu::bridge::kPadBtnLeft}; - - for (int i = 0; i <= GLFW_GAMEPAD_BUTTON_LAST; ++i) { - if (gpState.buttons[i] == GLFW_PRESS) { - bridge->kbPadState.buttons |= gpmap[i]; - } - } - } - } else { - bridge->kbPadState.leftStickX = 0x80; - bridge->kbPadState.leftStickY = 0x80; - bridge->kbPadState.rightStickX = 0x80; - bridge->kbPadState.rightStickY = 0x80; - bridge->kbPadState.buttons = 0; - - if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) { - bridge->kbPadState.leftStickX = 0; - } else if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) { - bridge->kbPadState.leftStickX = 0xff; - } - if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) { - bridge->kbPadState.leftStickY = 0; - } else if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) { - bridge->kbPadState.leftStickY = 0xff; - } - - if (glfwGetKey(window, GLFW_KEY_O) == GLFW_PRESS) { - bridge->kbPadState.rightStickX = 0; - } else if (glfwGetKey(window, GLFW_KEY_L) == GLFW_PRESS) { - bridge->kbPadState.rightStickX = 0xff; - } - if (glfwGetKey(window, GLFW_KEY_K) == GLFW_PRESS) { - bridge->kbPadState.rightStickY = 0; - } else if (glfwGetKey(window, GLFW_KEY_SEMICOLON) == GLFW_PRESS) { - bridge->kbPadState.rightStickY = 0xff; - } - - if (glfwGetKey(window, GLFW_KEY_UP) == GLFW_PRESS) { - bridge->kbPadState.buttons |= amdgpu::bridge::kPadBtnUp; - } - if (glfwGetKey(window, GLFW_KEY_DOWN) == GLFW_PRESS) { - bridge->kbPadState.buttons |= amdgpu::bridge::kPadBtnDown; - } - if (glfwGetKey(window, GLFW_KEY_LEFT) == GLFW_PRESS) { - bridge->kbPadState.buttons |= amdgpu::bridge::kPadBtnLeft; - } - if (glfwGetKey(window, GLFW_KEY_RIGHT) == GLFW_PRESS) { - bridge->kbPadState.buttons |= amdgpu::bridge::kPadBtnRight; - } - if (glfwGetKey(window, GLFW_KEY_Z) == GLFW_PRESS) { - bridge->kbPadState.buttons |= amdgpu::bridge::kPadBtnSquare; - } - if (glfwGetKey(window, GLFW_KEY_X) == GLFW_PRESS) { - bridge->kbPadState.buttons |= amdgpu::bridge::kPadBtnCross; - } - if (glfwGetKey(window, GLFW_KEY_C) == GLFW_PRESS) { - bridge->kbPadState.buttons |= amdgpu::bridge::kPadBtnCircle; - } - if (glfwGetKey(window, GLFW_KEY_V) == GLFW_PRESS) { - bridge->kbPadState.buttons |= amdgpu::bridge::kPadBtnTriangle; - } - - if (glfwGetKey(window, GLFW_KEY_Q) == GLFW_PRESS) { - bridge->kbPadState.buttons |= amdgpu::bridge::kPadBtnL1; - } - if (glfwGetKey(window, GLFW_KEY_E) == GLFW_PRESS) { - bridge->kbPadState.buttons |= amdgpu::bridge::kPadBtnL2; - bridge->kbPadState.l2 = 0xff; - } - if (glfwGetKey(window, GLFW_KEY_F) == GLFW_PRESS) { - bridge->kbPadState.buttons |= amdgpu::bridge::kPadBtnL3; - } - if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) { - bridge->kbPadState.buttons |= amdgpu::bridge::kPadBtnPs; - } - if (glfwGetKey(window, GLFW_KEY_I) == GLFW_PRESS) { - bridge->kbPadState.buttons |= amdgpu::bridge::kPadBtnR1; - } - if (glfwGetKey(window, GLFW_KEY_P) == GLFW_PRESS) { - bridge->kbPadState.buttons |= amdgpu::bridge::kPadBtnR2; - bridge->kbPadState.r2 = 0xff; - } - if (glfwGetKey(window, GLFW_KEY_APOSTROPHE) == GLFW_PRESS) { - bridge->kbPadState.buttons |= amdgpu::bridge::kPadBtnR3; - } - - if (glfwGetKey(window, GLFW_KEY_ENTER) == GLFW_PRESS) { - bridge->kbPadState.buttons |= amdgpu::bridge::kPadBtnOptions; - } - } - - bridge->kbPadState.timestamp = - std::chrono::high_resolution_clock::now().time_since_epoch().count(); - - if (pulledCount == 0) { - std::this_thread::sleep_for(std::chrono::microseconds(1)); - continue; - } - - for (auto cmd : std::span(commandsBuffer, pulledCount)) { - switch (cmd.id) { - case amdgpu::bridge::CommandId::ProtectMemory: { - device.protectMemory(cmd.memoryProt.pid, cmd.memoryProt.address, - cmd.memoryProt.size, cmd.memoryProt.prot); - break; - } - case amdgpu::bridge::CommandId::CommandBuffer: { - device.onCommandBuffer(cmd.commandBuffer.pid, cmd.commandBuffer.queue, - cmd.commandBuffer.address, - cmd.commandBuffer.size); - - break; - } - - case amdgpu::bridge::CommandId::Flip: { - if (!isImageAcquired) { - while (true) { - auto acquireNextImageResult = vkAcquireNextImageKHR( - vkContext.device, vkContext.swapchain, UINT64_MAX, - vkContext.presentCompleteSemaphore, VK_NULL_HANDLE, - &imageIndex); - if (acquireNextImageResult == VK_ERROR_OUT_OF_DATE_KHR) { - vkContext.recreateSwapchain(); - continue; - } - - if (acquireNextImageResult != VK_SUBOPTIMAL_KHR) { - VK_VERIFY(acquireNextImageResult); - } - break; - } - } - - if (!device.flip(cmd.flip.pid, cmd.flip.bufferIndex, cmd.flip.arg, - vkContext.swapchainImages[imageIndex], - vkContext.swapchainImageViews[imageIndex])) { - isImageAcquired = true; - break; - } - - VkPresentInfoKHR presentInfo{ - .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, - .waitSemaphoreCount = 1, - .pWaitSemaphores = &vkContext.renderCompleteSemaphore, - .swapchainCount = 1, - .pSwapchains = &vkContext.swapchain, - .pImageIndices = &imageIndex, - }; - - auto vkQueuePresentResult = - vkQueuePresentKHR(vkContext.presentQueue, &presentInfo); - - isImageAcquired = false; - - if (vkQueuePresentResult == VK_ERROR_OUT_OF_DATE_KHR || - vkQueuePresentResult == VK_SUBOPTIMAL_KHR) { - vkContext.recreateSwapchain(); - } else { - VK_VERIFY(vkQueuePresentResult); - } - break; - } - - case amdgpu::bridge::CommandId::MapProcess: - device.mapProcess(cmd.mapProcess.pid, cmd.mapProcess.vmId, shmName); - break; - - case amdgpu::bridge::CommandId::UnmapProcess: - device.unmapProcess(cmd.mapProcess.pid); - break; - - case amdgpu::bridge::CommandId::MapMemory: - device.mapMemory(cmd.mapMemory.pid, cmd.mapMemory.address, - cmd.mapMemory.size, cmd.mapMemory.memoryType, - cmd.mapMemory.dmemIndex, cmd.mapMemory.prot, - cmd.mapMemory.offset); - break; - - case amdgpu::bridge::CommandId::RegisterBuffer: - device.registerBuffer(cmd.buffer.pid, cmd.buffer); - break; - - case amdgpu::bridge::CommandId::RegisterBufferAttribute: - device.registerBufferAttribute(cmd.bufferAttribute.pid, - cmd.bufferAttribute); - break; - - default: - rx::die("Unexpected command id %u\n", (unsigned)cmd.id); - } - } - } - - vkDeviceWaitIdle(vk::context->device); -} diff --git a/rpcsx-os/bridge.cpp b/rpcsx-os/bridge.cpp deleted file mode 100644 index f7e4894..0000000 --- a/rpcsx-os/bridge.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include "bridge.hpp" - -amdgpu::bridge::BridgePusher rx::bridge; diff --git a/rpcsx-os/bridge.hpp b/rpcsx-os/bridge.hpp deleted file mode 100644 index 21c9f90..0000000 --- a/rpcsx-os/bridge.hpp +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -#include - -namespace rx { -extern amdgpu::bridge::BridgePusher bridge; -} diff --git a/rpcsx-os/main.cpp b/rpcsx-os/main.cpp deleted file mode 100644 index 7e528eb..0000000 --- a/rpcsx-os/main.cpp +++ /dev/null @@ -1,2277 +0,0 @@ -#include "AudioOut.hpp" -#include "amdgpu/bridge/bridge.hpp" -#include "audio/AlsaDevice.hpp" -#include "backtrace.hpp" -#include "bridge.hpp" -#include "io-device.hpp" -#include "io-devices.hpp" -#include "iodev/mbus.hpp" -#include "iodev/mbus_av.hpp" -#include "linker.hpp" -#include "ops.hpp" -#include "orbis/utils/Logs.hpp" -#include "thread.hpp" -#include "vfs.hpp" -#include "vm.hpp" -#include "xbyak/xbyak.h" -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -static int g_gpuPid; -extern bool allowMonoDebug; - -template std::vector toBytes(const T &value) { - std::vector result(sizeof(T)); - std::memcpy(result.data(), &value, sizeof(value)); - return result; -} - -__attribute__((no_stack_protector)) static void -handle_signal(int sig, siginfo_t *info, void *ucontext) { - if (auto hostFs = _readgsbase_u64()) { - _writefsbase_u64(hostFs); - } - - auto signalAddress = reinterpret_cast(info->si_addr); - - if (orbis::g_currentThread != nullptr && - orbis::g_currentThread->tproc->vmId >= 0 && sig == SIGSEGV && - signalAddress >= 0x40000 && signalAddress < 0x100'0000'0000) { - auto vmid = orbis::g_currentThread->tproc->vmId; - auto ctx = reinterpret_cast(ucontext); - bool isWrite = (ctx->uc_mcontext.gregs[REG_ERR] & 0x2) != 0; - auto origVmProt = rx::vm::getPageProtection(signalAddress); - int prot = 0; - auto page = signalAddress / amdgpu::bridge::kHostPageSize; - - if (origVmProt & rx::vm::kMapProtCpuRead) { - prot |= PROT_READ; - } - if (origVmProt & rx::vm::kMapProtCpuWrite) { - prot |= PROT_WRITE; - } - if (origVmProt & rx::vm::kMapProtCpuExec) { - prot |= PROT_EXEC; - } - - if (prot & (isWrite ? PROT_WRITE : PROT_READ)) { - auto bridge = rx::bridge.header; - - while (true) { - auto flags = - bridge->cachePages[vmid][page].load(std::memory_order::relaxed); - - if ((flags & amdgpu::bridge::kPageReadWriteLock) != 0) { - if ((flags & amdgpu::bridge::kPageLazyLock) != 0) { - if (std::uint32_t gpuCommand = 0; - !bridge->gpuCacheCommand[vmid].compare_exchange_weak(gpuCommand, - page)) { - continue; - } - - while (!bridge->cachePages[vmid][page].compare_exchange_weak( - flags, flags & ~amdgpu::bridge::kPageLazyLock, - std::memory_order::relaxed)) { - } - } - continue; - } - - if ((flags & amdgpu::bridge::kPageWriteWatch) == 0) { - break; - } - - if (!isWrite) { - prot &= ~PROT_WRITE; - break; - } - - if (bridge->cachePages[vmid][page].compare_exchange_weak( - flags, amdgpu::bridge::kPageInvalidated, - std::memory_order::relaxed)) { - break; - } - } - - if (::mprotect((void *)(page * amdgpu::bridge::kHostPageSize), - amdgpu::bridge::kHostPageSize, prot)) { - std::perror("cache reprotection error"); - std::abort(); - } - - _writefsbase_u64(orbis::g_currentThread->fsBase); - return; - } - - std::fprintf(stderr, "SIGSEGV, address %lx, access %s, prot %s\n", - signalAddress, isWrite ? "write" : "read", - rx::vm::mapProtToString(origVmProt).c_str()); - } - - if (orbis::g_currentThread != nullptr) { - orbis::g_currentThread->tproc->exitStatus = sig; - orbis::g_currentThread->tproc->event.emit(orbis::kEvFiltProc, - orbis::kNoteExit, sig); - } - - if (g_gpuPid > 0) { - // stop gpu thread - // ::kill(g_gpuPid, SIGINT); - } - - allowMonoDebug = true; - if (sig != SIGINT) { - char buf[128] = ""; - int len = snprintf(buf, sizeof(buf), " [%s] %u: Signal address=%p\n", - orbis::g_currentThread ? "guest" : "host", - orbis::g_currentThread ? orbis::g_currentThread->tid - : ::gettid(), - info->si_addr); - write(2, buf, len); - - if (std::size_t printed = - rx::printAddressLocation(buf, sizeof(buf), orbis::g_currentThread, - (std::uint64_t)info->si_addr)) { - printed += std::snprintf(buf + printed, sizeof(buf) - printed, "\n"); - write(2, buf, printed); - } - - if (orbis::g_currentThread) { - rx::printStackTrace(reinterpret_cast(ucontext), - orbis::g_currentThread, 2); - } else { - rx::printStackTrace(reinterpret_cast(ucontext), 2); - } - } - - struct sigaction act{}; - sigset_t mask; - sigemptyset(&mask); - - act.sa_handler = SIG_DFL; - act.sa_flags = SA_SIGINFO | SA_ONSTACK; - act.sa_mask = mask; - - if (sigaction(sig, &act, NULL)) { - perror("Error sigaction:"); - std::exit(-1); - } - - if (sig == SIGINT) { - std::raise(SIGINT); - } -} - -void setupSigHandlers() { - rx::thread::setupSignalStack(); - - struct sigaction act{}; - act.sa_sigaction = handle_signal; - act.sa_flags = SA_SIGINFO | SA_ONSTACK | SA_NODEFER; - - if (sigaction(SIGSYS, &act, NULL)) { - perror("Error sigaction:"); - exit(-1); - } - - if (sigaction(SIGILL, &act, NULL)) { - perror("Error sigaction:"); - exit(-1); - } - - if (sigaction(SIGSEGV, &act, NULL)) { - perror("Error sigaction:"); - exit(-1); - } - - if (sigaction(SIGBUS, &act, NULL)) { - perror("Error sigaction:"); - exit(-1); - } - - if (sigaction(SIGABRT, &act, NULL)) { - perror("Error sigaction:"); - exit(-1); - } - - if (sigaction(SIGINT, &act, NULL)) { - perror("Error sigaction:"); - exit(-1); - } - - if (sigaction(SIGFPE, &act, NULL)) { - perror("Error sigaction:"); - exit(-1); - } -} - -struct StackWriter { - std::uint64_t address; - - template std::uint64_t push(T value) { - address -= sizeof(value); - address &= ~(alignof(T) - 1); - *reinterpret_cast(address) = value; - return address; - } - - void align(std::uint64_t alignment) { address &= ~(alignment - 1); } - - std::uint64_t pushString(const char *value) { - auto len = std::strlen(value); - address -= len + 1; - std::memcpy(reinterpret_cast(address), value, len + 1); - return address; - } - - std::uint64_t alloc(std::uint64_t size, std::uint64_t alignment) { - address -= size; - address &= ~(alignment - 1); - return address; - } -}; - -static bool g_traceSyscalls = false; -static const char *getSyscallName(orbis::Thread *thread, int sysno) { - auto sysvec = thread->tproc->sysent; - - if (sysno >= sysvec->size) { - return nullptr; - } - - return orbis::getSysentName(sysvec->table[sysno].call); -} -static void onSysEnter(orbis::Thread *thread, int id, uint64_t *args, - int argsCount) { - if (!g_traceSyscalls) { - return; - } - flockfile(stderr); - std::fprintf(stderr, " [%u] ", thread->tid); - - if (auto name = getSyscallName(thread, id)) { - std::fprintf(stderr, "%s(", name); - } else { - std::fprintf(stderr, "sys_%u(", id); - } - - for (int i = 0; i < argsCount; ++i) { - if (i != 0) { - std::fprintf(stderr, ", "); - } - - std::fprintf(stderr, "%#lx", args[i]); - } - - std::fprintf(stderr, ")\n"); - funlockfile(stderr); -} - -static void onSysExit(orbis::Thread *thread, int id, uint64_t *args, - int argsCount, orbis::SysResult result) { - if (!result.isError() && !g_traceSyscalls) { - return; - } - - flockfile(stderr); - std::fprintf(stderr, "%c: [%u] ", result.isError() ? 'E' : 'S', thread->tid); - - if (auto name = getSyscallName(thread, id)) { - std::fprintf(stderr, "%s(", name); - } else { - std::fprintf(stderr, "sys_%u(", id); - } - - for (int i = 0; i < argsCount; ++i) { - if (i != 0) { - std::fprintf(stderr, ", "); - } - - std::fprintf(stderr, "%#lx", args[i]); - } - - std::fprintf(stderr, ") -> Status %d, Value %lx:%lx\n", result.value(), - thread->retval[0], thread->retval[1]); - - if (result.isError()) { - thread->where(); - } - funlockfile(stderr); -} - -static void ps4InitDev() { - auto dmem1 = createDmemCharacterDevice(1); - orbis::g_context.dmemDevice = dmem1; - - auto ttyFd = ::open("tty.txt", O_CREAT | O_TRUNC | O_WRONLY, 0666); - auto consoleDev = createConsoleCharacterDevice(STDIN_FILENO, ttyFd); - auto mbus = static_cast(createMBusCharacterDevice()); - auto mbusAv = static_cast(createMBusAVCharacterDevice()); - - // FIXME: make it configurable - auto defaultAudioDevice = orbis::knew(); - auto nullAudioDevice = orbis::knew(); - - auto hdmiAudioDevice = defaultAudioDevice; - auto analogAudioDevice = nullAudioDevice; - auto spdifAudioDevice = nullAudioDevice; - - rx::vfs::addDevice("dmem0", createDmemCharacterDevice(0)); - rx::vfs::addDevice("npdrm", createNpdrmCharacterDevice()); - rx::vfs::addDevice("icc_configuration", - createIccConfigurationCharacterDevice()); - rx::vfs::addDevice("console", consoleDev); - rx::vfs::addDevice("camera", createCameraCharacterDevice()); - rx::vfs::addDevice("dmem1", dmem1); - rx::vfs::addDevice("dmem2", createDmemCharacterDevice(2)); - rx::vfs::addDevice("stdout", consoleDev); - rx::vfs::addDevice("stderr", consoleDev); - rx::vfs::addDevice("deci_stdin", consoleDev); - rx::vfs::addDevice("deci_stdout", consoleDev); - rx::vfs::addDevice("deci_stderr", consoleDev); - rx::vfs::addDevice("deci_tty1", consoleDev); - rx::vfs::addDevice("deci_tty2", consoleDev); - rx::vfs::addDevice("deci_tty3", consoleDev); - rx::vfs::addDevice("deci_tty4", consoleDev); - rx::vfs::addDevice("deci_tty5", consoleDev); - rx::vfs::addDevice("deci_tty6", consoleDev); - rx::vfs::addDevice("deci_tty7", consoleDev); - rx::vfs::addDevice("stdin", consoleDev); - rx::vfs::addDevice("zero", createZeroCharacterDevice()); - rx::vfs::addDevice("null", createNullCharacterDevice()); - rx::vfs::addDevice("dipsw", createDipswCharacterDevice()); - rx::vfs::addDevice("dce", createDceCharacterDevice()); - rx::vfs::addDevice("hmd_cmd", createHmdCmdCharacterDevice()); - rx::vfs::addDevice("hmd_snsr", createHmdSnsrCharacterDevice()); - rx::vfs::addDevice("hmd_3da", createHmd3daCharacterDevice()); - rx::vfs::addDevice("hmd_dist", createHmdMmapCharacterDevice()); - rx::vfs::addDevice("hid", createHidCharacterDevice()); - rx::vfs::addDevice("gc", createGcCharacterDevice()); - rx::vfs::addDevice("rng", createRngCharacterDevice()); - rx::vfs::addDevice("sbl_srv", createSblSrvCharacterDevice()); - rx::vfs::addDevice("ajm", createAjmCharacterDevice()); - rx::vfs::addDevice("urandom", createUrandomCharacterDevice()); - rx::vfs::addDevice("mbus", mbus); - rx::vfs::addDevice("metadbg", createMetaDbgCharacterDevice()); - rx::vfs::addDevice("bt", createBtCharacterDevice()); - rx::vfs::addDevice("xpt0", createXptCharacterDevice()); - rx::vfs::addDevice("cd0", createCdCharacterDevice()); - rx::vfs::addDevice("da0", - createHddCharacterDevice(250ull * 1024 * 1024 * 1024)); - rx::vfs::addDevice("da0x0.crypt", createHddCharacterDevice(0x20000000)); - rx::vfs::addDevice("da0x1.crypt", createHddCharacterDevice(0x40000000)); - rx::vfs::addDevice("da0x2", createHddCharacterDevice(0x1000000)); - rx::vfs::addDevice("da0x2.crypt", createHddCharacterDevice(0x1000000)); - rx::vfs::addDevice("da0x3.crypt", createHddCharacterDevice(0x8000000)); - rx::vfs::addDevice("da0x4.crypt", createHddCharacterDevice(0x40000000)); - rx::vfs::addDevice("da0x4b.crypt", createHddCharacterDevice(0x40000000)); - rx::vfs::addDevice("da0x5.crypt", createHddCharacterDevice(0x40000000)); - rx::vfs::addDevice("da0x5b.crypt", createHddCharacterDevice(0x40000000)); - // rx::vfs::addDevice("da0x6x0", createHddCharacterDevice()); // boot log - rx::vfs::addDevice("da0x6", createHddCharacterDevice(0x200000000)); - rx::vfs::addDevice("da0x6x2.crypt", createHddCharacterDevice(0x200000000)); - rx::vfs::addDevice("da0x8", createHddCharacterDevice(0x40000000)); - rx::vfs::addDevice("da0x8.crypt", createHddCharacterDevice(0x40000000)); - rx::vfs::addDevice("da0x9.crypt", createHddCharacterDevice(0x200000000)); - rx::vfs::addDevice("da0x12.crypt", createHddCharacterDevice(0x180000000)); - rx::vfs::addDevice("da0x13.crypt", createHddCharacterDevice(0)); - rx::vfs::addDevice("da0x14.crypt", createHddCharacterDevice(0x40000000)); - rx::vfs::addDevice("da0x15", createHddCharacterDevice(0)); - rx::vfs::addDevice("da0x15.crypt", createHddCharacterDevice(0x400000000)); - rx::vfs::addDevice("notification0", createNotificationCharacterDevice(0)); - rx::vfs::addDevice("notification1", createNotificationCharacterDevice(1)); - rx::vfs::addDevice("notification2", createNotificationCharacterDevice(2)); - rx::vfs::addDevice("notification3", createNotificationCharacterDevice(3)); - rx::vfs::addDevice("notification4", createNotificationCharacterDevice(4)); - rx::vfs::addDevice("notification5", createNotificationCharacterDevice(5)); - rx::vfs::addDevice("aout0", createAoutCharacterDevice(0, hdmiAudioDevice)); - rx::vfs::addDevice("aout1", createAoutCharacterDevice(1, analogAudioDevice)); - rx::vfs::addDevice("aout2", createAoutCharacterDevice(2, spdifAudioDevice)); - rx::vfs::addDevice("av_control", createAVControlCharacterDevice()); - rx::vfs::addDevice("hdmi", createHDMICharacterDevice()); - rx::vfs::addDevice("mbus_av", mbusAv); - rx::vfs::addDevice("scanin", createScaninCharacterDevice()); - rx::vfs::addDevice("s3da", createS3DACharacterDevice()); - rx::vfs::addDevice("gbase", createGbaseCharacterDevice()); - rx::vfs::addDevice("devstat", createDevStatCharacterDevice()); - rx::vfs::addDevice("devact", createDevActCharacterDevice()); - rx::vfs::addDevice("devctl", createDevCtlCharacterDevice()); - rx::vfs::addDevice("uvd", createUVDCharacterDevice()); - rx::vfs::addDevice("vce", createVCECharacterDevice()); - rx::vfs::addDevice("evlg1", createEvlgCharacterDevice(ttyFd)); - rx::vfs::addDevice("srtc", createSrtcCharacterDevice()); - rx::vfs::addDevice("sshot", createScreenShotCharacterDevice()); - rx::vfs::addDevice("lvdctl", createLvdCtlCharacterDevice()); - rx::vfs::addDevice("lvd0", createHddCharacterDevice(0x100000000)); - rx::vfs::addDevice("icc_power", createIccPowerCharacterDevice()); - rx::vfs::addDevice("cayman/reg", createCaymanRegCharacterDevice()); - rx::vfs::addDevice("hctrl", createHidCharacterDevice()); - - // mbus->emitEvent({ - // .system = 2, - // .eventId = 1, - // .deviceId = 0, - // }); - - // mbus->emitEvent({ - // .system = 9, - // .eventId = 1, - // .deviceId = 100, - // }); - - mbusAv->emitEvent({ - .system = 9, - .eventId = 1, - .deviceId = 100, - }); - - auto shm = createShmDevice(); - rx::vfs::addDevice("shm", shm); - orbis::g_context.shmDevice = shm; - orbis::g_context.blockpoolDevice = createBlockPoolDevice(); -} - -static void ps4InitFd(orbis::Thread *mainThread) { - orbis::Ref stdinFile; - orbis::Ref stdoutFile; - orbis::Ref stderrFile; - rx::procOpsTable.open(mainThread, "/dev/stdin", 0, 0, &stdinFile); - rx::procOpsTable.open(mainThread, "/dev/stdout", 0, 0, &stdoutFile); - rx::procOpsTable.open(mainThread, "/dev/stderr", 0, 0, &stderrFile); - - mainThread->tproc->fileDescriptors.insert(stdinFile); - mainThread->tproc->fileDescriptors.insert(stdoutFile); - mainThread->tproc->fileDescriptors.insert(stderrFile); -} - -static orbis::Process *createGuestProcess() { - auto pid = orbis::g_context.allocatePid() * 10000 + 1; - return orbis::g_context.createProcess(pid); -} - -static orbis::Thread *createGuestThread() { - auto process = createGuestProcess(); - auto [baseId, thread] = process->threadsMap.emplace(); - thread->tproc = process; - thread->tid = process->pid + baseId; - thread->state = orbis::ThreadState::RUNNING; - return thread; -} - -template struct GuestAlloc { - orbis::ptr guestAddress; - - GuestAlloc(std::size_t size) { - if (size == 0) { - guestAddress = nullptr; - } else { - guestAddress = orbis::ptr(rx::vm::map( - nullptr, size, rx::vm::kMapProtCpuRead | rx::vm::kMapProtCpuWrite, - rx::vm::kMapFlagPrivate | rx::vm::kMapFlagAnonymous)); - } - } - - GuestAlloc() : GuestAlloc(sizeof(T)) {} - - GuestAlloc(const T &data) : GuestAlloc() { - if (orbis::uwrite(guestAddress, data) != orbis::ErrorCode{}) { - std::abort(); - } - } - - GuestAlloc(const void *data, std::size_t size) : GuestAlloc(size) { - if (orbis::uwriteRaw(guestAddress, data, size) != orbis::ErrorCode{}) { - std::abort(); - } - } - - GuestAlloc(const GuestAlloc &) = delete; - - GuestAlloc(GuestAlloc &&other) : guestAddress(other.guestAddress) { - other.guestAddress = 0; - } - GuestAlloc &operator=(GuestAlloc &&other) { - std::swap(guestAddress, other.guestAddress); - } - - ~GuestAlloc() { - if (guestAddress != 0) { - rx::vm::unmap(guestAddress, sizeof(T)); - } - } - - operator orbis::ptr() { return guestAddress; } - T *operator->() { return guestAddress; } - operator T &() { return *guestAddress; } -}; - -struct IpmiClient { - orbis::Ref clientImpl; - orbis::uint kid; - orbis::Thread *thread; - - orbis::sint - sendSyncMessageRaw(std::uint32_t method, - const std::vector> &inData, - std::vector> &outBuf) { - GuestAlloc serverResult; - GuestAlloc guestInDataArray{ - sizeof(orbis::IpmiDataInfo) * inData.size()}; - GuestAlloc guestOutBufArray{ - sizeof(orbis::IpmiBufferInfo) * outBuf.size()}; - - std::vector> guestAllocs; - guestAllocs.reserve(inData.size() + outBuf.size()); - - for (auto &data : inData) { - auto pointer = - guestAllocs.emplace_back(data.data(), data.size()).guestAddress; - - guestInDataArray.guestAddress[&data - inData.data()] = { - .data = pointer, .size = data.size()}; - } - - for (auto &buf : outBuf) { - auto pointer = - guestAllocs.emplace_back(buf.data(), buf.size()).guestAddress; - - guestOutBufArray.guestAddress[&buf - outBuf.data()] = { - .data = pointer, .capacity = buf.size()}; - } - - GuestAlloc params = orbis::IpmiSyncCallParams{ - .method = method, - .numInData = static_cast(inData.size()), - .numOutData = static_cast(outBuf.size()), - .pInData = guestInDataArray, - .pOutData = guestOutBufArray, - .pResult = serverResult, - .flags = (inData.size() >= 1 || outBuf.size() >= 1) ? 1u : 0u, - }; - - GuestAlloc errorCode; - orbis::sysIpmiClientInvokeSyncMethod(thread, errorCode, kid, params, - sizeof(orbis::IpmiSyncCallParams)); - - for (auto &buf : outBuf) { - auto size = guestOutBufArray.guestAddress[inData.data() - &buf].size; - buf.resize(size); - } - return serverResult; - } - - template - orbis::sint sendSyncMessage(std::uint32_t method, - const InputTypes &...input) { - std::vector> outBuf; - return sendSyncMessageRaw(method, {toBytes(input)...}, outBuf); - } - - template - requires((sizeof...(OutputTypes) > 0) || sizeof...(InputTypes) == 0) - std::tuple sendSyncMessage(std::uint32_t method, - InputTypes... input) { - std::vector> outBuf{sizeof(OutputTypes)...}; - sendSyncMessageRaw(method, {toBytes(input)...}, outBuf); - std::tuple output; - - auto unpack = [&](std::index_sequence) { - ((std::get(output) = *reinterpret_cast(outBuf.data())), - ...); - }; - unpack(std::make_index_sequence{}); - return output; - } -}; - -static IpmiClient audioIpmiClient; - -static IpmiClient createIpmiClient(orbis::Thread *thread, const char *name) { - orbis::Ref client; - GuestAlloc config = orbis::IpmiCreateClientConfig{ - .size = sizeof(orbis::IpmiCreateClientConfig), - }; - - orbis::uint kid; - - { - GuestAlloc guestName{name, std::strlen(name)}; - GuestAlloc params = orbis::IpmiCreateClientParams{ - .name = guestName, - .config = config, - }; - - GuestAlloc result; - GuestAlloc guestKid; - orbis::sysIpmiCreateClient(thread, guestKid, params, - sizeof(orbis::IpmiCreateClientParams)); - kid = guestKid; - } - - { - GuestAlloc status; - GuestAlloc params = orbis::IpmiClientConnectParams{.status = status}; - - GuestAlloc result; - while (true) { - auto errc = orbis::sysIpmiClientConnect( - thread, result, kid, params, sizeof(orbis::IpmiClientConnectParams)); - if (errc.value() == 0) { - break; - } - - std::this_thread::sleep_for(std::chrono::microseconds(300)); - } - } - - return {std::move(client), kid, thread}; -} - -struct ExecEnv { - std::uint64_t entryPoint; - std::uint64_t interpBase; -}; - -int ps4Exec(orbis::Thread *mainThread, ExecEnv execEnv, - orbis::utils::Ref executableModule, - std::span argv, std::span envp) { - const auto stackEndAddress = 0x7'ffff'c000ull; - const auto stackSize = 0x40000 * 32; - auto stackStartAddress = stackEndAddress - stackSize; - mainThread->stackStart = - rx::vm::map(reinterpret_cast(stackStartAddress), stackSize, - rx::vm::kMapProtCpuWrite | rx::vm::kMapProtCpuRead, - rx::vm::kMapFlagAnonymous | rx::vm::kMapFlagFixed | - rx::vm::kMapFlagPrivate | rx::vm::kMapFlagStack); - - mainThread->stackEnd = - reinterpret_cast(mainThread->stackStart) + stackSize; - - std::vector argvOffsets; - std::vector envpOffsets; - - StackWriter stack{reinterpret_cast(mainThread->stackEnd)}; - - for (auto &elem : argv) { - argvOffsets.push_back(stack.pushString(elem.data())); - } - - argvOffsets.push_back(0); - - for (auto &elem : envp) { - envpOffsets.push_back(stack.pushString(elem.data())); - } - - envpOffsets.push_back(0); - - // clang-format off - std::uint64_t auxv[] = { - AT_ENTRY, executableModule->entryPoint, - AT_BASE, execEnv.interpBase, - AT_PHDR, executableModule->phdrAddress, - AT_PHENT, sizeof(Elf64_Phdr), - AT_PHNUM, executableModule->phNum, - AT_NULL, 0 - }; - // clang-format on - - std::size_t argSize = - sizeof(std::uint64_t) + sizeof(std::uint64_t) * argvOffsets.size() + - sizeof(std::uint64_t) * envpOffsets.size() + sizeof(auxv); - - auto sp = stack.alloc(argSize, 32); - - auto arg = reinterpret_cast(sp); - *arg++ = argvOffsets.size() - 1; - - for (auto argvOffsets : argvOffsets) { - *arg++ = argvOffsets; - } - - for (auto envpOffset : envpOffsets) { - *arg++ = envpOffset; - } - - executableModule = {}; - - memcpy(arg, auxv, sizeof(auxv)); - - auto context = new ucontext_t{}; - - context->uc_mcontext.gregs[REG_RDI] = sp; - context->uc_mcontext.gregs[REG_RSP] = sp; - - // FIXME: should be at guest user space - context->uc_mcontext.gregs[REG_RDX] = - reinterpret_cast(+[] { std::printf("At exit\n"); }); - context->uc_mcontext.gregs[REG_RIP] = execEnv.entryPoint; - - mainThread->context = context; - rx::thread::invoke(mainThread); - std::abort(); -} - -struct Ps4ProcessParam { - orbis::size_t size; - orbis::uint32_t magic; - orbis::uint32_t version; - orbis::uint32_t sdkVersion; - orbis::uint32_t reserved; - orbis::ptr processName; - orbis::ptr userMainThreadName; - orbis::ptr userMainThreadPriority; - orbis::ptr userMainThreadStackSize; - orbis::ptr libcParam; -}; - -ExecEnv ps4CreateExecEnv(orbis::Thread *mainThread, - orbis::Ref executableModule, - bool isSystem) { - std::uint64_t interpBase = 0; - std::uint64_t entryPoint = executableModule->entryPoint; - - if (mainThread->tproc->processParam != nullptr && - mainThread->tproc->processParamSize >= sizeof(Ps4ProcessParam)) { - auto processParam = - reinterpret_cast(mainThread->tproc->processParam); - - auto sdkVersion = processParam // - + sizeof(uint64_t) // size - + sizeof(uint32_t) // magic - + sizeof(uint32_t); // entryCount - - mainThread->tproc->sdkVersion = *(uint32_t *)sdkVersion; - } - - if (orbis::g_context.sdkVersion == 0 && mainThread->tproc->sdkVersion != 0) { - orbis::g_context.sdkVersion = mainThread->tproc->sdkVersion; - } - if (mainThread->tproc->sdkVersion == 0) { - mainThread->tproc->sdkVersion = orbis::g_context.sdkVersion; - } - - if (executableModule->interp.empty()) { - return {.entryPoint = entryPoint, .interpBase = interpBase}; - } - - if (rx::vfs::exists(executableModule->interp, mainThread)) { - auto loader = - rx::linker::loadModuleFile(executableModule->interp, mainThread); - loader->id = mainThread->tproc->modulesMap.insert(loader); - interpBase = reinterpret_cast(loader->base); - entryPoint = loader->entryPoint; - - return {.entryPoint = entryPoint, .interpBase = interpBase}; - } - - auto libSceLibcInternal = rx::linker::loadModuleFile( - "/system/common/lib/libSceLibcInternal.sprx", mainThread); - - if (libSceLibcInternal == nullptr) { - std::fprintf(stderr, "libSceLibcInternal not found\n"); - std::abort(); - } - - libSceLibcInternal->id = - mainThread->tproc->modulesMap.insert(libSceLibcInternal); - - auto libkernel = rx::linker::loadModuleFile( - (isSystem ? "/system/common/lib/libkernel_sys.sprx" - : "/system/common/lib/libkernel.sprx"), - mainThread); - - if (libkernel == nullptr) { - std::fprintf(stderr, "libkernel not found\n"); - std::abort(); - } - - for (auto sym : libkernel->symbols) { - if (sym.id == 0xd2f4e7e480cc53d0) { - auto address = (uint64_t)libkernel->base + sym.address; - ::mprotect((void *)rx::alignDown(address, 0x1000), - rx::alignUp(sym.size + sym.address, 0x1000), PROT_WRITE); - std::printf("patching sceKernelGetMainSocId\n"); - struct GetMainSocId : Xbyak::CodeGenerator { - GetMainSocId(std::uint64_t address, std::uint64_t size) - : Xbyak::CodeGenerator(size, (void *)address) { - mov(eax, 0x710f00); - ret(); - } - } gen{address, sym.size}; - - ::mprotect((void *)rx::alignDown(address, 0x1000), - rx::alignUp(sym.size + sym.address, 0x1000), - PROT_READ | PROT_EXEC); - break; - } - } - - if (orbis::g_context.fwSdkVersion == 0) { - auto moduleParam = reinterpret_cast(libkernel->moduleParam); - auto fwSdkVersion = moduleParam // - + sizeof(uint64_t) // size - + sizeof(uint64_t); // magic - orbis::g_context.fwSdkVersion = *(uint32_t *)fwSdkVersion; - std::printf("fw sdk version: %x\n", orbis::g_context.fwSdkVersion); - } - - libkernel->id = mainThread->tproc->modulesMap.insert(libkernel); - interpBase = reinterpret_cast(libkernel->base); - entryPoint = libkernel->entryPoint; - - return {.entryPoint = entryPoint, .interpBase = interpBase}; -} - -int ps4Exec(orbis::Thread *mainThread, - orbis::utils::Ref executableModule, - std::span argv, std::span envp) { - auto execEnv = ps4CreateExecEnv(mainThread, executableModule, true); - return ps4Exec(mainThread, execEnv, std::move(executableModule), argv, envp); -} - -static void usage(const char *argv0) { - std::printf("%s [...] [args...]\n", argv0); - std::printf(" options:\n"); - std::printf(" --version, -v - print version\n"); - std::printf(" -m, --mount \n"); - std::printf(" -a, --enable-audio\n"); - std::printf(" -o, --override \n"); - std::printf(" --trace\n"); -} - -static std::filesystem::path getSelfDir() { - char path[PATH_MAX]; - int len = ::readlink("/proc/self/exe", path, sizeof(path)); - if (len < 0 || len >= sizeof(path)) { - // TODO - return std::filesystem::current_path(); - } - - return std::filesystem::path(path).parent_path(); -} - -static bool isRpcsxGpuPid(int pid) { - if (pid <= 0 || ::kill(pid, 0) != 0) { - return false; - } - - char path[PATH_MAX]; - std::string procPath = "/proc/" + std::to_string(pid) + "/exe"; - auto len = ::readlink(procPath.c_str(), path, sizeof(path)); - - if (len < 0 || len >= std::size(path)) { - return false; - } - - path[len] = 0; - - std::printf("filename is '%s'\n", - std::filesystem::path(path).filename().c_str()); - - return std::filesystem::path(path).filename().string().starts_with( - "rpcsx-gpu"); -} -static void runRpcsxGpu() { - const char *cmdBufferName = "/rpcsx-gpu-cmds"; - amdgpu::bridge::BridgeHeader *bridgeHeader = - amdgpu::bridge::openShmCommandBuffer(cmdBufferName); - - if (bridgeHeader != nullptr && bridgeHeader->pullerPid > 0 && - isRpcsxGpuPid(bridgeHeader->pullerPid)) { - bridgeHeader->pusherPid = ::getpid(); - g_gpuPid = bridgeHeader->pullerPid; - rx::bridge.header = bridgeHeader; - return; - } - - std::printf("Starting rpcsx-gpu\n"); - - if (bridgeHeader == nullptr) { - bridgeHeader = amdgpu::bridge::createShmCommandBuffer(cmdBufferName); - } - bridgeHeader->pusherPid = ::getpid(); - rx::bridge.header = bridgeHeader; - - auto rpcsxGpuPath = getSelfDir() / "rpcsx-gpu"; - - if (!std::filesystem::is_regular_file(rpcsxGpuPath)) { - std::printf("failed to find rpcsx-gpu, continue without GPU emulation\n"); - return; - } - - g_gpuPid = ::fork(); - - if (g_gpuPid == 0) { - // TODO - const char *argv[] = {rpcsxGpuPath.c_str(), nullptr}; - - ::execv(rpcsxGpuPath.c_str(), const_cast(argv)); - } -} - -static orbis::Semaphore *createSemaphore(std::string_view name, uint32_t attrs, - uint64_t initCount, - uint64_t maxCount) { - auto result = - orbis::g_context - .createSemaphore(orbis::kstring(name), attrs, initCount, maxCount) - .first; - std::memcpy(result->name, name.data(), name.size()); - result->name[name.size()] = 0; - return result; -} - -static orbis::EventFlag *createEventFlag(std::string_view name, uint32_t attrs, - uint64_t initPattern) { - return orbis::g_context - .createEventFlag(orbis::kstring(name), attrs, initPattern) - .first; -} - -static void createShm(const char *name, uint32_t flags, uint32_t mode, - uint64_t size) { - orbis::Ref shm; - auto shmDevice = orbis::g_context.shmDevice.staticCast(); - shmDevice->open(&shm, name, flags, mode, nullptr); - shm->ops->truncate(shm.get(), size, nullptr); -} - -struct IpmiServer { - orbis::Ref serverImpl; - - std::unordered_map> &outData, - const std::vector> &inData)>> - syncMethods; - std::unordered_map> &outData, - const std::vector> &inData)>> - asyncMethods; - std::vector> messages; - - IpmiServer &addSyncMethodStub( - std::uint32_t methodId, - std::function handler = [] -> std::int32_t { - return 0; - }) { - syncMethods[methodId] = [=](orbis::IpmiSession &session, - std::int32_t &errorCode, - std::vector> &outData, - const std::vector> &inData) - -> orbis::ErrorCode { - if (!outData.empty()) { - return orbis::ErrorCode::INVAL; - } - - errorCode = handler(); - return {}; - }; - return *this; - } - - IpmiServer &addSyncMethod( - std::uint32_t methodId, - std::function handler) { - syncMethods[methodId] = [=](orbis::IpmiSession &session, - std::int32_t &errorCode, - std::vector> &outData, - const std::vector> &inData) - -> orbis::ErrorCode { - if (outData.size() < 1) { - return orbis::ErrorCode::INVAL; - } - - std::uint64_t size = outData[0].size(); - errorCode = handler(outData[0].data(), size); - outData[0].resize(size); - return {}; - }; - return *this; - } - - template - IpmiServer & - addSyncMethod(std::uint32_t methodId, - std::function - handler) { - syncMethods[methodId] = [=](orbis::IpmiSession &session, - std::int32_t &errorCode, - std::vector> &outData, - const std::vector> &inData) - -> orbis::ErrorCode { - if (outData.size() != 1 || inData.size() != 1) { - return orbis::ErrorCode::INVAL; - } - - if (inData[0].size() != sizeof(T)) { - return orbis::ErrorCode::INVAL; - } - - std::uint64_t size = outData[0].size(); - errorCode = handler(outData[0].data(), size, - *reinterpret_cast(inData[0].data())); - outData[0].resize(size); - return {}; - }; - return *this; - } - - template - IpmiServer &addSyncMethod( - std::uint32_t methodId, - std::function handler) { - syncMethods[methodId] = [=](orbis::IpmiSession &session, - std::int32_t &errorCode, - std::vector> &outData, - const std::vector> &inData) - -> orbis::ErrorCode { - if (outData.size() != 1 || inData.size() != 1) { - return orbis::ErrorCode::INVAL; - } - - if (inData[0].size() != sizeof(InT)) { - return orbis::ErrorCode::INVAL; - } - if (outData[0].size() < sizeof(OutT)) { - return orbis::ErrorCode::INVAL; - } - - OutT out; - errorCode = handler(out, *reinterpret_cast(inData[0].data())); - std::memcpy(outData[0].data(), &out, sizeof(out)); - outData[0].resize(sizeof(OutT)); - return {}; - }; - return *this; - } - - template - IpmiServer & - addSyncMethod(std::uint32_t methodId, - std::function handler) { - syncMethods[methodId] = [=](orbis::IpmiSession &session, - std::int32_t &errorCode, - std::vector> &outData, - const std::vector> &inData) - -> orbis::ErrorCode { - if (inData.size() != 1 || !outData.empty()) { - return orbis::ErrorCode::INVAL; - } - - if (inData[0].size() != sizeof(T)) { - return orbis::ErrorCode::INVAL; - } - - errorCode = handler(*reinterpret_cast(inData[0].data())); - return {}; - }; - return *this; - } - - IpmiServer & - addSyncMethod(std::uint32_t methodId, - std::function> &outData, - const std::vector> &inData)> - handler) { - syncMethods[methodId] = [=](orbis::IpmiSession &session, - std::int32_t &errorCode, - std::vector> &outData, - const std::vector> &inData) - -> orbis::ErrorCode { - errorCode = handler(outData, inData); - return {}; - }; - return *this; - } - - IpmiServer & - addSyncMethod(std::uint32_t methodId, - std::function> &outData, - const std::vector> &inData)> - handler) { - syncMethods[methodId] = [=](orbis::IpmiSession &session, - std::int32_t &errorCode, - std::vector> &outData, - const std::vector> &inData) - -> orbis::ErrorCode { return handler(outData, inData); }; - return *this; - } - - IpmiServer & - addAsyncMethod(std::uint32_t methodId, - std::function> &outData, - const std::vector> &inData)> - handler) { - asyncMethods[methodId] = - [=](orbis::IpmiSession &session, std::int32_t &errorCode, - std::vector> &outData, - const std::vector> &inData) - -> orbis::ErrorCode { return handler(session, outData, inData); }; - return *this; - } - - IpmiServer & - addSyncMethod(std::uint32_t methodId, - std::function> &outData, - const std::vector> &inData)> - handler) { - asyncMethods[methodId] = - [=](orbis::IpmiSession &session, std::int32_t &errorCode, - std::vector> &outData, - const std::vector> &inData) - -> orbis::ErrorCode { return handler(session, outData, inData); }; - return *this; - } - - template IpmiServer &sendMsg(const T &data) { - std::vector message(sizeof(T)); - std::memcpy(message.data(), &data, sizeof(T)); - messages.push_back(std::move(message)); - return *this; - } - - orbis::ErrorCode handle(orbis::IpmiSession *session, - orbis::IpmiAsyncMessageHeader *message) { - std::vector> inData; - std::vector> outData; - auto bufLoc = std::bit_cast(message + 1); - - for (unsigned i = 0; i < message->numInData; ++i) { - auto size = *std::bit_cast(bufLoc); - bufLoc += sizeof(orbis::uint); - inData.push_back({bufLoc, size}); - bufLoc += size; - } - - orbis::IpmiClient::AsyncResponse response; - response.methodId = message->methodId + 1; - response.errorCode = 0; - orbis::ErrorCode result{}; - - if (auto it = asyncMethods.find(message->methodId); - it != asyncMethods.end()) { - auto &handler = it->second; - - result = handler(*session, response.errorCode, outData, inData); - } else { - std::fprintf(stderr, "Unimplemented async method %s::%x(inBufCount=%u)\n", - session->server->name.c_str(), message->methodId, - message->numInData); - - for (auto in : inData) { - std::fprintf(stderr, "in %zu\n", in.size()); - rx::hexdump(in); - } - } - - for (auto out : outData) { - response.data.push_back({out.data(), out.data() + out.size()}); - } - - std::lock_guard clientLock(session->client->mutex); - session->client->asyncResponses.push_front(std::move(response)); - std::fprintf(stderr, "%s:%x: sending async response\n", - session->client->name.c_str(), message->methodId); - session->client->asyncResponseCv.notify_all(session->client->mutex); - return result; - } - - orbis::ErrorCode handle(orbis::IpmiSession *session, - orbis::IpmiServer::Packet &packet, - orbis::IpmiSyncMessageHeader *message) { - std::size_t inBufferOffset = 0; - auto bufLoc = std::bit_cast(message + 1); - std::vector> inData; - std::vector> outData; - for (unsigned i = 0; i < message->numInData; ++i) { - auto size = *std::bit_cast(bufLoc); - bufLoc += sizeof(orbis::uint); - inData.push_back({bufLoc, size}); - bufLoc += size; - } - - for (unsigned i = 0; i < message->numOutData; ++i) { - auto size = *std::bit_cast(bufLoc); - bufLoc += sizeof(orbis::uint); - outData.push_back(std::vector(size)); - } - - orbis::IpmiSession::SyncResponse response; - response.errorCode = 0; - orbis::ErrorCode result{}; - - if (auto it = syncMethods.find(message->methodId); - it != syncMethods.end()) { - auto &handler = it->second; - - result = handler(*session, response.errorCode, outData, inData); - } else { - std::fprintf( - stderr, - "Unimplemented sync method %s::%x(inBufCount=%u, outBufCount=%u)\n", - session->server->name.c_str(), message->methodId, message->numInData, - message->numOutData); - - for (auto in : inData) { - std::fprintf(stderr, "in %zu\n", in.size()); - rx::hexdump(in); - } - - for (auto out : outData) { - std::fprintf(stderr, "out %zx\n", out.size()); - } - - for (auto out : outData) { - std::memset(out.data(), 0, out.size()); - } - // TODO: - // response.errorCode = message->numOutData == 0 || - // (message->numOutData == 1 && outData[0].empty()) - // ? 0 - // : -1, - } - - response.callerTid = packet.clientTid; - for (auto out : outData) { - response.data.push_back({out.data(), out.data() + out.size()}); - } - - std::lock_guard lock(session->mutex); - session->syncResponses.push_front(std::move(response)); - session->responseCv.notify_all(session->mutex); - - return result; - } -}; - -static IpmiServer &createIpmiServer(orbis::Process *process, const char *name) { - orbis::IpmiCreateServerConfig config{}; - orbis::Ref serverImpl; - orbis::ipmiCreateServer(process, nullptr, name, config, serverImpl); - auto server = std::make_shared(); - server->serverImpl = serverImpl; - - std::thread{[server, serverImpl, name] { - pthread_setname_np(pthread_self(), name); - while (true) { - orbis::IpmiServer::Packet packet; - { - std::lock_guard lock(serverImpl->mutex); - - while (serverImpl->packets.empty()) { - serverImpl->receiveCv.wait(serverImpl->mutex); - } - - packet = std::move(serverImpl->packets.front()); - serverImpl->packets.pop_front(); - } - - if (packet.info.type == 1) { - std::lock_guard serverLock(serverImpl->mutex); - - for (auto it = serverImpl->connectionRequests.begin(); - it != serverImpl->connectionRequests.end(); ++it) { - auto &conReq = *it; - std::lock_guard clientLock(conReq.client->mutex); - if (conReq.client->session != nullptr) { - continue; - } - - auto session = orbis::knew(); - if (session == nullptr) { - break; - } - - session->client = conReq.client; - session->server = serverImpl; - conReq.client->session = session; - - for (auto &message : server->messages) { - conReq.client->messageQueues[0].messages.push_back( - orbis::kvector(message.data(), - message.data() + message.size())); - } - - conReq.client->connectionStatus = 0; - conReq.client->sessionCv.notify_all(conReq.client->mutex); - conReq.client->connectCv.notify_all(conReq.client->mutex); - break; - } - - continue; - } - - if ((packet.info.type & ~0x8010) == 0x41) { - auto msgHeader = std::bit_cast( - packet.message.data()); - auto process = orbis::g_context.findProcessById(msgHeader->pid); - if (process == nullptr) { - continue; - } - auto client = orbis::g_context.ipmiMap.get(packet.info.clientKid) - .cast(); - if (client == nullptr) { - continue; - } - auto session = client->session; - if (session == nullptr) { - continue; - } - - server->handle(client->session.get(), packet, msgHeader); - packet = {}; - continue; - } - - if ((packet.info.type & ~0x10) == 0x43) { - auto msgHeader = (orbis::IpmiAsyncMessageHeader *)packet.message.data(); - auto process = orbis::g_context.findProcessById(msgHeader->pid); - if (process == nullptr) { - continue; - } - auto client = orbis::g_context.ipmiMap.get(packet.info.clientKid) - .cast(); - if (client == nullptr) { - continue; - } - auto session = client->session; - if (session == nullptr) { - continue; - } - - server->handle(client->session.get(), msgHeader); - continue; - } - - std::fprintf(stderr, "IPMI: Unhandled packet %s::%u\n", - serverImpl->name.c_str(), packet.info.type); - } - }}.detach(); - - return *server; -} - -static void createMiniSysCoreObjects(orbis::Process *process) { - createEventFlag("SceBootStatusFlags", 0x121, ~0ull); -} - -static void createSysAvControlObjects(orbis::Process *process) { - createIpmiServer(process, "SceAvSettingIpc"); - - createIpmiServer(process, "SceAvCaptureIpc"); - createEventFlag("SceAvCaptureIpc", 0x121, 0); - createEventFlag("SceAvSettingEvf", 0x121, 0xffff00000000); - - createShm("/SceAvSetting", 0xa02, 0x1a4, 4096); -} - -struct SceSysAudioSystemThreadArgs { - uint32_t threadId; -}; - -struct SceSysAudioSystemPortAndThreadArgs { - uint32_t audioPort; - uint32_t threadId; -}; - -static void createAudioSystemObjects(orbis::Process *process) { - auto audioOut = orbis::Ref(orbis::knew()); - - createIpmiServer(process, "SceSysAudioSystemIpc") - .addSyncMethod( - 0x12340000, - [=](const auto &args) -> std::int32_t { - ORBIS_LOG_TODO("IPMI: SceSysAudioSystemCreateControl", - args.threadId); - audioOut->channelInfo.idControl = args.threadId; - return 0; - }) - .addSyncMethod( - 0x1234000f, - [=](const auto &args) -> std::int32_t { - ORBIS_LOG_TODO("IPMI: SceSysAudioSystemOpenMixFlag", args.threadId); - // very bad - char buffer[32]; - std::snprintf(buffer, sizeof(buffer), "sceAudioOutMix%x", - args.threadId); - auto [eventFlag, inserted] = - orbis::g_context.createEventFlag(buffer, 0x100, 0); - - if (!inserted) { - return 17; // FIXME: verify - } - - audioOut->channelInfo.evf = eventFlag; - return 0; - }) - .addSyncMethod( - 0x12340001, - [=](const auto &args) -> std::int32_t { - ORBIS_LOG_TODO("IPMI: SceSysAudioSystemOpenPort", args.threadId, - args.audioPort); - audioOut->channelInfo.port = args.audioPort; - audioOut->channelInfo.channel = args.threadId; - return 0; - }) - .addSyncMethod( - 0x12340002, - [=](const auto &args) -> std::int32_t { - ORBIS_LOG_TODO("IPMI: SceSysAudioSystemStartListening", - args.threadId, args.audioPort); - - audioOut->start(); - return 0; - }) - .addSyncMethod( - 0x12340006, [=](const auto &args) -> std::int32_t { - ORBIS_LOG_TODO("IPMI: SceSysAudioSystemStopListening", - args.audioPort, args.threadId); - // TODO: implement - return 0; - }); -} - -struct SceMbusIpcAddHandleByUserIdMethodArgs { - orbis::uint32_t deviceType; // 0 - pad, 1 - aout, 2 - ain, 4 - camera, 6 - kb, 7 - mouse, 8 - vr - orbis::uint32_t deviceId; - orbis::uint32_t userId; - orbis::uint32_t type; - orbis::uint32_t index; - orbis::uint32_t reserved; - orbis::uint32_t pid; -}; - -static_assert(sizeof(SceMbusIpcAddHandleByUserIdMethodArgs) == 0x1c); - -struct SceUserServiceEvent { - std::uint32_t eventType; // 0 - login, 1 - logout - std::uint32_t user; -}; - -static void createSysCoreObjects(orbis::Process *process) { - createIpmiServer(process, "SceMbusIpc") - .addSyncMethod( - 0xce110007, [](const auto &args) -> std::int32_t { - ORBIS_LOG_TODO("IPMI: SceMbusIpcAddHandleByUserId", args.deviceType, - args.deviceId, args.userId, args.type, args.index, - args.reserved, args.pid); - if (args.deviceType == 1) { - struct HandleA { - int32_t pid; - int32_t port; - int32_t unk0 = 0x20100000; - int32_t unk1 = 1; - } handleA; - handleA.pid = args.pid; - handleA.port = args.deviceId; - audioIpmiClient.sendSyncMessage(0x1234000a, handleA); - struct HandleC { - int32_t pid; - int32_t port; - int32_t unk0 = 1; - int32_t unk1 = 0; - int32_t unk2 = 1; - int32_t unk3 = 0; - int32_t unk4 = 0; - int32_t unk5 = 0; - int32_t unk6 = 0; - int32_t unk7 = 1; - int32_t unk8 = 0; - } handleC; - handleC.pid = args.pid; - handleC.port = args.deviceId; - audioIpmiClient.sendSyncMessage(0x1234000c, handleC); - } - return 0; - }); - createIpmiServer(process, "SceSysCoreApp"); - createIpmiServer(process, "SceSysCoreApp2"); - createIpmiServer(process, "SceMDBG0SRV"); - - createSemaphore("SceSysCoreProcSpawnSema", 0x101, 0, 1); - createSemaphore("SceTraceMemorySem", 0x100, 1, 1); - createSemaphore("SceSysCoreEventSemaphore", 0x101, 0, 0x2d2); - createSemaphore("SceSysCoreProcSema", 0x101, 0, 1); - createSemaphore("AppmgrCoredumpHandlingEventSema", 0x101, 0, 4); - - createEventFlag("SceMdbgVrTriggerDump", 0x121, 0); -} - -static void createGnmCompositorObjects(orbis::Process *process) { - createEventFlag("SceCompositorCrashEventFlags", 0x122, 0); - createEventFlag("SceCompositorEventflag", 0x122, 0); - createEventFlag("SceCompositorResetStatusEVF", 0x122, 0); - - createShm("/tmp/SceHmd/Vr2d_shm_pass", 0xa02, 0x1b6, 16384); -} - -static void createShellCoreObjects(orbis::Process *process) { - - // FIXME: replace with fmt library - auto fmtHex = [](auto value, bool upperCase = false) { - std::stringstream ss; - ss << std::hex << std::setw(8) << std::setfill('0'); - if (upperCase) { - ss << std::uppercase; - } - ss << value; - return std::move(ss).str(); - }; - - createIpmiServer(process, "SceSystemLoggerService"); - createIpmiServer(process, "SceLoginMgrServer"); - createIpmiServer(process, "SceLncService") - .addSyncMethod(orbis::g_context.fwSdkVersion > 0x6000000 ? 0x30013 - : 0x30010, - [](void *out, std::uint64_t &size) -> std::int32_t { - struct SceLncServiceAppStatus { - std::uint32_t unk0; - std::uint32_t unk1; - std::uint32_t unk2; - }; - - if (size < sizeof(SceLncServiceAppStatus)) { - return -1; - } - - *(SceLncServiceAppStatus *)out = { - .unk0 = 1, - .unk1 = 1, - .unk2 = 1, - }; - - size = sizeof(SceLncServiceAppStatus); - return 0; - }); - createIpmiServer(process, "SceAppMessaging"); - createIpmiServer(process, "SceShellCoreUtil"); - createIpmiServer(process, "SceNetCtl"); - createIpmiServer(process, "SceNpMgrIpc") - .addSyncMethod( - 0, - [=](void *out, std::uint64_t &size) -> std::int32_t { - std::string_view result = "SceNpMgrEvf"; - if (size < result.size() + 1) { - return 0x8002'0000 + static_cast(orbis::ErrorCode::INVAL); - } - std::strncpy((char *)out, result.data(), result.size() + 1); - size = result.size() + 1; - orbis::g_context.createEventFlag(orbis::kstring(result), 0x200, 0); - return 0; - }) - .addSyncMethodStub(0xd); - createIpmiServer(process, "SceNpService") - .addSyncMethod(0, [=](void *out, std::uint64_t &size, - std::uint32_t val) { return 0; }) - .addSyncMethod(0xa0001, - [=](void *out, std::uint64_t &size) -> std::int32_t { - if (size < 1) { - return 0x8002'0000 + - static_cast(orbis::ErrorCode::INVAL); - } - size = 1; - *reinterpret_cast(out) = 1; - return 0; - }) - .addSyncMethod(0xa0002, - [=](void *out, std::uint64_t &size) -> std::int32_t { - if (size < 1) { - return 0x8002'0000 + - static_cast(orbis::ErrorCode::INVAL); - } - size = 1; - *reinterpret_cast(out) = 1; - return 0; - }) - .addSyncMethod( - 0xd0000, // sceNpTpipIpcClientGetShmIndex - [=](std::uint32_t &shmIndex, std::uint32_t appId) -> std::int32_t { - shmIndex = 0; - return 0; - }); - - createIpmiServer(process, "SceNpTrophyIpc") - .addSyncMethod(2, - [](std::vector> &out, - const std::vector> &in) { - if (out.size() != 1 || - out[0].size() < sizeof(std::uint32_t)) { - return orbis::ErrorCode::INVAL; - } - out = {toBytes(0)}; - return orbis::ErrorCode{}; - }) - .addAsyncMethod(0x30040, - [](orbis::IpmiSession &session, - std::vector> &out, - const std::vector> &in) { - session.client->eventFlags[0].set(1); - return orbis::ErrorCode{}; - }) - .addSyncMethod(0x90000, - [](std::vector> &out, - const std::vector> &in) { - if (out.size() != 1 || - out[0].size() < sizeof(std::uint32_t)) { - return orbis::ErrorCode::INVAL; - } - out = {toBytes(1)}; - return orbis::ErrorCode{}; - }) - .addSyncMethod(0x90003, - [](std::vector> &out, - const std::vector> &in) { - if (out.size() != 1 || - out[0].size() < sizeof(std::uint32_t)) { - return orbis::ErrorCode::INVAL; - } - out = {toBytes(1)}; - return orbis::ErrorCode{}; - }) - .addAsyncMethod(0x90024, - [](orbis::IpmiSession &session, - std::vector> &out, - const std::vector> &in) { - out.push_back(toBytes(0)); - // session.client->eventFlags[0].set(1); - return orbis::ErrorCode{}; - }) - .addAsyncMethod(0x90026, [](orbis::IpmiSession &session, - std::vector> &out, - const std::vector> &in) { - session.client->eventFlags[0].set(1); - return orbis::ErrorCode{}; - }); - createIpmiServer(process, "SceNpUdsIpc"); - createIpmiServer(process, "SceLibNpRifMgrIpc"); - createIpmiServer(process, "SceNpPartner001"); - createIpmiServer(process, "SceNpPartnerSubs"); - createIpmiServer(process, "SceNpGameIntent"); - createIpmiServer(process, "SceBgft"); - createIpmiServer(process, "SceCntMgrService"); - createIpmiServer(process, "ScePlayGo"); - createIpmiServer(process, "SceCompAppProxyUtil"); - createIpmiServer(process, "SceShareSpIpcService"); - createIpmiServer(process, "SceRnpsAppMgr"); - createIpmiServer(process, "SceUpdateService"); - createIpmiServer(process, "ScePatchChecker"); - createIpmiServer(process, "SceMorpheusUpdService"); - createIpmiServer(process, "ScePsmSharedDmem"); - - auto saveDataSem = createSemaphore("SceSaveData0000000000000001", 0x101, 0, 1); - auto saveDataSem_0 = createSemaphore("SceSaveData0000000000000001_0", 0x101, 0, 1); - createShm("SceSaveData0000000000000001_0", 0x202, 0x1b6, 0x40000); - createShm("SceSaveDataI0000000000000001", 0x202, 0x1b6, 43008); - createShm("SceSaveDataI0000000000000001_0", 0x202, 0x1b6, 43008); - createShm("SceNpPlusLogger", 0x202, 0x1b6, 0x40000); - auto ruiEvf = createEventFlag("SceSaveDataMemoryRUI00000010", 0x120, 0x1000000100010000); - - createIpmiServer(process, "SceSaveData") - .addSyncMethod( - 0x12340000, - [=](void *out, std::uint64_t &size) -> std::int32_t { - ruiEvf->set(~0ull); - { - saveDataSem->value++; - saveDataSem->cond.notify_one(saveDataSem->mtx); - } - { - saveDataSem_0->value++; - saveDataSem_0->cond.notify_one(saveDataSem_0->mtx); - } - return 0; - }) - .addSyncMethod( - 0x12340001, - [](void *out, std::uint64_t &size) -> std::int32_t { - { - auto [dev, devPath] = rx::vfs::get("/app0"); - if (auto hostFs = dev.cast()) { - std::error_code ec; - auto saveDir = hostFs->hostPath + "/.rpcsx/saves/"; - if (!std::filesystem::exists(saveDir)) { - return 0x8002'0000 + - static_cast(orbis::ErrorCode::NOENT); - } - } - } - std::string_view result = "/saves"; - if (size < result.size() + 1) { - return 0x8002'0000 + static_cast(orbis::ErrorCode::INVAL); - } - std::strncpy((char *)out, result.data(), result.size() + 1); - size = result.size() + 1; - orbis::g_context.createEventFlag(orbis::kstring(result), 0x200, 0); - return 0; - }) - .addSyncMethod( - 0x12340002, [](void *out, std::uint64_t &size) -> std::int32_t { - { - auto [dev, devPath] = rx::vfs::get("/app0"); - if (auto hostFs = dev.cast()) { - std::error_code ec; - auto saveDir = hostFs->hostPath + "/.rpcsx/saves/"; - std::filesystem::create_directories(saveDir, ec); - rx::vfs::mount("/saves/", - createHostIoDevice(saveDir, "/saves/")); - } - } - return 0; - }); - - createIpmiServer(process, "SceStickerCoreServer"); - createIpmiServer(process, "SceDbRecoveryShellCore"); - createIpmiServer(process, "SceUserService") - .sendMsg(SceUserServiceEvent{.eventType = 0, .user = 1}) - .addSyncMethod(0x30011, - [](void *ptr, std::uint64_t &size) -> std::int32_t { - if (size < sizeof(orbis::uint32_t)) { - return 0x8000'0000; - } - - *(orbis::uint32_t *)ptr = 1; - size = sizeof(orbis::uint32_t); - return 0; - }); - - createIpmiServer(process, "SceDbPreparationServer"); - createIpmiServer(process, "SceScreenShot"); - createIpmiServer(process, "SceAppDbIpc"); - createIpmiServer(process, "SceAppInst"); - createIpmiServer(process, "SceAppContent"); - createIpmiServer(process, "SceNpEntAccess"); - createIpmiServer(process, "SceMwIPMIServer"); - createIpmiServer(process, "SceAutoMounterIpc"); - createIpmiServer(process, "SceBackupRestoreUtil"); - createIpmiServer(process, "SceDataTransfer"); - createIpmiServer(process, "SceEventService"); - createIpmiServer(process, "SceShareFactoryUtil"); - createIpmiServer(process, "SceCloudConnectManager"); - createIpmiServer(process, "SceHubAppUtil"); - createIpmiServer(process, "SceTcIPMIServer"); - - createSemaphore("SceLncSuspendBlock00000001", 0x101, 1, 1); - createSemaphore("SceAppMessaging00000001", 0x100, 1, 0x7fffffff); - - createEventFlag("SceAutoMountUsbMass", 0x120, 0); - createEventFlag("SceLoginMgrUtilityEventFlag", 0x112, 0); - createEventFlag("SceLoginMgrSharePlayEventFlag", 0x112, 0); - createEventFlag("SceLoginMgrServerHmdConnect", 0x112, 0); - createEventFlag("SceLoginMgrServerDialogRequest", 0x112, 0); - createEventFlag("SceLoginMgrServerDialogResponse", 0x112, 0); - createEventFlag("SceGameLiveStreamingSpectator", 0x120, 0x8000000000000000); - createEventFlag("SceGameLiveStreamingUserId", 0x120, 0x8000000000000000); - createEventFlag("SceGameLiveStreamingMsgCount", 0x120, 0x8000000000000000); - createEventFlag("SceGameLiveStreamingBCCtrl", 0x120, 0); - createEventFlag("SceGameLiveStreamingEvntArg", 0x120, 0); - createEventFlag("SceLncUtilSystemStatus", 0x120, 0); - createEventFlag("SceShellCoreUtilRunLevel", 0x100, 0); - createEventFlag("SceSystemStateMgrInfo", 0x120, 0x10000000a); - createEventFlag("SceSystemStateMgrStatus", 0x120, 0); - createEventFlag("SceAppInstallerEventFlag", 0x120, 0); - createEventFlag("SceShellCoreUtilPowerControl", 0x120, 0x400000); - createEventFlag("SceShellCoreUtilAppFocus", 0x120, 1); - createEventFlag("SceShellCoreUtilCtrlFocus", 0x120, 0); - createEventFlag("SceShellCoreUtilUIStatus", 0x120, 0x20001); - createEventFlag("SceShellCoreUtilDevIdxBehavior", 0x120, 0); - createEventFlag("SceNpMgrVshReq", 0x121, 0); - createEventFlag("SceNpIdMapperVshReq", 0x121, 0); - createEventFlag("SceRtcUtilTzdataUpdateFlag", 0x120, 0); - createEventFlag("SceDataTransfer", 0x120, 0); - - createEventFlag("SceLncUtilAppStatus1", 0x100, 0); - createEventFlag("SceAppMessaging1", 0x120, 1); - createEventFlag("SceShellCoreUtil1", 0x120, 0x3f8c); - createEventFlag("SceNpScoreIpc_" + fmtHex(process->pid), 0x120, 0); - createEventFlag("/vmicDdEvfAin", 0x120, 0); - - createSemaphore("SceAppMessaging1", 0x101, 1, 0x7fffffff); - createSemaphore("SceLncSuspendBlock1", 0x101, 1, 10000); - - createShm("SceGlsSharedMemory", 0x202, 0x1a4, 262144); - createShm("SceShellCoreUtil", 0x202, 0x1a4, 16384); - createShm("SceNpTpip", 0x202, 0x1ff, 43008); - - createShm("vmicDdShmAin", 0x202, 0x1b6, 43008); - - createSemaphore("SceNpTpip 0", 0x101, 0, 1); -} - -static orbis::SysResult launchDaemon(orbis::Thread *thread, std::string path, - std::vector argv, - std::vector envv, - orbis::AppInfo appInfo) { - auto childPid = orbis::g_context.allocatePid() * 10000 + 1; - auto flag = orbis::knew>(); - *flag = false; - - int hostPid = ::fork(); - - if (hostPid) { - while (*flag == false) { - std::this_thread::sleep_for(std::chrono::milliseconds(10)); - } - - orbis::kfree(flag, sizeof(*flag)); - return {}; - } - - auto process = orbis::g_context.createProcess(childPid); - auto logFd = ::open(("log-" + std::to_string(childPid) + ".txt").c_str(), - O_CREAT | O_TRUNC | O_WRONLY, 0666); - - dup2(logFd, 1); - dup2(logFd, 2); - - process->hostPid = ::getpid(); - process->sysent = thread->tproc->sysent; - process->onSysEnter = thread->tproc->onSysEnter; - process->onSysExit = thread->tproc->onSysExit; - process->ops = thread->tproc->ops; - process->parentProcess = thread->tproc; - process->appInfo = appInfo; - - process->authInfo = { - .unk0 = 0x380000000000000f, - .caps = - { - -1ul, - -1ul, - -1ul, - -1ul, - }, - .attrs = - { - 0x4000400040000000, - 0x4000000000000000, - 0x0080000000000002, - 0xF0000000FFFF4000, - }, - }; - process->budgetId = 0; - process->isInSandbox = false; - - rx::vm::fork(childPid); - rx::vfs::fork(); - - *flag = true; - - auto [baseId, newThread] = process->threadsMap.emplace(); - newThread->tproc = process; - newThread->tid = process->pid + baseId; - newThread->state = orbis::ThreadState::RUNNING; - newThread->context = thread->context; - newThread->fsBase = thread->fsBase; - - orbis::g_currentThread = newThread; - thread = orbis::g_currentThread; - - setupSigHandlers(); - rx::thread::initialize(); - rx::thread::setupThisThread(); - - ps4InitFd(newThread); - - orbis::Ref socket; - createSocket(&socket, "", 1, 1, 0); - process->fileDescriptors.insert(socket); - - ORBIS_LOG_ERROR(__FUNCTION__, path); - - { - orbis::Ref file; - auto result = rx::vfs::open(path, kOpenFlagReadOnly, 0, &file, thread); - if (result.isError()) { - return result; - } - } - - rx::vm::reset(); - - thread->tproc->nextTlsSlot = 1; - auto executableModule = rx::linker::loadModuleFile(path, thread); - - executableModule->id = thread->tproc->modulesMap.insert(executableModule); - thread->tproc->processParam = executableModule->processParam; - thread->tproc->processParamSize = executableModule->processParamSize; - - g_traceSyscalls = false; - - thread->tproc->event.emit(orbis::kEvFiltProc, orbis::kNoteExec); - - std::thread([&] { - rx::thread::setupSignalStack(); - rx::thread::setupThisThread(); - ps4Exec(thread, executableModule, argv, envv); - }).join(); - std::abort(); -} - -int main(int argc, const char *argv[]) { - if (argc == 2) { - if (std::strcmp(argv[1], "-h") == 0 || - std::strcmp(argv[1], "--help") == 0) { - usage(argv[0]); - return 1; - } - - if (argv[1] == std::string_view("-v") || - argv[1] == std::string_view("--version")) { - std::printf("v%s\n", rx::getVersion().toString().c_str()); - return 0; - } - } - - if (argc < 2) { - usage(argv[0]); - return 1; - } - - setupSigHandlers(); - rx::vfs::initialize(); - - bool enableAudio = false; - bool asRoot = false; - bool isSystem = false; - bool isSafeMode = false; - - int argIndex = 1; - while (argIndex < argc) { - if (argv[argIndex] == std::string_view("--mount") || - argv[argIndex] == std::string_view("-m")) { - if (argc <= argIndex + 2) { - usage(argv[0]); - return 1; - } - - std::printf("mounting '%s' to virtual '%s'\n", argv[argIndex + 1], - argv[argIndex + 2]); - if (!std::filesystem::is_directory(argv[argIndex + 1])) { - std::fprintf(stderr, "Directory '%s' not exists\n", argv[argIndex + 1]); - return 1; - } - - rx::vfs::mount( - argv[argIndex + 2], - createHostIoDevice(argv[argIndex + 1], argv[argIndex + 2])); - argIndex += 3; - continue; - } - - if (argv[argIndex] == std::string_view("--trace")) { - argIndex++; - g_traceSyscalls = true; - continue; - } - - if (argv[argIndex] == std::string_view("--root")) { - argIndex++; - asRoot = true; - continue; - } - - if (argv[argIndex] == std::string_view("--system")) { - argIndex++; - isSystem = true; - asRoot = true; - continue; - } - - if (argv[argIndex] == std::string_view("--safemode")) { - argIndex++; - isSafeMode = true; - asRoot = true; - continue; - } - - if (argv[argIndex] == std::string_view("--override") || - argv[argIndex] == std::string_view("-o")) { - if (argc <= argIndex + 2) { - usage(argv[0]); - return 1; - } - - rx::linker::override(argv[argIndex + 1], argv[argIndex + 2]); - - argIndex += 3; - continue; - } - - if (argv[argIndex] == std::string_view("--enable-audio") || - argv[argIndex] == std::string_view("-a")) { - argIndex++; - enableAudio = true; - continue; - } - - break; - } - - if (argIndex >= argc) { - usage(argv[0]); - return 1; - } - - rx::thread::initialize(); - - // rx::vm::printHostStats(); - orbis::g_context.allocatePid(); - auto initProcess = orbis::g_context.createProcess(asRoot ? 1 : 10); - // pthread_setname_np(pthread_self(), "10.MAINTHREAD"); - - rx::vm::initialize(initProcess->pid); - runRpcsxGpu(); - - int status = 0; - - initProcess->sysent = &orbis::ps4_sysvec; - initProcess->onSysEnter = onSysEnter; - initProcess->onSysExit = onSysExit; - initProcess->ops = &rx::procOpsTable; - initProcess->hostPid = ::getpid(); - initProcess->appInfo = { - .unk4 = (isSystem ? orbis::slong(0x80000000'00000000) : 0), - }; - - if (isSystem) { - orbis::g_context.safeMode = isSafeMode ? 1 : 0; - initProcess->authInfo = {.unk0 = 0x380000000000000f, - .caps = - { - -1ul, - -1ul, - -1ul, - -1ul, - }, - .attrs = - { - 0x4000400040000000, - 0x4000000000000000, - 0x0080000000000002, - 0xF0000000FFFF4000, - }, - .ucred = { - -1ul, - -1ul, - 0x3800000000000022, - -1ul, - (1ul << 0x3a), - -1ul, - -1ul, - }}; - initProcess->budgetId = 0; - initProcess->isInSandbox = false; - } else { - initProcess->authInfo = { - .unk0 = 0x3100000000000001, - .caps = - { - 0x2000038000000000, - 0x000000000000FF00, - 0x0000000000000000, - 0x0000000000000000, - }, - .attrs = - { - 0x4000400040000000, - 0x4000000000000000, - 0x0080000000000002, - 0xF0000000FFFF4000, - }, - }; - initProcess->budgetId = 1; - initProcess->isInSandbox = true; - } - - auto [baseId, mainThread] = initProcess->threadsMap.emplace(); - mainThread->tproc = initProcess; - mainThread->tid = initProcess->pid + baseId; - mainThread->state = orbis::ThreadState::RUNNING; - mainThread->hostTid = ::gettid(); - orbis::g_currentThread = mainThread; - - auto executableModule = - rx::linker::loadModuleFile(argv[argIndex], mainThread); - - if (executableModule == nullptr) { - std::fprintf(stderr, "Failed to open '%s'\n", argv[argIndex]); - std::abort(); - } - - executableModule->id = initProcess->modulesMap.insert(executableModule); - initProcess->processParam = executableModule->processParam; - initProcess->processParamSize = executableModule->processParamSize; - - if (prctl(PR_SET_SYSCALL_USER_DISPATCH, PR_SYS_DISPATCH_ON, - (void *)0x100'0000'0000, ~0ull - 0x100'0000'0000, nullptr)) { - perror("prctl failed\n"); - exit(-1); - } - - if (executableModule->type == rx::linker::kElfTypeSceDynExec || - executableModule->type == rx::linker::kElfTypeSceExec || - executableModule->type == rx::linker::kElfTypeExec) { - ps4InitDev(); - ps4InitFd(mainThread); - - std::vector ps4Argv(argv + argIndex, - argv + argIndex + argc - argIndex); - - auto execEnv = ps4CreateExecEnv(mainThread, executableModule, isSystem); - - // data transfer mode - // 0 - normal - // 1 - source - // 2 - ? - orbis::g_context.regMgrInt[0x2110000] = 0; - - orbis::g_context.regMgrInt[0x20b0000] = 1; // prefer X - orbis::g_context.regMgrInt[0x2020000] = 1; // region - - // orbis::g_context.regMgrInt[0x2130000] = 0x1601; - orbis::g_context.regMgrInt[0x2130000] = 0; - orbis::g_context.regMgrInt[0x73800200] = 1; - orbis::g_context.regMgrInt[0x73800300] = 0; - orbis::g_context.regMgrInt[0x73800400] = 0; - orbis::g_context.regMgrInt[0x73800500] = 0; // enable log - - // user settings - orbis::g_context.regMgrInt[0x7800100] = 0; - orbis::g_context.regMgrInt[0x7810100] = 0; - orbis::g_context.regMgrInt[0x7820100] = 0; - orbis::g_context.regMgrInt[0x7830100] = 0; - orbis::g_context.regMgrInt[0x7840100] = 0; - orbis::g_context.regMgrInt[0x7850100] = 0; - orbis::g_context.regMgrInt[0x7860100] = 0; - orbis::g_context.regMgrInt[0x7870100] = 0; - orbis::g_context.regMgrInt[0x7880100] = 0; - orbis::g_context.regMgrInt[0x7890100] = 0; - orbis::g_context.regMgrInt[0x78a0100] = 0; - orbis::g_context.regMgrInt[0x78b0100] = 0; - orbis::g_context.regMgrInt[0x78c0100] = 0; - orbis::g_context.regMgrInt[0x78d0100] = 0; - orbis::g_context.regMgrInt[0x78e0100] = 0; - orbis::g_context.regMgrInt[0x78f0100] = 0; - - orbis::g_context.regMgrInt[0x2040000] = 0; // do not require initial setup - orbis::g_context.regMgrInt[0x2800600] = 0; // IDU version - orbis::g_context.regMgrInt[0x2860100] = 0; // IDU mode - orbis::g_context.regMgrInt[0x2860300] = 0; // Arcade mode - orbis::g_context.regMgrInt[0x7010000] = 0; // auto login - orbis::g_context.regMgrInt[0x9010000] = 0; // video out color effect - - if (!isSystem) { - createMiniSysCoreObjects(initProcess); - createSysAvControlObjects(initProcess); - createSysCoreObjects(initProcess); - createGnmCompositorObjects(initProcess); - createShellCoreObjects(initProcess); - if (enableAudio) { - createAudioSystemObjects(initProcess); - } - - // ? - createIpmiServer(initProcess, "SceCdlgRichProf"); - createIpmiServer(initProcess, "SceRemoteplayIpc"); - createIpmiServer(initProcess, "SceGlsIpc"); - createIpmiServer(initProcess, "SceImeService"); - createIpmiServer(initProcess, "SceErrorDlgServ"); - - createEventFlag("SceNpTusIpc_0000000a", 0x120, 0); - createSemaphore("SceLncSuspendBlock00000000", 0x101, 1, 1); - createSemaphore("SceNpPlusLogger 0", 0x101, 0, 0x7fffffff); - - initProcess->cwd = "/app0/"; - - if (!enableAudio) { - launchDaemon(mainThread, "/system/sys/orbis_audiod.elf", - {"/system/sys/orbis_audiod.elf"}, {}, - { - .titleId = "NPXS20973", - .unk4 = orbis::slong(0x80000000'00000000), - }); - // confirmed to work and known method of initialization since 5.05 version - if (orbis::g_context.fwSdkVersion >= 0x5050000) { - auto fakeIpmiThread = createGuestThread(); - audioIpmiClient = createIpmiClient(fakeIpmiThread, "SceSysAudioSystemIpc"); - // HACK: here is a bug in audiod because we send this very early and audiod has time to reset the state due to initialization - // so we wait for a second, during this time audiod should have time to initialize on most systems - std::this_thread::sleep_for(std::chrono::seconds(1)); - struct Data1 { - int32_t pid = 0; - int32_t someSwitch = 0x14; // 0x14 for init, 0x19 for mute - int32_t someFlag = 0; - } data1; - data1.pid = fakeIpmiThread->tproc->pid; - struct Data2 { - void* unk0 = 0; - int32_t unk1 = 0x105; - int32_t unk2 = 0x10000; - int64_t unk3 = 0; - int32_t unk4 = 0; - int32_t unk5 = 0; - int32_t unk6 = 0; - int64_t unk7 = 0; - int32_t unk8 = 0x2; - char unk9[24]{0}; - } data2; - std::uint32_t method = orbis::g_context.fwSdkVersion >= 0x8000000 ? 0x1234002c : 0x1234002b; - audioIpmiClient.sendSyncMessage(method, data1, data2); - } - } - } - - status = - ps4Exec(mainThread, execEnv, std::move(executableModule), ps4Argv, {}); - } else { - std::fprintf(stderr, "Unexpected executable type\n"); - status = 1; - } - - // rx::vm::printHostStats(); - rx::vm::deinitialize(); - rx::thread::deinitialize(); - - return status; -} diff --git a/rpcsx-os/AudioOut.cpp b/rpcsx/AudioOut.cpp similarity index 86% rename from rpcsx-os/AudioOut.cpp rename to rpcsx/AudioOut.cpp index 3646d86..9a9226b 100644 --- a/rpcsx-os/AudioOut.cpp +++ b/rpcsx/AudioOut.cpp @@ -1,7 +1,10 @@ #include "AudioOut.hpp" +#include "rx/mem.hpp" +#include "rx/watchdog.hpp" #include #include #include +#include #include #include #include @@ -28,21 +31,23 @@ AudioOut::~AudioOut() { void AudioOut::start() { std::lock_guard lock(thrMtx); - threads.push_back(std::thread( - [this, channelInfo = channelInfo] { channelEntry(channelInfo); })); + threads.emplace_back( + [this, channelInfo = channelInfo] { channelEntry(channelInfo); }); } void AudioOut::channelEntry(AudioOutChannelInfo info) { - char control_shm_name[32]; - char audio_shm_name[32]; + char control_shm_name[128]; + char audio_shm_name[128]; - std::snprintf(control_shm_name, sizeof(control_shm_name), "/rpcsx-shm_%d_C", - info.idControl); - std::snprintf(audio_shm_name, sizeof(audio_shm_name), "/rpcsx-shm_%d_%d_A", - info.channel, info.port); + std::format_to( + control_shm_name, "{}", + rx::getShmGuestPath(std::format("shm_{}_C", info.idControl)).string()); + std::format_to( + audio_shm_name, "{}", + rx::getShmGuestPath(std::format("shm_{}_{}_A", info.channel, info.port)) + .string()); - int controlFd = - ::shm_open(control_shm_name, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); + int controlFd = ::open(control_shm_name, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); if (controlFd == -1) { perror("shm_open"); std::abort(); @@ -50,20 +55,19 @@ void AudioOut::channelEntry(AudioOutChannelInfo info) { struct stat controlStat; if (::fstat(controlFd, &controlStat)) { - perror("shm_open"); + perror("fstat"); std::abort(); } auto controlPtr = reinterpret_cast( - ::mmap(NULL, controlStat.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, - controlFd, 0)); + rx::mem::map(nullptr, controlStat.st_size, PROT_READ | PROT_WRITE, + MAP_SHARED, controlFd)); if (controlPtr == MAP_FAILED) { perror("mmap"); std::abort(); } - int bufferFd = - ::shm_open(audio_shm_name, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); + int bufferFd = ::open(audio_shm_name, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); if (bufferFd == -1) { perror("open"); std::abort(); @@ -71,7 +75,7 @@ void AudioOut::channelEntry(AudioOutChannelInfo info) { struct stat bufferStat; if (::fstat(bufferFd, &bufferStat)) { - perror("shm_open"); + perror("fstat"); std::abort(); } @@ -145,7 +149,7 @@ void AudioOut::channelEntry(AudioOutChannelInfo info) { // output std::unique_lock lock(soxMtx); sox_format_t *output = - sox_open_write("default", &out_si, NULL, "alsa", NULL, NULL); + sox_open_write("default", &out_si, NULL, "alsa", nullptr, nullptr); soxMtx.unlock(); if (!output) { diff --git a/rpcsx-os/AudioOut.hpp b/rpcsx/AudioOut.hpp similarity index 100% rename from rpcsx-os/AudioOut.hpp rename to rpcsx/AudioOut.hpp diff --git a/rpcsx-os/CMakeLists.txt b/rpcsx/CMakeLists.txt similarity index 70% rename from rpcsx-os/CMakeLists.txt rename to rpcsx/CMakeLists.txt index cb34369..6fc8c30 100644 --- a/rpcsx-os/CMakeLists.txt +++ b/rpcsx/CMakeLists.txt @@ -6,7 +6,7 @@ add_library(standalone-config INTERFACE) target_include_directories(standalone-config INTERFACE orbis-kernel-config) add_library(orbis::kernel::config ALIAS standalone-config) -add_executable(rpcsx-os +add_executable(rpcsx audio/AudioDevice.cpp audio/AlsaDevice.cpp @@ -60,19 +60,34 @@ add_executable(rpcsx-os main.cpp AudioOut.cpp backtrace.cpp - bridge.cpp vm.cpp ops.cpp linker.cpp io-device.cpp thread.cpp vfs.cpp + ipmi.cpp ) -target_include_directories(rpcsx-os PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) -target_link_libraries(rpcsx-os PUBLIC orbis::kernel amdgpu::bridge rx libcrypto libunwind::unwind-x86_64 xbyak::xbyak sox::sox ALSA::ALSA) -target_base_address(rpcsx-os 0x0000010000000000) -target_compile_options(rpcsx-os PRIVATE "-mfsgsbase") +add_subdirectory(gpu) +add_subdirectory(core) -set_target_properties(rpcsx-os PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) -install(TARGETS rpcsx-os RUNTIME DESTINATION bin) +target_include_directories(rpcsx PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) +target_link_libraries(rpcsx +PUBLIC + rpcsx-gpu + orbis::kernel + rx + libcrypto + libunwind::unwind-x86_64 + xbyak::xbyak + sox::sox + ALSA::ALSA + rpcsx-core +) + +target_base_address(rpcsx 0x0000070000000000) +target_compile_options(rpcsx PRIVATE "-mfsgsbase") + +set_target_properties(rpcsx PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) +install(TARGETS rpcsx RUNTIME DESTINATION bin) diff --git a/rpcsx-os/audio/AlsaDevice.cpp b/rpcsx/audio/AlsaDevice.cpp similarity index 100% rename from rpcsx-os/audio/AlsaDevice.cpp rename to rpcsx/audio/AlsaDevice.cpp diff --git a/rpcsx-os/audio/AlsaDevice.hpp b/rpcsx/audio/AlsaDevice.hpp similarity index 100% rename from rpcsx-os/audio/AlsaDevice.hpp rename to rpcsx/audio/AlsaDevice.hpp diff --git a/rpcsx-os/audio/AudioDevice.cpp b/rpcsx/audio/AudioDevice.cpp similarity index 100% rename from rpcsx-os/audio/AudioDevice.cpp rename to rpcsx/audio/AudioDevice.cpp diff --git a/rpcsx-os/audio/AudioDevice.hpp b/rpcsx/audio/AudioDevice.hpp similarity index 100% rename from rpcsx-os/audio/AudioDevice.hpp rename to rpcsx/audio/AudioDevice.hpp diff --git a/rpcsx-os/backtrace.cpp b/rpcsx/backtrace.cpp similarity index 100% rename from rpcsx-os/backtrace.cpp rename to rpcsx/backtrace.cpp diff --git a/rpcsx-os/backtrace.hpp b/rpcsx/backtrace.hpp similarity index 100% rename from rpcsx-os/backtrace.hpp rename to rpcsx/backtrace.hpp diff --git a/rpcsx/core/CMakeLists.txt b/rpcsx/core/CMakeLists.txt new file mode 100644 index 0000000..c982779 --- /dev/null +++ b/rpcsx/core/CMakeLists.txt @@ -0,0 +1,13 @@ +add_library(rpcsx-core +STATIC + src/Config.cpp + src/watchdog.cpp +) + +target_include_directories(rpcsx-core + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/include + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/.. +) +target_link_libraries(rpcsx-core PUBLIC orbis::kernel rx rpcsx-gpu) diff --git a/rpcsx/core/include/rx/Config.hpp b/rpcsx/core/include/rx/Config.hpp new file mode 100644 index 0000000..4572cb5 --- /dev/null +++ b/rpcsx/core/include/rx/Config.hpp @@ -0,0 +1,11 @@ +#pragma once + +namespace rx { +// FIXME: serialization +struct Config { + int gpuIndex = 0; + bool validateGpu = false; +}; + +extern Config g_config; +} // namespace rx diff --git a/rpcsx/core/include/rx/watchdog.hpp b/rpcsx/core/include/rx/watchdog.hpp new file mode 100644 index 0000000..b12cdf2 --- /dev/null +++ b/rpcsx/core/include/rx/watchdog.hpp @@ -0,0 +1,12 @@ +#pragma once + +#include +#include + +namespace rx { +const char *getShmPath(); +std::filesystem::path getShmGuestPath(std::string_view path); +void createGpuDevice(); +void shutdown(); +int startWatchdog(); +} // namespace rx diff --git a/rpcsx/core/src/Config.cpp b/rpcsx/core/src/Config.cpp new file mode 100644 index 0000000..f605ff6 --- /dev/null +++ b/rpcsx/core/src/Config.cpp @@ -0,0 +1,3 @@ +#include "rx/Config.hpp" + +rx::Config rx::g_config; diff --git a/rpcsx/core/src/watchdog.cpp b/rpcsx/core/src/watchdog.cpp new file mode 100644 index 0000000..a460e98 --- /dev/null +++ b/rpcsx/core/src/watchdog.cpp @@ -0,0 +1,194 @@ +#include "rx/watchdog.hpp" +#include "gpu/Device.hpp" +#include "orbis/KernelContext.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static std::atomic g_exitRequested; +static std::atomic g_runGpuRequested; +static pid_t g_watchdogPid; +static pid_t g_gpuPid; +static char g_shmPath[256]; + +enum class MessageId { + RunGPU, +}; + +static void runGPU() { + if (g_gpuPid != 0 || orbis::g_context.gpuDevice != nullptr) { + return; + } + + auto childPid = ::fork(); + + if (childPid != 0) { + g_gpuPid = childPid; + return; + } + + amdgpu::Device *gpu; + { + pthread_setname_np(pthread_self(), "rpcsx-gpu"); + std::lock_guard lock(orbis::g_context.gpuDeviceMtx); + if (orbis::g_context.gpuDevice != nullptr) { + std::exit(0); + } + + int logFd = + ::open("log-gpu.txt", O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR); + dup2(logFd, 1); + dup2(logFd, 2); + ::close(logFd); + + gpu = orbis::knew(); + orbis::g_context.gpuDevice = gpu; + } + + gpu->start(); + std::exit(0); +} + +static void handleManagementSignal(siginfo_t *info) { + switch (static_cast(info->si_value.sival_int)) { + case MessageId::RunGPU: + g_runGpuRequested = true; + break; + } +} + +static void handle_watchdog_signal(int sig, siginfo_t *info, void *) { + if (sig == SIGUSR1) { + handleManagementSignal(info); + } + + if (sig == SIGINT || sig == SIGQUIT) { + g_exitRequested = true; + } +} + +static void sendMessage(MessageId id) { + sigqueue(g_watchdogPid, SIGUSR1, + { + .sival_int = static_cast(id), + }); +} + +const char *rx::getShmPath() { return g_shmPath; } +std::filesystem::path rx::getShmGuestPath(std::string_view path) { + return std::format("{}/guest/{}", getShmPath(), path); +} + +void rx::createGpuDevice() { sendMessage(MessageId::RunGPU); } +void rx::shutdown() { kill(g_watchdogPid, SIGQUIT); } + +static void killProcesses(std::vector list) { + int iteration = 0; + while (!list.empty()) { + auto signal = iteration++ > 20 ? SIGKILL : SIGQUIT; + + for (std::size_t i = 0; i < list.size();) { + if (list[i] == 0 || ::kill(list[i], signal) != 0) { + if (i + 1 < list.size()) { + std::swap(list[i], list.back()); + } + + list.pop_back(); + continue; + } + + ++i; + } + + if (signal == SIGKILL) { + break; + } + + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } +} + +int rx::startWatchdog() { + auto watchdogPid = ::getpid(); + g_watchdogPid = watchdogPid; + std::format_to(g_shmPath, "/dev/shm/rpcsx/{}", watchdogPid); + + if (!std::filesystem::create_directories(g_shmPath)) { + perror("failed to create shared memory directory"); + std::exit(-1); + } + + if (!std::filesystem::create_directory(std::format("{}/guest", g_shmPath))) { + perror("failed to create guest shared memory directory"); + std::exit(-1); + } + + pid_t initProcessPid = fork(); + + if (initProcessPid == 0) { + return watchdogPid; + } + + pthread_setname_np(pthread_self(), "rpcsx-watchdog"); + + struct sigaction act{}; + act.sa_sigaction = handle_watchdog_signal; + act.sa_flags = SA_SIGINFO; + + if (sigaction(SIGUSR1, &act, nullptr)) { + perror("Error sigaction:"); + std::exit(-1); + } + + if (sigaction(SIGINT, &act, nullptr)) { + perror("Error sigaction:"); + std::exit(-1); + } + + if (sigaction(SIGQUIT, &act, nullptr)) { + perror("Error sigaction:"); + std::exit(-1); + } + + int stat = 0; + while (true) { + auto childPid = wait(&stat); + + if (g_exitRequested == true) { + break; + } + + if (childPid == initProcessPid) { + initProcessPid = 0; + break; + } + + if (childPid == g_gpuPid) { + g_gpuPid = 0; + // FIXME: Restart GPU? + break; + } + + if (g_runGpuRequested) { + std::println("watchdog: gpu start requested"); + g_runGpuRequested = false; + runGPU(); + } + } + + std::filesystem::remove_all(g_shmPath); + killProcesses({initProcessPid, g_gpuPid}); + ::wait(nullptr); + std::_Exit(stat); +} diff --git a/rpcsx-gpu/CMakeLists.txt b/rpcsx/gpu/CMakeLists.txt similarity index 68% rename from rpcsx-gpu/CMakeLists.txt rename to rpcsx/gpu/CMakeLists.txt index a3aa8ce..90ffc5d 100644 --- a/rpcsx-gpu/CMakeLists.txt +++ b/rpcsx/gpu/CMakeLists.txt @@ -8,9 +8,9 @@ add_precompiled_vulkan_spirv(rpcsx-gpu-shaders shaders/rect_list.geom.glsl ) -add_executable(rpcsx-gpu +add_library(rpcsx-gpu +STATIC Cache.cpp - main.cpp Device.cpp FlipPipeline.cpp Pipe.cpp @@ -21,7 +21,6 @@ add_executable(rpcsx-gpu target_link_libraries(rpcsx-gpu PUBLIC rpcsx-gpu-shaders - amdgpu::bridge rx gcn-shader glfw @@ -30,9 +29,8 @@ PUBLIC rdna-semantic-spirv gnm::vulkan gnm + orbis::kernel + rpcsx-core ) -install(TARGETS rpcsx-gpu RUNTIME DESTINATION bin) -set_target_properties(rpcsx-gpu PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) -target_base_address(rpcsx-gpu 0x0000060000000000) add_subdirectory(lib) diff --git a/rpcsx-gpu/Cache.cpp b/rpcsx/gpu/Cache.cpp similarity index 94% rename from rpcsx-gpu/Cache.cpp rename to rpcsx/gpu/Cache.cpp index b7b0be7..c317153 100644 --- a/rpcsx-gpu/Cache.cpp +++ b/rpcsx/gpu/Cache.cpp @@ -1,8 +1,8 @@ #include "Cache.hpp" #include "Device.hpp" -#include "amdgpu/bridge/bridge.hpp" #include "amdgpu/tiler.hpp" #include "gnm/vulkan.hpp" +#include "rx/mem.hpp" #include "shader/Evaluator.hpp" #include "shader/GcnConverter.hpp" #include "shader/dialect.hpp" @@ -22,16 +22,15 @@ using namespace amdgpu; using namespace shader; -static void notifyPageChanges(bridge::BridgeHeader *bridge, int vmId, - std::uint32_t firstPage, +static void notifyPageChanges(Device *device, int vmId, std::uint32_t firstPage, std::uint32_t pageCount) { std::uint64_t command = (static_cast(pageCount - 1) << 32) | firstPage; while (true) { - for (std::size_t i = 0; i < std::size(bridge->cacheCommands); ++i) { + for (std::size_t i = 0; i < std::size(device->cacheCommands); ++i) { std::uint64_t expCommand = 0; - if (bridge->cacheCommands[vmId][i].compare_exchange_strong( + if (device->cacheCommands[vmId][i].compare_exchange_strong( expCommand, command, std::memory_order::acquire, std::memory_order::relaxed)) { return; @@ -40,67 +39,16 @@ static void notifyPageChanges(bridge::BridgeHeader *bridge, int vmId, } } -static void modifyWatchFlags(bridge::BridgeHeader *bridge, int vmId, - std::uint64_t address, std::uint64_t size, - std::uint8_t addFlags, std::uint8_t removeFlags) { - auto firstPage = address / bridge::kHostPageSize; - auto lastPage = - (address + size + bridge::kHostPageSize - 1) / bridge::kHostPageSize; - bool hasChanges = false; - for (auto page = firstPage; page < lastPage; ++page) { - auto prevValue = - bridge->cachePages[vmId][page].load(std::memory_order::relaxed); - auto newValue = (prevValue & ~removeFlags) | addFlags; - - if (newValue == prevValue) { - continue; - } - - while (!bridge->cachePages[vmId][page].compare_exchange_weak( - prevValue, newValue, std::memory_order::relaxed)) { - newValue = (prevValue & ~removeFlags) | addFlags; - } - - if (newValue != prevValue) { - hasChanges = true; - } - } - - if (hasChanges) { - notifyPageChanges(bridge, vmId, firstPage, lastPage - firstPage); - } -} - -static void watchWrites(bridge::BridgeHeader *bridge, int vmId, - std::uint64_t address, std::uint64_t size) { - modifyWatchFlags(bridge, vmId, address, size, bridge::kPageWriteWatch, - bridge::kPageInvalidated); -} -static void lockReadWrite(bridge::BridgeHeader *bridge, int vmId, - std::uint64_t address, std::uint64_t size, - bool isLazy) { - modifyWatchFlags(bridge, vmId, address, size, - bridge::kPageReadWriteLock | - (isLazy ? bridge::kPageLazyLock : 0), - bridge::kPageInvalidated); -} -static void unlockReadWrite(bridge::BridgeHeader *bridge, int vmId, - std::uint64_t address, std::uint64_t size) { - modifyWatchFlags(bridge, vmId, address, size, bridge::kPageWriteWatch, - bridge::kPageReadWriteLock | bridge::kPageLazyLock); -} - -static bool testHostInvalidations(bridge::BridgeHeader *bridge, int vmId, +static bool testHostInvalidations(Device *device, int vmId, std::uint64_t address, std::uint64_t size) { - auto firstPage = address / bridge::kHostPageSize; - auto lastPage = - (address + size + bridge::kHostPageSize - 1) / bridge::kHostPageSize; + auto firstPage = address / rx::mem::pageSize; + auto lastPage = (address + size + rx::mem::pageSize - 1) / rx::mem::pageSize; for (auto page = firstPage; page < lastPage; ++page) { auto prevValue = - bridge->cachePages[vmId][page].load(std::memory_order::relaxed); + device->cachePages[vmId][page].load(std::memory_order::relaxed); - if (~prevValue & bridge::kPageInvalidated) { + if (~prevValue & kPageInvalidated) { continue; } @@ -110,25 +58,23 @@ static bool testHostInvalidations(bridge::BridgeHeader *bridge, int vmId, return false; } -static bool handleHostInvalidations(bridge::BridgeHeader *bridge, int vmId, +static bool handleHostInvalidations(Device *device, int vmId, std::uint64_t address, std::uint64_t size) { - auto firstPage = address / bridge::kHostPageSize; - auto lastPage = - (address + size + bridge::kHostPageSize - 1) / bridge::kHostPageSize; + auto firstPage = address / rx::mem::pageSize; + auto lastPage = (address + size + rx::mem::pageSize - 1) / rx::mem::pageSize; bool hasInvalidations = false; for (auto page = firstPage; page < lastPage; ++page) { auto prevValue = - bridge->cachePages[vmId][page].load(std::memory_order::relaxed); + device->cachePages[vmId][page].load(std::memory_order::relaxed); - if (~prevValue & bridge::kPageInvalidated) { + if (~prevValue & kPageInvalidated) { continue; } - while (!bridge->cachePages[vmId][page].compare_exchange_weak( - prevValue, prevValue & ~bridge::kPageInvalidated, - std::memory_order::relaxed)) { + while (!device->cachePages[vmId][page].compare_exchange_weak( + prevValue, prevValue & ~kPageInvalidated, std::memory_order::relaxed)) { } hasInvalidations = true; @@ -137,18 +83,16 @@ static bool handleHostInvalidations(bridge::BridgeHeader *bridge, int vmId, return hasInvalidations; } -static void markHostInvalidated(bridge::BridgeHeader *bridge, int vmId, - std::uint64_t address, std::uint64_t size) { - auto firstPage = address / bridge::kHostPageSize; - auto lastPage = - (address + size + bridge::kHostPageSize - 1) / bridge::kHostPageSize; +static void markHostInvalidated(Device *device, int vmId, std::uint64_t address, + std::uint64_t size) { + auto firstPage = address / rx::mem::pageSize; + auto lastPage = (address + size + rx::mem::pageSize - 1) / rx::mem::pageSize; for (auto page = firstPage; page < lastPage; ++page) { std::uint8_t prevValue = 0; - while (!bridge->cachePages[vmId][page].compare_exchange_weak( - prevValue, prevValue | bridge::kPageInvalidated, - std::memory_order::relaxed)) { + while (!device->cachePages[vmId][page].compare_exchange_weak( + prevValue, prevValue | kPageInvalidated, std::memory_order::relaxed)) { } } } @@ -676,7 +620,7 @@ struct CachedBuffer : Cache::Entry { struct CachedHostVisibleBuffer : CachedBuffer { using CachedBuffer::update; - bool expensive() { return addressRange.size() >= bridge::kHostPageSize; } + bool expensive() { return addressRange.size() >= rx::mem::pageSize; } void flush(void *target, rx::AddressRange range) { if (!hasDelayedFlush) { @@ -1258,7 +1202,7 @@ Cache::Buffer Cache::Tag::getBuffer(rx::AddressRange range, Access access) { if ((access & Access::Read) != Access::None) { if (!cached->expensive() || - handleHostInvalidations(getDevice()->bridge, mParent->mVmId, + handleHostInvalidations(getDevice(), mParent->mVmId, addressRange.beginAddress(), addressRange.size()) || !mParent->isInSync(addressRange, cached->tagId)) { @@ -1631,7 +1575,7 @@ Cache::Image Cache::Tag::getImage(const ImageKey &key, Access access) { if ((access & Access::Read) != Access::None) { if (!cached->expensive() || - testHostInvalidations(getDevice()->bridge, mParent->mVmId, + testHostInvalidations(getDevice(), mParent->mVmId, updateRange.beginAddress(), updateRange.size()) || !mParent->isInSync(cached->addressRange, cached->tagId)) { @@ -2316,8 +2260,7 @@ VkImage Cache::getFrameBuffer(Scheduler &scheduler, int index) { return {}; } void Cache::invalidate(Tag &tag, rx::AddressRange range) { flush(tag, range); - markHostInvalidated(mDevice->bridge, mVmId, range.beginAddress(), - range.size()); + markHostInvalidated(mDevice, mVmId, range.beginAddress(), range.size()); } void Cache::flush(Tag &tag, rx::AddressRange range) { flushImages(tag, range); @@ -2340,7 +2283,7 @@ void Cache::trackUpdate(EntryType type, rx::AddressRange range, table.map(range.beginAddress(), range.endAddress(), std::move(entry)); if (watchChanges) { - watchWrites(mDevice->bridge, mVmId, range.beginAddress(), range.size()); + mDevice->watchWrites(mVmId, range.beginAddress(), range.size()); } } @@ -2355,38 +2298,7 @@ void Cache::trackWrite(rx::AddressRange range, TagId tagId, bool lockMemory) { return; } - lockReadWrite(mDevice->bridge, mVmId, range.beginAddress(), range.size(), - true); - - static auto updateThread = std::thread{[this] { - auto &sched = mDevice->graphicsPipes[0].scheduler; - auto vmId = mVmId; - while (true) { - auto page = mDevice->bridge->gpuCacheCommand[vmId].load( - std::memory_order::relaxed); - if (page == 0) { - continue; - } - - mDevice->bridge->gpuCacheCommand[vmId].store(0, - std::memory_order::relaxed); - auto address = static_cast(page) * bridge::kHostPageSize; - - auto range = - rx::AddressRange::fromBeginSize(address, bridge::kHostPageSize); - auto tag = mDevice->getCacheTag(vmId, sched); - - flushImages(tag, range); - sched.submit(); - sched.wait(); - - auto flushedRange = flushBuffers(range); - - assert(flushedRange.isValid() && flushedRange.size() > 0); - unlockReadWrite(mDevice->bridge, vmId, flushedRange.beginAddress(), - flushedRange.size()); - } - }}; + mDevice->lockReadWrite(mVmId, range.beginAddress(), range.size(), true); } rx::AddressRange Cache::flushImages(Tag &tag, rx::AddressRange range) { diff --git a/rpcsx-gpu/Cache.hpp b/rpcsx/gpu/Cache.hpp similarity index 100% rename from rpcsx-gpu/Cache.hpp rename to rpcsx/gpu/Cache.hpp diff --git a/rpcsx/gpu/Device.cpp b/rpcsx/gpu/Device.cpp new file mode 100644 index 0000000..215b463 --- /dev/null +++ b/rpcsx/gpu/Device.cpp @@ -0,0 +1,1070 @@ +#include "Device.hpp" +#include "FlipPipeline.hpp" +#include "Renderer.hpp" +#include "amdgpu/tiler.hpp" +#include "gnm/constants.hpp" +#include "gnm/pm4.hpp" +#include "orbis/KernelContext.hpp" +#include "orbis/note.hpp" +#include "rx/Config.hpp" +#include "rx/bits.hpp" +#include "rx/die.hpp" +#include "rx/mem.hpp" +#include "rx/watchdog.hpp" +#include "shader/spv.hpp" +#include "shaders/rdna-semantic-spirv.hpp" +#include "vk.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace amdgpu; + +static VKAPI_ATTR VkBool32 VKAPI_CALL debugUtilsMessageCallback( + VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, + VkDebugUtilsMessageTypeFlagsEXT messageType, + const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData, + void *pUserData) { + if (pCallbackData->pMessage) { + std::println("{}", pCallbackData->pMessage); + } + + if (messageSeverity == VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) { + // std::abort(); + } + return VK_FALSE; +} + +enum class DisplayEvent : std::uint16_t { + Flip, + VBlank, + PreVBlankStart, +}; + +static constexpr std::uint64_t +makeDisplayEvent(DisplayEvent id, std::uint16_t unk0 = 0, + std::uint32_t unk1 = 0x1000'0000) { + std::uint64_t result = 0; + result |= static_cast(id) << 48; + result |= static_cast(unk0) << 32; + result |= static_cast(unk1); + return result; +} + +static vk::Context createVkContext(Device *device) { + std::vector optionalLayers; + bool enableValidation = rx::g_config.validateGpu; + + glfwInit(); + glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); + const char **glfwExtensions; + uint32_t glfwExtensionCount = 0; + glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount); + std::vector requiredExtensions{ + glfwExtensions, glfwExtensions + glfwExtensionCount}; + if (enableValidation) { + optionalLayers.push_back("VK_LAYER_KHRONOS_validation"); + requiredExtensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); + } + + vk::Context result = + vk::Context::create({}, optionalLayers, requiredExtensions, {}); + vk::context = &result; + + if (enableValidation) { + VkDebugUtilsMessengerCreateInfoEXT debugUtilsMessengerCreateInfo{ + .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, + .messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT, + .messageType = + VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_DEVICE_ADDRESS_BINDING_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT, + .pfnUserCallback = debugUtilsMessageCallback, + }; + + VK_VERIFY(vk::CreateDebugUtilsMessengerEXT( + result.instance, &debugUtilsMessengerCreateInfo, vk::context->allocator, + &device->debugMessenger)); + } + + device->window = glfwCreateWindow(1920, 1080, "RPCSX", nullptr, nullptr); + glfwCreateWindowSurface(vk::context->instance, device->window, nullptr, + &device->surface); + + result.createDevice(device->surface, rx::g_config.gpuIndex, + { + // VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME, + // VK_EXT_DEPTH_CLIP_ENABLE_EXTENSION_NAME, + // VK_EXT_INLINE_UNIFORM_BLOCK_EXTENSION_NAME, + // VK_EXT_DESCRIPTOR_BUFFER_EXTENSION_NAME, + // VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME, + // VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME, + VK_EXT_SEPARATE_STENCIL_USAGE_EXTENSION_NAME, + VK_KHR_SWAPCHAIN_EXTENSION_NAME, + VK_EXT_SHADER_OBJECT_EXTENSION_NAME, + VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME, + VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME, + }, + { + VK_KHR_FRAGMENT_SHADER_BARYCENTRIC_EXTENSION_NAME, + VK_KHR_SHADER_NON_SEMANTIC_INFO_EXTENSION_NAME, + }); + + auto getTotalMemorySize = [&](int memoryType) -> VkDeviceSize { + auto deviceLocalMemoryType = + result.findPhysicalMemoryTypeIndex(~0, memoryType); + + if (deviceLocalMemoryType < 0) { + return 0; + } + + auto heapIndex = + result.physicalMemoryProperties.memoryTypes[deviceLocalMemoryType] + .heapIndex; + + return result.physicalMemoryProperties.memoryHeaps[heapIndex].size; + }; + + auto localMemoryTotalSize = + getTotalMemorySize(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + auto hostVisibleMemoryTotalSize = + getTotalMemorySize(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); + + vk::getHostVisibleMemory().initHostVisible( + std::min(hostVisibleMemoryTotalSize / 2, 1ul * 1024 * 1024 * 1024)); + vk::getDeviceLocalMemory().initDeviceLocal( + std::min(localMemoryTotalSize / 4, 4ul * 1024 * 1024 * 1024)); + + vk::context = &device->vkContext; + return result; +} + +const auto kCachePageSize = 0x100'0000'0000 / rx::mem::pageSize; + +Device::Device() : vkContext(createVkContext(this)) { + if (!shader::spv::validate(g_rdna_semantic_spirv)) { + shader::spv::dump(g_rdna_semantic_spirv, true); + rx::die("builtin semantic validation failed"); + } + + if (auto sem = shader::spv::deserialize( + shaderSemanticContext, g_rdna_semantic_spirv, + shaderSemanticContext.getUnknownLocation())) { + auto shaderSemantic = *sem; + shader::gcn::canonicalizeSemantic(shaderSemanticContext, shaderSemantic); + shader::gcn::collectSemanticModuleInfo(gcnSemanticModuleInfo, + shaderSemantic); + gcnSemantic = shader::gcn::collectSemanticInfo(gcnSemanticModuleInfo); + } else { + rx::die("failed to deserialize builtin semantics\n"); + } + + for (auto &pipe : graphicsPipes) { + pipe.device = this; + } + + for (auto &cachePage : cachePages) { + cachePage = static_cast *>( + orbis::kalloc(kCachePageSize, 1)); + std::memset(cachePage, 0, kCachePageSize); + } + + cacheUpdateThread = std::jthread([this](const std::stop_token &stopToken) { + auto &sched = graphicsPipes[0].scheduler; + while (!stopToken.stop_requested()) { + for (int vmId = 0; vmId < kMaxProcessCount; ++vmId) { + auto page = gpuCacheCommand[vmId].load(std::memory_order::relaxed); + if (page == 0) { + continue; + } + + gpuCacheCommand[vmId].store(0, std::memory_order::relaxed); + auto address = static_cast(page) * rx::mem::pageSize; + + auto range = + rx::AddressRange::fromBeginSize(address, rx::mem::pageSize); + auto tag = getCacheTag(vmId, sched); + + tag.getCache()->flushImages(tag, range); + sched.submit(); + sched.wait(); + + auto flushedRange = tag.getCache()->flushBuffers(range); + + assert(flushedRange.isValid() && flushedRange.size() > 0); + unlockReadWrite(vmId, flushedRange.beginAddress(), flushedRange.size()); + } + } + }); + + for (auto &pipe : computePipes) { + pipe.device = this; + } + + for (int i = 0; i < kGfxPipeCount; ++i) { + graphicsPipes[i].setDeQueue( + Queue{ + .base = mainGfxRings[i], + .size = sizeof(mainGfxRings[i]), + .rptr = mainGfxRings[i], + .wptr = mainGfxRings[i], + }, + 0); + } +} + +Device::~Device() { + vkDeviceWaitIdle(vk::context->device); + + if (debugMessenger != VK_NULL_HANDLE) { + vk::DestroyDebugUtilsMessengerEXT(vk::context->instance, debugMessenger, + vk::context->allocator); + } + + for (auto fd : dmemFd) { + if (fd >= 0) { + ::close(fd); + } + } + + for (auto &[pid, info] : processInfo) { + if (info.vmFd >= 0) { + ::close(info.vmFd); + } + } + + for (auto &cachePage : cachePages) { + orbis::kfree(cachePage, kCachePageSize); + } +} + +void Device::start() { + vk::context->createSwapchain(); + + for (std::size_t i = 0; i < std::size(dmemFd); ++i) { + if (dmemFd[i] != -1) { + continue; + } + + auto path = std::format("{}/dmem-{}", rx::getShmPath(), i); + if (!std::filesystem::exists(path)) { + std::println("Waiting for dmem {}", i); + + while (!std::filesystem::exists(path)) { + std::this_thread::sleep_for(std::chrono::milliseconds(300)); + } + } + + dmemFd[i] = ::open(path.c_str(), O_RDWR, S_IRUSR | S_IWUSR); + + if (dmemFd[i] < 0) { + std::println(stderr, "failed to open dmem {}", path); + std::abort(); + } + } + + std::jthread vblankThread([](const std::stop_token &stopToken) { + orbis::g_context.deviceEventEmitter->emit( + orbis::kEvFiltDisplay, 0, + makeDisplayEvent(DisplayEvent::PreVBlankStart)); + auto prevVBlank = std::chrono::steady_clock::now(); + auto period = std::chrono::seconds(1) / 59.94; + + while (!stopToken.stop_requested()) { + prevVBlank += + std::chrono::duration_cast(period); + std::this_thread::sleep_until(prevVBlank); + orbis::g_context.deviceEventEmitter->emit( + orbis::kEvFiltDisplay, 0, makeDisplayEvent(DisplayEvent::VBlank)); + } + }); + + uint32_t gpIndex = -1; + GLFWgamepadstate gpState; + + while (true) { + glfwPollEvents(); + + if (gpIndex > GLFW_JOYSTICK_LAST) { + for (int i = 0; i <= GLFW_JOYSTICK_LAST; ++i) { + if (glfwJoystickIsGamepad(i) == GLFW_TRUE) { + std::print("Gamepad \"{}\" activated", glfwGetGamepadName(i)); + gpIndex = i; + break; + } + } + } else if (gpIndex <= GLFW_JOYSTICK_LAST) { + if (!glfwJoystickIsGamepad(gpIndex)) { + gpIndex = -1; + } + } + + if (gpIndex <= GLFW_JOYSTICK_LAST) { + if (glfwGetGamepadState(gpIndex, &gpState) == GLFW_TRUE) { + kbPadState.leftStickX = + gpState.axes[GLFW_GAMEPAD_AXIS_LEFT_X] * 127.5f + 127.5f; + kbPadState.leftStickY = + gpState.axes[GLFW_GAMEPAD_AXIS_LEFT_Y] * 127.5f + 127.5f; + kbPadState.rightStickX = + gpState.axes[GLFW_GAMEPAD_AXIS_RIGHT_X] * 127.5f + 127.5f; + kbPadState.rightStickY = + gpState.axes[GLFW_GAMEPAD_AXIS_RIGHT_Y] * 127.5f + 127.5f; + kbPadState.l2 = + (gpState.axes[GLFW_GAMEPAD_AXIS_LEFT_TRIGGER] + 1.0f) * 127.5f; + kbPadState.r2 = + (gpState.axes[GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER] + 1.0f) * 127.5f; + kbPadState.buttons = 0; + + if (kbPadState.l2 == 0xFF) { + kbPadState.buttons |= kPadBtnL2; + } + + if (kbPadState.r2 == 0xFF) { + kbPadState.buttons |= kPadBtnR2; + } + + static const uint32_t gpmap[GLFW_GAMEPAD_BUTTON_LAST + 1] = { + [GLFW_GAMEPAD_BUTTON_A] = kPadBtnCross, + [GLFW_GAMEPAD_BUTTON_B] = kPadBtnCircle, + [GLFW_GAMEPAD_BUTTON_X] = kPadBtnSquare, + [GLFW_GAMEPAD_BUTTON_Y] = kPadBtnTriangle, + [GLFW_GAMEPAD_BUTTON_LEFT_BUMPER] = kPadBtnL1, + [GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER] = kPadBtnR1, + [GLFW_GAMEPAD_BUTTON_BACK] = 0, + [GLFW_GAMEPAD_BUTTON_START] = kPadBtnOptions, + [GLFW_GAMEPAD_BUTTON_GUIDE] = 0, + [GLFW_GAMEPAD_BUTTON_LEFT_THUMB] = kPadBtnL3, + [GLFW_GAMEPAD_BUTTON_RIGHT_THUMB] = kPadBtnR3, + [GLFW_GAMEPAD_BUTTON_DPAD_UP] = kPadBtnUp, + [GLFW_GAMEPAD_BUTTON_DPAD_RIGHT] = kPadBtnRight, + [GLFW_GAMEPAD_BUTTON_DPAD_DOWN] = kPadBtnDown, + [GLFW_GAMEPAD_BUTTON_DPAD_LEFT] = kPadBtnLeft}; + + for (int i = 0; i <= GLFW_GAMEPAD_BUTTON_LAST; ++i) { + if (gpState.buttons[i] == GLFW_PRESS) { + kbPadState.buttons |= gpmap[i]; + } + } + } + } else { + kbPadState.leftStickX = 0x80; + kbPadState.leftStickY = 0x80; + kbPadState.rightStickX = 0x80; + kbPadState.rightStickY = 0x80; + kbPadState.buttons = 0; + + if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) { + kbPadState.leftStickX = 0; + } else if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) { + kbPadState.leftStickX = 0xff; + } + if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) { + kbPadState.leftStickY = 0; + } else if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) { + kbPadState.leftStickY = 0xff; + } + + if (glfwGetKey(window, GLFW_KEY_O) == GLFW_PRESS) { + kbPadState.rightStickY = 0; + } else if (glfwGetKey(window, GLFW_KEY_L) == GLFW_PRESS) { + kbPadState.rightStickY = 0xff; + } + if (glfwGetKey(window, GLFW_KEY_K) == GLFW_PRESS) { + kbPadState.rightStickX = 0; + } else if (glfwGetKey(window, GLFW_KEY_SEMICOLON) == GLFW_PRESS) { + kbPadState.rightStickX = 0xff; + } + + if (glfwGetKey(window, GLFW_KEY_UP) == GLFW_PRESS) { + kbPadState.buttons |= kPadBtnUp; + } + if (glfwGetKey(window, GLFW_KEY_DOWN) == GLFW_PRESS) { + kbPadState.buttons |= kPadBtnDown; + } + if (glfwGetKey(window, GLFW_KEY_LEFT) == GLFW_PRESS) { + kbPadState.buttons |= kPadBtnLeft; + } + if (glfwGetKey(window, GLFW_KEY_RIGHT) == GLFW_PRESS) { + kbPadState.buttons |= kPadBtnRight; + } + if (glfwGetKey(window, GLFW_KEY_Z) == GLFW_PRESS) { + kbPadState.buttons |= kPadBtnSquare; + } + if (glfwGetKey(window, GLFW_KEY_X) == GLFW_PRESS) { + kbPadState.buttons |= kPadBtnCross; + } + if (glfwGetKey(window, GLFW_KEY_C) == GLFW_PRESS) { + kbPadState.buttons |= kPadBtnCircle; + } + if (glfwGetKey(window, GLFW_KEY_V) == GLFW_PRESS) { + kbPadState.buttons |= kPadBtnTriangle; + } + + if (glfwGetKey(window, GLFW_KEY_Q) == GLFW_PRESS) { + kbPadState.buttons |= kPadBtnL1; + } + if (glfwGetKey(window, GLFW_KEY_E) == GLFW_PRESS) { + kbPadState.buttons |= kPadBtnL2; + kbPadState.l2 = 0xff; + } + if (glfwGetKey(window, GLFW_KEY_F) == GLFW_PRESS) { + kbPadState.buttons |= kPadBtnL3; + } + if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) { + kbPadState.buttons |= kPadBtnPs; + } + if (glfwGetKey(window, GLFW_KEY_I) == GLFW_PRESS) { + kbPadState.buttons |= kPadBtnR1; + } + if (glfwGetKey(window, GLFW_KEY_P) == GLFW_PRESS) { + kbPadState.buttons |= kPadBtnR2; + kbPadState.r2 = 0xff; + } + if (glfwGetKey(window, GLFW_KEY_APOSTROPHE) == GLFW_PRESS) { + kbPadState.buttons |= kPadBtnR3; + } + + if (glfwGetKey(window, GLFW_KEY_ENTER) == GLFW_PRESS) { + kbPadState.buttons |= kPadBtnOptions; + } + } + + kbPadState.timestamp = + std::chrono::high_resolution_clock::now().time_since_epoch().count(); + + if (glfwWindowShouldClose(window)) { + rx::shutdown(); + break; + } + + processPipes(); + } +} + +void Device::submitCommand(Queue &ring, + std::span command) { + std::scoped_lock lock(writeCommandMtx); + if (ring.wptr + command.size() > ring.base + ring.size) { + while (ring.wptr != ring.rptr) { + } + + for (auto it = ring.wptr; it < ring.base + ring.size; ++it) { + *it = 2 << 30; + } + + ring.wptr = ring.base; + } + + std::memcpy(ring.wptr, command.data(), command.size_bytes()); + ring.wptr += command.size(); +} + +void Device::submitGfxCommand(int gfxPipe, + std::span command) { + auto &ring = graphicsPipes[gfxPipe].deQueues[2]; + submitCommand(ring, command); +} + +void Device::submitGfxCommand(int gfxPipe, int vmId, + std::span command) { + auto op = rx::getBits(command[0], 15, 8); + auto type = rx::getBits(command[0], 31, 30); + auto len = rx::getBits(command[0], 29, 16) + 2; + + if ((op != gnm::IT_INDIRECT_BUFFER && op != gnm::IT_INDIRECT_BUFFER_CNST) || + type != 3 || len != 4 || command.size() != len) { + std::println(stderr, "unexpected gfx command for main ring: {}, {}, {}", op, + type, len); + rx::die(""); + } + + std::vector patchedCommand{command.data(), + command.data() + command.size()}; + patchedCommand[3] &= ~(~0 << 24); + patchedCommand[3] |= vmId << 24; + + submitGfxCommand(gfxPipe, patchedCommand); +} + +void Device::submitSwitchBuffer(int gfxPipe) { + submitGfxCommand(gfxPipe, createPm4Packet(gnm::IT_SWITCH_BUFFER, 0)); +} +void Device::submitFlip(int gfxPipe, std::uint32_t pid, int bufferIndex, + std::uint64_t flipArg) { + submitGfxCommand(gfxPipe, + createPm4Packet(IT_FLIP, bufferIndex, flipArg & 0xffff'ffff, + flipArg >> 32, pid)); +} + +void Device::submitMapMemory(int gfxPipe, std::uint32_t pid, + std::uint64_t address, std::uint64_t size, + int memoryType, int dmemIndex, int prot, + std::int64_t offset) { + submitGfxCommand(gfxPipe, + createPm4Packet(IT_MAP_MEMORY, pid, address & 0xffff'ffff, + address >> 32, size & 0xffff'ffff, + size >> 32, memoryType, dmemIndex, prot, + offset & 0xffff'ffff, offset >> 32)); +} +void Device::submitUnmapMemory(int gfxPipe, std::uint32_t pid, + std::uint64_t address, std::uint64_t size) { + submitGfxCommand( + gfxPipe, createPm4Packet(IT_UNMAP_MEMORY, pid, address & 0xffff'ffff, + address >> 32, size & 0xffff'ffff, size >> 32)); +} + +void Device::submitMapProcess(int gfxPipe, std::uint32_t pid, int vmId) { + submitGfxCommand(gfxPipe, createPm4Packet(gnm::IT_MAP_PROCESS, pid, vmId)); +} + +void Device::submitUnmapProcess(int gfxPipe, std::uint32_t pid) { + submitGfxCommand(gfxPipe, createPm4Packet(IT_UNMAP_PROCESS, pid)); +} + +void Device::submitProtectMemory(int gfxPipe, std::uint32_t pid, + std::uint64_t address, std::uint64_t size, + int prot) { + submitGfxCommand(gfxPipe, + createPm4Packet(IT_PROTECT_MEMORY, pid, + address & 0xffff'ffff, address >> 32, + size & 0xffff'ffff, size >> 32, prot)); +} + +void Device::mapProcess(std::uint32_t pid, int vmId) { + auto &process = processInfo[pid]; + process.vmId = vmId; + + auto memory = amdgpu::RemoteMemory{vmId}; + + std::string pidVmName = std::format("{}/memory-{}", rx::getShmPath(), pid); + int memoryFd = ::open(pidVmName.c_str(), O_RDWR, S_IRUSR | S_IWUSR); + process.vmFd = memoryFd; + + if (memoryFd < 0) { + std::println("failed to open shared memory of process {}", (int)pid); + std::abort(); + } + + for (auto [startAddress, endAddress, slot] : process.vmTable) { + auto gpuProt = slot.prot >> 4; + if (gpuProt == 0) { + continue; + } + + auto devOffset = slot.offset + startAddress - slot.baseAddress; + int mapFd = memoryFd; + + if (slot.memoryType >= 0) { + mapFd = dmemFd[slot.memoryType]; + } + + auto mmapResult = + ::mmap(memory.getPointer(startAddress), endAddress - startAddress, + gpuProt, MAP_FIXED | MAP_SHARED, mapFd, devOffset); + + if (mmapResult == MAP_FAILED) { + std::println( + stderr, + "failed to map process {} memory, address {}-{}, type {:x}, vmId {}", + (int)pid, memory.getPointer(startAddress), + memory.getPointer(endAddress), slot.memoryType, vmId); + std::abort(); + } + + std::println(stderr, + "map process {} memory, address {}-{}, type {:x}, vmId {}", + (int)pid, memory.getPointer(startAddress), + memory.getPointer(endAddress), slot.memoryType, vmId); + } +} + +void Device::unmapProcess(std::uint32_t pid) { + auto &process = processInfo[pid]; + auto startAddress = static_cast(process.vmId) << 40; + auto size = static_cast(1) << 40; + rx::mem::reserve(reinterpret_cast(startAddress), size); + + ::close(process.vmFd); + process.vmFd = -1; + process.vmId = -1; +} + +void Device::protectMemory(std::uint32_t pid, std::uint64_t address, + std::uint64_t size, int prot) { + auto &process = processInfo[pid]; + + auto vmSlotIt = process.vmTable.queryArea(address); + if (vmSlotIt == process.vmTable.end()) { + std::abort(); + } + + auto vmSlot = (*vmSlotIt).payload; + + process.vmTable.map(address, address + size, + VmMapSlot{ + .memoryType = vmSlot.memoryType, + .prot = static_cast(prot), + .offset = vmSlot.offset, + .baseAddress = vmSlot.baseAddress, + }); + + if (process.vmId >= 0) { + auto memory = amdgpu::RemoteMemory{process.vmId}; + rx::mem::protect(memory.getPointer(address), size, prot >> 4); + + std::println(stderr, "protect process {} memory, address {}-{}, prot {:x}", + (int)pid, memory.getPointer(address), + memory.getPointer(address + size), prot); + } +} + +void Device::onCommandBuffer(std::uint32_t pid, int cmdHeader, + std::uint64_t address, std::uint64_t size) { + auto &process = processInfo[pid]; + if (process.vmId < 0) { + return; + } + + auto memory = RemoteMemory{process.vmId}; + + auto op = rx::getBits(cmdHeader, 15, 8); + + if (op == gnm::IT_INDIRECT_BUFFER_CNST) { + graphicsPipes[0].setCeQueue(Queue::createFromRange( + process.vmId, memory.getPointer(address), + size / sizeof(std::uint32_t))); + } else if (op == gnm::IT_INDIRECT_BUFFER) { + graphicsPipes[0].setDeQueue( + Queue::createFromRange(process.vmId, + memory.getPointer(address), + size / sizeof(std::uint32_t)), + 1); + } else { + rx::die("unimplemented command buffer %x", cmdHeader); + } +} + +bool Device::processPipes() { + bool allProcessed = true; + + for (auto &pipe : computePipes) { + if (!pipe.processAllRings()) { + allProcessed = false; + } + } + + for (auto &pipe : graphicsPipes) { + if (!pipe.processAllRings()) { + allProcessed = false; + } + } + + return allProcessed; +} + +static void +transitionImageLayout(VkCommandBuffer commandBuffer, VkImage image, + VkImageLayout oldLayout, VkImageLayout newLayout, + const VkImageSubresourceRange &subresourceRange) { + VkImageMemoryBarrier barrier{}; + barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + barrier.oldLayout = oldLayout; + barrier.newLayout = newLayout; + barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.image = image; + barrier.subresourceRange = subresourceRange; + + auto layoutToStageAccess = [](VkImageLayout layout) + -> std::pair { + switch (layout) { + case VK_IMAGE_LAYOUT_UNDEFINED: + case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR: + case VK_IMAGE_LAYOUT_GENERAL: + return {VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0}; + + case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: + return {VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT}; + + case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: + return {VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_READ_BIT}; + + case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: + return {VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_ACCESS_SHADER_READ_BIT}; + + case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: + return {VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT, + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT}; + + case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: + return {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | + VK_ACCESS_COLOR_ATTACHMENT_READ_BIT}; + + default: + std::abort(); + } + }; + + auto [sourceStage, sourceAccess] = layoutToStageAccess(oldLayout); + auto [destinationStage, destinationAccess] = layoutToStageAccess(newLayout); + + barrier.srcAccessMask = sourceAccess; + barrier.dstAccessMask = destinationAccess; + + vkCmdPipelineBarrier(commandBuffer, sourceStage, destinationStage, 0, 0, + nullptr, 0, nullptr, 1, &barrier); +} + +bool Device::flip(std::uint32_t pid, int bufferIndex, std::uint64_t arg, + VkImage swapchainImage, VkImageView swapchainImageView) { + auto &pipe = graphicsPipes[0]; + auto &scheduler = pipe.scheduler; + auto &process = processInfo[pid]; + if (process.vmId < 0) { + return false; + } + + if (bufferIndex < 0) { + flipBuffer[process.vmId] = bufferIndex; + flipArg[process.vmId] = arg; + flipCount[process.vmId] = flipCount[process.vmId] + 1; + return false; + } + + auto &buffer = process.buffers[bufferIndex]; + auto &bufferAttr = process.bufferAttributes[buffer.attrId]; + + gnm::DataFormat dfmt; + gnm::NumericFormat nfmt; + auto flipType = FlipType::Alt; + switch (bufferAttr.pixelFormat) { + case 0x80000000: + dfmt = gnm::kDataFormat8_8_8_8; + nfmt = gnm::kNumericFormatSrgb; + break; + + case 0x80002200: + dfmt = gnm::kDataFormat8_8_8_8; + nfmt = gnm::kNumericFormatSrgb; + flipType = FlipType::Std; + break; + + case 0x88740000: + case 0x88060000: + dfmt = gnm::kDataFormat2_10_10_10; + nfmt = gnm::kNumericFormatSNorm; + break; + + case 0x88000000: + dfmt = gnm::kDataFormat2_10_10_10; + nfmt = gnm::kNumericFormatSrgb; + break; + + case 0xc1060000: + dfmt = gnm::kDataFormat16_16_16_16; + nfmt = gnm::kNumericFormatFloat; + break; + + default: + rx::die("unimplemented color buffer format %x", bufferAttr.pixelFormat); + } + + // std::printf("displaying buffer %lx\n", buffer.address); + + auto cacheTag = getCacheTag(process.vmId, scheduler); + auto &sched = cacheTag.getScheduler(); + + transitionImageLayout(sched.getCommandBuffer(), swapchainImage, + VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .levelCount = 1, + .layerCount = 1, + }); + + amdgpu::flip( + cacheTag, vk::context->swapchainExtent, buffer.address, + swapchainImageView, {bufferAttr.width, bufferAttr.height}, flipType, + getDefaultTileModes()[bufferAttr.tilingMode == 1 ? 10 : 8], dfmt, nfmt); + + transitionImageLayout(sched.getCommandBuffer(), swapchainImage, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, + { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .levelCount = 1, + .layerCount = 1, + }); + + sched.submit(); + + auto submitCompleteTask = scheduler.createExternalSubmit(); + + { + VkSemaphoreSubmitInfo waitSemSubmitInfos[] = { + { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, + .semaphore = vk::context->presentCompleteSemaphore, + .value = 1, + .stageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, + }, + { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, + .semaphore = scheduler.getSemaphoreHandle(), + .value = submitCompleteTask - 1, + .stageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT, + }, + }; + + VkSemaphoreSubmitInfo signalSemSubmitInfos[] = { + { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, + .semaphore = vk::context->renderCompleteSemaphore, + .value = 1, + .stageMask = VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT, + }, + { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO, + .semaphore = scheduler.getSemaphoreHandle(), + .value = submitCompleteTask, + .stageMask = VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT, + }, + }; + + VkSubmitInfo2 submitInfo{ + .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO_2, + .waitSemaphoreInfoCount = 2, + .pWaitSemaphoreInfos = waitSemSubmitInfos, + .signalSemaphoreInfoCount = 2, + .pSignalSemaphoreInfos = signalSemSubmitInfos, + }; + + vkQueueSubmit2(vk::context->presentQueue, 1, &submitInfo, VK_NULL_HANDLE); + } + + scheduler.then([=, this, cacheTag = std::move(cacheTag)] { + flipBuffer[process.vmId] = bufferIndex; + flipArg[process.vmId] = arg; + flipCount[process.vmId] = flipCount[process.vmId] + 1; + + auto mem = RemoteMemory{process.vmId}; + auto bufferInUse = + mem.getPointer(bufferInUseAddress[process.vmId]); + if (bufferInUse != nullptr) { + bufferInUse[bufferIndex] = 0; + } + }); + + return true; +} + +void Device::flip(std::uint32_t pid, int bufferIndex, std::uint64_t arg) { + if (!isImageAcquired) { + while (true) { + auto acquireNextImageResult = vkAcquireNextImageKHR( + vk::context->device, vk::context->swapchain, UINT64_MAX, + vk::context->presentCompleteSemaphore, VK_NULL_HANDLE, &imageIndex); + if (acquireNextImageResult == VK_ERROR_OUT_OF_DATE_KHR) { + vk::context->recreateSwapchain(); + continue; + } + + if (acquireNextImageResult != VK_SUBOPTIMAL_KHR) { + VK_VERIFY(acquireNextImageResult); + } + break; + } + } + + bool flipComplete = + flip(pid, bufferIndex, arg, vk::context->swapchainImages[imageIndex], + vk::context->swapchainImageViews[imageIndex]); + + orbis::g_context.deviceEventEmitter->emit( + orbis::kEvFiltDisplay, 0, makeDisplayEvent(DisplayEvent::Flip)); + if (!flipComplete) { + isImageAcquired = true; + return; + } + + isImageAcquired = false; + + VkPresentInfoKHR presentInfo{ + .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, + .waitSemaphoreCount = 1, + .pWaitSemaphores = &vk::context->renderCompleteSemaphore, + .swapchainCount = 1, + .pSwapchains = &vk::context->swapchain, + .pImageIndices = &imageIndex, + }; + + auto vkQueuePresentResult = + vkQueuePresentKHR(vk::context->presentQueue, &presentInfo); + + if (vkQueuePresentResult == VK_ERROR_OUT_OF_DATE_KHR || + vkQueuePresentResult == VK_SUBOPTIMAL_KHR) { + vk::context->recreateSwapchain(); + } else { + VK_VERIFY(vkQueuePresentResult); + } +} + +void Device::waitForIdle() { + while (true) { + bool allProcessed = true; + for (auto &queue : graphicsPipes[0].deQueues) { + if (queue.wptr != queue.rptr) { + allProcessed = false; + } + } + + if (allProcessed) { + break; + } + } +} + +void Device::mapMemory(std::uint32_t pid, std::uint64_t address, + std::uint64_t size, int memoryType, int dmemIndex, + int prot, std::int64_t offset) { + auto &process = processInfo[pid]; + + process.vmTable.map(address, address + size, + VmMapSlot{ + .memoryType = memoryType >= 0 ? dmemIndex : -1, + .prot = prot, + .offset = offset, + .baseAddress = address, + }); + + if (process.vmId < 0) { + return; + } + + auto memory = amdgpu::RemoteMemory{process.vmId}; + + int mapFd = process.vmFd; + + if (memoryType >= 0) { + mapFd = dmemFd[dmemIndex]; + } + + auto mmapResult = ::mmap(memory.getPointer(address), size, prot >> 4, + MAP_FIXED | MAP_SHARED, mapFd, offset); + + if (mmapResult == MAP_FAILED) { + perror("::mmap"); + + rx::mem::printStats(); + rx::die("failed to map process %u memory, address %p-%p, type %x, offset " + "%lx, prot %x", + (int)pid, memory.getPointer(address), + memory.getPointer(address + size), memoryType, offset, prot); + } + + std::println(stderr, "map memory of process {}, address {}-{}, prot {:x}", + (int)pid, memory.getPointer(address), + memory.getPointer(address + size), prot); +} + +void Device::unmapMemory(std::uint32_t pid, std::uint64_t address, + std::uint64_t size) { + // TODO + protectMemory(pid, address, size, 0); +} + +void Device::registerBuffer(std::uint32_t pid, Buffer buffer) { + auto &process = processInfo[pid]; + + if (buffer.attrId >= 10 || buffer.index >= 10) { + rx::die("out of buffers %u, %u", buffer.attrId, buffer.index); + } + + process.buffers[buffer.index] = buffer; +} + +void Device::registerBufferAttribute(std::uint32_t pid, BufferAttribute attr) { + auto &process = processInfo[pid]; + if (attr.attrId >= 10) { + rx::die("out of buffer attributes %u", attr.attrId); + } + + process.bufferAttributes[attr.attrId] = attr; +} + +static void notifyPageChanges(Device *device, int vmId, std::uint32_t firstPage, + std::uint32_t pageCount) { + std::uint64_t command = + (static_cast(pageCount - 1) << 32) | firstPage; + + while (true) { + for (std::size_t i = 0; i < std::size(device->cacheCommands); ++i) { + std::uint64_t expCommand = 0; + if (device->cacheCommands[vmId][i].compare_exchange_strong( + expCommand, command, std::memory_order::acquire, + std::memory_order::relaxed)) { + return; + } + } + } +} + +static void modifyWatchFlags(Device *device, int vmId, std::uint64_t address, + std::uint64_t size, std::uint8_t addFlags, + std::uint8_t removeFlags) { + auto firstPage = address / rx::mem::pageSize; + auto lastPage = (address + size + rx::mem::pageSize - 1) / rx::mem::pageSize; + bool hasChanges = false; + for (auto page = firstPage; page < lastPage; ++page) { + auto prevValue = + device->cachePages[vmId][page].load(std::memory_order::relaxed); + auto newValue = (prevValue & ~removeFlags) | addFlags; + + if (newValue == prevValue) { + continue; + } + + while (!device->cachePages[vmId][page].compare_exchange_weak( + prevValue, newValue, std::memory_order::relaxed)) { + newValue = (prevValue & ~removeFlags) | addFlags; + } + + if (newValue != prevValue) { + hasChanges = true; + } + } + + if (hasChanges) { + notifyPageChanges(device, vmId, firstPage, lastPage - firstPage); + } +} + +void Device::watchWrites(int vmId, std::uint64_t address, std::uint64_t size) { + modifyWatchFlags(this, vmId, address, size, kPageWriteWatch, + kPageInvalidated); +} +void Device::lockReadWrite(int vmId, std::uint64_t address, std::uint64_t size, + bool isLazy) { + modifyWatchFlags(this, vmId, address, size, + kPageReadWriteLock | (isLazy ? kPageLazyLock : 0), + kPageInvalidated); +} +void Device::unlockReadWrite(int vmId, std::uint64_t address, + std::uint64_t size) { + modifyWatchFlags(this, vmId, address, size, kPageWriteWatch, + kPageReadWriteLock | kPageLazyLock); +} diff --git a/rpcsx/gpu/Device.hpp b/rpcsx/gpu/Device.hpp new file mode 100644 index 0000000..8e62162 --- /dev/null +++ b/rpcsx/gpu/Device.hpp @@ -0,0 +1,224 @@ +#pragma once +#include "Cache.hpp" +#include "FlipPipeline.hpp" +#include "Pipe.hpp" +#include "amdgpu/tiler_vulkan.hpp" +#include "orbis/KernelAllocator.hpp" +#include "orbis/utils/Rc.hpp" +#include "orbis/utils/SharedMutex.hpp" +#include "rx/MemoryTable.hpp" +#include "shader/SemanticInfo.hpp" +#include "shader/SpvConverter.hpp" +#include "shader/gcn.hpp" +#include +#include +#include +#include +#include + +namespace amdgpu { + +enum : std::uint8_t { + IT_FLIP = 0xF0, + IT_MAP_MEMORY, + IT_UNMAP_MEMORY, + IT_PROTECT_MEMORY, + IT_UNMAP_PROCESS, +}; + +template + requires(sizeof...(T) > 0) +std::array createPm4Packet(std::uint32_t op, + T... data) { + return {static_cast((3 << 30) | (op << 8) | + ((sizeof...(T) - 1) << 16)), + static_cast(data)...}; +} + +struct VmMapSlot { + int memoryType; + int prot; + std::int64_t offset; + std::uint64_t baseAddress; + + auto operator<=>(const VmMapSlot &) const = default; +}; + +struct BufferAttribute { + std::uint8_t attrId; + std::uint8_t submit; + std::uint64_t canary; + std::uint32_t pixelFormat; + std::uint32_t tilingMode; + std::uint32_t pitch; + std::uint32_t width; + std::uint32_t height; +}; + +struct Buffer { + std::uint64_t canary; + std::uint32_t index; + std::uint32_t attrId; + std::uint64_t address; + std::uint64_t address2; +}; + +struct ProcessInfo { + int vmId = -1; + int vmFd = -1; + BufferAttribute bufferAttributes[10]; + Buffer buffers[10]; + rx::MemoryTableWithPayload vmTable; +}; + +enum { + kPageWriteWatch = 1 << 0, + kPageReadWriteLock = 1 << 1, + kPageInvalidated = 1 << 2, + kPageLazyLock = 1 << 3 +}; + +struct PadState { + std::uint64_t timestamp; + std::uint32_t unk; + std::uint32_t buttons; + std::uint8_t leftStickX; + std::uint8_t leftStickY; + std::uint8_t rightStickX; + std::uint8_t rightStickY; + std::uint8_t l2; + std::uint8_t r2; +}; + +enum { + kPadBtnL3 = 1 << 1, + kPadBtnR3 = 1 << 2, + kPadBtnOptions = 1 << 3, + kPadBtnUp = 1 << 4, + kPadBtnRight = 1 << 5, + kPadBtnDown = 1 << 6, + kPadBtnLeft = 1 << 7, + kPadBtnL2 = 1 << 8, + kPadBtnR2 = 1 << 9, + kPadBtnL1 = 1 << 10, + kPadBtnR1 = 1 << 11, + kPadBtnTriangle = 1 << 12, + kPadBtnCircle = 1 << 13, + kPadBtnCross = 1 << 14, + kPadBtnSquare = 1 << 15, + kPadBtnPs = 1 << 16, + kPadBtnTouchPad = 1 << 20, + kPadBtnIntercepted = 1 << 31, +}; + +struct RemoteMemory { + int vmId; + + template T *getPointer(std::uint64_t address) const { + return address ? reinterpret_cast( + static_cast(vmId) << 40 | address) + : nullptr; + } +}; + +struct Device : orbis::RcBase { + static constexpr auto kComputePipeCount = 8; + static constexpr auto kGfxPipeCount = 2; + static constexpr auto kMaxProcessCount = 6; + + shader::SemanticInfo gcnSemantic; + shader::spv::Context shaderSemanticContext; + shader::gcn::SemanticModuleInfo gcnSemanticModuleInfo; + Registers::Config config; + GLFWwindow *window = nullptr; + VkSurfaceKHR surface = VK_NULL_HANDLE; + VkDebugUtilsMessengerEXT debugMessenger = VK_NULL_HANDLE; + vk::Context vkContext; + + GpuTiler tiler; + GraphicsPipe graphicsPipes[kGfxPipeCount]{0, 1}; + ComputePipe computePipes[kComputePipeCount]{0, 1, 2, 3, 4, 5, 6, 7}; + FlipPipeline flipPipeline; + + orbis::shared_mutex writeCommandMtx; + uint32_t imageIndex = 0; + bool isImageAcquired = false; + + std::jthread cacheUpdateThread; + + int dmemFd[3] = {-1, -1, -1}; + orbis::kmap processInfo; + + Cache caches[kMaxProcessCount]{ + {this, 0}, {this, 1}, {this, 2}, {this, 3}, {this, 4}, {this, 5}, + }; + + PadState kbPadState; + std::atomic cacheCommands[kMaxProcessCount][4]; + std::atomic gpuCacheCommand[kMaxProcessCount]; + std::atomic *cachePages[kMaxProcessCount]; + + volatile std::uint32_t flipBuffer[kMaxProcessCount]; + volatile std::uint64_t flipArg[kMaxProcessCount]; + volatile std::uint64_t flipCount[kMaxProcessCount]; + volatile std::uint64_t bufferInUseAddress[kMaxProcessCount]; + + std::uint32_t mainGfxRings[kGfxPipeCount][0x4000 / sizeof(std::uint32_t)]; + + Device(); + ~Device(); + + void start(); + + Cache::Tag getCacheTag(int vmId, Scheduler &scheduler) { + return caches[vmId].createTag(scheduler); + } + + Cache::GraphicsTag getGraphicsTag(int vmId, Scheduler &scheduler) { + return caches[vmId].createGraphicsTag(scheduler); + } + + Cache::ComputeTag getComputeTag(int vmId, Scheduler &scheduler) { + return caches[vmId].createComputeTag(scheduler); + } + + void submitCommand(Queue &ring, std::span command); + void submitGfxCommand(int gfxPipe, std::span command); + void submitGfxCommand(int gfxPipe, int vmId, + std::span command); + void submitSwitchBuffer(int gfxPipe); + void submitFlip(int gfxPipe, std::uint32_t pid, int bufferIndex, + std::uint64_t flipArg); + void submitMapMemory(int gfxPipe, std::uint32_t pid, std::uint64_t address, + std::uint64_t size, int memoryType, int dmemIndex, + int prot, std::int64_t offset); + void submitUnmapMemory(int gfxPipe, std::uint32_t pid, std::uint64_t address, + std::uint64_t size); + void submitMapProcess(int gfxPipe, std::uint32_t pid, int vmId); + void submitUnmapProcess(int gfxPipe, std::uint32_t pid); + void submitProtectMemory(int gfxPipe, std::uint32_t pid, + std::uint64_t address, std::uint64_t size, int prot); + + void mapProcess(std::uint32_t pid, int vmId); + void unmapProcess(std::uint32_t pid); + void protectMemory(std::uint32_t pid, std::uint64_t address, + std::uint64_t size, int prot); + void onCommandBuffer(std::uint32_t pid, int cmdHeader, std::uint64_t address, + std::uint64_t size); + bool processPipes(); + bool flip(std::uint32_t pid, int bufferIndex, std::uint64_t arg, + VkImage swapchainImage, VkImageView swapchainImageView); + void flip(std::uint32_t pid, int bufferIndex, std::uint64_t arg); + void waitForIdle(); + void mapMemory(std::uint32_t pid, std::uint64_t address, std::uint64_t size, + int memoryType, int dmemIndex, int prot, std::int64_t offset); + void unmapMemory(std::uint32_t pid, std::uint64_t address, + std::uint64_t size); + void registerBuffer(std::uint32_t pid, Buffer buffer); + void registerBufferAttribute(std::uint32_t pid, BufferAttribute attr); + void watchWrites(int vmId, std::uint64_t address, std::uint64_t size); + void lockReadWrite(int vmId, std::uint64_t address, std::uint64_t size, + bool isLazy); + void unlockReadWrite(int vmId, std::uint64_t address, std::uint64_t size); +}; +} // namespace amdgpu diff --git a/rpcsx-gpu/FlipPipeline.cpp b/rpcsx/gpu/FlipPipeline.cpp similarity index 100% rename from rpcsx-gpu/FlipPipeline.cpp rename to rpcsx/gpu/FlipPipeline.cpp diff --git a/rpcsx-gpu/FlipPipeline.hpp b/rpcsx/gpu/FlipPipeline.hpp similarity index 100% rename from rpcsx-gpu/FlipPipeline.hpp rename to rpcsx/gpu/FlipPipeline.hpp diff --git a/rpcsx-gpu/Pipe.cpp b/rpcsx/gpu/Pipe.cpp similarity index 86% rename from rpcsx-gpu/Pipe.cpp rename to rpcsx/gpu/Pipe.cpp index 5a91d6f..81ee2c6 100644 --- a/rpcsx-gpu/Pipe.cpp +++ b/rpcsx/gpu/Pipe.cpp @@ -4,15 +4,29 @@ #include "Renderer.hpp" #include "gnm/mmio.hpp" #include "gnm/pm4.hpp" +#include "orbis/KernelContext.hpp" #include "vk.hpp" #include #include +#include #include #include #include using namespace amdgpu; +enum GraphicsCoreEvent { + kGcEventCompute0RelMem = 0x00, + kGcEventCompute1RelMem = 0x01, + kGcEventCompute2RelMem = 0x02, + kGcEventCompute3RelMem = 0x03, + kGcEventCompute4RelMem = 0x04, + kGcEventCompute5RelMem = 0x05, + kGcEventCompute6RelMem = 0x06, + kGcEventGfxEop = 0x40, + kGcEventClockSet = 0x84, +}; + static Scheduler createGfxScheduler(int index) { auto queue = vk::context->presentQueue; auto family = vk::context->presentQueueFamily; @@ -31,6 +45,12 @@ static Scheduler createGfxScheduler(int index) { static Scheduler createComputeScheduler(int index) { auto &compQueues = vk::context->computeQueues; + + if (compQueues.empty()) { + // Workaround for LLVM device + return createGfxScheduler(index); + } + auto [queue, family] = compQueues[index % compQueues.size()]; return Scheduler{queue, family}; @@ -142,8 +162,9 @@ GraphicsPipe::GraphicsPipe(int index) : scheduler(createGfxScheduler(index)) { processorHandlers[gnm::IT_NOP] = &GraphicsPipe::handleNop; } - auto &dataHandlers = commandHandlers[2]; - auto &deHandlers = commandHandlers[1]; + auto &dataHandlers = commandHandlers[3]; + auto &deHandlers = commandHandlers[2]; + auto &mainHandlers = commandHandlers[1]; auto &ceHandlers = commandHandlers[0]; deHandlers[gnm::IT_SET_BASE] = &GraphicsPipe::setBase; @@ -175,7 +196,8 @@ GraphicsPipe::GraphicsPipe(int index) : scheduler(createGfxScheduler(index)) { deHandlers[gnm::IT_NUM_INSTANCES] = &GraphicsPipe::numInstances; deHandlers[gnm::IT_DRAW_INDEX_MULTI_AUTO] = &GraphicsPipe::drawIndexMultiAuto; - // IT_INDIRECT_BUFFER_CNST + mainHandlers[gnm::IT_INDIRECT_BUFFER_CNST] = + &GraphicsPipe::indirectBufferConst; // IT_STRMOUT_BUFFER_UPDATE deHandlers[gnm::IT_DRAW_INDEX_OFFSET_2] = &GraphicsPipe::drawIndexOffset2; @@ -186,6 +208,7 @@ GraphicsPipe::GraphicsPipe(int index) : scheduler(createGfxScheduler(index)) { // IT_COPY_DW deHandlers[gnm::IT_WAIT_REG_MEM] = &GraphicsPipe::waitRegMem; deHandlers[gnm::IT_INDIRECT_BUFFER] = &GraphicsPipe::indirectBuffer; + mainHandlers[gnm::IT_INDIRECT_BUFFER] = &GraphicsPipe::indirectBuffer; // IT_COPY_DATA deHandlers[gnm::IT_PFP_SYNC_ME] = &GraphicsPipe::pfpSyncMe; // IT_SURFACE_SYNC @@ -216,11 +239,15 @@ GraphicsPipe::GraphicsPipe(int index) : scheduler(createGfxScheduler(index)) { deHandlers[gnm::IT_WAIT_ON_CE_COUNTER] = &GraphicsPipe::waitOnCeCounter; deHandlers[gnm::IT_SET_CE_DE_COUNTERS] = &GraphicsPipe::setCeDeCounters; // IT_WAIT_ON_AVAIL_BUFFER - // IT_SWITCH_BUFFER + mainHandlers[gnm::IT_SWITCH_BUFFER] = &GraphicsPipe::switchBuffer; // IT_SET_RESOURCES - // IT_MAP_PROCESS - // IT_MAP_QUEUES - // IT_UNMAP_QUEUES + mainHandlers[gnm::IT_MAP_PROCESS] = &GraphicsPipe::mapProcess; + mainHandlers[gnm::IT_MAP_QUEUES] = &GraphicsPipe::mapQueues; + mainHandlers[gnm::IT_UNMAP_QUEUES] = &GraphicsPipe::unmapQueues; + mainHandlers[IT_MAP_MEMORY] = &GraphicsPipe::mapMemory; + mainHandlers[IT_UNMAP_MEMORY] = &GraphicsPipe::unmapMemory; + mainHandlers[IT_PROTECT_MEMORY] = &GraphicsPipe::protectMemory; + mainHandlers[IT_UNMAP_PROCESS] = &GraphicsPipe::unmapProcess; // IT_QUERY_STATUS // IT_RUN_LIST // IT_DISPATCH_DRAW_PREAMBLE @@ -232,6 +259,8 @@ GraphicsPipe::GraphicsPipe(int index) : scheduler(createGfxScheduler(index)) { ceHandlers[gnm::IT_LOAD_CONST_RAM] = &GraphicsPipe::loadConstRam; ceHandlers[gnm::IT_WRITE_CONST_RAM] = &GraphicsPipe::writeConstRam; ceHandlers[gnm::IT_DUMP_CONST_RAM] = &GraphicsPipe::dumpConstRam; + + mainHandlers[IT_FLIP] = &GraphicsPipe::flip; } void GraphicsPipe::setCeQueue(Queue queue) { @@ -289,9 +318,7 @@ bool GraphicsPipe::processAllRings() { } } - for (int i = 0; i < 3; ++i) { - auto &queue = deQueues[i]; - + for (auto &queue : deQueues) { if (queue.rptr == queue.wptr) { continue; } @@ -308,16 +335,17 @@ bool GraphicsPipe::processAllRings() { } void GraphicsPipe::processRing(Queue &queue) { - auto cp = 1; + int cp; if (queue.indirectLevel < 0) { cp = 0; - } else if (queue.indirectLevel == 2) { - cp = 2; + } else { + cp = queue.indirectLevel + 1; } while (queue.rptr != queue.wptr) { if (queue.rptr >= queue.base + queue.size) { queue.rptr = queue.base; + continue; } auto header = *queue.rptr; @@ -327,8 +355,11 @@ void GraphicsPipe::processRing(Queue &queue) { auto op = rx::getBits(header, 15, 8); auto len = rx::getBits(header, 29, 16) + 2; - // std::fprintf(stderr, "queue %d: %s\n", queue.indirectLevel, - // gnm::pm4OpcodeToString(op)); + // if (auto str = gnm::pm4OpcodeToString(op)) { + // std::println(stderr, "queue {}: {}", queue.indirectLevel, str); + // } else { + // std::println(stderr, "queue {}: {:x}", queue.indirectLevel, op); + // } if (op == gnm::IT_COND_EXEC) { rx::die("unimplemented COND_EXEC"); @@ -353,7 +384,10 @@ void GraphicsPipe::processRing(Queue &queue) { continue; } - rx::die("unexpected pm4 packet type %u", type); + rx::die("unexpected pm4 packet type %u, ring %u, header %u, rptr %p, wptr " + "%p, base %p", + type, queue.indirectLevel, header, queue.rptr, queue.wptr, + queue.base); } } @@ -707,17 +741,38 @@ bool GraphicsPipe::waitRegMem(Queue &queue) { return compare(function, pollData, mask, reference); } + +bool GraphicsPipe::indirectBufferConst(Queue &queue) { + rx::dieIf(queue.indirectLevel < 0, "unexpected indirect buffer from CP"); + + auto addressLo = queue.rptr[1] & ~3; + auto addressHi = queue.rptr[2] & ((1 << 8) - 1); + int vmId = queue.rptr[3] >> 24; + auto ibSize = queue.rptr[3] & ((1 << 20) - 1); + auto address = addressLo | (static_cast(addressHi) << 32); + + if (queue.indirectLevel != 0) { + vmId = queue.vmId; + } + + auto rptr = RemoteMemory{vmId}.getPointer(address); + setCeQueue(Queue::createFromRange(vmId, rptr, ibSize)); + return true; +} bool GraphicsPipe::indirectBuffer(Queue &queue) { rx::dieIf(queue.indirectLevel < 0, "unexpected indirect buffer from CP"); auto addressLo = queue.rptr[1] & ~3; - auto addressHi = queue.rptr[2] & ((1 << 16) - 1); - auto vmId = queue.rptr[3] >> 24; - auto ibSize = queue.rptr[4] & ((1 << 20) - 1); + auto addressHi = queue.rptr[2] & ((1 << 8) - 1); + int vmId = queue.rptr[3] >> 24; + auto ibSize = queue.rptr[3] & ((1 << 20) - 1); auto address = addressLo | (static_cast(addressHi) << 32); - auto rptr = RemoteMemory{queue.vmId}.getPointer(address); - setDeQueue(Queue::createFromRange(queue.vmId, rptr, ibSize), + if (queue.indirectLevel != 0) { + vmId = queue.vmId; + } + auto rptr = RemoteMemory{vmId}.getPointer(address); + setDeQueue(Queue::createFromRange(vmId, rptr, ibSize), queue.indirectLevel + 1); return true; } @@ -834,6 +889,11 @@ bool GraphicsPipe::eventWriteEop(Queue &queue) { rx::die("unimplemented event write eop data %#x", dataSel); } + if (intSel) { + orbis::g_context.deviceEventEmitter->emit(orbis::kEvFiltGraphicsCore, 0, + kGcEventGfxEop); + } + return true; } @@ -1056,15 +1116,15 @@ bool GraphicsPipe::setUConfigReg(Queue &queue) { auto data = queue.rptr + 2; if (index != 0) { - std::fprintf( + std::println( stderr, - "set UConfig regs with index, offset: %x, count %u, index %u, %s\n", + "set UConfig regs with index, offset: {:x}, count {}, index {}, {}", offset, len, index, gnm::mmio::registerName(decltype(uConfig)::kMmioOffset + offset)); for (std::size_t i = 0; i < len; ++i) { - std::fprintf( - stderr, "writing to %s value %x\n", + std::println( + stderr, "writing to {} value {:x}", gnm::mmio::registerName(decltype(uConfig)::kMmioOffset + offset + i), data[i]); } @@ -1092,15 +1152,15 @@ bool GraphicsPipe::setContextReg(Queue &queue) { auto data = queue.rptr + 2; if (index != 0) { - std::fprintf( + std::println( stderr, - "set Context regs with index, offset: %x, count %u, index %u, %s\n", + "set Context regs with index, offset: {:x}, count {}, index {}, {}", offset, len, index, gnm::mmio::registerName(decltype(context)::kMmioOffset + offset)); for (std::size_t i = 0; i < len; ++i) { - std::fprintf( - stderr, "writing to %s value %x\n", + std::println( + stderr, "writing to {} value {:x}", gnm::mmio::registerName(decltype(context)::kMmioOffset + offset + i), data[i]); } @@ -1195,3 +1255,87 @@ bool GraphicsPipe::unknownPacket(Queue &queue) { rx::die("unimplemented gfx pm4 packet: %s, queue %u\n", gnm::pm4OpcodeToString(op), queue.indirectLevel); } + +bool GraphicsPipe::switchBuffer(Queue &queue) { + // FIXME: implement + return true; +} + +bool GraphicsPipe::mapProcess(Queue &queue) { + auto pid = queue.rptr[1]; + int vmId = queue.rptr[2]; + + device->mapProcess(pid, vmId); + return true; +} + +bool GraphicsPipe::mapQueues(Queue &queue) { + // FIXME: implement + return true; +} + +bool GraphicsPipe::unmapQueues(Queue &queue) { + // FIXME: implement + return true; +} + +bool GraphicsPipe::mapMemory(Queue &queue) { + auto pid = queue.rptr[1]; + auto addressLo = queue.rptr[2]; + auto addressHi = queue.rptr[3]; + auto sizeLo = queue.rptr[4]; + auto sizeHi = queue.rptr[5]; + auto memoryType = queue.rptr[6]; + auto dmemIndex = queue.rptr[7]; + auto prot = queue.rptr[8]; + auto offsetLo = queue.rptr[9]; + auto offsetHi = queue.rptr[10]; + + auto address = addressLo | (static_cast(addressHi) << 32); + auto size = sizeLo | (static_cast(sizeHi) << 32); + auto offset = offsetLo | (static_cast(offsetHi) << 32); + + device->mapMemory(pid, address, size, memoryType, dmemIndex, prot, offset); + return true; +} +bool GraphicsPipe::unmapMemory(Queue &queue) { + auto pid = queue.rptr[1]; + auto addressLo = queue.rptr[2]; + auto addressHi = queue.rptr[3]; + auto sizeLo = queue.rptr[4]; + auto sizeHi = queue.rptr[5]; + + auto address = addressLo | (static_cast(addressHi) << 32); + auto size = sizeLo | (static_cast(sizeHi) << 32); + device->unmapMemory(pid, address, size); + return true; +} +bool GraphicsPipe::protectMemory(Queue &queue) { + auto pid = queue.rptr[1]; + auto addressLo = queue.rptr[2]; + auto addressHi = queue.rptr[3]; + auto sizeLo = queue.rptr[4]; + auto sizeHi = queue.rptr[5]; + auto prot = queue.rptr[6]; + auto address = addressLo | (static_cast(addressHi) << 32); + auto size = sizeLo | (static_cast(sizeHi) << 32); + + device->protectMemory(pid, address, size, prot); + return true; +} +bool GraphicsPipe::unmapProcess(Queue &queue) { + auto pid = queue.rptr[1]; + device->unmapProcess(pid); + return true; +} + +bool GraphicsPipe::flip(Queue &queue) { + auto buffer = queue.rptr[1]; + auto dataLo = queue.rptr[2]; + auto dataHi = queue.rptr[3]; + auto pid = queue.rptr[4]; + auto data = dataLo | (static_cast(dataHi) << 32); + + device->flip(pid, buffer, data); + return true; +} diff --git a/rpcsx-gpu/Pipe.hpp b/rpcsx/gpu/Pipe.hpp similarity index 89% rename from rpcsx-gpu/Pipe.hpp rename to rpcsx/gpu/Pipe.hpp index ef9a564..1dc9e44 100644 --- a/rpcsx-gpu/Pipe.hpp +++ b/rpcsx/gpu/Pipe.hpp @@ -75,7 +75,7 @@ struct GraphicsPipe { Queue ceQueue; using CommandHandler = bool (GraphicsPipe::*)(Queue &); - CommandHandler commandHandlers[3][255]; + CommandHandler commandHandlers[4][255]; GraphicsPipe(int index); @@ -96,6 +96,7 @@ struct GraphicsPipe { bool writeData(Queue &queue); bool memSemaphore(Queue &queue); bool waitRegMem(Queue &queue); + bool indirectBufferConst(Queue &queue); bool indirectBuffer(Queue &queue); bool condWrite(Queue &queue); bool eventWrite(Queue &queue); @@ -130,6 +131,16 @@ struct GraphicsPipe { bool unknownPacket(Queue &queue); + bool switchBuffer(Queue &queue); + bool mapProcess(Queue &queue); + bool mapQueues(Queue &queue); + bool unmapQueues(Queue &queue); + bool mapMemory(Queue &queue); + bool unmapMemory(Queue &queue); + bool protectMemory(Queue &queue); + bool unmapProcess(Queue &queue); + bool flip(Queue &queue); + std::uint32_t *getMmRegister(std::uint32_t dwAddress); }; } // namespace amdgpu \ No newline at end of file diff --git a/rpcsx-gpu/Registers.cpp b/rpcsx/gpu/Registers.cpp similarity index 100% rename from rpcsx-gpu/Registers.cpp rename to rpcsx/gpu/Registers.cpp diff --git a/rpcsx-gpu/Registers.hpp b/rpcsx/gpu/Registers.hpp similarity index 100% rename from rpcsx-gpu/Registers.hpp rename to rpcsx/gpu/Registers.hpp diff --git a/rpcsx-gpu/Renderer.cpp b/rpcsx/gpu/Renderer.cpp similarity index 100% rename from rpcsx-gpu/Renderer.cpp rename to rpcsx/gpu/Renderer.cpp diff --git a/rpcsx-gpu/Renderer.hpp b/rpcsx/gpu/Renderer.hpp similarity index 100% rename from rpcsx-gpu/Renderer.hpp rename to rpcsx/gpu/Renderer.hpp diff --git a/rpcsx-gpu/lib/CMakeLists.txt b/rpcsx/gpu/lib/CMakeLists.txt similarity index 100% rename from rpcsx-gpu/lib/CMakeLists.txt rename to rpcsx/gpu/lib/CMakeLists.txt diff --git a/rpcsx-gpu/lib/amdgpu-tiler/CMakeLists.txt b/rpcsx/gpu/lib/amdgpu-tiler/CMakeLists.txt similarity index 100% rename from rpcsx-gpu/lib/amdgpu-tiler/CMakeLists.txt rename to rpcsx/gpu/lib/amdgpu-tiler/CMakeLists.txt diff --git a/rpcsx-gpu/lib/amdgpu-tiler/include/amdgpu/tiler.hpp b/rpcsx/gpu/lib/amdgpu-tiler/include/amdgpu/tiler.hpp similarity index 100% rename from rpcsx-gpu/lib/amdgpu-tiler/include/amdgpu/tiler.hpp rename to rpcsx/gpu/lib/amdgpu-tiler/include/amdgpu/tiler.hpp diff --git a/rpcsx-gpu/lib/amdgpu-tiler/include/amdgpu/tiler_cpu.hpp b/rpcsx/gpu/lib/amdgpu-tiler/include/amdgpu/tiler_cpu.hpp similarity index 100% rename from rpcsx-gpu/lib/amdgpu-tiler/include/amdgpu/tiler_cpu.hpp rename to rpcsx/gpu/lib/amdgpu-tiler/include/amdgpu/tiler_cpu.hpp diff --git a/rpcsx-gpu/lib/amdgpu-tiler/include/amdgpu/tiler_vulkan.hpp b/rpcsx/gpu/lib/amdgpu-tiler/include/amdgpu/tiler_vulkan.hpp similarity index 100% rename from rpcsx-gpu/lib/amdgpu-tiler/include/amdgpu/tiler_vulkan.hpp rename to rpcsx/gpu/lib/amdgpu-tiler/include/amdgpu/tiler_vulkan.hpp diff --git a/rpcsx-gpu/lib/amdgpu-tiler/shaders/detiler1d.comp.glsl b/rpcsx/gpu/lib/amdgpu-tiler/shaders/detiler1d.comp.glsl similarity index 100% rename from rpcsx-gpu/lib/amdgpu-tiler/shaders/detiler1d.comp.glsl rename to rpcsx/gpu/lib/amdgpu-tiler/shaders/detiler1d.comp.glsl diff --git a/rpcsx-gpu/lib/amdgpu-tiler/shaders/detiler2d.comp.glsl b/rpcsx/gpu/lib/amdgpu-tiler/shaders/detiler2d.comp.glsl similarity index 100% rename from rpcsx-gpu/lib/amdgpu-tiler/shaders/detiler2d.comp.glsl rename to rpcsx/gpu/lib/amdgpu-tiler/shaders/detiler2d.comp.glsl diff --git a/rpcsx-gpu/lib/amdgpu-tiler/shaders/detilerLinear.comp.glsl b/rpcsx/gpu/lib/amdgpu-tiler/shaders/detilerLinear.comp.glsl similarity index 100% rename from rpcsx-gpu/lib/amdgpu-tiler/shaders/detilerLinear.comp.glsl rename to rpcsx/gpu/lib/amdgpu-tiler/shaders/detilerLinear.comp.glsl diff --git a/rpcsx-gpu/lib/amdgpu-tiler/shaders/tiler.glsl b/rpcsx/gpu/lib/amdgpu-tiler/shaders/tiler.glsl similarity index 100% rename from rpcsx-gpu/lib/amdgpu-tiler/shaders/tiler.glsl rename to rpcsx/gpu/lib/amdgpu-tiler/shaders/tiler.glsl diff --git a/rpcsx-gpu/lib/amdgpu-tiler/shaders/tiler1d.comp.glsl b/rpcsx/gpu/lib/amdgpu-tiler/shaders/tiler1d.comp.glsl similarity index 100% rename from rpcsx-gpu/lib/amdgpu-tiler/shaders/tiler1d.comp.glsl rename to rpcsx/gpu/lib/amdgpu-tiler/shaders/tiler1d.comp.glsl diff --git a/rpcsx-gpu/lib/amdgpu-tiler/shaders/tiler2d.comp.glsl b/rpcsx/gpu/lib/amdgpu-tiler/shaders/tiler2d.comp.glsl similarity index 100% rename from rpcsx-gpu/lib/amdgpu-tiler/shaders/tiler2d.comp.glsl rename to rpcsx/gpu/lib/amdgpu-tiler/shaders/tiler2d.comp.glsl diff --git a/rpcsx-gpu/lib/amdgpu-tiler/shaders/tilerLinear.comp.glsl b/rpcsx/gpu/lib/amdgpu-tiler/shaders/tilerLinear.comp.glsl similarity index 100% rename from rpcsx-gpu/lib/amdgpu-tiler/shaders/tilerLinear.comp.glsl rename to rpcsx/gpu/lib/amdgpu-tiler/shaders/tilerLinear.comp.glsl diff --git a/rpcsx-gpu/lib/amdgpu-tiler/src/tiler.cpp b/rpcsx/gpu/lib/amdgpu-tiler/src/tiler.cpp similarity index 100% rename from rpcsx-gpu/lib/amdgpu-tiler/src/tiler.cpp rename to rpcsx/gpu/lib/amdgpu-tiler/src/tiler.cpp diff --git a/rpcsx-gpu/lib/amdgpu-tiler/src/tiler_cpu.cpp b/rpcsx/gpu/lib/amdgpu-tiler/src/tiler_cpu.cpp similarity index 100% rename from rpcsx-gpu/lib/amdgpu-tiler/src/tiler_cpu.cpp rename to rpcsx/gpu/lib/amdgpu-tiler/src/tiler_cpu.cpp diff --git a/rpcsx-gpu/lib/amdgpu-tiler/src/tiler_vulkan.cpp b/rpcsx/gpu/lib/amdgpu-tiler/src/tiler_vulkan.cpp similarity index 100% rename from rpcsx-gpu/lib/amdgpu-tiler/src/tiler_vulkan.cpp rename to rpcsx/gpu/lib/amdgpu-tiler/src/tiler_vulkan.cpp diff --git a/rpcsx-gpu/lib/gcn-shader/CMakeLists.txt b/rpcsx/gpu/lib/gcn-shader/CMakeLists.txt similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/CMakeLists.txt rename to rpcsx/gpu/lib/gcn-shader/CMakeLists.txt diff --git a/rpcsx-gpu/lib/gcn-shader/include/shader/Access.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/Access.hpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/include/shader/Access.hpp rename to rpcsx/gpu/lib/gcn-shader/include/shader/Access.hpp diff --git a/rpcsx-gpu/lib/gcn-shader/include/shader/Evaluator.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/Evaluator.hpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/include/shader/Evaluator.hpp rename to rpcsx/gpu/lib/gcn-shader/include/shader/Evaluator.hpp diff --git a/rpcsx-gpu/lib/gcn-shader/include/shader/GcnConverter.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/GcnConverter.hpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/include/shader/GcnConverter.hpp rename to rpcsx/gpu/lib/gcn-shader/include/shader/GcnConverter.hpp diff --git a/rpcsx-gpu/lib/gcn-shader/include/shader/GcnInstruction.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/GcnInstruction.hpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/include/shader/GcnInstruction.hpp rename to rpcsx/gpu/lib/gcn-shader/include/shader/GcnInstruction.hpp diff --git a/rpcsx-gpu/lib/gcn-shader/include/shader/ModuleInfo.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/ModuleInfo.hpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/include/shader/ModuleInfo.hpp rename to rpcsx/gpu/lib/gcn-shader/include/shader/ModuleInfo.hpp diff --git a/rpcsx-gpu/lib/gcn-shader/include/shader/SemanticInfo.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/SemanticInfo.hpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/include/shader/SemanticInfo.hpp rename to rpcsx/gpu/lib/gcn-shader/include/shader/SemanticInfo.hpp diff --git a/rpcsx-gpu/lib/gcn-shader/include/shader/SpvConverter.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/SpvConverter.hpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/include/shader/SpvConverter.hpp rename to rpcsx/gpu/lib/gcn-shader/include/shader/SpvConverter.hpp diff --git a/rpcsx-gpu/lib/gcn-shader/include/shader/SpvTypeInfo.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/SpvTypeInfo.hpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/include/shader/SpvTypeInfo.hpp rename to rpcsx/gpu/lib/gcn-shader/include/shader/SpvTypeInfo.hpp diff --git a/rpcsx-gpu/lib/gcn-shader/include/shader/Vector.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/Vector.hpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/include/shader/Vector.hpp rename to rpcsx/gpu/lib/gcn-shader/include/shader/Vector.hpp diff --git a/rpcsx-gpu/lib/gcn-shader/include/shader/analyze.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/analyze.hpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/include/shader/analyze.hpp rename to rpcsx/gpu/lib/gcn-shader/include/shader/analyze.hpp diff --git a/rpcsx-gpu/lib/gcn-shader/include/shader/dialect.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/dialect.hpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/include/shader/dialect.hpp rename to rpcsx/gpu/lib/gcn-shader/include/shader/dialect.hpp diff --git a/rpcsx-gpu/lib/gcn-shader/include/shader/dialect/amdgpu.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/dialect/amdgpu.hpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/include/shader/dialect/amdgpu.hpp rename to rpcsx/gpu/lib/gcn-shader/include/shader/dialect/amdgpu.hpp diff --git a/rpcsx-gpu/lib/gcn-shader/include/shader/dialect/builtin.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/dialect/builtin.hpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/include/shader/dialect/builtin.hpp rename to rpcsx/gpu/lib/gcn-shader/include/shader/dialect/builtin.hpp diff --git a/rpcsx-gpu/lib/gcn-shader/include/shader/dialect/ds.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/dialect/ds.hpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/include/shader/dialect/ds.hpp rename to rpcsx/gpu/lib/gcn-shader/include/shader/dialect/ds.hpp diff --git a/rpcsx-gpu/lib/gcn-shader/include/shader/dialect/exp.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/dialect/exp.hpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/include/shader/dialect/exp.hpp rename to rpcsx/gpu/lib/gcn-shader/include/shader/dialect/exp.hpp diff --git a/rpcsx-gpu/lib/gcn-shader/include/shader/dialect/memssa.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/dialect/memssa.hpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/include/shader/dialect/memssa.hpp rename to rpcsx/gpu/lib/gcn-shader/include/shader/dialect/memssa.hpp diff --git a/rpcsx-gpu/lib/gcn-shader/include/shader/dialect/mimg.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/dialect/mimg.hpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/include/shader/dialect/mimg.hpp rename to rpcsx/gpu/lib/gcn-shader/include/shader/dialect/mimg.hpp diff --git a/rpcsx-gpu/lib/gcn-shader/include/shader/dialect/mtbuf.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/dialect/mtbuf.hpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/include/shader/dialect/mtbuf.hpp rename to rpcsx/gpu/lib/gcn-shader/include/shader/dialect/mtbuf.hpp diff --git a/rpcsx-gpu/lib/gcn-shader/include/shader/dialect/mubuf.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/dialect/mubuf.hpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/include/shader/dialect/mubuf.hpp rename to rpcsx/gpu/lib/gcn-shader/include/shader/dialect/mubuf.hpp diff --git a/rpcsx-gpu/lib/gcn-shader/include/shader/dialect/smrd.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/dialect/smrd.hpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/include/shader/dialect/smrd.hpp rename to rpcsx/gpu/lib/gcn-shader/include/shader/dialect/smrd.hpp diff --git a/rpcsx-gpu/lib/gcn-shader/include/shader/dialect/sop1.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/dialect/sop1.hpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/include/shader/dialect/sop1.hpp rename to rpcsx/gpu/lib/gcn-shader/include/shader/dialect/sop1.hpp diff --git a/rpcsx-gpu/lib/gcn-shader/include/shader/dialect/sop2.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/dialect/sop2.hpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/include/shader/dialect/sop2.hpp rename to rpcsx/gpu/lib/gcn-shader/include/shader/dialect/sop2.hpp diff --git a/rpcsx-gpu/lib/gcn-shader/include/shader/dialect/sopc.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/dialect/sopc.hpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/include/shader/dialect/sopc.hpp rename to rpcsx/gpu/lib/gcn-shader/include/shader/dialect/sopc.hpp diff --git a/rpcsx-gpu/lib/gcn-shader/include/shader/dialect/sopk.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/dialect/sopk.hpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/include/shader/dialect/sopk.hpp rename to rpcsx/gpu/lib/gcn-shader/include/shader/dialect/sopk.hpp diff --git a/rpcsx-gpu/lib/gcn-shader/include/shader/dialect/sopp.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/dialect/sopp.hpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/include/shader/dialect/sopp.hpp rename to rpcsx/gpu/lib/gcn-shader/include/shader/dialect/sopp.hpp diff --git a/rpcsx-gpu/lib/gcn-shader/include/shader/dialect/vintrp.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/dialect/vintrp.hpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/include/shader/dialect/vintrp.hpp rename to rpcsx/gpu/lib/gcn-shader/include/shader/dialect/vintrp.hpp diff --git a/rpcsx-gpu/lib/gcn-shader/include/shader/dialect/vop1.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/dialect/vop1.hpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/include/shader/dialect/vop1.hpp rename to rpcsx/gpu/lib/gcn-shader/include/shader/dialect/vop1.hpp diff --git a/rpcsx-gpu/lib/gcn-shader/include/shader/dialect/vop2.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/dialect/vop2.hpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/include/shader/dialect/vop2.hpp rename to rpcsx/gpu/lib/gcn-shader/include/shader/dialect/vop2.hpp diff --git a/rpcsx-gpu/lib/gcn-shader/include/shader/dialect/vop3.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/dialect/vop3.hpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/include/shader/dialect/vop3.hpp rename to rpcsx/gpu/lib/gcn-shader/include/shader/dialect/vop3.hpp diff --git a/rpcsx-gpu/lib/gcn-shader/include/shader/dialect/vopc.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/dialect/vopc.hpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/include/shader/dialect/vopc.hpp rename to rpcsx/gpu/lib/gcn-shader/include/shader/dialect/vopc.hpp diff --git a/rpcsx-gpu/lib/gcn-shader/include/shader/eval.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/eval.hpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/include/shader/eval.hpp rename to rpcsx/gpu/lib/gcn-shader/include/shader/eval.hpp diff --git a/rpcsx-gpu/lib/gcn-shader/include/shader/gcn.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/gcn.hpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/include/shader/gcn.hpp rename to rpcsx/gpu/lib/gcn-shader/include/shader/gcn.hpp diff --git a/rpcsx-gpu/lib/gcn-shader/include/shader/glsl.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/glsl.hpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/include/shader/glsl.hpp rename to rpcsx/gpu/lib/gcn-shader/include/shader/glsl.hpp diff --git a/rpcsx-gpu/lib/gcn-shader/include/shader/graph.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/graph.hpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/include/shader/graph.hpp rename to rpcsx/gpu/lib/gcn-shader/include/shader/graph.hpp diff --git a/rpcsx-gpu/lib/gcn-shader/include/shader/ir.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/ir.hpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/include/shader/ir.hpp rename to rpcsx/gpu/lib/gcn-shader/include/shader/ir.hpp diff --git a/rpcsx-gpu/lib/gcn-shader/include/shader/ir/Block.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/ir/Block.hpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/include/shader/ir/Block.hpp rename to rpcsx/gpu/lib/gcn-shader/include/shader/ir/Block.hpp diff --git a/rpcsx-gpu/lib/gcn-shader/include/shader/ir/Builder.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/ir/Builder.hpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/include/shader/ir/Builder.hpp rename to rpcsx/gpu/lib/gcn-shader/include/shader/ir/Builder.hpp diff --git a/rpcsx-gpu/lib/gcn-shader/include/shader/ir/Context.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/ir/Context.hpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/include/shader/ir/Context.hpp rename to rpcsx/gpu/lib/gcn-shader/include/shader/ir/Context.hpp diff --git a/rpcsx-gpu/lib/gcn-shader/include/shader/ir/Impl.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/ir/Impl.hpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/include/shader/ir/Impl.hpp rename to rpcsx/gpu/lib/gcn-shader/include/shader/ir/Impl.hpp diff --git a/rpcsx-gpu/lib/gcn-shader/include/shader/ir/Instruction.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/ir/Instruction.hpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/include/shader/ir/Instruction.hpp rename to rpcsx/gpu/lib/gcn-shader/include/shader/ir/Instruction.hpp diff --git a/rpcsx-gpu/lib/gcn-shader/include/shader/ir/InstructionImpl.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/ir/InstructionImpl.hpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/include/shader/ir/InstructionImpl.hpp rename to rpcsx/gpu/lib/gcn-shader/include/shader/ir/InstructionImpl.hpp diff --git a/rpcsx-gpu/lib/gcn-shader/include/shader/ir/Kind.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/ir/Kind.hpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/include/shader/ir/Kind.hpp rename to rpcsx/gpu/lib/gcn-shader/include/shader/ir/Kind.hpp diff --git a/rpcsx-gpu/lib/gcn-shader/include/shader/ir/Location.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/ir/Location.hpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/include/shader/ir/Location.hpp rename to rpcsx/gpu/lib/gcn-shader/include/shader/ir/Location.hpp diff --git a/rpcsx-gpu/lib/gcn-shader/include/shader/ir/NameStorage.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/ir/NameStorage.hpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/include/shader/ir/NameStorage.hpp rename to rpcsx/gpu/lib/gcn-shader/include/shader/ir/NameStorage.hpp diff --git a/rpcsx-gpu/lib/gcn-shader/include/shader/ir/Node.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/ir/Node.hpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/include/shader/ir/Node.hpp rename to rpcsx/gpu/lib/gcn-shader/include/shader/ir/Node.hpp diff --git a/rpcsx-gpu/lib/gcn-shader/include/shader/ir/NodeImpl.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/ir/NodeImpl.hpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/include/shader/ir/NodeImpl.hpp rename to rpcsx/gpu/lib/gcn-shader/include/shader/ir/NodeImpl.hpp diff --git a/rpcsx-gpu/lib/gcn-shader/include/shader/ir/Operand.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/ir/Operand.hpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/include/shader/ir/Operand.hpp rename to rpcsx/gpu/lib/gcn-shader/include/shader/ir/Operand.hpp diff --git a/rpcsx-gpu/lib/gcn-shader/include/shader/ir/OperandPrint.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/ir/OperandPrint.hpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/include/shader/ir/OperandPrint.hpp rename to rpcsx/gpu/lib/gcn-shader/include/shader/ir/OperandPrint.hpp diff --git a/rpcsx-gpu/lib/gcn-shader/include/shader/ir/PointerWrapper.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/ir/PointerWrapper.hpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/include/shader/ir/PointerWrapper.hpp rename to rpcsx/gpu/lib/gcn-shader/include/shader/ir/PointerWrapper.hpp diff --git a/rpcsx-gpu/lib/gcn-shader/include/shader/ir/PreincNodeIterable.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/ir/PreincNodeIterable.hpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/include/shader/ir/PreincNodeIterable.hpp rename to rpcsx/gpu/lib/gcn-shader/include/shader/ir/PreincNodeIterable.hpp diff --git a/rpcsx-gpu/lib/gcn-shader/include/shader/ir/PrintableWrapper.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/ir/PrintableWrapper.hpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/include/shader/ir/PrintableWrapper.hpp rename to rpcsx/gpu/lib/gcn-shader/include/shader/ir/PrintableWrapper.hpp diff --git a/rpcsx-gpu/lib/gcn-shader/include/shader/ir/Region.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/ir/Region.hpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/include/shader/ir/Region.hpp rename to rpcsx/gpu/lib/gcn-shader/include/shader/ir/Region.hpp diff --git a/rpcsx-gpu/lib/gcn-shader/include/shader/ir/RegionImpl.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/ir/RegionImpl.hpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/include/shader/ir/RegionImpl.hpp rename to rpcsx/gpu/lib/gcn-shader/include/shader/ir/RegionImpl.hpp diff --git a/rpcsx-gpu/lib/gcn-shader/include/shader/ir/RegionLike.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/ir/RegionLike.hpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/include/shader/ir/RegionLike.hpp rename to rpcsx/gpu/lib/gcn-shader/include/shader/ir/RegionLike.hpp diff --git a/rpcsx-gpu/lib/gcn-shader/include/shader/ir/RegionLikeImpl.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/ir/RegionLikeImpl.hpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/include/shader/ir/RegionLikeImpl.hpp rename to rpcsx/gpu/lib/gcn-shader/include/shader/ir/RegionLikeImpl.hpp diff --git a/rpcsx-gpu/lib/gcn-shader/include/shader/ir/Value.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/ir/Value.hpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/include/shader/ir/Value.hpp rename to rpcsx/gpu/lib/gcn-shader/include/shader/ir/Value.hpp diff --git a/rpcsx-gpu/lib/gcn-shader/include/shader/ir/ValueImpl.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/ir/ValueImpl.hpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/include/shader/ir/ValueImpl.hpp rename to rpcsx/gpu/lib/gcn-shader/include/shader/ir/ValueImpl.hpp diff --git a/rpcsx-gpu/lib/gcn-shader/include/shader/opt.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/opt.hpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/include/shader/opt.hpp rename to rpcsx/gpu/lib/gcn-shader/include/shader/opt.hpp diff --git a/rpcsx-gpu/lib/gcn-shader/include/shader/spv.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/spv.hpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/include/shader/spv.hpp rename to rpcsx/gpu/lib/gcn-shader/include/shader/spv.hpp diff --git a/rpcsx-gpu/lib/gcn-shader/include/shader/transform.hpp b/rpcsx/gpu/lib/gcn-shader/include/shader/transform.hpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/include/shader/transform.hpp rename to rpcsx/gpu/lib/gcn-shader/include/shader/transform.hpp diff --git a/rpcsx-gpu/lib/gcn-shader/shaders/CMakeLists.txt b/rpcsx/gpu/lib/gcn-shader/shaders/CMakeLists.txt similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/shaders/CMakeLists.txt rename to rpcsx/gpu/lib/gcn-shader/shaders/CMakeLists.txt diff --git a/rpcsx-gpu/lib/gcn-shader/shaders/rdna.glsl b/rpcsx/gpu/lib/gcn-shader/shaders/rdna.glsl similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/shaders/rdna.glsl rename to rpcsx/gpu/lib/gcn-shader/shaders/rdna.glsl diff --git a/rpcsx-gpu/lib/gcn-shader/src/Evaluator.cpp b/rpcsx/gpu/lib/gcn-shader/src/Evaluator.cpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/src/Evaluator.cpp rename to rpcsx/gpu/lib/gcn-shader/src/Evaluator.cpp diff --git a/rpcsx-gpu/lib/gcn-shader/src/GcnConverter.cpp b/rpcsx/gpu/lib/gcn-shader/src/GcnConverter.cpp similarity index 99% rename from rpcsx-gpu/lib/gcn-shader/src/GcnConverter.cpp rename to rpcsx/gpu/lib/gcn-shader/src/GcnConverter.cpp index c449570..631ee31 100644 --- a/rpcsx-gpu/lib/gcn-shader/src/GcnConverter.cpp +++ b/rpcsx/gpu/lib/gcn-shader/src/GcnConverter.cpp @@ -1108,6 +1108,13 @@ static void instructionsToSpv(GcnConverter &converter, gcn::Import &importer, auto omod = *inst.getOperand(2).getAsInt32(); auto value = inst.getOperand(3).getAsValue(); + if (resultType == ir::spv::OpTypeInt) { + auto floatType = + context.getTypeFloat(*resultType.getOperand(0).getAsInt32()); + value = builder.createSpvBitcast(resultType.getLocation(), floatType, value); + resultType = floatType; + } + if (resultType == ir::spv::OpTypeFloat) { auto resultWidth = *resultType.getOperand(0).getAsInt32(); auto createConstant = [&](auto value) { diff --git a/rpcsx-gpu/lib/gcn-shader/src/GcnInstruction.cpp b/rpcsx/gpu/lib/gcn-shader/src/GcnInstruction.cpp similarity index 99% rename from rpcsx-gpu/lib/gcn-shader/src/GcnInstruction.cpp rename to rpcsx/gpu/lib/gcn-shader/src/GcnInstruction.cpp index d903b19..0492cd5 100644 --- a/rpcsx-gpu/lib/gcn-shader/src/GcnInstruction.cpp +++ b/rpcsx/gpu/lib/gcn-shader/src/GcnInstruction.cpp @@ -284,7 +284,8 @@ readVop3Inst(GcnInstruction &inst, std::uint64_t &address, } bool usesSrc2 = - op >= ir::vop3::MAD_LEGACY_F32 && op <= ir::vop3::DIV_FIXUP_F64; + (op >= ir::vop3::MAD_LEGACY_F32 && op <= ir::vop3::DIV_FIXUP_F64) || + (op >= ir::vop3::MQSAD_U32_U8 && op <= ir::vop3::MAD_I64_I32); inst.addOperand(createSgprGcnOperand(address, src0) .withR() diff --git a/rpcsx-gpu/lib/gcn-shader/src/ModuleInfo.cpp b/rpcsx/gpu/lib/gcn-shader/src/ModuleInfo.cpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/src/ModuleInfo.cpp rename to rpcsx/gpu/lib/gcn-shader/src/ModuleInfo.cpp diff --git a/rpcsx-gpu/lib/gcn-shader/src/SemanticModuleInfo.cpp b/rpcsx/gpu/lib/gcn-shader/src/SemanticModuleInfo.cpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/src/SemanticModuleInfo.cpp rename to rpcsx/gpu/lib/gcn-shader/src/SemanticModuleInfo.cpp diff --git a/rpcsx-gpu/lib/gcn-shader/src/SpvConverter.cpp b/rpcsx/gpu/lib/gcn-shader/src/SpvConverter.cpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/src/SpvConverter.cpp rename to rpcsx/gpu/lib/gcn-shader/src/SpvConverter.cpp diff --git a/rpcsx-gpu/lib/gcn-shader/src/SpvTypeInfo.cpp b/rpcsx/gpu/lib/gcn-shader/src/SpvTypeInfo.cpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/src/SpvTypeInfo.cpp rename to rpcsx/gpu/lib/gcn-shader/src/SpvTypeInfo.cpp diff --git a/rpcsx-gpu/lib/gcn-shader/src/analyze.cpp b/rpcsx/gpu/lib/gcn-shader/src/analyze.cpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/src/analyze.cpp rename to rpcsx/gpu/lib/gcn-shader/src/analyze.cpp diff --git a/rpcsx-gpu/lib/gcn-shader/src/eval.cpp b/rpcsx/gpu/lib/gcn-shader/src/eval.cpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/src/eval.cpp rename to rpcsx/gpu/lib/gcn-shader/src/eval.cpp diff --git a/rpcsx-gpu/lib/gcn-shader/src/gcn.cpp b/rpcsx/gpu/lib/gcn-shader/src/gcn.cpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/src/gcn.cpp rename to rpcsx/gpu/lib/gcn-shader/src/gcn.cpp diff --git a/rpcsx-gpu/lib/gcn-shader/src/glsl.cpp b/rpcsx/gpu/lib/gcn-shader/src/glsl.cpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/src/glsl.cpp rename to rpcsx/gpu/lib/gcn-shader/src/glsl.cpp diff --git a/rpcsx-gpu/lib/gcn-shader/src/opt.cpp b/rpcsx/gpu/lib/gcn-shader/src/opt.cpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/src/opt.cpp rename to rpcsx/gpu/lib/gcn-shader/src/opt.cpp diff --git a/rpcsx-gpu/lib/gcn-shader/src/spv.cpp b/rpcsx/gpu/lib/gcn-shader/src/spv.cpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/src/spv.cpp rename to rpcsx/gpu/lib/gcn-shader/src/spv.cpp diff --git a/rpcsx-gpu/lib/gcn-shader/src/transform.cpp b/rpcsx/gpu/lib/gcn-shader/src/transform.cpp similarity index 100% rename from rpcsx-gpu/lib/gcn-shader/src/transform.cpp rename to rpcsx/gpu/lib/gcn-shader/src/transform.cpp diff --git a/rpcsx-gpu/lib/gnm/CMakeLists.txt b/rpcsx/gpu/lib/gnm/CMakeLists.txt similarity index 100% rename from rpcsx-gpu/lib/gnm/CMakeLists.txt rename to rpcsx/gpu/lib/gnm/CMakeLists.txt diff --git a/rpcsx-gpu/lib/gnm/include/gnm/constants.hpp b/rpcsx/gpu/lib/gnm/include/gnm/constants.hpp similarity index 100% rename from rpcsx-gpu/lib/gnm/include/gnm/constants.hpp rename to rpcsx/gpu/lib/gnm/include/gnm/constants.hpp diff --git a/rpcsx-gpu/lib/gnm/include/gnm/descriptors.hpp b/rpcsx/gpu/lib/gnm/include/gnm/descriptors.hpp similarity index 100% rename from rpcsx-gpu/lib/gnm/include/gnm/descriptors.hpp rename to rpcsx/gpu/lib/gnm/include/gnm/descriptors.hpp diff --git a/rpcsx-gpu/lib/gnm/include/gnm/gnm.hpp b/rpcsx/gpu/lib/gnm/include/gnm/gnm.hpp similarity index 100% rename from rpcsx-gpu/lib/gnm/include/gnm/gnm.hpp rename to rpcsx/gpu/lib/gnm/include/gnm/gnm.hpp diff --git a/rpcsx-gpu/lib/gnm/include/gnm/mmio.hpp b/rpcsx/gpu/lib/gnm/include/gnm/mmio.hpp similarity index 100% rename from rpcsx-gpu/lib/gnm/include/gnm/mmio.hpp rename to rpcsx/gpu/lib/gnm/include/gnm/mmio.hpp diff --git a/rpcsx-gpu/lib/gnm/include/gnm/pm4.hpp b/rpcsx/gpu/lib/gnm/include/gnm/pm4.hpp similarity index 100% rename from rpcsx-gpu/lib/gnm/include/gnm/pm4.hpp rename to rpcsx/gpu/lib/gnm/include/gnm/pm4.hpp diff --git a/rpcsx-gpu/lib/gnm/lib/CMakeLists.txt b/rpcsx/gpu/lib/gnm/lib/CMakeLists.txt similarity index 100% rename from rpcsx-gpu/lib/gnm/lib/CMakeLists.txt rename to rpcsx/gpu/lib/gnm/lib/CMakeLists.txt diff --git a/rpcsx-gpu/lib/gnm/lib/gnm-vulkan/CMakeLists.txt b/rpcsx/gpu/lib/gnm/lib/gnm-vulkan/CMakeLists.txt similarity index 100% rename from rpcsx-gpu/lib/gnm/lib/gnm-vulkan/CMakeLists.txt rename to rpcsx/gpu/lib/gnm/lib/gnm-vulkan/CMakeLists.txt diff --git a/rpcsx-gpu/lib/gnm/lib/gnm-vulkan/include/gnm/vulkan.hpp b/rpcsx/gpu/lib/gnm/lib/gnm-vulkan/include/gnm/vulkan.hpp similarity index 100% rename from rpcsx-gpu/lib/gnm/lib/gnm-vulkan/include/gnm/vulkan.hpp rename to rpcsx/gpu/lib/gnm/lib/gnm-vulkan/include/gnm/vulkan.hpp diff --git a/rpcsx-gpu/lib/gnm/lib/gnm-vulkan/src/vulkan.cpp b/rpcsx/gpu/lib/gnm/lib/gnm-vulkan/src/vulkan.cpp similarity index 99% rename from rpcsx-gpu/lib/gnm/lib/gnm-vulkan/src/vulkan.cpp rename to rpcsx/gpu/lib/gnm/lib/gnm-vulkan/src/vulkan.cpp index cf080da..7abf68c 100644 --- a/rpcsx-gpu/lib/gnm/lib/gnm-vulkan/src/vulkan.cpp +++ b/rpcsx/gpu/lib/gnm/lib/gnm-vulkan/src/vulkan.cpp @@ -111,7 +111,7 @@ static std::unordered_map g_toVkFormats = { { makeFormatPair(kDataFormat10_10_10_2, kNumericFormatSInt), VK_FORMAT_A2R10G10B10_SINT_PACK32}, // { makeFormatPair(kDataFormat10_10_10_2, kNumericFormatSNormNoZero), VK_FORMAT_A2R10G10B10_SNORM_PACK32}, // { makeFormatPair(kDataFormat10_10_10_2, kNumericFormatFloat), VK_FORMAT_A2R10G10B10_UFLOAT_PACK32}, -// { makeFormatPair(kDataFormat10_10_10_2, kNumericFormatSrgb), VK_FORMAT_A2R10G10B10_SRGB_PACK32}, +{ makeFormatPair(kDataFormat10_10_10_2, kNumericFormatSrgb), VK_FORMAT_A2R10G10B10_SINT_PACK32}, // { makeFormatPair(kDataFormat10_10_10_2, kNumericFormatUBNorm), VK_FORMAT_A2R10G10B10_UNORM_PACK32}, // { makeFormatPair(kDataFormat10_10_10_2, kNumericFormatUBNormNoZero), VK_FORMAT_A2R10G10B10_UNORM_PACK32}, // { makeFormatPair(kDataFormat10_10_10_2, kNumericFormatUBInt), VK_FORMAT_A2R10G10B10_UINT_PACK32}, @@ -124,7 +124,7 @@ static std::unordered_map g_toVkFormats = { { makeFormatPair(kDataFormat2_10_10_10, kNumericFormatSInt), VK_FORMAT_A2R10G10B10_SINT_PACK32}, // { makeFormatPair(kDataFormat2_10_10_10, kNumericFormatSNormNoZero), VK_FORMAT_A2R10G10B10_SNORM_PACK32}, // { makeFormatPair(kDataFormat2_10_10_10, kNumericFormatFloat), VK_FORMAT_A2R10G10B10_UFLOAT_PACK32}, -// { makeFormatPair(kDataFormat2_10_10_10, kNumericFormatSrgb), VK_FORMAT_A2R10G10B10_SRGB_PACK32}, +{ makeFormatPair(kDataFormat2_10_10_10, kNumericFormatSrgb), VK_FORMAT_A2R10G10B10_SINT_PACK32}, // { makeFormatPair(kDataFormat2_10_10_10, kNumericFormatUBNorm), VK_FORMAT_A2R10G10B10_UNORM_PACK32}, // { makeFormatPair(kDataFormat2_10_10_10, kNumericFormatUBNormNoZero), VK_FORMAT_A2R10G10B10_UNORM_PACK32}, // { makeFormatPair(kDataFormat2_10_10_10, kNumericFormatUBInt), VK_FORMAT_A2R10G10B10_UINT_PACK32}, diff --git a/rpcsx-gpu/lib/gnm/src/mmio.cpp b/rpcsx/gpu/lib/gnm/src/mmio.cpp similarity index 100% rename from rpcsx-gpu/lib/gnm/src/mmio.cpp rename to rpcsx/gpu/lib/gnm/src/mmio.cpp diff --git a/rpcsx-gpu/lib/gnm/src/pm4.cpp b/rpcsx/gpu/lib/gnm/src/pm4.cpp similarity index 100% rename from rpcsx-gpu/lib/gnm/src/pm4.cpp rename to rpcsx/gpu/lib/gnm/src/pm4.cpp diff --git a/rpcsx-gpu/lib/vk/CMakeLists.txt b/rpcsx/gpu/lib/vk/CMakeLists.txt similarity index 100% rename from rpcsx-gpu/lib/vk/CMakeLists.txt rename to rpcsx/gpu/lib/vk/CMakeLists.txt diff --git a/rpcsx-gpu/lib/vk/include/Scheduler.hpp b/rpcsx/gpu/lib/vk/include/Scheduler.hpp similarity index 100% rename from rpcsx-gpu/lib/vk/include/Scheduler.hpp rename to rpcsx/gpu/lib/vk/include/Scheduler.hpp diff --git a/rpcsx-gpu/lib/vk/include/vk.hpp b/rpcsx/gpu/lib/vk/include/vk.hpp similarity index 90% rename from rpcsx-gpu/lib/vk/include/vk.hpp rename to rpcsx/gpu/lib/vk/include/vk.hpp index 367d69c..0647df8 100644 --- a/rpcsx-gpu/lib/vk/include/vk.hpp +++ b/rpcsx/gpu/lib/vk/include/vk.hpp @@ -53,13 +53,17 @@ struct Context { Context() = default; Context(const Context &) = delete; - Context(Context &&other) { other.swap(*this); } - Context &operator=(Context &&other) { + Context(Context &&other) noexcept { other.swap(*this); } + Context &operator=(Context &&other) noexcept { other.swap(*this); return *this; } ~Context() { + if (instance == VK_NULL_HANDLE) { + return; + } + for (auto imageView : swapchainImageViews) { vkDestroyImageView(device, imageView, allocator); } @@ -89,7 +93,7 @@ struct Context { } } - void swap(Context &other) { + void swap(Context &other) noexcept { std::swap(instance, other.instance); std::swap(physicalMemoryProperties, other.physicalMemoryProperties); std::swap(allocator, other.allocator); @@ -134,7 +138,7 @@ class DeviceMemory { public: DeviceMemory(DeviceMemory &) = delete; - DeviceMemory(DeviceMemory &&other) { *this = std::move(other); } + DeviceMemory(DeviceMemory &&other) noexcept { *this = std::move(other); } DeviceMemory() = default; ~DeviceMemory() { @@ -144,16 +148,16 @@ public: mDeviceMemory = nullptr; } - DeviceMemory &operator=(DeviceMemory &&other) { + DeviceMemory &operator=(DeviceMemory &&other) noexcept { std::swap(mDeviceMemory, other.mDeviceMemory); std::swap(mSize, other.mSize); std::swap(mMemoryTypeIndex, other.mMemoryTypeIndex); return *this; } - VkDeviceMemory getHandle() const { return mDeviceMemory; } - VkDeviceSize getSize() const { return mSize; } - unsigned getMemoryTypeIndex() const { return mMemoryTypeIndex; } + [[nodiscard]] VkDeviceMemory getHandle() const { return mDeviceMemory; } + [[nodiscard]] VkDeviceSize getSize() const { return mSize; } + [[nodiscard]] unsigned getMemoryTypeIndex() const { return mMemoryTypeIndex; } static DeviceMemory AllocateFromType(std::size_t size, unsigned memoryTypeIndex) { @@ -360,12 +364,12 @@ public: // } table.unmap(offset, offset + requirements.size); - return {mMemory.getHandle(), - offset, - requirements.size, - mData, - this, - [](DeviceMemoryRef &memoryRef) { + return {.deviceMemory = mMemory.getHandle(), + .offset = offset, + .size = requirements.size, + .data = mData, + .allocator = this, + .release = [](DeviceMemoryRef &memoryRef) { auto self = reinterpret_cast(memoryRef.allocator); self->deallocate(memoryRef); @@ -402,9 +406,9 @@ public: Semaphore(const Semaphore &) = delete; Semaphore() = default; - Semaphore(Semaphore &&other) { *this = std::move(other); } + Semaphore(Semaphore &&other) noexcept { *this = std::move(other); } - Semaphore &operator=(Semaphore &&other) { + Semaphore &operator=(Semaphore &&other) noexcept { std::swap(mSemaphore, other.mSemaphore); return *this; } @@ -447,7 +451,7 @@ public: VK_VERIFY(vkSignalSemaphore(context->device, &signalInfo)); } - [[gnu::used]] std::uint64_t getCounterValue() const { + [[gnu::used, nodiscard]] std::uint64_t getCounterValue() const { std::uint64_t result = 0; VK_VERIFY(vkGetSemaphoreCounterValue(context->device, mSemaphore, &result)); return result; @@ -466,9 +470,9 @@ public: BinSemaphore(const BinSemaphore &) = delete; BinSemaphore() = default; - BinSemaphore(BinSemaphore &&other) { *this = std::move(other); } + BinSemaphore(BinSemaphore &&other) noexcept { *this = std::move(other); } - BinSemaphore &operator=(BinSemaphore &&other) { + BinSemaphore &operator=(BinSemaphore &&other) noexcept { std::swap(mSemaphore, other.mSemaphore); return *this; } @@ -493,7 +497,7 @@ public: return result; } - VkSemaphore getHandle() const { return mSemaphore; } + [[nodiscard]] VkSemaphore getHandle() const { return mSemaphore; } bool operator==(std::nullptr_t) const { return mSemaphore == nullptr; } }; @@ -505,9 +509,9 @@ public: Fence(const Fence &) = delete; Fence() = default; - Fence(Fence &&other) { *this = std::move(other); } + Fence(Fence &&other) noexcept { *this = std::move(other); } - Fence &operator=(Fence &&other) { + Fence &operator=(Fence &&other) noexcept { std::swap(mFence, other.mFence); return *this; } @@ -531,7 +535,7 @@ public: VK_VERIFY(vkWaitForFences(context->device, 1, &mFence, 1, UINT64_MAX)); } - bool isComplete() const { + [[nodiscard]] bool isComplete() const { return vkGetFenceStatus(context->device, mFence) == VK_SUCCESS; } @@ -549,9 +553,9 @@ public: CommandBuffer(const CommandBuffer &) = delete; CommandBuffer() = default; - CommandBuffer(CommandBuffer &&other) { *this = std::move(other); } + CommandBuffer(CommandBuffer &&other) noexcept { *this = std::move(other); } - CommandBuffer &operator=(CommandBuffer &&other) { + CommandBuffer &operator=(CommandBuffer &&other) noexcept { std::swap(mCmdBuffer, other.mCmdBuffer); return *this; } @@ -590,14 +594,14 @@ public: CommandPool(const CommandPool &) = delete; CommandPool() = default; - CommandPool(CommandPool &&other) { *this = std::move(other); } + CommandPool(CommandPool &&other) noexcept { *this = std::move(other); } ~CommandPool() { if (mHandle != nullptr) { vkDestroyCommandPool(context->device, mHandle, context->allocator); } } - CommandPool &operator=(CommandPool &&other) { + CommandPool &operator=(CommandPool &&other) noexcept { std::swap(mHandle, other.mHandle); return *this; } @@ -621,11 +625,11 @@ public: } CommandBuffer createPrimaryBuffer(VkCommandBufferUsageFlags flags) { - return CommandBuffer(mHandle, VK_COMMAND_BUFFER_LEVEL_PRIMARY, flags); + return {mHandle, VK_COMMAND_BUFFER_LEVEL_PRIMARY, flags}; } operator VkCommandPool() const { return mHandle; } - VkCommandPool getHandle() const { return mHandle; } + [[nodiscard]] VkCommandPool getHandle() const { return mHandle; } bool operator==(std::nullptr_t) const { return mHandle == nullptr; } }; @@ -661,7 +665,7 @@ public: Buffer(const Buffer &) = delete; Buffer() = default; - Buffer(Buffer &&other) { *this = std::move(other); } + Buffer(Buffer &&other) noexcept { *this = std::move(other); } ~Buffer() { if (mBuffer != nullptr) { vkDestroyBuffer(context->device, mBuffer, context->allocator); @@ -672,7 +676,7 @@ public: } } - Buffer &operator=(Buffer &&other) { + Buffer &operator=(Buffer &&other) noexcept { std::swap(mBuffer, other.mBuffer); std::swap(mAddress, other.mAddress); std::swap(mMemory, other.mMemory); @@ -700,7 +704,7 @@ public: operator VkBuffer() const { return mBuffer; } - std::byte *getData() const { + [[nodiscard]] std::byte *getData() const { rx::dieIf(mMemory.data == nullptr, "unexpected Buffer::getData call with device local memory"); return reinterpret_cast(mMemory.data) + mMemory.offset; @@ -743,11 +747,11 @@ public: return result; } - VkDeviceAddress getAddress() const { return mAddress; } - VkBuffer getHandle() const { return mBuffer; } + [[nodiscard]] VkDeviceAddress getAddress() const { return mAddress; } + [[nodiscard]] VkBuffer getHandle() const { return mBuffer; } [[nodiscard]] VkBuffer release() { return std::exchange(mBuffer, nullptr); } - VkMemoryRequirements getMemoryRequirements() const { + [[nodiscard]] VkMemoryRequirements getMemoryRequirements() const { VkMemoryRequirements requirements{}; vkGetBufferMemoryRequirements(context->device, mBuffer, &requirements); return requirements; @@ -780,7 +784,7 @@ public: vkCmdPipelineBarrier2(cmdBuffer, &depInfo); } - const DeviceMemoryRef &getMemory() const { return mMemory; } + [[nodiscard]] const DeviceMemoryRef &getMemory() const { return mMemory; } bool operator==(std::nullptr_t) const { return mBuffer == nullptr; } bool operator!=(std::nullptr_t) const { return mBuffer != nullptr; } }; @@ -800,7 +804,7 @@ public: Image(const Image &) = delete; Image() = default; - Image(Image &&other) { *this = std::move(other); } + Image(Image &&other) noexcept { *this = std::move(other); } ~Image() { if (mImage != VK_NULL_HANDLE) { @@ -812,7 +816,7 @@ public: } } - Image &operator=(Image &&other) { + Image &operator=(Image &&other) noexcept { std::swap(mImage, other.mImage); std::swap(mImageType, other.mImageType); std::swap(mFormat, other.mFormat); @@ -877,21 +881,21 @@ public: return result; } - VkExtent3D getExtent() const { return mExtent; } - VkImageType getImageType() const { return mImageType; } - VkFormat getFormat() const { return mFormat; } - VkImageAspectFlags getAspects() { return mAspects; } - std::uint32_t getWidth() const { return getExtent().width; } - std::uint32_t getHeight() const { return getExtent().height; } - std::uint32_t getDepth() const { return getExtent().depth; } - std::uint32_t getArrayLayers() const { return mArrayLayers; } - std::uint32_t getMipLevels() const { return mMipLevels; } - VkSampleCountFlagBits getSamples() const { return mSamples; } + [[nodiscard]] VkExtent3D getExtent() const { return mExtent; } + [[nodiscard]] VkImageType getImageType() const { return mImageType; } + [[nodiscard]] VkFormat getFormat() const { return mFormat; } + [[nodiscard]] VkImageAspectFlags getAspects() const { return mAspects; } + [[nodiscard]] std::uint32_t getWidth() const { return getExtent().width; } + [[nodiscard]] std::uint32_t getHeight() const { return getExtent().height; } + [[nodiscard]] std::uint32_t getDepth() const { return getExtent().depth; } + [[nodiscard]] std::uint32_t getArrayLayers() const { return mArrayLayers; } + [[nodiscard]] std::uint32_t getMipLevels() const { return mMipLevels; } + [[nodiscard]] VkSampleCountFlagBits getSamples() const { return mSamples; } - VkImage getHandle() const { return mImage; } + [[nodiscard]] VkImage getHandle() const { return mImage; } [[nodiscard]] VkImage release() { return std::exchange(mImage, nullptr); } - VkMemoryRequirements getMemoryRequirements() const { + [[nodiscard]] VkMemoryRequirements getMemoryRequirements() const { VkMemoryRequirements requirements{}; vkGetImageMemoryRequirements(context->device, mImage, &requirements); return requirements; @@ -921,7 +925,7 @@ public: ImageView(const ImageView &) = delete; ImageView() = default; - ImageView(ImageView &&other) { *this = std::move(other); } + ImageView(ImageView &&other) noexcept { *this = std::move(other); } ~ImageView() { if (mHandle != nullptr) { @@ -929,7 +933,7 @@ public: } } - ImageView &operator=(ImageView &&other) { + ImageView &operator=(ImageView &&other) noexcept { std::swap(mHandle, other.mHandle); std::swap(mType, other.mType); std::swap(mFormat, other.mFormat); @@ -954,7 +958,7 @@ public: &mHandle)); } - VkImageView getHandle() const { return mHandle; } + [[nodiscard]] VkImageView getHandle() const { return mHandle; } [[nodiscard]] VkImageView release() { return std::exchange(mHandle, nullptr); diff --git a/rpcsx-gpu/lib/vk/src/vk.cpp b/rpcsx/gpu/lib/vk/src/vk.cpp similarity index 100% rename from rpcsx-gpu/lib/vk/src/vk.cpp rename to rpcsx/gpu/lib/vk/src/vk.cpp diff --git a/rpcsx-gpu/shaders/fill_red.frag.glsl b/rpcsx/gpu/shaders/fill_red.frag.glsl similarity index 100% rename from rpcsx-gpu/shaders/fill_red.frag.glsl rename to rpcsx/gpu/shaders/fill_red.frag.glsl diff --git a/rpcsx-gpu/shaders/flip.vert.glsl b/rpcsx/gpu/shaders/flip.vert.glsl similarity index 100% rename from rpcsx-gpu/shaders/flip.vert.glsl rename to rpcsx/gpu/shaders/flip.vert.glsl diff --git a/rpcsx-gpu/shaders/flip_alt.frag.glsl b/rpcsx/gpu/shaders/flip_alt.frag.glsl similarity index 100% rename from rpcsx-gpu/shaders/flip_alt.frag.glsl rename to rpcsx/gpu/shaders/flip_alt.frag.glsl diff --git a/rpcsx-gpu/shaders/flip_std.frag.glsl b/rpcsx/gpu/shaders/flip_std.frag.glsl similarity index 100% rename from rpcsx-gpu/shaders/flip_std.frag.glsl rename to rpcsx/gpu/shaders/flip_std.frag.glsl diff --git a/rpcsx-gpu/shaders/rect_list.geom.glsl b/rpcsx/gpu/shaders/rect_list.geom.glsl similarity index 100% rename from rpcsx-gpu/shaders/rect_list.geom.glsl rename to rpcsx/gpu/shaders/rect_list.geom.glsl diff --git a/rpcsx-os/io-device.cpp b/rpcsx/io-device.cpp similarity index 97% rename from rpcsx-os/io-device.cpp rename to rpcsx/io-device.cpp index 564b63d..1c4eb93 100644 --- a/rpcsx-os/io-device.cpp +++ b/rpcsx/io-device.cpp @@ -203,7 +203,7 @@ static orbis::ErrorCode convertErrc(std::errc errc) { } } -static orbis::ErrorCode convertErrorCode(const std::error_code &code) { +orbis::ErrorCode convertErrorCode(const std::error_code &code) { if (!code) { return {}; } @@ -340,18 +340,18 @@ static orbis::ErrorCode host_mmap(orbis::File *file, void **address, return orbis::ErrorCode::ISDIR; auto result = - rx::vm::map(*address, size, prot, flags, rx::vm::kMapInternalReserveOnly, + vm::map(*address, size, prot, flags, vm::kMapInternalReserveOnly, hostFile->device.cast().get(), offset); if (result == (void *)-1) { return orbis::ErrorCode::NOMEM; } - size = rx::alignUp(size, rx::vm::kPageSize); + size = rx::alignUp(size, vm::kPageSize); result = ::mmap( - result, size, prot & rx::vm::kMapProtCpuAll, - ((flags & rx::vm::kMapFlagPrivate) != 0 ? MAP_PRIVATE : MAP_SHARED) | + result, size, prot & vm::kMapProtCpuAll, + ((flags & vm::kMapFlagPrivate) != 0 ? MAP_PRIVATE : MAP_SHARED) | MAP_FIXED, hostFile->hostFd, offset); if (result == (void *)-1) { @@ -368,7 +368,7 @@ static orbis::ErrorCode host_mmap(orbis::File *file, void **address, fstat(hostFile->hostFd, &stat); if (stat.st_size < offset + size) { std::size_t rest = - std::min(offset + size - stat.st_size, rx::vm::kPageSize); + std::min(offset + size - stat.st_size, vm::kPageSize); if (rest > rx::mem::pageSize) { auto fillSize = rx::alignUp(rest, rx::mem::pageSize) - rx::mem::pageSize; @@ -378,7 +378,7 @@ static orbis::ErrorCode host_mmap(orbis::File *file, void **address, (char *)result + (stat.st_size - offset)); auto ptr = ::mmap((char *)result + size - fillSize, fillSize, - prot & rx::vm::kMapProtCpuAll, + prot & vm::kMapProtCpuAll, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0); if (ptr == (void *)-1) { @@ -439,7 +439,7 @@ static orbis::ErrorCode host_truncate(orbis::File *file, std::uint64_t len, } if (hostFile->alignTruncate) { - len = rx::alignUp(len, rx::vm::kPageSize); + len = rx::alignUp(len, vm::kPageSize); } if (::ftruncate(hostFile->hostFd, len)) { @@ -498,7 +498,7 @@ static orbis::ErrorCode socket_bind(orbis::File *file, if (address->family == 1) { auto vfsPath = std::string_view((const char *)address->data); - auto [device, path] = rx::vfs::get(vfsPath); + auto [device, path] = vfs::get(vfsPath); if (auto hostDev = device.cast()) { auto socketPath = std::filesystem::path(hostDev->hostPath); @@ -591,7 +591,7 @@ static orbis::ErrorCode socket_connect(orbis::File *file, if (address->family == 1) { auto vfsPath = std::string_view((const char *)address->data); - auto [device, path] = rx::vfs::get(vfsPath); + auto [device, path] = vfs::get(vfsPath); if (auto hostDev = device.cast()) { auto socketPath = std::filesystem::path(hostDev->hostPath); diff --git a/rpcsx-os/io-device.hpp b/rpcsx/io-device.hpp similarity index 97% rename from rpcsx-os/io-device.hpp rename to rpcsx/io-device.hpp index 02679a1..26f6937 100644 --- a/rpcsx-os/io-device.hpp +++ b/rpcsx/io-device.hpp @@ -4,6 +4,7 @@ #include "orbis/file.hpp" #include "orbis/utils/Rc.hpp" #include +#include enum OpenFlags { kOpenFlagReadOnly = 0x0, @@ -67,6 +68,7 @@ struct HostFsDevice : IoDevice { orbis::Thread *thread) override; }; +orbis::ErrorCode convertErrorCode(const std::error_code &code); orbis::ErrorCode convertErrno(); IoDevice *createHostIoDevice(orbis::kstring hostPath, orbis::kstring virtualPath); orbis::Ref wrapSocket(int hostFd, orbis::kstring name, int dom, int type, int prot); diff --git a/rpcsx-os/io-devices.hpp b/rpcsx/io-devices.hpp similarity index 100% rename from rpcsx-os/io-devices.hpp rename to rpcsx/io-devices.hpp diff --git a/rpcsx-os/iodev/MBusEvent.hpp b/rpcsx/iodev/MBusEvent.hpp similarity index 100% rename from rpcsx-os/iodev/MBusEvent.hpp rename to rpcsx/iodev/MBusEvent.hpp diff --git a/rpcsx-os/iodev/ajm.cpp b/rpcsx/iodev/ajm.cpp similarity index 100% rename from rpcsx-os/iodev/ajm.cpp rename to rpcsx/iodev/ajm.cpp diff --git a/rpcsx-os/iodev/aout.cpp b/rpcsx/iodev/aout.cpp similarity index 100% rename from rpcsx-os/iodev/aout.cpp rename to rpcsx/iodev/aout.cpp diff --git a/rpcsx-os/iodev/av_control.cpp b/rpcsx/iodev/av_control.cpp similarity index 100% rename from rpcsx-os/iodev/av_control.cpp rename to rpcsx/iodev/av_control.cpp diff --git a/rpcsx-os/iodev/blockpool.cpp b/rpcsx/iodev/blockpool.cpp similarity index 96% rename from rpcsx-os/iodev/blockpool.cpp rename to rpcsx/iodev/blockpool.cpp index a620204..416b286 100644 --- a/rpcsx-os/iodev/blockpool.cpp +++ b/rpcsx/iodev/blockpool.cpp @@ -65,7 +65,7 @@ static orbis::ErrorCode blockpool_mmap(orbis::File *file, void **address, size = std::min( 0x1000000, size); // FIXME: hack, investigate why we report so many memory size = std::min(blockPool->len, size); - auto result = rx::vm::map(*address, size, prot, flags); + auto result = vm::map(*address, size, prot, flags); if (result == (void *)-1) { return orbis::ErrorCode::INVAL; // TODO @@ -96,7 +96,7 @@ orbis::ErrorCode BlockPoolDevice::map(void **address, std::uint64_t len, std::int32_t prot, std::int32_t flags, orbis::Thread *thread) { ORBIS_LOG_FATAL("blockpool device map", *address, len); - auto result = rx::vm::map(*address, len, prot, flags); + auto result = vm::map(*address, len, prot, flags); if (result == (void *)-1) { return orbis::ErrorCode::NOMEM; @@ -108,7 +108,7 @@ orbis::ErrorCode BlockPoolDevice::map(void **address, std::uint64_t len, orbis::ErrorCode BlockPoolDevice::unmap(void *address, std::uint64_t len, orbis::Thread *thread) { ORBIS_LOG_FATAL("blockpool device unmap", address, len); - if (rx::vm::unmap(address, len)) { + if (vm::unmap(address, len)) { return {}; } return orbis::ErrorCode::INVAL; diff --git a/rpcsx-os/iodev/blockpool.hpp b/rpcsx/iodev/blockpool.hpp similarity index 100% rename from rpcsx-os/iodev/blockpool.hpp rename to rpcsx/iodev/blockpool.hpp diff --git a/rpcsx-os/iodev/bt.cpp b/rpcsx/iodev/bt.cpp similarity index 100% rename from rpcsx-os/iodev/bt.cpp rename to rpcsx/iodev/bt.cpp diff --git a/rpcsx-os/iodev/camera.cpp b/rpcsx/iodev/camera.cpp similarity index 100% rename from rpcsx-os/iodev/camera.cpp rename to rpcsx/iodev/camera.cpp diff --git a/rpcsx-os/iodev/cayman_reg.cpp b/rpcsx/iodev/cayman_reg.cpp similarity index 100% rename from rpcsx-os/iodev/cayman_reg.cpp rename to rpcsx/iodev/cayman_reg.cpp diff --git a/rpcsx-os/iodev/cd.cpp b/rpcsx/iodev/cd.cpp similarity index 100% rename from rpcsx-os/iodev/cd.cpp rename to rpcsx/iodev/cd.cpp diff --git a/rpcsx-os/iodev/console.cpp b/rpcsx/iodev/console.cpp similarity index 100% rename from rpcsx-os/iodev/console.cpp rename to rpcsx/iodev/console.cpp diff --git a/rpcsx-os/iodev/dce.cpp b/rpcsx/iodev/dce.cpp similarity index 81% rename from rpcsx-os/iodev/dce.cpp rename to rpcsx/iodev/dce.cpp index 8dccc99..6aeff72 100644 --- a/rpcsx-os/iodev/dce.cpp +++ b/rpcsx/iodev/dce.cpp @@ -1,4 +1,4 @@ -#include "bridge.hpp" +#include "gpu/Device.hpp" #include "io-device.hpp" #include "iodev/dmem.hpp" #include "orbis/KernelAllocator.hpp" @@ -9,10 +9,14 @@ #include "orbis/thread/Thread.hpp" #include "orbis/utils/Logs.hpp" #include "orbis/utils/SharedMutex.hpp" +#include "rx/mem.hpp" +#include "rx/watchdog.hpp" #include "vm.hpp" +#include #include #include #include +#include #include static constexpr auto kDceControlMemoryOffset = 0; @@ -129,13 +133,13 @@ struct ResolutionStatus { static void runBridge(int vmId) { std::thread{[=] { pthread_setname_np(pthread_self(), "Bridge"); - auto bridge = rx::bridge.header; + auto gpu = orbis::g_context.gpuDevice.staticCast(); std::vector fetchedCommands; - fetchedCommands.reserve(std::size(bridge->cacheCommands)); + fetchedCommands.reserve(std::size(gpu->cacheCommands)); while (true) { - for (auto &command : bridge->cacheCommands) { + for (auto &command : gpu->cacheCommands) { std::uint64_t value = command[vmId].load(std::memory_order::relaxed); if (value != 0) { @@ -153,33 +157,30 @@ static void runBridge(int vmId) { auto count = static_cast(command >> 32) + 1; auto pageFlags = - bridge->cachePages[vmId][page].load(std::memory_order::relaxed); + gpu->cachePages[vmId][page].load(std::memory_order::relaxed); - auto address = - static_cast(page) * amdgpu::bridge::kHostPageSize; - auto origVmProt = rx::vm::getPageProtection(address); + auto address = static_cast(page) * rx::mem::pageSize; + auto origVmProt = vm::getPageProtection(address); int prot = 0; - if (origVmProt & rx::vm::kMapProtCpuRead) { + if (origVmProt & vm::kMapProtCpuRead) { prot |= PROT_READ; } - if (origVmProt & rx::vm::kMapProtCpuWrite) { + if (origVmProt & vm::kMapProtCpuWrite) { prot |= PROT_WRITE; } - if (origVmProt & rx::vm::kMapProtCpuExec) { + if (origVmProt & vm::kMapProtCpuExec) { prot |= PROT_EXEC; } - if (pageFlags & amdgpu::bridge::kPageReadWriteLock) { + if (pageFlags & amdgpu::kPageReadWriteLock) { prot &= ~(PROT_READ | PROT_WRITE); - } else if (pageFlags & amdgpu::bridge::kPageWriteWatch) { + } else if (pageFlags & amdgpu::kPageWriteWatch) { prot &= ~PROT_WRITE; } - // std::fprintf(stderr, "protection %lx-%lx\n", address, - // address + amdgpu::bridge::kHostPageSize * count); if (::mprotect(reinterpret_cast(address), - amdgpu::bridge::kHostPageSize * count, prot)) { + rx::mem::pageSize * count, prot)) { perror("protection failed"); std::abort(); } @@ -197,7 +198,7 @@ struct DceDevice : IoDevice { orbis::shared_mutex mtx; std::uint32_t freeVmIds = (1 << (kVmIdCount + 1)) - 1; orbis::uint64_t dmemOffset = ~static_cast(0); - VideoOutBuffer bufferAttributes{}; // TODO + orbis::ErrorCode open(orbis::Ref *file, const char *path, std::uint32_t flags, std::uint32_t mode, orbis::Thread *thread) override; @@ -206,7 +207,7 @@ struct DceDevice : IoDevice { int id = std::countr_zero(freeVmIds); if (id >= kVmIdCount) { - std::fprintf(stderr, "out of vm slots\n"); + std::println(stderr, "out of vm slots"); std::abort(); } @@ -235,7 +236,7 @@ static void initDceMemory(DceDevice *device) { } void *address = nullptr; - if (dmem->mmap(&address, kDceControlMemorySize, rx::vm::kMapProtCpuWrite, 0, + if (dmem->mmap(&address, kDceControlMemorySize, vm::kMapProtCpuWrite, 0, start) != orbis::ErrorCode{}) { std::abort(); } @@ -245,13 +246,14 @@ static void initDceMemory(DceDevice *device) { *reinterpret_cast(dceControl + 0x138) = 1; *reinterpret_cast(dceControl + 0x140) = orbis::kEvFiltDisplay; - rx::vm::unmap(address, kDceControlMemorySize); + vm::unmap(address, kDceControlMemorySize); device->dmemOffset = start; } static orbis::ErrorCode dce_ioctl(orbis::File *file, std::uint64_t request, void *argp, orbis::Thread *thread) { auto device = static_cast(file->device.get()); + auto gpu = orbis::g_context.gpuDevice.staticCast(); if (request == 0xc0308203) { // returns: @@ -297,11 +299,11 @@ static orbis::ErrorCode dce_ioctl(orbis::File *file, std::uint64_t request, FlipControlStatus flipStatus{}; // TODO: lock bridge header - flipStatus.flipArg = rx::bridge.header->flipArg[thread->tproc->vmId]; - flipStatus.count = rx::bridge.header->flipCount[thread->tproc->vmId]; + flipStatus.flipArg = gpu->flipArg[thread->tproc->vmId]; + flipStatus.count = gpu->flipCount[thread->tproc->vmId]; flipStatus.processTime = 0; // TODO flipStatus.tsc = 0; // TODO - flipStatus.currentBuffer = rx::bridge.header->flipBuffer[thread->tproc->vmId]; + flipStatus.currentBuffer = gpu->flipBuffer[thread->tproc->vmId]; flipStatus.flipPendingNum0 = 0; // TODO flipStatus.gcQueueNum = 0; // TODO flipStatus.flipPendingNum1 = 0; // TODO @@ -331,7 +333,7 @@ static orbis::ErrorCode dce_ioctl(orbis::File *file, std::uint64_t request, *(std::uint64_t *)args->size = kDceControlMemorySize; // size } else if (args->id == 31) { if ((std::uint64_t)args->ptr == 0xc) { - rx::bridge.header->bufferInUseAddress[thread->tproc->vmId] = args->size; + gpu->bufferInUseAddress[thread->tproc->vmId] = args->size; } else if ((std::uint64_t)args->ptr != 1) { ORBIS_LOG_ERROR("buffer in use", args->ptr, args->size); thread->where(); @@ -360,8 +362,13 @@ static orbis::ErrorCode dce_ioctl(orbis::File *file, std::uint64_t request, ORBIS_LOG_ERROR("dce: RegisterBuffer", args->canary, args->index, args->address, args->address2); - rx::bridge.sendRegisterBuffer(thread->tproc->pid, args->canary, args->index, - args->attrid, args->address, args->address2); + gpu->registerBuffer(thread->tproc->pid, { + .canary = args->canary, + .index = args->index, + .attrId = args->attrid, + .address = args->address, + .address2 = args->address2, + }); return {}; } @@ -374,10 +381,17 @@ static orbis::ErrorCode dce_ioctl(orbis::File *file, std::uint64_t request, args->unk4_zero, args->unk5_zero, args->options, args->reserved1, args->reserved2); - rx::bridge.sendRegisterBufferAttribute( - thread->tproc->pid, args->attrid, args->submit, args->canary, - args->pixelFormat, args->tilingMode, args->pitch, args->width, - args->height); + gpu->registerBufferAttribute(thread->tproc->pid, + { + .attrId = args->attrid, + .submit = args->submit, + .canary = args->canary, + .pixelFormat = args->pixelFormat, + .tilingMode = args->tilingMode, + .pitch = args->pitch, + .width = args->width, + .height = args->height, + }); return {}; } @@ -390,18 +404,11 @@ static orbis::ErrorCode dce_ioctl(orbis::File *file, std::uint64_t request, // args->displayBufferIndex, args->flipMode, args->unk1, // args->flipArg, args->flipArg2, args->eop_nz, args->unk2, // args->eop_val, args->unk3, args->unk4, args->rout); - - rx::bridge.sendFlip(thread->tproc->pid, args->displayBufferIndex, - /*args->flipMode,*/ args->flipArg); + gpu->submitFlip(thread->tproc->gfxRing, thread->tproc->pid, + args->displayBufferIndex, + /*args->flipMode,*/ args->flipArg); // *args->rout = 0; - - // rx::bridge.header->flipBuffer = args->displayBufferIndex; - // rx::bridge.header->flipArg = args->flipArg; - // rx::bridge.header->flipCount += 1; - // *reinterpret_cast(rx::bridge.header->bufferInUseAddress) - // = - // 0; return {}; } @@ -435,6 +442,20 @@ static const orbis::FileOps ops = { .mmap = dce_mmap, }; +static void createGpu() { + { + std::lock_guard lock(orbis::g_context.gpuDeviceMtx); + if (orbis::g_context.gpuDevice != nullptr) { + return; + } + + rx::createGpuDevice(); + } + + while (orbis::g_context.gpuDevice == nullptr) { + } +} + orbis::ErrorCode DceDevice::open(orbis::Ref *file, const char *path, std::uint32_t flags, std::uint32_t mode, orbis::Thread *thread) { @@ -444,9 +465,15 @@ orbis::ErrorCode DceDevice::open(orbis::Ref *file, *file = newFile; if (thread->tproc->vmId == -1) { + createGpu(); auto vmId = allocateVmId(); - rx::bridge.sendMapProcess(thread->tproc->pid, vmId); - thread->tproc->vmId = vmId; + + std::lock_guard lock(orbis::g_context.gpuDeviceMtx); + { + auto gpu = orbis::g_context.gpuDevice.staticCast(); + gpu->submitMapProcess(thread->tproc->gfxRing, thread->tproc->pid, vmId); + thread->tproc->vmId = vmId; + } runBridge(vmId); } diff --git a/rpcsx-os/iodev/devact.cpp b/rpcsx/iodev/devact.cpp similarity index 100% rename from rpcsx-os/iodev/devact.cpp rename to rpcsx/iodev/devact.cpp diff --git a/rpcsx-os/iodev/devctl.cpp b/rpcsx/iodev/devctl.cpp similarity index 100% rename from rpcsx-os/iodev/devctl.cpp rename to rpcsx/iodev/devctl.cpp diff --git a/rpcsx-os/iodev/devstat.cpp b/rpcsx/iodev/devstat.cpp similarity index 100% rename from rpcsx-os/iodev/devstat.cpp rename to rpcsx/iodev/devstat.cpp diff --git a/rpcsx-os/iodev/dipsw.cpp b/rpcsx/iodev/dipsw.cpp similarity index 100% rename from rpcsx-os/iodev/dipsw.cpp rename to rpcsx/iodev/dipsw.cpp diff --git a/rpcsx-os/iodev/dmem.cpp b/rpcsx/iodev/dmem.cpp similarity index 89% rename from rpcsx-os/iodev/dmem.cpp rename to rpcsx/iodev/dmem.cpp index 441d37b..d171e01 100644 --- a/rpcsx-os/iodev/dmem.cpp +++ b/rpcsx/iodev/dmem.cpp @@ -1,14 +1,18 @@ #include "dmem.hpp" -#include "bridge.hpp" +#include "gpu/Device.hpp" #include "io-device.hpp" #include "orbis/KernelAllocator.hpp" +#include "orbis/KernelContext.hpp" #include "orbis/file.hpp" #include "orbis/thread/Process.hpp" #include "orbis/thread/Thread.hpp" #include "orbis/utils/Logs.hpp" #include "rx/align.hpp" +#include "rx/watchdog.hpp" #include "vm.hpp" #include +#include +#include #include #include #include @@ -32,7 +36,7 @@ DmemDevice::~DmemDevice() { close(shmFd); } - shm_unlink(("/rpcsx-dmem-" + std::to_string(index)).c_str()); + std::filesystem::remove(std::format("{}/dmem-{}", rx::getShmPath(), index)); } orbis::ErrorCode DmemDevice::mmap(void **address, std::uint64_t len, @@ -41,8 +45,7 @@ orbis::ErrorCode DmemDevice::mmap(void **address, std::uint64_t len, if (prot == 0) { // hack // fixme: implement protect for pid - prot = rx::vm::kMapProtCpuWrite | rx::vm::kMapProtCpuRead | - rx::vm::kMapProtGpuAll; + prot = vm::kMapProtCpuWrite | vm::kMapProtCpuRead | vm::kMapProtGpuAll; } int memoryType = 0; @@ -51,9 +54,8 @@ orbis::ErrorCode DmemDevice::mmap(void **address, std::uint64_t len, memoryType = allocationInfoIt->memoryType; } - auto result = - rx::vm::map(*address, len, prot, flags, rx::vm::kMapInternalReserveOnly, - this, directMemoryStart); + auto result = vm::map(*address, len, prot, flags, vm::kMapInternalReserveOnly, + this, directMemoryStart); ORBIS_LOG_WARNING("dmem mmap", index, directMemoryStart, len, prot, flags, result, *address); @@ -66,9 +68,12 @@ orbis::ErrorCode DmemDevice::mmap(void **address, std::uint64_t len, return orbis::ErrorCode::INVAL; } - rx::bridge.sendMapMemory(orbis::g_currentThread->tproc->pid, memoryType, - index, reinterpret_cast(result), len, - prot, directMemoryStart); + if (auto gpu = orbis::g_context.gpuDevice.staticCast()) { + gpu->submitMapMemory(orbis::g_currentThread->tproc->gfxRing, + orbis::g_currentThread->tproc->pid, + reinterpret_cast(result), len, + memoryType, index, prot, directMemoryStart); + } *address = result; @@ -287,6 +292,11 @@ orbis::ErrorCode DmemDevice::allocate(std::uint64_t *start, return orbis::ErrorCode::AGAIN; } +orbis::ErrorCode DmemDevice::release(std::uint64_t start, std::uint64_t size) { + allocations.unmap(start, start + size); + return {}; +} + orbis::ErrorCode DmemDevice::queryMaxFreeChunkSize(std::uint64_t *start, std::uint64_t searchEnd, std::uint64_t alignment, @@ -295,8 +305,8 @@ orbis::ErrorCode DmemDevice::queryMaxFreeChunkSize(std::uint64_t *start, std::size_t resultSize = 0; std::size_t resultOffset = 0; - alignment = std::max(alignment, rx::vm::kPageSize); - alignment = rx::alignUp(alignment, rx::vm::kPageSize); + alignment = std::max(alignment, vm::kPageSize); + alignment = rx::alignUp(alignment, vm::kPageSize); while (offset < searchEnd) { offset += alignment - 1; @@ -361,8 +371,9 @@ IoDevice *createDmemCharacterDevice(int index) { auto *newDevice = orbis::knew(); newDevice->index = index; newDevice->dmemTotalSize = dmemSize; - auto shmFd = ::shm_open(("/rpcsx-dmem-" + std::to_string(index)).c_str(), - O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); + + auto path = std::format("{}/dmem-{}", rx::getShmPath(), index); + auto shmFd = ::open(path.c_str(), O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); if (ftruncate(shmFd, dmemSize) < 0) { ::close(shmFd); diff --git a/rpcsx-os/iodev/dmem.hpp b/rpcsx/iodev/dmem.hpp similarity index 100% rename from rpcsx-os/iodev/dmem.hpp rename to rpcsx/iodev/dmem.hpp diff --git a/rpcsx-os/iodev/evlg.cpp b/rpcsx/iodev/evlg.cpp similarity index 100% rename from rpcsx-os/iodev/evlg.cpp rename to rpcsx/iodev/evlg.cpp diff --git a/rpcsx-os/iodev/gbase.cpp b/rpcsx/iodev/gbase.cpp similarity index 100% rename from rpcsx-os/iodev/gbase.cpp rename to rpcsx/iodev/gbase.cpp diff --git a/rpcsx-os/iodev/gc.cpp b/rpcsx/iodev/gc.cpp similarity index 62% rename from rpcsx-os/iodev/gc.cpp rename to rpcsx/iodev/gc.cpp index 8bdb2de..bf518c4 100644 --- a/rpcsx-os/iodev/gc.cpp +++ b/rpcsx/iodev/gc.cpp @@ -1,6 +1,8 @@ -#include "bridge.hpp" +#include "gpu/Device.hpp" #include "io-device.hpp" +#include "iodev/dmem.hpp" #include "orbis/KernelAllocator.hpp" +#include "orbis/KernelContext.hpp" #include "orbis/file.hpp" #include "orbis/thread/Process.hpp" #include "orbis/thread/Thread.hpp" @@ -9,6 +11,7 @@ #include "vm.hpp" #include #include +#include #include #include @@ -24,6 +27,7 @@ struct GcDevice : public IoDevice { orbis::shared_mutex mtx; orbis::kmap clients; orbis::kmap computeQueues; + void *submitArea = nullptr; orbis::ErrorCode open(orbis::Ref *file, const char *path, std::uint32_t flags, std::uint32_t mode, orbis::Thread *thread) override; @@ -34,66 +38,61 @@ struct GcDevice : public IoDevice { struct GcFile : public orbis::File { orbis::Process *process = nullptr; - ~GcFile() { device.staticCast()->removeClient(process); } -}; + int gfxPipe = 0; -static std::uint64_t g_submitDoneFlag; + ~GcFile() { device.rawStaticCast()->removeClient(process); } +}; static orbis::ErrorCode gc_ioctl(orbis::File *file, std::uint64_t request, void *argp, orbis::Thread *thread) { // 0xc00c8110 // 0xc0848119 - auto device = file->device.staticCast(); - std::lock_guard lock(device->mtx); + auto gcFile = static_cast(file); + auto device = file->device.rawStaticCast(); + // std::lock_guard lock(device->mtx); switch (request) { case 0xc008811b: // get submit done flag ptr? - // TODO + if (device->submitArea == nullptr) { + auto dmem = orbis::g_context.dmemDevice.staticCast(); + std::uint64_t start = 0; + auto err = dmem->allocate(&start, ~0, vm::kPageSize, 0, 0); + if (err != orbis::ErrorCode{}) { + return err; + } + auto address = reinterpret_cast(0xfe0100000); + err = dmem->mmap(&address, vm::kPageSize, + vm::kMapProtCpuReadWrite | vm::kMapProtGpuAll, + vm::kMapFlagShared, start); + if (err != orbis::ErrorCode{}) { + dmem->release(start, vm::kPageSize); + return err; + } + device->submitArea = address; + } + ORBIS_LOG_ERROR("gc ioctl 0xc008811b", *(std::uint64_t *)argp); - *reinterpret_cast(argp) = &g_submitDoneFlag; + *reinterpret_cast(argp) = device->submitArea; break; case 0xc0108102: { // submit? struct Args { - std::uint32_t arg0; - std::uint32_t count; - std::uint64_t *cmds; + orbis::uint32_t arg0; + orbis::uint32_t count; + orbis::uint32_t *cmds; }; auto args = reinterpret_cast(argp); - - // flockfile(stderr); - // if (thread->tproc->pid != amdgpu::bridge::expGpuPid) { - // ORBIS_LOG_ERROR("gc ioctl submit", args->arg0, args->count, args->cmds); - // } - - for (unsigned i = 0; i < args->count; ++i) { - auto cmd = args->cmds + (i * 2); - auto cmdId = cmd[0] & 0xffff'ffff; - auto addressLoPart = cmd[0] >> 32; - auto addressHiPart = cmd[1] & 0xff; - auto address = addressLoPart | (addressHiPart << 32); - auto unkPreservedVal = cmd[1] & 0xfff00000ffffff00; - auto size = ((cmd[1] >> 32) & 0xfffff) << 2; - - // std::fprintf(stderr, " %lx\n", cmd[0]); - // std::fprintf(stderr, " %lx\n", cmd[1]); - // std::fprintf(stderr, " %u:\n", i); - // std::fprintf(stderr, " cmdId = %lx\n", cmdId); - // std::fprintf(stderr, " address = %lx\n", address); - // std::fprintf(stderr, " unkPreservedVal = %lx\n", unkPreservedVal); - // std::fprintf(stderr, " size = %lu\n", size); - - // for (std::size_t i = 0; i < std::min(size, 64); i += 4) { - // std::fprintf(stderr, "%08x ", *(unsigned *)(address + i)); - // } - // std::fprintf(stderr, "\n"); - - rx::bridge.sendCommandBuffer(thread->tproc->pid, cmdId, address, size); + if (auto gpu = orbis::g_context.gpuDevice.staticCast()) { + for (unsigned i = 0; i < args->count; ++i) { + gpu->submitGfxCommand(gcFile->gfxPipe, + orbis::g_currentThread->tproc->vmId, + {args->cmds + i * 4, 4}); + } + } else { + return orbis::ErrorCode::INVAL; } - // funlockfile(stderr); - break; } @@ -104,6 +103,11 @@ static orbis::ErrorCode gc_ioctl(orbis::File *file, std::uint64_t request, }; auto args = reinterpret_cast(argp); + if (auto gpu = orbis::g_context.gpuDevice.staticCast()) { + gpu->submitSwitchBuffer(orbis::g_currentThread->tproc->vmId); + } else { + return orbis::ErrorCode::INVAL; + } // ORBIS_LOG_ERROR("gc ioctl 0xc0088101", args->arg0, args->arg1); break; @@ -113,45 +117,33 @@ static orbis::ErrorCode gc_ioctl(orbis::File *file, std::uint64_t request, struct Args { std::uint32_t arg0; std::uint32_t count; - std::uint64_t *cmds; + std::uint32_t *cmds; std::uint64_t arg3; // flipArg? std::uint32_t arg4; // bufferIndex? }; auto args = reinterpret_cast(argp); - flockfile(stderr); - ORBIS_LOG_ERROR("gc ioctl 0xc020810c", args->arg0, args->count, args->cmds, - args->arg3, args->arg4); - - for (unsigned i = 0; i < args->count; ++i) { - auto cmd = args->cmds + (i * 2); - auto cmdId = cmd[0] & 0xffff'ffff; - auto addressLoPart = cmd[0] >> 32; - auto addressHiPart = cmd[1] & 0xff; - auto address = addressLoPart | (addressHiPart << 32); - auto unkPreservedVal = cmd[1] & 0xfff00000ffffff00; - auto size = ((cmd[1] >> 32) & 0xfffff) << 2; - - // std::fprintf(stderr, " %lx\n", cmd[0]); - // std::fprintf(stderr, " %lx\n", cmd[1]); - // std::fprintf(stderr, " %u:\n", i); - // std::fprintf(stderr, " cmdId = %lx\n", cmdId); - // std::fprintf(stderr, " address = %lx\n", address); - // std::fprintf(stderr, " unkPreservedVal = %lx\n", unkPreservedVal); - // std::fprintf(stderr, " size = %lu\n", size); - - rx::bridge.sendCommandBuffer(thread->tproc->pid, cmdId, address, size); + if (auto gpu = orbis::g_context.gpuDevice.staticCast()) { + for (unsigned i = 0; i < args->count; ++i) { + gpu->submitGfxCommand(gcFile->gfxPipe, + orbis::g_currentThread->tproc->vmId, + {args->cmds + i * 4, 4}); + } + } else { + return orbis::ErrorCode::INVAL; } - funlockfile(stderr); // orbis::bridge.sendDoFlip(); break; } case 0xc0048116: { // submit done? - // ORBIS_LOG_ERROR("gc ioctl 0xc0048116", *(std::uint32_t *)argp); - // thread->where(); + if (auto gpu = orbis::g_context.gpuDevice.staticCast()) { + gpu->waitForIdle(); + } else { + return orbis::ErrorCode::INVAL; + } break; } @@ -217,19 +209,21 @@ static orbis::ErrorCode gc_ioctl(orbis::File *file, std::uint64_t request, args->queueId, args->offset, args->ringBaseAddress, args->readPtrAddress, args->dingDongPtr, args->lenLog2); - auto id = ((args->pipeHi * 4) + args->pipeLo) * 8 + args->queueId; - device->computeQueues[id] = { - .ringBaseAddress = args->ringBaseAddress, - .readPtrAddress = args->readPtrAddress, - .dingDongPtr = args->dingDongPtr, - .len = static_cast(1) << args->lenLog2, - }; - args->pipeHi = 0x769c766; - args->pipeLo = 0x72e8e3c1; - args->queueId = -0x248d50d8; - args->offset = 0xd245ed58; + rx::die("gc ioctl map compute queue"); - ((std::uint64_t *)args->dingDongPtr)[0xf0 / sizeof(std::uint64_t)] = 1; + // auto id = ((args->pipeHi * 4) + args->pipeLo) * 8 + args->queueId; + // device->computeQueues[id] = { + // .ringBaseAddress = args->ringBaseAddress, + // .readPtrAddress = args->readPtrAddress, + // .dingDongPtr = args->dingDongPtr, + // .len = static_cast(1) << args->lenLog2, + // }; + // args->pipeHi = 0x769c766; + // args->pipeLo = 0x72e8e3c1; + // args->queueId = -0x248d50d8; + // args->offset = 0xd245ed58; + + // ((std::uint64_t *)args->dingDongPtr)[0xf0 / sizeof(std::uint64_t)] = 1; break; } @@ -245,17 +239,18 @@ static orbis::ErrorCode gc_ioctl(orbis::File *file, std::uint64_t request, auto args = reinterpret_cast(argp); ORBIS_LOG_ERROR("gc ioctl ding dong for workload", args->pipeHi, args->pipeLo, args->queueId, args->nextStartOffsetInDw); + rx::die("gc ioctl ding dong for workload"); - auto id = ((args->pipeHi * 4) + args->pipeLo) * 8 + args->queueId; + // auto id = ((args->pipeHi * 4) + args->pipeLo) * 8 + args->queueId; - auto queue = device->computeQueues.at(id); - auto address = (queue.ringBaseAddress + queue.offset); - auto endOffset = static_cast(args->nextStartOffsetInDw) << 2; - auto size = endOffset - queue.offset; + // auto queue = device->computeQueues.at(id); + // auto address = (queue.ringBaseAddress + queue.offset); + // auto endOffset = static_cast(args->nextStartOffsetInDw) << + // 2; auto size = endOffset - queue.offset; - rx::bridge.sendCommandBuffer(thread->tproc->pid, id, address, size); + // rx::bridge.sendCommandBuffer(thread->tproc->pid, id, address, size); - queue.offset = endOffset; + // queue.offset = endOffset; break; } @@ -275,7 +270,7 @@ static orbis::ErrorCode gc_ioctl(orbis::File *file, std::uint64_t request, case 0x802450c9: { // used during Net initialization - std::fprintf(stderr, "***WARNING*** Unknown gc ioctl_%lx(0x%lx)\n", request, + std::println(stderr, "***WARNING*** Unknown gc ioctl_{:x}(0x{:x})", request, (unsigned long)*(std::uint32_t *)argp); break; } @@ -313,7 +308,7 @@ static orbis::ErrorCode gc_mmap(orbis::File *file, void **address, std::int32_t flags, std::int64_t offset, orbis::Thread *thread) { ORBIS_LOG_FATAL("gc mmap", address, size, offset); - auto result = rx::vm::map(*address, size, prot, flags); + auto result = vm::map(*address, size, prot, flags); if (result == (void *)-1) { return orbis::ErrorCode::INVAL; // TODO diff --git a/rpcsx-os/iodev/hdd.cpp b/rpcsx/iodev/hdd.cpp similarity index 100% rename from rpcsx-os/iodev/hdd.cpp rename to rpcsx/iodev/hdd.cpp diff --git a/rpcsx-os/iodev/hdmi.cpp b/rpcsx/iodev/hdmi.cpp similarity index 100% rename from rpcsx-os/iodev/hdmi.cpp rename to rpcsx/iodev/hdmi.cpp diff --git a/rpcsx-os/iodev/hid.cpp b/rpcsx/iodev/hid.cpp similarity index 68% rename from rpcsx-os/iodev/hid.cpp rename to rpcsx/iodev/hid.cpp index 47cb559..6d5757a 100644 --- a/rpcsx-os/iodev/hid.cpp +++ b/rpcsx/iodev/hid.cpp @@ -1,7 +1,7 @@ -#include "amdgpu/bridge/bridge.hpp" -#include "bridge.hpp" +#include "gpu/Device.hpp" #include "io-device.hpp" #include "orbis/KernelAllocator.hpp" +#include "orbis/KernelContext.hpp" #include "orbis/file.hpp" #include "orbis/thread/Thread.hpp" #include "orbis/utils/Logs.hpp" @@ -35,46 +35,28 @@ static orbis::ErrorCode hid_ioctl(orbis::File *file, std::uint64_t request, return {}; case 0x8030482e: { - ORBIS_LOG_FATAL("hid ioctl", request); + // ORBIS_LOG_FATAL("hid ioctl", request); // read state struct ReadStateArgs { std::uint32_t hidId; std::uint32_t unk0; - amdgpu::bridge::PadState *state; + amdgpu::PadState *state; std::uint32_t unk2; std::uint32_t *connected; std::uint32_t *unk4; std::uint64_t unk5; }; - // enum { - // kPadBtnL3 = 1 << 1, - // kPadBtnR3 = 1 << 2, - // kPadBtnOptions = 1 << 3, - // kPadBtnUp = 1 << 4, - // kPadBtnRight = 1 << 5, - // kPadBtnDown = 1 << 6, - // kPadBtnLeft = 1 << 7, - // kPadBtnL2 = 1 << 8, - // kPadBtnR2 = 1 << 9, - // kPadBtnL1 = 1 << 10, - // kPadBtnR1 = 1 << 11, - // kPadBtnTriangle = 1 << 12, - // kPadBtnCircle = 1 << 13, - // kPadBtnCross = 1 << 14, - // kPadBtnSquare = 1 << 15, - // kPadBtnTouchPad = 1 << 20, - // kPadBtnIntercepted = 1 << 31, - // }; - auto args = *reinterpret_cast(argp); // ORBIS_LOG_ERROR("hid read state", args.hidId, args.unk0, args.state, // args.unk2, args.connected, args.unk4, args.unk5); - *args.state = rx::bridge.header->kbPadState; - *args.connected = 1; - *args.unk4 = 1; // is wireless? - thread->retval[0] = 1; + if (auto gpu = orbis::g_context.gpuDevice.staticCast()) { + *args.state = gpu->kbPadState; + *args.connected = 1; + *args.unk4 = 1; // is wireless? + thread->retval[0] = 1; + } return {}; } @@ -88,16 +70,17 @@ static orbis::ErrorCode hid_ioctl(orbis::File *file, std::uint64_t request, struct MiniReadStateArgs { orbis::uint hidId; orbis::uint unk0; - orbis::ptr state; + orbis::ptr state; orbis::uint count; orbis::uint padding; orbis::ptr unk5; }; - - auto args = *reinterpret_cast(argp); - *args.state = rx::bridge.header->kbPadState; - thread->retval[0] = 1; - return{}; + if (auto gpu = orbis::g_context.gpuDevice.staticCast()) { + auto args = *reinterpret_cast(argp); + *args.state = gpu->kbPadState; + thread->retval[0] = 1; + } + return {}; } default: diff --git a/rpcsx-os/iodev/hmd_3da.cpp b/rpcsx/iodev/hmd_3da.cpp similarity index 100% rename from rpcsx-os/iodev/hmd_3da.cpp rename to rpcsx/iodev/hmd_3da.cpp diff --git a/rpcsx-os/iodev/hmd_cmd.cpp b/rpcsx/iodev/hmd_cmd.cpp similarity index 100% rename from rpcsx-os/iodev/hmd_cmd.cpp rename to rpcsx/iodev/hmd_cmd.cpp diff --git a/rpcsx-os/iodev/hmd_mmap.cpp b/rpcsx/iodev/hmd_mmap.cpp similarity index 96% rename from rpcsx-os/iodev/hmd_mmap.cpp rename to rpcsx/iodev/hmd_mmap.cpp index 32cff3a..4f0ff14 100644 --- a/rpcsx-os/iodev/hmd_mmap.cpp +++ b/rpcsx/iodev/hmd_mmap.cpp @@ -23,7 +23,7 @@ static orbis::ErrorCode hmd_mmap_mmap(orbis::File *file, void **address, std::int32_t flags, std::int64_t offset, orbis::Thread *thread) { ORBIS_LOG_FATAL("hmd_mmap mmap", address, size, offset); - auto result = rx::vm::map(*address, size, prot, flags); + auto result = vm::map(*address, size, prot, flags); if (result == (void *)-1) { return orbis::ErrorCode::INVAL; // TODO diff --git a/rpcsx-os/iodev/hmd_snsr.cpp b/rpcsx/iodev/hmd_snsr.cpp similarity index 100% rename from rpcsx-os/iodev/hmd_snsr.cpp rename to rpcsx/iodev/hmd_snsr.cpp diff --git a/rpcsx-os/iodev/icc_configuration.cpp b/rpcsx/iodev/icc_configuration.cpp similarity index 100% rename from rpcsx-os/iodev/icc_configuration.cpp rename to rpcsx/iodev/icc_configuration.cpp diff --git a/rpcsx-os/iodev/icc_power.cpp b/rpcsx/iodev/icc_power.cpp similarity index 100% rename from rpcsx-os/iodev/icc_power.cpp rename to rpcsx/iodev/icc_power.cpp diff --git a/rpcsx-os/iodev/lvdctl.cpp b/rpcsx/iodev/lvdctl.cpp similarity index 100% rename from rpcsx-os/iodev/lvdctl.cpp rename to rpcsx/iodev/lvdctl.cpp diff --git a/rpcsx-os/iodev/mbus.cpp b/rpcsx/iodev/mbus.cpp similarity index 100% rename from rpcsx-os/iodev/mbus.cpp rename to rpcsx/iodev/mbus.cpp diff --git a/rpcsx-os/iodev/mbus.hpp b/rpcsx/iodev/mbus.hpp similarity index 100% rename from rpcsx-os/iodev/mbus.hpp rename to rpcsx/iodev/mbus.hpp diff --git a/rpcsx-os/iodev/mbus_av.cpp b/rpcsx/iodev/mbus_av.cpp similarity index 100% rename from rpcsx-os/iodev/mbus_av.cpp rename to rpcsx/iodev/mbus_av.cpp diff --git a/rpcsx-os/iodev/mbus_av.hpp b/rpcsx/iodev/mbus_av.hpp similarity index 100% rename from rpcsx-os/iodev/mbus_av.hpp rename to rpcsx/iodev/mbus_av.hpp diff --git a/rpcsx-os/iodev/metadbg.cpp b/rpcsx/iodev/metadbg.cpp similarity index 100% rename from rpcsx-os/iodev/metadbg.cpp rename to rpcsx/iodev/metadbg.cpp diff --git a/rpcsx-os/iodev/notification.cpp b/rpcsx/iodev/notification.cpp similarity index 100% rename from rpcsx-os/iodev/notification.cpp rename to rpcsx/iodev/notification.cpp diff --git a/rpcsx-os/iodev/npdrm.cpp b/rpcsx/iodev/npdrm.cpp similarity index 100% rename from rpcsx-os/iodev/npdrm.cpp rename to rpcsx/iodev/npdrm.cpp diff --git a/rpcsx-os/iodev/null.cpp b/rpcsx/iodev/null.cpp similarity index 100% rename from rpcsx-os/iodev/null.cpp rename to rpcsx/iodev/null.cpp diff --git a/rpcsx-os/iodev/rng.cpp b/rpcsx/iodev/rng.cpp similarity index 96% rename from rpcsx-os/iodev/rng.cpp rename to rpcsx/iodev/rng.cpp index 52b2d35..77dca67 100644 --- a/rpcsx-os/iodev/rng.cpp +++ b/rpcsx/iodev/rng.cpp @@ -23,7 +23,7 @@ static orbis::ErrorCode rng_mmap(orbis::File *file, void **address, std::int32_t flags, std::int64_t offset, orbis::Thread *thread) { ORBIS_LOG_FATAL("rng mmap", address, size, offset); - auto result = rx::vm::map(*address, size, prot, flags); + auto result = vm::map(*address, size, prot, flags); if (result == (void *)-1) { return orbis::ErrorCode::INVAL; // TODO diff --git a/rpcsx-os/iodev/s3da.cpp b/rpcsx/iodev/s3da.cpp similarity index 100% rename from rpcsx-os/iodev/s3da.cpp rename to rpcsx/iodev/s3da.cpp diff --git a/rpcsx-os/iodev/sbl_srv.cpp b/rpcsx/iodev/sbl_srv.cpp similarity index 96% rename from rpcsx-os/iodev/sbl_srv.cpp rename to rpcsx/iodev/sbl_srv.cpp index 8bdda8d..b018ece 100644 --- a/rpcsx-os/iodev/sbl_srv.cpp +++ b/rpcsx/iodev/sbl_srv.cpp @@ -29,7 +29,7 @@ static orbis::ErrorCode sbl_srv_mmap(orbis::File *file, void **address, std::int32_t flags, std::int64_t offset, orbis::Thread *thread) { ORBIS_LOG_FATAL("sbl_srv mmap", address, size, offset); - auto result = rx::vm::map(*address, size, prot, flags); + auto result = vm::map(*address, size, prot, flags); if (result == (void *)-1) { return orbis::ErrorCode::INVAL; // TODO diff --git a/rpcsx-os/iodev/scanin.cpp b/rpcsx/iodev/scanin.cpp similarity index 100% rename from rpcsx-os/iodev/scanin.cpp rename to rpcsx/iodev/scanin.cpp diff --git a/rpcsx-os/iodev/shm.cpp b/rpcsx/iodev/shm.cpp similarity index 69% rename from rpcsx-os/iodev/shm.cpp rename to rpcsx/iodev/shm.cpp index c93d84a..ba02cfa 100644 --- a/rpcsx-os/iodev/shm.cpp +++ b/rpcsx/iodev/shm.cpp @@ -4,7 +4,9 @@ #include "orbis/file.hpp" #include "orbis/thread/Thread.hpp" #include "orbis/utils/Logs.hpp" +#include "rx/watchdog.hpp" #include +#include #include struct ShmDevice : IoDevice { @@ -15,34 +17,20 @@ struct ShmDevice : IoDevice { orbis::Thread *thread) override; }; -static std::string realShmPath(const char *path) { - std::string name = "/rpcsx-"; - if (path[0] == '/') { - name += path + 1; - } else { - name += path; - } - - for (auto pos = name.find('/', 1); pos != std::string::npos; - pos = name.find('/', pos + 1)) { - name[pos] = '$'; - } - - return name; -} - orbis::ErrorCode ShmDevice::open(orbis::Ref *file, const char *path, std::uint32_t flags, std::uint32_t mode, orbis::Thread *thread) { ORBIS_LOG_WARNING("shm_open", path, flags, mode); - auto name = realShmPath(path); + auto hostPath = rx::getShmGuestPath(path); auto realFlags = O_RDWR; // TODO if (flags & 0x200) { realFlags |= O_CREAT; } - int fd = shm_open(name.c_str(), realFlags, S_IRUSR | S_IWUSR); + std::filesystem::create_directories(hostPath.parent_path()); + + int fd = ::open(hostPath.c_str(), realFlags, S_IRUSR | S_IWUSR); if (fd < 0) { return convertErrno(); } @@ -53,14 +41,19 @@ orbis::ErrorCode ShmDevice::open(orbis::Ref *file, } orbis::ErrorCode ShmDevice::unlink(const char *path, bool recursive, - orbis::Thread *thread) { + orbis::Thread *thread) { ORBIS_LOG_WARNING("shm_unlink", path); - auto name = realShmPath(path); + auto hostPath = rx::getShmGuestPath(path); - if (shm_unlink(name.c_str())) { - return convertErrno(); + std::error_code ec; + + if (recursive) { + std::filesystem::remove_all(hostPath, ec); + } else { + std::filesystem::remove(hostPath, ec); } - return{}; + return convertErrorCode(ec); } + IoDevice *createShmDevice() { return orbis::knew(); } diff --git a/rpcsx-os/iodev/srtc.cpp b/rpcsx/iodev/srtc.cpp similarity index 100% rename from rpcsx-os/iodev/srtc.cpp rename to rpcsx/iodev/srtc.cpp diff --git a/rpcsx-os/iodev/sshot.cpp b/rpcsx/iodev/sshot.cpp similarity index 100% rename from rpcsx-os/iodev/sshot.cpp rename to rpcsx/iodev/sshot.cpp diff --git a/rpcsx-os/iodev/urandom.cpp b/rpcsx/iodev/urandom.cpp similarity index 100% rename from rpcsx-os/iodev/urandom.cpp rename to rpcsx/iodev/urandom.cpp diff --git a/rpcsx-os/iodev/uvd.cpp b/rpcsx/iodev/uvd.cpp similarity index 100% rename from rpcsx-os/iodev/uvd.cpp rename to rpcsx/iodev/uvd.cpp diff --git a/rpcsx-os/iodev/vce.cpp b/rpcsx/iodev/vce.cpp similarity index 100% rename from rpcsx-os/iodev/vce.cpp rename to rpcsx/iodev/vce.cpp diff --git a/rpcsx-os/iodev/xpt.cpp b/rpcsx/iodev/xpt.cpp similarity index 100% rename from rpcsx-os/iodev/xpt.cpp rename to rpcsx/iodev/xpt.cpp diff --git a/rpcsx-os/iodev/zero.cpp b/rpcsx/iodev/zero.cpp similarity index 100% rename from rpcsx-os/iodev/zero.cpp rename to rpcsx/iodev/zero.cpp diff --git a/rpcsx/ipmi.cpp b/rpcsx/ipmi.cpp new file mode 100644 index 0000000..4d31043 --- /dev/null +++ b/rpcsx/ipmi.cpp @@ -0,0 +1,841 @@ +#include "ipmi.hpp" + +#include "AudioOut.hpp" +#include "io-device.hpp" +#include "orbis/KernelContext.hpp" +#include "orbis/osem.hpp" +#include "orbis/utils/Logs.hpp" +#include "rx/hexdump.hpp" +#include "vfs.hpp" +#include "vm.hpp" +#include +#include +#include + +ipmi::IpmiClient ipmi::audioIpmiClient; + +template struct GuestAlloc { + orbis::ptr guestAddress; + + GuestAlloc(std::size_t size) { + if (size == 0) { + guestAddress = nullptr; + } else { + guestAddress = orbis::ptr( + vm::map(nullptr, size, vm::kMapProtCpuRead | vm::kMapProtCpuWrite, + vm::kMapFlagPrivate | vm::kMapFlagAnonymous)); + } + } + + GuestAlloc() : GuestAlloc(sizeof(T)) {} + + GuestAlloc(const T &data) : GuestAlloc() { + if (orbis::uwrite(guestAddress, data) != orbis::ErrorCode{}) { + std::abort(); + } + } + + GuestAlloc(const void *data, std::size_t size) : GuestAlloc(size) { + if (orbis::uwriteRaw(guestAddress, data, size) != orbis::ErrorCode{}) { + std::abort(); + } + } + + GuestAlloc(const GuestAlloc &) = delete; + + GuestAlloc(GuestAlloc &&other) noexcept : guestAddress(other.guestAddress) { + other.guestAddress = 0; + } + GuestAlloc &operator=(GuestAlloc &&other) noexcept { + std::swap(guestAddress, other.guestAddress); + } + + ~GuestAlloc() { + if (guestAddress != 0) { + vm::unmap(guestAddress, sizeof(T)); + } + } + + operator orbis::ptr() { return guestAddress; } + T *operator->() { return guestAddress; } + operator T &() { return *guestAddress; } +}; + +orbis::sint ipmi::IpmiClient::sendSyncMessageRaw( + std::uint32_t method, const std::vector> &inData, + std::vector> &outBuf) { + GuestAlloc serverResult; + GuestAlloc guestInDataArray{sizeof(orbis::IpmiDataInfo) * + inData.size()}; + GuestAlloc guestOutBufArray{ + sizeof(orbis::IpmiBufferInfo) * outBuf.size()}; + + std::vector> guestAllocs; + guestAllocs.reserve(inData.size() + outBuf.size()); + + for (auto &data : inData) { + auto pointer = + guestAllocs.emplace_back(data.data(), data.size()).guestAddress; + + guestInDataArray.guestAddress[&data - inData.data()] = { + .data = pointer, .size = data.size()}; + } + + for (auto &buf : outBuf) { + auto pointer = + guestAllocs.emplace_back(buf.data(), buf.size()).guestAddress; + + guestOutBufArray.guestAddress[&buf - outBuf.data()] = { + .data = pointer, .capacity = buf.size()}; + } + + GuestAlloc params = orbis::IpmiSyncCallParams{ + .method = method, + .numInData = static_cast(inData.size()), + .numOutData = static_cast(outBuf.size()), + .pInData = guestInDataArray, + .pOutData = guestOutBufArray, + .pResult = serverResult, + .flags = (inData.size() >= 1 || outBuf.size() >= 1) ? 1u : 0u, + }; + + GuestAlloc errorCode; + orbis::sysIpmiClientInvokeSyncMethod(thread, errorCode, kid, params, + sizeof(orbis::IpmiSyncCallParams)); + + for (auto &buf : outBuf) { + auto size = guestOutBufArray.guestAddress[inData.data() - &buf].size; + buf.resize(size); + } + return serverResult; +} + +ipmi::IpmiClient ipmi::createIpmiClient(orbis::Thread *thread, + const char *name) { + orbis::Ref client; + GuestAlloc config = orbis::IpmiCreateClientConfig{ + .size = sizeof(orbis::IpmiCreateClientConfig), + }; + + orbis::uint kid; + + { + GuestAlloc guestName{name, std::strlen(name)}; + GuestAlloc params = orbis::IpmiCreateClientParams{ + .name = guestName, + .config = config, + }; + + GuestAlloc result; + GuestAlloc guestKid; + orbis::sysIpmiCreateClient(thread, guestKid, params, + sizeof(orbis::IpmiCreateClientParams)); + kid = guestKid; + } + + { + GuestAlloc status; + GuestAlloc params = orbis::IpmiClientConnectParams{.status = status}; + + GuestAlloc result; + while (true) { + auto errc = orbis::sysIpmiClientConnect( + thread, result, kid, params, sizeof(orbis::IpmiClientConnectParams)); + if (errc.value() == 0) { + break; + } + + std::this_thread::sleep_for(std::chrono::microseconds(300)); + } + } + + return {.clientImpl = std::move(client), .kid = kid, .thread = thread}; +} + +orbis::Semaphore *ipmi::createSemaphore(std::string_view name, uint32_t attrs, + uint64_t initCount, uint64_t maxCount) { + auto result = + orbis::g_context + .createSemaphore(orbis::kstring(name), attrs, initCount, maxCount) + .first; + std::memcpy(result->name, name.data(), name.size()); + result->name[name.size()] = 0; + return result; +} + +orbis::EventFlag *ipmi::createEventFlag(std::string_view name, uint32_t attrs, + uint64_t initPattern) { + return orbis::g_context + .createEventFlag(orbis::kstring(name), attrs, initPattern) + .first; +} + +void ipmi::createShm(const char *name, uint32_t flags, uint32_t mode, + uint64_t size) { + orbis::Ref shm; + auto shmDevice = orbis::g_context.shmDevice.staticCast(); + shmDevice->open(&shm, name, flags, mode, nullptr); + shm->ops->truncate(shm.get(), size, nullptr); +} + +orbis::ErrorCode +ipmi::IpmiServer::handle(orbis::IpmiSession *session, + orbis::IpmiAsyncMessageHeader *message) { + std::vector> inData; + std::vector> outData; + auto bufLoc = std::bit_cast(message + 1); + + for (unsigned i = 0; i < message->numInData; ++i) { + auto size = *std::bit_cast(bufLoc); + bufLoc += sizeof(orbis::uint); + inData.push_back({bufLoc, size}); + bufLoc += size; + } + + orbis::IpmiClient::AsyncResponse response; + response.methodId = message->methodId + 1; + response.errorCode = 0; + orbis::ErrorCode result{}; + + if (auto it = asyncMethods.find(message->methodId); + it != asyncMethods.end()) { + auto &handler = it->second; + + result = handler(*session, response.errorCode, outData, inData); + } else { + std::println(stderr, "Unimplemented async method {}::{:x}(inBufCount={})", + session->server->name, unsigned(message->methodId), + unsigned(message->numInData)); + + for (auto in : inData) { + std::println(stderr, "in {}", in.size()); + rx::hexdump(in); + } + } + + for (auto out : outData) { + response.data.push_back({out.data(), out.data() + out.size()}); + } + + std::lock_guard clientLock(session->client->mutex); + session->client->asyncResponses.push_front(std::move(response)); + std::fprintf(stderr, "%s:%x: sending async response\n", + session->client->name.c_str(), message->methodId); + session->client->asyncResponseCv.notify_all(session->client->mutex); + return result; +} +orbis::ErrorCode +ipmi::IpmiServer::handle(orbis::IpmiSession *session, + orbis::IpmiServer::Packet &packet, + orbis::IpmiSyncMessageHeader *message) { + auto bufLoc = std::bit_cast(message + 1); + std::vector> inData; + std::vector> outData; + for (unsigned i = 0; i < message->numInData; ++i) { + auto size = *std::bit_cast(bufLoc); + bufLoc += sizeof(orbis::uint); + inData.emplace_back(bufLoc, size); + bufLoc += size; + } + + for (unsigned i = 0; i < message->numOutData; ++i) { + auto size = *std::bit_cast(bufLoc); + bufLoc += sizeof(orbis::uint); + outData.emplace_back(size); + } + + orbis::IpmiSession::SyncResponse response; + response.errorCode = 0; + orbis::ErrorCode result{}; + + if (auto it = syncMethods.find(message->methodId); it != syncMethods.end()) { + auto &handler = it->second; + + result = handler(*session, response.errorCode, outData, inData); + } else { + std::println( + stderr, + "Unimplemented sync method {}::{:x}(inBufCount={}, outBufCount={})", + session->server->name, unsigned(message->methodId), + unsigned(message->numInData), unsigned(message->numOutData)); + + for (auto in : inData) { + std::println(stderr, "in {}", in.size()); + rx::hexdump(in); + } + + for (auto &out : outData) { + std::println(stderr, "out {:x}", out.size()); + } + + for (auto out : outData) { + std::memset(out.data(), 0, out.size()); + } + // TODO: + // response.errorCode = message->numOutData == 0 || + // (message->numOutData == 1 && outData[0].empty()) + // ? 0 + // : -1, + } + + response.callerTid = packet.clientTid; + for (auto out : outData) { + response.data.push_back({out.data(), out.data() + out.size()}); + } + + std::lock_guard lock(session->mutex); + session->syncResponses.push_front(std::move(response)); + session->responseCv.notify_all(session->mutex); + + return result; +} + +ipmi::IpmiServer &ipmi::createIpmiServer(orbis::Process *process, + const char *name) { + orbis::IpmiCreateServerConfig config{}; + orbis::Ref serverImpl; + orbis::ipmiCreateServer(process, nullptr, name, config, serverImpl); + auto server = std::make_shared(); + server->serverImpl = serverImpl; + + std::thread{[server, serverImpl, name] { + pthread_setname_np(pthread_self(), name); + while (true) { + orbis::IpmiServer::Packet packet; + { + std::lock_guard lock(serverImpl->mutex); + + while (serverImpl->packets.empty()) { + serverImpl->receiveCv.wait(serverImpl->mutex); + } + + packet = std::move(serverImpl->packets.front()); + serverImpl->packets.pop_front(); + } + + if (packet.info.type == 1) { + std::lock_guard serverLock(serverImpl->mutex); + + for (auto it = serverImpl->connectionRequests.begin(); + it != serverImpl->connectionRequests.end(); ++it) { + auto &conReq = *it; + std::lock_guard clientLock(conReq.client->mutex); + if (conReq.client->session != nullptr) { + continue; + } + + auto session = orbis::knew(); + if (session == nullptr) { + break; + } + + session->client = conReq.client; + session->server = serverImpl; + conReq.client->session = session; + + for (auto &message : server->messages) { + conReq.client->messageQueues[0].messages.push_back( + orbis::kvector(message.data(), + message.data() + message.size())); + } + + conReq.client->connectionStatus = 0; + conReq.client->sessionCv.notify_all(conReq.client->mutex); + conReq.client->connectCv.notify_all(conReq.client->mutex); + break; + } + + continue; + } + + if ((packet.info.type & ~0x8010) == 0x41) { + auto msgHeader = std::bit_cast( + packet.message.data()); + auto process = orbis::g_context.findProcessById(msgHeader->pid); + if (process == nullptr) { + continue; + } + auto client = orbis::g_context.ipmiMap.get(packet.info.clientKid) + .cast(); + if (client == nullptr) { + continue; + } + auto session = client->session; + if (session == nullptr) { + continue; + } + + server->handle(client->session.get(), packet, msgHeader); + packet = {}; + continue; + } + + if ((packet.info.type & ~0x10) == 0x43) { + auto msgHeader = (orbis::IpmiAsyncMessageHeader *)packet.message.data(); + auto process = orbis::g_context.findProcessById(msgHeader->pid); + if (process == nullptr) { + continue; + } + auto client = orbis::g_context.ipmiMap.get(packet.info.clientKid) + .cast(); + if (client == nullptr) { + continue; + } + auto session = client->session; + if (session == nullptr) { + continue; + } + + server->handle(client->session.get(), msgHeader); + continue; + } + + std::println(stderr, "IPMI: Unhandled packet {}::{}", serverImpl->name, + packet.info.type); + } + }}.detach(); + + return *server; +} + +void ipmi::createMiniSysCoreObjects(orbis::Process *) { + createEventFlag("SceBootStatusFlags", 0x121, ~0ull); +} + +void ipmi::createSysAvControlObjects(orbis::Process *process) { + createIpmiServer(process, "SceAvSettingIpc"); + + createIpmiServer(process, "SceAvCaptureIpc"); + createEventFlag("SceAvCaptureIpc", 0x121, 0); + createEventFlag("SceAvSettingEvf", 0x121, 0xffff00000000); + + createShm("/SceAvSetting", 0xa02, 0x1a4, 4096); +} + +struct SceSysAudioSystemThreadArgs { + uint32_t threadId; +}; + +struct SceSysAudioSystemPortAndThreadArgs { + uint32_t audioPort; + uint32_t threadId; +}; + +void ipmi::createAudioSystemObjects(orbis::Process *process) { + auto audioOut = orbis::Ref(orbis::knew()); + + createIpmiServer(process, "SceSysAudioSystemIpc") + .addSyncMethod( + 0x12340000, + [=](const auto &args) -> std::int32_t { + ORBIS_LOG_TODO("IPMI: SceSysAudioSystemCreateControl", + args.threadId); + audioOut->channelInfo.idControl = args.threadId; + return 0; + }) + .addSyncMethod( + 0x1234000f, + [=](const auto &args) -> std::int32_t { + ORBIS_LOG_TODO("IPMI: SceSysAudioSystemOpenMixFlag", args.threadId); + // very bad + char buffer[32]; + std::snprintf(buffer, sizeof(buffer), "sceAudioOutMix%x", + args.threadId); + auto [eventFlag, inserted] = + orbis::g_context.createEventFlag(buffer, 0x100, 0); + + if (!inserted) { + return 17; // FIXME: verify + } + + audioOut->channelInfo.evf = eventFlag; + return 0; + }) + .addSyncMethod( + 0x12340001, + [=](const auto &args) -> std::int32_t { + ORBIS_LOG_TODO("IPMI: SceSysAudioSystemOpenPort", args.threadId, + args.audioPort); + audioOut->channelInfo.port = args.audioPort; + audioOut->channelInfo.channel = args.threadId; + return 0; + }) + .addSyncMethod( + 0x12340002, + [=](const auto &args) -> std::int32_t { + ORBIS_LOG_TODO("IPMI: SceSysAudioSystemStartListening", + args.threadId, args.audioPort); + + audioOut->start(); + return 0; + }) + .addSyncMethod( + 0x12340006, [=](const auto &args) -> std::int32_t { + ORBIS_LOG_TODO("IPMI: SceSysAudioSystemStopListening", + args.audioPort, args.threadId); + // TODO: implement + return 0; + }); +} + +struct SceMbusIpcAddHandleByUserIdMethodArgs { + orbis::uint32_t deviceType; // 0 - pad, 1 - aout, 2 - ain, 4 - camera, 6 - kb, + // 7 - mouse, 8 - vr + orbis::uint32_t deviceId; + orbis::uint32_t userId; + orbis::uint32_t type; + orbis::uint32_t index; + orbis::uint32_t reserved; + orbis::uint32_t pid; +}; + +static_assert(sizeof(SceMbusIpcAddHandleByUserIdMethodArgs) == 0x1c); + +struct SceUserServiceEvent { + std::uint32_t eventType; // 0 - login, 1 - logout + std::uint32_t user; +}; + +void ipmi::createSysCoreObjects(orbis::Process *process) { + createIpmiServer(process, "SceMbusIpc") + .addSyncMethod( + 0xce110007, [](const auto &args) -> std::int32_t { + ORBIS_LOG_TODO("IPMI: SceMbusIpcAddHandleByUserId", args.deviceType, + args.deviceId, args.userId, args.type, args.index, + args.reserved, args.pid); + if (args.deviceType == 1) { + struct HandleA { + int32_t pid; + int32_t port; + int32_t unk0 = 0x20100000; + int32_t unk1 = 1; + } handleA; + handleA.pid = args.pid; + handleA.port = args.deviceId; + audioIpmiClient.sendSyncMessage(0x1234000a, handleA); + struct HandleC { + int32_t pid; + int32_t port; + int32_t unk0 = 1; + int32_t unk1 = 0; + int32_t unk2 = 1; + int32_t unk3 = 0; + int32_t unk4 = 0; + int32_t unk5 = 0; + int32_t unk6 = 0; + int32_t unk7 = 1; + int32_t unk8 = 0; + } handleC; + handleC.pid = args.pid; + handleC.port = args.deviceId; + audioIpmiClient.sendSyncMessage(0x1234000c, handleC); + } + return 0; + }); + createIpmiServer(process, "SceSysCoreApp"); + createIpmiServer(process, "SceSysCoreApp2"); + createIpmiServer(process, "SceMDBG0SRV"); + + createSemaphore("SceSysCoreProcSpawnSema", 0x101, 0, 1); + createSemaphore("SceTraceMemorySem", 0x100, 1, 1); + createSemaphore("SceSysCoreEventSemaphore", 0x101, 0, 0x2d2); + createSemaphore("SceSysCoreProcSema", 0x101, 0, 1); + createSemaphore("AppmgrCoredumpHandlingEventSema", 0x101, 0, 4); + + createEventFlag("SceMdbgVrTriggerDump", 0x121, 0); +} + +void ipmi::createGnmCompositorObjects(orbis::Process *) { + createEventFlag("SceCompositorCrashEventFlags", 0x122, 0); + createEventFlag("SceCompositorEventflag", 0x122, 0); + createEventFlag("SceCompositorResetStatusEVF", 0x122, 0); + + createShm("/tmp/SceHmd/Vr2d_shm_pass", 0xa02, 0x1b6, 16384); +} + +void ipmi::createShellCoreObjects(orbis::Process *process) { + auto fmtHex = [](auto value, bool upperCase = false) { + if (upperCase) { + return std::format("{:X}", value); + } + return std::format("{:x}", value); + }; + + createIpmiServer(process, "SceSystemLoggerService"); + createIpmiServer(process, "SceLoginMgrServer"); + createIpmiServer(process, "SceLncService") + .addSyncMethod(orbis::g_context.fwSdkVersion > 0x6000000 ? 0x30013 + : 0x30010, + [](void *out, std::uint64_t &size) -> std::int32_t { + struct SceLncServiceAppStatus { + std::uint32_t unk0; + std::uint32_t unk1; + std::uint32_t unk2; + }; + + if (size < sizeof(SceLncServiceAppStatus)) { + return -1; + } + + *(SceLncServiceAppStatus *)out = { + .unk0 = 1, + .unk1 = 1, + .unk2 = 1, + }; + + size = sizeof(SceLncServiceAppStatus); + return 0; + }); + createIpmiServer(process, "SceAppMessaging"); + createIpmiServer(process, "SceShellCoreUtil"); + createIpmiServer(process, "SceNetCtl"); + createIpmiServer(process, "SceNpMgrIpc") + .addSyncMethod( + 0, + [=](void *out, std::uint64_t &size) -> std::int32_t { + std::string_view result = "SceNpMgrEvf"; + if (size < result.size() + 1) { + return 0x8002'0000 + static_cast(orbis::ErrorCode::INVAL); + } + std::strncpy((char *)out, result.data(), result.size() + 1); + size = result.size() + 1; + orbis::g_context.createEventFlag(orbis::kstring(result), 0x200, 0); + return 0; + }) + .addSyncMethodStub(0xd); + createIpmiServer(process, "SceNpService") + .addSyncMethod( + 0, [=](void *, std::uint64_t &, std::uint32_t) { return 0; }) + .addSyncMethod(0xa0001, + [=](void *out, std::uint64_t &size) -> std::int32_t { + if (size < 1) { + return 0x8002'0000 + + static_cast(orbis::ErrorCode::INVAL); + } + size = 1; + *reinterpret_cast(out) = 1; + return 0; + }) + .addSyncMethod(0xa0002, + [=](void *out, std::uint64_t &size) -> std::int32_t { + if (size < 1) { + return 0x8002'0000 + + static_cast(orbis::ErrorCode::INVAL); + } + size = 1; + *reinterpret_cast(out) = 1; + return 0; + }) + .addSyncMethod( + 0xd0000, // sceNpTpipIpcClientGetShmIndex + [=](std::uint32_t &shmIndex, std::uint32_t) -> std::int32_t { + shmIndex = 0; + return 0; + }); + + createIpmiServer(process, "SceNpTrophyIpc") + .addSyncMethod(2, + [](std::vector> &out, + const std::vector> &) { + if (out.size() != 1 || + out[0].size() < sizeof(std::uint32_t)) { + return orbis::ErrorCode::INVAL; + } + out = {toBytes(0)}; + return orbis::ErrorCode{}; + }) + .addAsyncMethod(0x30040, + [](orbis::IpmiSession &session, + std::vector> &, + const std::vector> &) { + session.client->eventFlags[0].set(1); + return orbis::ErrorCode{}; + }) + .addSyncMethod(0x90000, + [](std::vector> &out, + const std::vector> &) { + if (out.size() != 1 || + out[0].size() < sizeof(std::uint32_t)) { + return orbis::ErrorCode::INVAL; + } + out = {toBytes(1)}; + return orbis::ErrorCode{}; + }) + .addSyncMethod(0x90003, + [](std::vector> &out, + const std::vector> &) { + if (out.size() != 1 || + out[0].size() < sizeof(std::uint32_t)) { + return orbis::ErrorCode::INVAL; + } + out = {toBytes(1)}; + return orbis::ErrorCode{}; + }) + .addAsyncMethod(0x90024, + [](orbis::IpmiSession &, + std::vector> &out, + const std::vector> &) { + out.push_back(toBytes(0)); + // session.client->eventFlags[0].set(1); + return orbis::ErrorCode{}; + }) + .addAsyncMethod(0x90026, [](orbis::IpmiSession &session, + std::vector> &, + const std::vector> &) { + session.client->eventFlags[0].set(1); + return orbis::ErrorCode{}; + }); + createIpmiServer(process, "SceNpUdsIpc"); + createIpmiServer(process, "SceLibNpRifMgrIpc"); + createIpmiServer(process, "SceNpPartner001"); + createIpmiServer(process, "SceNpPartnerSubs"); + createIpmiServer(process, "SceNpGameIntent"); + createIpmiServer(process, "SceBgft"); + createIpmiServer(process, "SceCntMgrService"); + createIpmiServer(process, "ScePlayGo"); + createIpmiServer(process, "SceCompAppProxyUtil"); + createIpmiServer(process, "SceShareSpIpcService"); + createIpmiServer(process, "SceRnpsAppMgr"); + createIpmiServer(process, "SceUpdateService"); + createIpmiServer(process, "ScePatchChecker"); + createIpmiServer(process, "SceMorpheusUpdService"); + createIpmiServer(process, "ScePsmSharedDmem"); + + auto saveDataSem = + createSemaphore("SceSaveData0000000000000001", 0x101, 0, 1); + auto saveDataSem_0 = + createSemaphore("SceSaveData0000000000000001_0", 0x101, 0, 1); + createShm("SceSaveData0000000000000001_0", 0x202, 0x1b6, 0x40000); + createShm("SceSaveDataI0000000000000001", 0x202, 0x1b6, 43008); + createShm("SceSaveDataI0000000000000001_0", 0x202, 0x1b6, 43008); + createShm("SceNpPlusLogger", 0x202, 0x1b6, 0x40000); + auto ruiEvf = createEventFlag("SceSaveDataMemoryRUI00000010", 0x120, + 0x1000000100010000); + + createIpmiServer(process, "SceSaveData") + .addSyncMethod(0x12340000, + [=](void *, std::uint64_t &) -> std::int32_t { + ruiEvf->set(~0ull); + { + saveDataSem->value++; + saveDataSem->cond.notify_one(saveDataSem->mtx); + } + { + saveDataSem_0->value++; + saveDataSem_0->cond.notify_one(saveDataSem_0->mtx); + } + return 0; + }) + .addSyncMethod( + 0x12340001, + [](void *out, std::uint64_t &size) -> std::int32_t { + { + auto [dev, devPath] = vfs::get("/app0"); + if (auto hostFs = dev.cast()) { + std::error_code ec; + auto saveDir = hostFs->hostPath + "/.rpcsx/saves/"; + if (!std::filesystem::exists(saveDir)) { + return 0x8002'0000 + + static_cast(orbis::ErrorCode::NOENT); + } + } + } + std::string_view result = "/saves"; + if (size < result.size() + 1) { + return 0x8002'0000 + static_cast(orbis::ErrorCode::INVAL); + } + std::strncpy((char *)out, result.data(), result.size() + 1); + size = result.size() + 1; + orbis::g_context.createEventFlag(orbis::kstring(result), 0x200, 0); + return 0; + }) + .addSyncMethod(0x12340002, [](void *, std::uint64_t &) -> std::int32_t { + { + auto [dev, devPath] = vfs::get("/app0"); + if (auto hostFs = dev.cast()) { + std::error_code ec; + auto saveDir = hostFs->hostPath + "/.rpcsx/saves/"; + std::filesystem::create_directories(saveDir, ec); + vfs::mount("/saves/", createHostIoDevice(saveDir, "/saves/")); + } + } + return 0; + }); + + createIpmiServer(process, "SceStickerCoreServer"); + createIpmiServer(process, "SceDbRecoveryShellCore"); + createIpmiServer(process, "SceUserService") + .sendMsg(SceUserServiceEvent{.eventType = 0, .user = 1}) + .addSyncMethod(0x30011, + [](void *ptr, std::uint64_t &size) -> std::int32_t { + if (size < sizeof(orbis::uint32_t)) { + return 0x8000'0000; + } + + *(orbis::uint32_t *)ptr = 1; + size = sizeof(orbis::uint32_t); + return 0; + }); + + createIpmiServer(process, "SceDbPreparationServer"); + createIpmiServer(process, "SceScreenShot"); + createIpmiServer(process, "SceAppDbIpc"); + createIpmiServer(process, "SceAppInst"); + createIpmiServer(process, "SceAppContent"); + createIpmiServer(process, "SceNpEntAccess"); + createIpmiServer(process, "SceMwIPMIServer"); + createIpmiServer(process, "SceAutoMounterIpc"); + createIpmiServer(process, "SceBackupRestoreUtil"); + createIpmiServer(process, "SceDataTransfer"); + createIpmiServer(process, "SceEventService"); + createIpmiServer(process, "SceShareFactoryUtil"); + createIpmiServer(process, "SceCloudConnectManager"); + createIpmiServer(process, "SceHubAppUtil"); + createIpmiServer(process, "SceTcIPMIServer"); + + createSemaphore("SceLncSuspendBlock00000001", 0x101, 1, 1); + createSemaphore("SceAppMessaging00000001", 0x100, 1, 0x7fffffff); + + createEventFlag("SceAutoMountUsbMass", 0x120, 0); + createEventFlag("SceLoginMgrUtilityEventFlag", 0x112, 0); + createEventFlag("SceLoginMgrSharePlayEventFlag", 0x112, 0); + createEventFlag("SceLoginMgrServerHmdConnect", 0x112, 0); + createEventFlag("SceLoginMgrServerDialogRequest", 0x112, 0); + createEventFlag("SceLoginMgrServerDialogResponse", 0x112, 0); + createEventFlag("SceGameLiveStreamingSpectator", 0x120, 0x8000000000000000); + createEventFlag("SceGameLiveStreamingUserId", 0x120, 0x8000000000000000); + createEventFlag("SceGameLiveStreamingMsgCount", 0x120, 0x8000000000000000); + createEventFlag("SceGameLiveStreamingBCCtrl", 0x120, 0); + createEventFlag("SceGameLiveStreamingEvntArg", 0x120, 0); + createEventFlag("SceLncUtilSystemStatus", 0x120, 0); + createEventFlag("SceShellCoreUtilRunLevel", 0x100, 0); + createEventFlag("SceSystemStateMgrInfo", 0x120, 0x10000000a); + createEventFlag("SceSystemStateMgrStatus", 0x120, 0); + createEventFlag("SceAppInstallerEventFlag", 0x120, 0); + createEventFlag("SceShellCoreUtilPowerControl", 0x120, 0x400000); + createEventFlag("SceShellCoreUtilAppFocus", 0x120, 1); + createEventFlag("SceShellCoreUtilCtrlFocus", 0x120, 0); + createEventFlag("SceShellCoreUtilUIStatus", 0x120, 0x20001); + createEventFlag("SceShellCoreUtilDevIdxBehavior", 0x120, 0); + createEventFlag("SceNpMgrVshReq", 0x121, 0); + createEventFlag("SceNpIdMapperVshReq", 0x121, 0); + createEventFlag("SceRtcUtilTzdataUpdateFlag", 0x120, 0); + createEventFlag("SceDataTransfer", 0x120, 0); + + createEventFlag("SceLncUtilAppStatus1", 0x100, 0); + createEventFlag("SceAppMessaging1", 0x120, 1); + createEventFlag("SceShellCoreUtil1", 0x120, 0x3f8c); + createEventFlag("SceNpScoreIpc_" + fmtHex(process->pid), 0x120, 0); + createEventFlag("/vmicDdEvfAin", 0x120, 0); + + createSemaphore("SceAppMessaging1", 0x101, 1, 0x7fffffff); + createSemaphore("SceLncSuspendBlock1", 0x101, 1, 10000); + + createShm("SceGlsSharedMemory", 0x202, 0x1a4, 262144); + createShm("SceShellCoreUtil", 0x202, 0x1a4, 16384); + createShm("SceNpTpip", 0x202, 0x1ff, 43008); + + createShm("vmicDdShmAin", 0x202, 0x1b6, 43008); + + createSemaphore("SceNpTpip 0", 0x101, 0, 1); +} diff --git a/rpcsx/ipmi.hpp b/rpcsx/ipmi.hpp new file mode 100644 index 0000000..5637e7a --- /dev/null +++ b/rpcsx/ipmi.hpp @@ -0,0 +1,275 @@ +#pragma once + +#include "orbis/thread/Process.hpp" + +namespace ipmi { +template std::vector toBytes(const T &value) { + std::vector result(sizeof(T)); + std::memcpy(result.data(), &value, sizeof(value)); + return result; +} + +struct IpmiClient { + orbis::Ref clientImpl; + orbis::uint kid; + orbis::Thread *thread; + + orbis::sint + sendSyncMessageRaw(std::uint32_t method, + const std::vector> &inData, + std::vector> &outBuf); + + template + orbis::sint sendSyncMessage(std::uint32_t method, + const InputTypes &...input) { + std::vector> outBuf; + return sendSyncMessageRaw(method, {toBytes(input)...}, outBuf); + } + + template + requires((sizeof...(OutputTypes) > 0) || sizeof...(InputTypes) == 0) + std::tuple sendSyncMessage(std::uint32_t method, + InputTypes... input) { + std::vector> outBuf{sizeof(OutputTypes)...}; + sendSyncMessageRaw(method, {toBytes(input)...}, outBuf); + std::tuple output; + + auto unpack = [&](std::index_sequence) { + ((std::get(output) = *reinterpret_cast(outBuf.data())), + ...); + }; + unpack(std::make_index_sequence{}); + return output; + } +}; + +struct IpmiServer { + orbis::Ref serverImpl; + + std::unordered_map> &outData, + const std::vector> &inData)>> + syncMethods; + std::unordered_map> &outData, + const std::vector> &inData)>> + asyncMethods; + std::vector> messages; + + IpmiServer &addSyncMethodStub( + std::uint32_t methodId, + std::function handler = [] -> std::int32_t { + return 0; + }) { + syncMethods[methodId] = [=](orbis::IpmiSession &session, + std::int32_t &errorCode, + std::vector> &outData, + const std::vector> &inData) + -> orbis::ErrorCode { + if (!outData.empty()) { + return orbis::ErrorCode::INVAL; + } + + errorCode = handler(); + return {}; + }; + return *this; + } + + IpmiServer &addSyncMethod( + std::uint32_t methodId, + std::function handler) { + syncMethods[methodId] = [=](orbis::IpmiSession &session, + std::int32_t &errorCode, + std::vector> &outData, + const std::vector> &inData) + -> orbis::ErrorCode { + if (outData.size() < 1) { + return orbis::ErrorCode::INVAL; + } + + std::uint64_t size = outData[0].size(); + errorCode = handler(outData[0].data(), size); + outData[0].resize(size); + return {}; + }; + return *this; + } + + template + IpmiServer & + addSyncMethod(std::uint32_t methodId, + std::function + handler) { + syncMethods[methodId] = [=](orbis::IpmiSession &session, + std::int32_t &errorCode, + std::vector> &outData, + const std::vector> &inData) + -> orbis::ErrorCode { + if (outData.size() != 1 || inData.size() != 1) { + return orbis::ErrorCode::INVAL; + } + + if (inData[0].size() != sizeof(T)) { + return orbis::ErrorCode::INVAL; + } + + std::uint64_t size = outData[0].size(); + errorCode = handler(outData[0].data(), size, + *reinterpret_cast(inData[0].data())); + outData[0].resize(size); + return {}; + }; + return *this; + } + + template + IpmiServer &addSyncMethod( + std::uint32_t methodId, + std::function handler) { + syncMethods[methodId] = [=](orbis::IpmiSession &session, + std::int32_t &errorCode, + std::vector> &outData, + const std::vector> &inData) + -> orbis::ErrorCode { + if (outData.size() != 1 || inData.size() != 1) { + return orbis::ErrorCode::INVAL; + } + + if (inData[0].size() != sizeof(InT)) { + return orbis::ErrorCode::INVAL; + } + if (outData[0].size() < sizeof(OutT)) { + return orbis::ErrorCode::INVAL; + } + + OutT out; + errorCode = handler(out, *reinterpret_cast(inData[0].data())); + std::memcpy(outData[0].data(), &out, sizeof(out)); + outData[0].resize(sizeof(OutT)); + return {}; + }; + return *this; + } + + template + IpmiServer & + addSyncMethod(std::uint32_t methodId, + std::function handler) { + syncMethods[methodId] = [=](orbis::IpmiSession &session, + std::int32_t &errorCode, + std::vector> &outData, + const std::vector> &inData) + -> orbis::ErrorCode { + if (inData.size() != 1 || !outData.empty()) { + return orbis::ErrorCode::INVAL; + } + + if (inData[0].size() != sizeof(T)) { + return orbis::ErrorCode::INVAL; + } + + errorCode = handler(*reinterpret_cast(inData[0].data())); + return {}; + }; + return *this; + } + + IpmiServer & + addSyncMethod(std::uint32_t methodId, + std::function> &outData, + const std::vector> &inData)> + handler) { + syncMethods[methodId] = [=](orbis::IpmiSession &session, + std::int32_t &errorCode, + std::vector> &outData, + const std::vector> &inData) + -> orbis::ErrorCode { + errorCode = handler(outData, inData); + return {}; + }; + return *this; + } + + IpmiServer & + addSyncMethod(std::uint32_t methodId, + std::function> &outData, + const std::vector> &inData)> + handler) { + syncMethods[methodId] = [=](orbis::IpmiSession &session, + std::int32_t &errorCode, + std::vector> &outData, + const std::vector> &inData) + -> orbis::ErrorCode { return handler(outData, inData); }; + return *this; + } + + IpmiServer & + addAsyncMethod(std::uint32_t methodId, + std::function> &outData, + const std::vector> &inData)> + handler) { + asyncMethods[methodId] = + [=](orbis::IpmiSession &session, std::int32_t &errorCode, + std::vector> &outData, + const std::vector> &inData) + -> orbis::ErrorCode { return handler(session, outData, inData); }; + return *this; + } + + IpmiServer & + addSyncMethod(std::uint32_t methodId, + std::function> &outData, + const std::vector> &inData)> + handler) { + asyncMethods[methodId] = + [=](orbis::IpmiSession &session, std::int32_t &errorCode, + std::vector> &outData, + const std::vector> &inData) + -> orbis::ErrorCode { return handler(session, outData, inData); }; + return *this; + } + + template IpmiServer &sendMsg(const T &data) { + std::vector message(sizeof(T)); + std::memcpy(message.data(), &data, sizeof(T)); + messages.push_back(std::move(message)); + return *this; + } + + orbis::ErrorCode handle(orbis::IpmiSession *session, + orbis::IpmiAsyncMessageHeader *message); + + orbis::ErrorCode handle(orbis::IpmiSession *session, + orbis::IpmiServer::Packet &packet, + orbis::IpmiSyncMessageHeader *message); +}; + +extern ipmi::IpmiClient audioIpmiClient; + +IpmiClient createIpmiClient(orbis::Thread *thread, const char *name); +IpmiServer &createIpmiServer(orbis::Process *process, const char *name); +orbis::EventFlag *createEventFlag(std::string_view name, uint32_t attrs, + uint64_t initPattern); +orbis::Semaphore *createSemaphore(std::string_view name, uint32_t attrs, + uint64_t initCount, uint64_t maxCount); +void createShm(const char *name, uint32_t flags, uint32_t mode, uint64_t size); + +void createMiniSysCoreObjects(orbis::Process *process); +void createSysAvControlObjects(orbis::Process *process); +void createAudioSystemObjects(orbis::Process *process); +void createSysCoreObjects(orbis::Process *process); +void createGnmCompositorObjects(orbis::Process *process); +void createShellCoreObjects(orbis::Process *process); +} // namespace ipmi diff --git a/rpcsx-os/linker.cpp b/rpcsx/linker.cpp similarity index 98% rename from rpcsx-os/linker.cpp rename to rpcsx/linker.cpp index 1e19717..c9dd110 100644 --- a/rpcsx-os/linker.cpp +++ b/rpcsx/linker.cpp @@ -456,10 +456,10 @@ Ref rx::linker::loadModule(std::span image, auto imageSize = endAddress - baseAddress; auto imageBase = reinterpret_cast( - rx::vm::map(reinterpret_cast(baseAddress), - rx::alignUp(imageSize, rx::vm::kPageSize), 0, - rx::vm::kMapFlagPrivate | rx::vm::kMapFlagAnonymous | - (baseAddress ? rx::vm::kMapFlagFixed : 0))); + vm::map(reinterpret_cast(baseAddress), + rx::alignUp(imageSize, vm::kPageSize), 0, + vm::kMapFlagPrivate | vm::kMapFlagAnonymous | + (baseAddress ? vm::kMapFlagFixed : 0))); if (imageBase == MAP_FAILED) { std::abort(); @@ -908,7 +908,7 @@ Ref rx::linker::loadModule(std::span image, static Ref loadModuleFileImpl(std::string_view path, orbis::Thread *thread) { orbis::Ref instance; - if (rx::vfs::open(path, kOpenFlagReadOnly, 0, &instance, thread).isError()) { + if (vfs::open(path, kOpenFlagReadOnly, 0, &instance, thread).isError()) { return {}; } diff --git a/rpcsx-os/linker.hpp b/rpcsx/linker.hpp similarity index 100% rename from rpcsx-os/linker.hpp rename to rpcsx/linker.hpp diff --git a/rpcsx/main.cpp b/rpcsx/main.cpp new file mode 100644 index 0000000..7657d37 --- /dev/null +++ b/rpcsx/main.cpp @@ -0,0 +1,1155 @@ +#include "audio/AlsaDevice.hpp" +#include "backtrace.hpp" +#include "gpu/Device.hpp" +#include "io-device.hpp" +#include "io-devices.hpp" +#include "iodev/mbus.hpp" +#include "iodev/mbus_av.hpp" +#include "ipmi.hpp" +#include "linker.hpp" +#include "ops.hpp" +#include "orbis/utils/Logs.hpp" +#include "rx/Config.hpp" +#include "rx/mem.hpp" +#include "rx/watchdog.hpp" +#include "thread.hpp" +#include "vfs.hpp" +#include "vm.hpp" +#include "xbyak/xbyak.h" +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +static int g_gpuPid; +extern bool allowMonoDebug; + +__attribute__((no_stack_protector)) static void +handle_signal(int sig, siginfo_t *info, void *ucontext) { + if (auto hostFs = _readgsbase_u64()) { + _writefsbase_u64(hostFs); + } + + auto signalAddress = reinterpret_cast(info->si_addr); + + if (orbis::g_currentThread != nullptr && + orbis::g_currentThread->tproc->vmId >= 0 && sig == SIGSEGV && + signalAddress >= 0x40000 && signalAddress < 0x100'0000'0000) { + auto vmid = orbis::g_currentThread->tproc->vmId; + auto ctx = reinterpret_cast(ucontext); + bool isWrite = (ctx->uc_mcontext.gregs[REG_ERR] & 0x2) != 0; + auto origVmProt = vm::getPageProtection(signalAddress); + int prot = 0; + auto page = signalAddress / rx::mem::pageSize; + + if (origVmProt & vm::kMapProtCpuRead) { + prot |= PROT_READ; + } + if (origVmProt & vm::kMapProtCpuWrite) { + prot |= PROT_WRITE; + } + if (origVmProt & vm::kMapProtCpuExec) { + prot |= PROT_EXEC; + } + + auto gpuDevice = orbis::g_context.gpuDevice.staticCast(); + + if (gpuDevice && (prot & (isWrite ? PROT_WRITE : PROT_READ)) != 0) { + while (true) { + auto flags = + gpuDevice->cachePages[vmid][page].load(std::memory_order::relaxed); + + if ((flags & amdgpu::kPageReadWriteLock) != 0) { + if ((flags & amdgpu::kPageLazyLock) != 0) { + if (std::uint32_t gpuCommand = 0; + !gpuDevice->gpuCacheCommand[vmid].compare_exchange_weak( + gpuCommand, page)) { + continue; + } + + while (!gpuDevice->cachePages[vmid][page].compare_exchange_weak( + flags, flags & ~amdgpu::kPageLazyLock, + std::memory_order::relaxed)) { + } + } + continue; + } + + if ((flags & amdgpu::kPageWriteWatch) == 0) { + break; + } + + if (!isWrite) { + prot &= ~PROT_WRITE; + break; + } + + if (gpuDevice->cachePages[vmid][page].compare_exchange_weak( + flags, amdgpu::kPageInvalidated, std::memory_order::relaxed)) { + break; + } + } + + if (::mprotect((void *)(page * rx::mem::pageSize), rx::mem::pageSize, + prot)) { + std::perror("cache reprotection error"); + std::abort(); + } + + _writefsbase_u64(orbis::g_currentThread->fsBase); + return; + } + + std::fprintf(stderr, "SIGSEGV, address %lx, access %s, prot %s\n", + signalAddress, isWrite ? "write" : "read", + vm::mapProtToString(origVmProt).c_str()); + } + + if (orbis::g_currentThread != nullptr) { + orbis::g_currentThread->tproc->exitStatus = sig; + orbis::g_currentThread->tproc->event.emit(orbis::kEvFiltProc, + orbis::kNoteExit, sig); + } + + if (g_gpuPid > 0) { + // stop gpu thread + // ::kill(g_gpuPid, SIGINT); + } + + allowMonoDebug = true; + if (sig != SIGINT) { + char buf[128] = ""; + int len = snprintf(buf, sizeof(buf), " [%s] %u: Signal address=%p\n", + orbis::g_currentThread ? "guest" : "host", + orbis::g_currentThread ? orbis::g_currentThread->tid + : ::gettid(), + info->si_addr); + write(2, buf, len); + + if (std::size_t printed = + rx::printAddressLocation(buf, sizeof(buf), orbis::g_currentThread, + (std::uint64_t)info->si_addr)) { + printed += std::snprintf(buf + printed, sizeof(buf) - printed, "\n"); + write(2, buf, printed); + } + + if (orbis::g_currentThread) { + rx::printStackTrace(reinterpret_cast(ucontext), + orbis::g_currentThread, 2); + } else { + rx::printStackTrace(reinterpret_cast(ucontext), 2); + } + } + + struct sigaction act{}; + sigset_t mask; + sigemptyset(&mask); + + act.sa_handler = SIG_DFL; + act.sa_flags = SA_SIGINFO | SA_ONSTACK; + act.sa_mask = mask; + + if (sigaction(sig, &act, NULL)) { + perror("Error sigaction:"); + std::exit(-1); + } + + if (sig == SIGINT) { + std::raise(SIGINT); + } +} + +void setupSigHandlers() { + rx::thread::setupSignalStack(); + + struct sigaction act{}; + act.sa_sigaction = handle_signal; + act.sa_flags = SA_SIGINFO | SA_ONSTACK | SA_NODEFER; + + if (sigaction(SIGSYS, &act, NULL)) { + perror("Error sigaction:"); + exit(-1); + } + + if (sigaction(SIGILL, &act, NULL)) { + perror("Error sigaction:"); + exit(-1); + } + + if (sigaction(SIGSEGV, &act, NULL)) { + perror("Error sigaction:"); + exit(-1); + } + + if (sigaction(SIGBUS, &act, NULL)) { + perror("Error sigaction:"); + exit(-1); + } + + if (sigaction(SIGABRT, &act, NULL)) { + perror("Error sigaction:"); + exit(-1); + } + + if (sigaction(SIGFPE, &act, NULL)) { + perror("Error sigaction:"); + exit(-1); + } +} + +struct StackWriter { + std::uint64_t address; + + template std::uint64_t push(T value) { + address -= sizeof(value); + address &= ~(alignof(T) - 1); + *reinterpret_cast(address) = value; + return address; + } + + void align(std::uint64_t alignment) { address &= ~(alignment - 1); } + + std::uint64_t pushString(const char *value) { + auto len = std::strlen(value); + address -= len + 1; + std::memcpy(reinterpret_cast(address), value, len + 1); + return address; + } + + std::uint64_t alloc(std::uint64_t size, std::uint64_t alignment) { + address -= size; + address &= ~(alignment - 1); + return address; + } +}; + +static bool g_traceSyscalls = false; +static const char *getSyscallName(orbis::Thread *thread, int sysno) { + auto sysvec = thread->tproc->sysent; + + if (sysno >= sysvec->size) { + return nullptr; + } + + return orbis::getSysentName(sysvec->table[sysno].call); +} +static void onSysEnter(orbis::Thread *thread, int id, uint64_t *args, + int argsCount) { + if (!g_traceSyscalls) { + return; + } + flockfile(stderr); + std::fprintf(stderr, " [%u] ", thread->tid); + + if (auto name = getSyscallName(thread, id)) { + std::fprintf(stderr, "%s(", name); + } else { + std::fprintf(stderr, "sys_%u(", id); + } + + for (int i = 0; i < argsCount; ++i) { + if (i != 0) { + std::fprintf(stderr, ", "); + } + + std::fprintf(stderr, "%#lx", args[i]); + } + + std::fprintf(stderr, ")\n"); + funlockfile(stderr); +} + +static void onSysExit(orbis::Thread *thread, int id, uint64_t *args, + int argsCount, orbis::SysResult result) { + if (!result.isError() && !g_traceSyscalls) { + return; + } + + flockfile(stderr); + std::fprintf(stderr, "%c: [%u] ", result.isError() ? 'E' : 'S', thread->tid); + + if (auto name = getSyscallName(thread, id)) { + std::fprintf(stderr, "%s(", name); + } else { + std::fprintf(stderr, "sys_%u(", id); + } + + for (int i = 0; i < argsCount; ++i) { + if (i != 0) { + std::fprintf(stderr, ", "); + } + + std::fprintf(stderr, "%#lx", args[i]); + } + + std::fprintf(stderr, ") -> Status %d, Value %lx:%lx\n", result.value(), + thread->retval[0], thread->retval[1]); + + if (result.isError()) { + thread->where(); + } + funlockfile(stderr); +} + +static void ps4InitDev() { + auto dmem1 = createDmemCharacterDevice(1); + orbis::g_context.dmemDevice = dmem1; + + auto ttyFd = ::open("tty.txt", O_CREAT | O_TRUNC | O_WRONLY, 0666); + auto consoleDev = createConsoleCharacterDevice(STDIN_FILENO, ttyFd); + auto mbus = static_cast(createMBusCharacterDevice()); + auto mbusAv = static_cast(createMBusAVCharacterDevice()); + + // FIXME: make it configurable + auto defaultAudioDevice = orbis::knew(); + auto nullAudioDevice = orbis::knew(); + + auto hdmiAudioDevice = defaultAudioDevice; + auto analogAudioDevice = nullAudioDevice; + auto spdifAudioDevice = nullAudioDevice; + + vfs::addDevice("dmem0", createDmemCharacterDevice(0)); + vfs::addDevice("npdrm", createNpdrmCharacterDevice()); + vfs::addDevice("icc_configuration", createIccConfigurationCharacterDevice()); + vfs::addDevice("console", consoleDev); + vfs::addDevice("camera", createCameraCharacterDevice()); + vfs::addDevice("dmem1", dmem1); + vfs::addDevice("dmem2", createDmemCharacterDevice(2)); + vfs::addDevice("stdout", consoleDev); + vfs::addDevice("stderr", consoleDev); + vfs::addDevice("deci_stdin", consoleDev); + vfs::addDevice("deci_stdout", consoleDev); + vfs::addDevice("deci_stderr", consoleDev); + vfs::addDevice("deci_tty1", consoleDev); + vfs::addDevice("deci_tty2", consoleDev); + vfs::addDevice("deci_tty3", consoleDev); + vfs::addDevice("deci_tty4", consoleDev); + vfs::addDevice("deci_tty5", consoleDev); + vfs::addDevice("deci_tty6", consoleDev); + vfs::addDevice("deci_tty7", consoleDev); + vfs::addDevice("stdin", consoleDev); + vfs::addDevice("zero", createZeroCharacterDevice()); + vfs::addDevice("null", createNullCharacterDevice()); + vfs::addDevice("dipsw", createDipswCharacterDevice()); + vfs::addDevice("dce", createDceCharacterDevice()); + vfs::addDevice("hmd_cmd", createHmdCmdCharacterDevice()); + vfs::addDevice("hmd_snsr", createHmdSnsrCharacterDevice()); + vfs::addDevice("hmd_3da", createHmd3daCharacterDevice()); + vfs::addDevice("hmd_dist", createHmdMmapCharacterDevice()); + vfs::addDevice("hid", createHidCharacterDevice()); + vfs::addDevice("gc", createGcCharacterDevice()); + vfs::addDevice("rng", createRngCharacterDevice()); + vfs::addDevice("sbl_srv", createSblSrvCharacterDevice()); + vfs::addDevice("ajm", createAjmCharacterDevice()); + vfs::addDevice("urandom", createUrandomCharacterDevice()); + vfs::addDevice("mbus", mbus); + vfs::addDevice("metadbg", createMetaDbgCharacterDevice()); + vfs::addDevice("bt", createBtCharacterDevice()); + vfs::addDevice("xpt0", createXptCharacterDevice()); + vfs::addDevice("cd0", createCdCharacterDevice()); + vfs::addDevice("da0", createHddCharacterDevice(250ull * 1024 * 1024 * 1024)); + vfs::addDevice("da0x0.crypt", createHddCharacterDevice(0x20000000)); + vfs::addDevice("da0x1.crypt", createHddCharacterDevice(0x40000000)); + vfs::addDevice("da0x2", createHddCharacterDevice(0x1000000)); + vfs::addDevice("da0x2.crypt", createHddCharacterDevice(0x1000000)); + vfs::addDevice("da0x3.crypt", createHddCharacterDevice(0x8000000)); + vfs::addDevice("da0x4.crypt", createHddCharacterDevice(0x40000000)); + vfs::addDevice("da0x4b.crypt", createHddCharacterDevice(0x40000000)); + vfs::addDevice("da0x5.crypt", createHddCharacterDevice(0x40000000)); + vfs::addDevice("da0x5b.crypt", createHddCharacterDevice(0x40000000)); + // vfs::addDevice("da0x6x0", createHddCharacterDevice()); // boot log + vfs::addDevice("da0x6", createHddCharacterDevice(0x200000000)); + vfs::addDevice("da0x6x2.crypt", createHddCharacterDevice(0x200000000)); + vfs::addDevice("da0x8", createHddCharacterDevice(0x40000000)); + vfs::addDevice("da0x8.crypt", createHddCharacterDevice(0x40000000)); + vfs::addDevice("da0x9.crypt", createHddCharacterDevice(0x200000000)); + vfs::addDevice("da0x12.crypt", createHddCharacterDevice(0x180000000)); + vfs::addDevice("da0x13.crypt", createHddCharacterDevice(0)); + vfs::addDevice("da0x14.crypt", createHddCharacterDevice(0x40000000)); + vfs::addDevice("da0x15", createHddCharacterDevice(0)); + vfs::addDevice("da0x15.crypt", createHddCharacterDevice(0x400000000)); + vfs::addDevice("notification0", createNotificationCharacterDevice(0)); + vfs::addDevice("notification1", createNotificationCharacterDevice(1)); + vfs::addDevice("notification2", createNotificationCharacterDevice(2)); + vfs::addDevice("notification3", createNotificationCharacterDevice(3)); + vfs::addDevice("notification4", createNotificationCharacterDevice(4)); + vfs::addDevice("notification5", createNotificationCharacterDevice(5)); + vfs::addDevice("aout0", createAoutCharacterDevice(0, hdmiAudioDevice)); + vfs::addDevice("aout1", createAoutCharacterDevice(1, analogAudioDevice)); + vfs::addDevice("aout2", createAoutCharacterDevice(2, spdifAudioDevice)); + vfs::addDevice("av_control", createAVControlCharacterDevice()); + vfs::addDevice("hdmi", createHDMICharacterDevice()); + vfs::addDevice("mbus_av", mbusAv); + vfs::addDevice("scanin", createScaninCharacterDevice()); + vfs::addDevice("s3da", createS3DACharacterDevice()); + vfs::addDevice("gbase", createGbaseCharacterDevice()); + vfs::addDevice("devstat", createDevStatCharacterDevice()); + vfs::addDevice("devact", createDevActCharacterDevice()); + vfs::addDevice("devctl", createDevCtlCharacterDevice()); + vfs::addDevice("uvd", createUVDCharacterDevice()); + vfs::addDevice("vce", createVCECharacterDevice()); + vfs::addDevice("evlg1", createEvlgCharacterDevice(ttyFd)); + vfs::addDevice("srtc", createSrtcCharacterDevice()); + vfs::addDevice("sshot", createScreenShotCharacterDevice()); + vfs::addDevice("lvdctl", createLvdCtlCharacterDevice()); + vfs::addDevice("lvd0", createHddCharacterDevice(0x100000000)); + vfs::addDevice("icc_power", createIccPowerCharacterDevice()); + vfs::addDevice("cayman/reg", createCaymanRegCharacterDevice()); + vfs::addDevice("hctrl", createHidCharacterDevice()); + + // mbus->emitEvent({ + // .system = 2, + // .eventId = 1, + // .deviceId = 0, + // }); + + // mbus->emitEvent({ + // .system = 9, + // .eventId = 1, + // .deviceId = 100, + // }); + + mbusAv->emitEvent({ + .system = 9, + .eventId = 1, + .deviceId = 100, + }); + + auto shm = createShmDevice(); + vfs::addDevice("shm", shm); + orbis::g_context.shmDevice = shm; + orbis::g_context.blockpoolDevice = createBlockPoolDevice(); +} + +static void ps4InitFd(orbis::Thread *mainThread) { + orbis::Ref stdinFile; + orbis::Ref stdoutFile; + orbis::Ref stderrFile; + rx::procOpsTable.open(mainThread, "/dev/stdin", 0, 0, &stdinFile); + rx::procOpsTable.open(mainThread, "/dev/stdout", 0, 0, &stdoutFile); + rx::procOpsTable.open(mainThread, "/dev/stderr", 0, 0, &stderrFile); + + mainThread->tproc->fileDescriptors.insert(stdinFile); + mainThread->tproc->fileDescriptors.insert(stdoutFile); + mainThread->tproc->fileDescriptors.insert(stderrFile); +} + +static orbis::Process *createGuestProcess() { + auto pid = orbis::g_context.allocatePid() * 10000 + 1; + return orbis::g_context.createProcess(pid); +} + +static orbis::Thread *createGuestThread() { + auto process = createGuestProcess(); + auto [baseId, thread] = process->threadsMap.emplace(); + thread->tproc = process; + thread->tid = process->pid + baseId; + thread->state = orbis::ThreadState::RUNNING; + return thread; +} + +struct ExecEnv { + std::uint64_t entryPoint; + std::uint64_t interpBase; +}; + +int ps4Exec(orbis::Thread *mainThread, ExecEnv execEnv, + orbis::utils::Ref executableModule, + std::span argv, std::span envp) { + const auto stackEndAddress = 0x7'ffff'c000ull; + const auto stackSize = 0x40000 * 32; + auto stackStartAddress = stackEndAddress - stackSize; + mainThread->stackStart = + vm::map(reinterpret_cast(stackStartAddress), stackSize, + vm::kMapProtCpuWrite | vm::kMapProtCpuRead, + vm::kMapFlagAnonymous | vm::kMapFlagFixed | vm::kMapFlagPrivate | + vm::kMapFlagStack); + + mainThread->stackEnd = + reinterpret_cast(mainThread->stackStart) + stackSize; + + std::vector argvOffsets; + std::vector envpOffsets; + + StackWriter stack{reinterpret_cast(mainThread->stackEnd)}; + + for (auto &elem : argv) { + argvOffsets.push_back(stack.pushString(elem.data())); + } + + argvOffsets.push_back(0); + + for (auto &elem : envp) { + envpOffsets.push_back(stack.pushString(elem.data())); + } + + envpOffsets.push_back(0); + + // clang-format off + std::uint64_t auxv[] = { + AT_ENTRY, executableModule->entryPoint, + AT_BASE, execEnv.interpBase, + AT_PHDR, executableModule->phdrAddress, + AT_PHENT, sizeof(Elf64_Phdr), + AT_PHNUM, executableModule->phNum, + AT_NULL, 0 + }; + // clang-format on + + std::size_t argSize = + sizeof(std::uint64_t) + sizeof(std::uint64_t) * argvOffsets.size() + + sizeof(std::uint64_t) * envpOffsets.size() + sizeof(auxv); + + auto sp = stack.alloc(argSize, 32); + + auto arg = reinterpret_cast(sp); + *arg++ = argvOffsets.size() - 1; + + for (auto argvOffsets : argvOffsets) { + *arg++ = argvOffsets; + } + + for (auto envpOffset : envpOffsets) { + *arg++ = envpOffset; + } + + executableModule = {}; + + memcpy(arg, auxv, sizeof(auxv)); + + auto context = new ucontext_t{}; + + context->uc_mcontext.gregs[REG_RDI] = sp; + context->uc_mcontext.gregs[REG_RSP] = sp; + + // FIXME: should be at guest user space + context->uc_mcontext.gregs[REG_RDX] = + reinterpret_cast(+[] { std::printf("At exit\n"); }); + context->uc_mcontext.gregs[REG_RIP] = execEnv.entryPoint; + + mainThread->context = context; + rx::thread::invoke(mainThread); + std::abort(); +} + +struct Ps4ProcessParam { + orbis::size_t size; + orbis::uint32_t magic; + orbis::uint32_t version; + orbis::uint32_t sdkVersion; + orbis::uint32_t reserved; + orbis::ptr processName; + orbis::ptr userMainThreadName; + orbis::ptr userMainThreadPriority; + orbis::ptr userMainThreadStackSize; + orbis::ptr libcParam; +}; + +ExecEnv ps4CreateExecEnv(orbis::Thread *mainThread, + const orbis::Ref &executableModule, + bool isSystem) { + std::uint64_t interpBase = 0; + std::uint64_t entryPoint = executableModule->entryPoint; + + if (mainThread->tproc->processParam != nullptr && + mainThread->tproc->processParamSize >= sizeof(Ps4ProcessParam)) { + auto processParam = + reinterpret_cast(mainThread->tproc->processParam); + + auto sdkVersion = processParam // + + sizeof(uint64_t) // size + + sizeof(uint32_t) // magic + + sizeof(uint32_t); // entryCount + + mainThread->tproc->sdkVersion = *(uint32_t *)sdkVersion; + } + + if (orbis::g_context.sdkVersion == 0 && mainThread->tproc->sdkVersion != 0) { + orbis::g_context.sdkVersion = mainThread->tproc->sdkVersion; + } + if (mainThread->tproc->sdkVersion == 0) { + mainThread->tproc->sdkVersion = orbis::g_context.sdkVersion; + } + + if (executableModule->interp.empty()) { + return {.entryPoint = entryPoint, .interpBase = interpBase}; + } + + if (vfs::exists(executableModule->interp, mainThread)) { + auto loader = + rx::linker::loadModuleFile(executableModule->interp, mainThread); + loader->id = mainThread->tproc->modulesMap.insert(loader); + interpBase = reinterpret_cast(loader->base); + entryPoint = loader->entryPoint; + + return {.entryPoint = entryPoint, .interpBase = interpBase}; + } + + auto libSceLibcInternal = rx::linker::loadModuleFile( + "/system/common/lib/libSceLibcInternal.sprx", mainThread); + + if (libSceLibcInternal == nullptr) { + std::println(stderr, "libSceLibcInternal not found"); + std::abort(); + } + + libSceLibcInternal->id = + mainThread->tproc->modulesMap.insert(libSceLibcInternal); + + auto libkernel = rx::linker::loadModuleFile( + (isSystem ? "/system/common/lib/libkernel_sys.sprx" + : "/system/common/lib/libkernel.sprx"), + mainThread); + + if (libkernel == nullptr) { + std::println(stderr, "libkernel not found"); + std::abort(); + } + + for (auto sym : libkernel->symbols) { + if (sym.id == 0xd2f4e7e480cc53d0) { + auto address = (uint64_t)libkernel->base + sym.address; + ::mprotect((void *)rx::alignDown(address, 0x1000), + rx::alignUp(sym.size + sym.address, 0x1000), PROT_WRITE); + std::println("patching sceKernelGetMainSocId"); + struct GetMainSocId : Xbyak::CodeGenerator { + GetMainSocId(std::uint64_t address, std::uint64_t size) + : Xbyak::CodeGenerator(size, (void *)address) { + mov(eax, 0x710f00); + ret(); + } + } gen{address, sym.size}; + + ::mprotect((void *)rx::alignDown(address, 0x1000), + rx::alignUp(sym.size + sym.address, 0x1000), + PROT_READ | PROT_EXEC); + break; + } + } + + if (orbis::g_context.fwSdkVersion == 0) { + auto moduleParam = reinterpret_cast(libkernel->moduleParam); + auto fwSdkVersion = moduleParam // + + sizeof(uint64_t) // size + + sizeof(uint64_t); // magic + orbis::g_context.fwSdkVersion = *(uint32_t *)fwSdkVersion; + std::printf("fw sdk version: %x\n", orbis::g_context.fwSdkVersion); + } + + libkernel->id = mainThread->tproc->modulesMap.insert(libkernel); + interpBase = reinterpret_cast(libkernel->base); + entryPoint = libkernel->entryPoint; + + return {.entryPoint = entryPoint, .interpBase = interpBase}; +} + +int ps4Exec(orbis::Thread *mainThread, + orbis::utils::Ref executableModule, + std::span argv, std::span envp) { + auto execEnv = ps4CreateExecEnv(mainThread, executableModule, true); + return ps4Exec(mainThread, execEnv, std::move(executableModule), argv, envp); +} + +static void usage(const char *argv0) { + std::println("{} [...] [args...]", argv0); + std::println(" options:"); + std::println(" --version, -v - print version"); + std::println(" -m, --mount "); + std::println(" -o, --override "); + std::println( + " --gpu - specify physical gpu index to use, default is 0"); + // std::println(" --presenter "); + std::println(" --trace"); +} + +static orbis::SysResult launchDaemon(orbis::Thread *thread, std::string path, + std::vector argv, + std::vector envv, + orbis::AppInfo appInfo) { + auto childPid = orbis::g_context.allocatePid() * 10000 + 1; + auto flag = orbis::knew>(); + *flag = false; + + int hostPid = ::fork(); + + if (hostPid) { + while (*flag == false) { + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } + + orbis::kfree(flag, sizeof(*flag)); + return {}; + } + + auto process = orbis::g_context.createProcess(childPid); + auto logFd = ::open(("log-" + std::to_string(childPid) + ".txt").c_str(), + O_CREAT | O_TRUNC | O_WRONLY, 0666); + + dup2(logFd, 1); + dup2(logFd, 2); + + process->hostPid = ::getpid(); + process->sysent = thread->tproc->sysent; + process->onSysEnter = thread->tproc->onSysEnter; + process->onSysExit = thread->tproc->onSysExit; + process->ops = thread->tproc->ops; + process->parentProcess = thread->tproc; + process->appInfo = appInfo; + + process->authInfo = { + .unk0 = 0x380000000000000f, + .caps = + { + -1ul, + -1ul, + -1ul, + -1ul, + }, + .attrs = + { + 0x4000400040000000, + 0x4000000000000000, + 0x0080000000000002, + 0xF0000000FFFF4000, + }, + }; + process->budgetId = 0; + process->isInSandbox = false; + + vm::fork(childPid); + vfs::fork(); + + *flag = true; + + auto [baseId, newThread] = process->threadsMap.emplace(); + newThread->tproc = process; + newThread->tid = process->pid + baseId; + newThread->state = orbis::ThreadState::RUNNING; + newThread->context = thread->context; + newThread->fsBase = thread->fsBase; + + orbis::g_currentThread = newThread; + thread = orbis::g_currentThread; + + setupSigHandlers(); + rx::thread::initialize(); + rx::thread::setupThisThread(); + + ps4InitFd(newThread); + + orbis::Ref socket; + createSocket(&socket, "", 1, 1, 0); + process->fileDescriptors.insert(socket); + + ORBIS_LOG_ERROR(__FUNCTION__, path); + + { + orbis::Ref file; + auto result = vfs::open(path, kOpenFlagReadOnly, 0, &file, thread); + if (result.isError()) { + return result; + } + } + + vm::reset(); + + thread->tproc->nextTlsSlot = 1; + auto executableModule = rx::linker::loadModuleFile(path, thread); + + executableModule->id = thread->tproc->modulesMap.insert(executableModule); + thread->tproc->processParam = executableModule->processParam; + thread->tproc->processParamSize = executableModule->processParamSize; + + g_traceSyscalls = false; + + thread->tproc->event.emit(orbis::kEvFiltProc, orbis::kNoteExec); + + std::thread([&] { + rx::thread::setupSignalStack(); + rx::thread::setupThisThread(); + ps4Exec(thread, executableModule, argv, envv); + }).join(); + std::abort(); +} + +int main(int argc, const char *argv[]) { + if (argc == 2) { + if (std::strcmp(argv[1], "-h") == 0 || + std::strcmp(argv[1], "--help") == 0) { + usage(argv[0]); + return 1; + } + + if (argv[1] == std::string_view("-v") || + argv[1] == std::string_view("--version")) { + std::printf("v%s\n", rx::getVersion().toString().c_str()); + return 0; + } + } + + if (argc < 2) { + usage(argv[0]); + return 1; + } + + orbis::g_context.deviceEventEmitter = orbis::knew(); + + bool enableAudioIpmi = false; + bool asRoot = false; + bool isSystem = false; + bool isSafeMode = false; + + int argIndex = 1; + while (argIndex < argc) { + if (argv[argIndex] == std::string_view("--mount") || + argv[argIndex] == std::string_view("-m")) { + if (argc <= argIndex + 2) { + usage(argv[0]); + return 1; + } + + std::println("mounting '{}' to virtual '{}'", argv[argIndex + 1], + argv[argIndex + 2]); + if (!std::filesystem::is_directory(argv[argIndex + 1])) { + std::println(stderr, "Directory '{}' not exists", argv[argIndex + 1]); + return 1; + } + + vfs::mount(argv[argIndex + 2], + createHostIoDevice(argv[argIndex + 1], argv[argIndex + 2])); + argIndex += 3; + continue; + } + + if (argv[argIndex] == std::string_view("--trace")) { + argIndex++; + g_traceSyscalls = true; + continue; + } + + if (argv[argIndex] == std::string_view("--root")) { + argIndex++; + asRoot = true; + continue; + } + + if (argv[argIndex] == std::string_view("--system")) { + argIndex++; + isSystem = true; + asRoot = true; + continue; + } + + if (argv[argIndex] == std::string_view("--safemode")) { + argIndex++; + isSafeMode = true; + asRoot = true; + continue; + } + + if (argv[argIndex] == std::string_view("--override") || + argv[argIndex] == std::string_view("-o")) { + if (argc <= argIndex + 2) { + usage(argv[0]); + return 1; + } + + rx::linker::override(argv[argIndex + 1], argv[argIndex + 2]); + + argIndex += 3; + continue; + } + + if (argv[argIndex] == std::string_view("--enable-audio") || + argv[argIndex] == std::string_view("-a")) { + argIndex++; + enableAudioIpmi = true; + continue; + } + + if (argv[argIndex] == std::string_view("--gpu")) { + if (argc <= argIndex + 1) { + usage(argv[0]); + return 1; + } + + rx::g_config.gpuIndex = std::atoi(argv[argIndex + 1]); + + argIndex += 2; + continue; + } + + if (argv[argIndex] == std::string_view("--validate")) { + rx::g_config.validateGpu = true; + argIndex++; + continue; + } + + break; + } + + rx::startWatchdog(); + + setupSigHandlers(); + + rx::createGpuDevice(); + vfs::initialize(); + + if (argIndex >= argc) { + usage(argv[0]); + return 1; + } + + rx::thread::initialize(); + + // vm::printHostStats(); + orbis::g_context.allocatePid(); + auto initProcess = orbis::g_context.createProcess(asRoot ? 1 : 10); + // pthread_setname_np(pthread_self(), "10.MAINTHREAD"); + + vm::initialize(initProcess->pid); + + int status = 0; + + initProcess->sysent = &orbis::ps4_sysvec; + initProcess->onSysEnter = onSysEnter; + initProcess->onSysExit = onSysExit; + initProcess->ops = &rx::procOpsTable; + initProcess->hostPid = ::getpid(); + initProcess->appInfo = { + .unk4 = (isSystem ? orbis::slong(0x80000000'00000000) : 0), + }; + + if (isSystem) { + orbis::g_context.safeMode = isSafeMode ? 1 : 0; + initProcess->authInfo = {.unk0 = 0x380000000000000f, + .caps = + { + -1ul, + -1ul, + -1ul, + -1ul, + }, + .attrs = + { + 0x4000400040000000, + 0x4000000000000000, + 0x0080000000000002, + 0xF0000000FFFF4000, + }, + .ucred = { + -1ul, + -1ul, + 0x3800000000000022, + -1ul, + (1ul << 0x3a), + -1ul, + -1ul, + }}; + initProcess->budgetId = 0; + initProcess->isInSandbox = false; + } else { + initProcess->authInfo = { + .unk0 = 0x3100000000000001, + .caps = + { + 0x2000038000000000, + 0x000000000000FF00, + 0x0000000000000000, + 0x0000000000000000, + }, + .attrs = + { + 0x4000400040000000, + 0x4000000000000000, + 0x0080000000000002, + 0xF0000000FFFF4000, + }, + }; + initProcess->budgetId = 1; + initProcess->isInSandbox = true; + } + + auto [baseId, mainThread] = initProcess->threadsMap.emplace(); + mainThread->tproc = initProcess; + mainThread->tid = initProcess->pid + baseId; + mainThread->state = orbis::ThreadState::RUNNING; + mainThread->hostTid = ::gettid(); + orbis::g_currentThread = mainThread; + + auto executableModule = + rx::linker::loadModuleFile(argv[argIndex], mainThread); + + if (executableModule == nullptr) { + std::println(stderr, "Failed to open '{}'", argv[argIndex]); + std::abort(); + } + + executableModule->id = initProcess->modulesMap.insert(executableModule); + initProcess->processParam = executableModule->processParam; + initProcess->processParamSize = executableModule->processParamSize; + + if (prctl(PR_SET_SYSCALL_USER_DISPATCH, PR_SYS_DISPATCH_ON, + (void *)0x100'0000'0000, ~0ull - 0x100'0000'0000, nullptr)) { + perror("prctl failed\n"); + return 1; + } + + if (executableModule->type != rx::linker::kElfTypeSceDynExec && + executableModule->type != rx::linker::kElfTypeSceExec && + executableModule->type != rx::linker::kElfTypeExec) { + std::println(stderr, "Unexpected executable type"); + status = 1; + return 1; + } + + ps4InitDev(); + ps4InitFd(mainThread); + + std::vector ps4Argv(argv + argIndex, + argv + argIndex + argc - argIndex); + + auto execEnv = ps4CreateExecEnv(mainThread, executableModule, isSystem); + + // data transfer mode + // 0 - normal + // 1 - source + // 2 - ? + orbis::g_context.regMgrInt[0x2110000] = 0; + + orbis::g_context.regMgrInt[0x20b0000] = 1; // prefer X + orbis::g_context.regMgrInt[0x2020000] = 1; // region + + // orbis::g_context.regMgrInt[0x2130000] = 0x1601; + orbis::g_context.regMgrInt[0x2130000] = 0; + orbis::g_context.regMgrInt[0x73800200] = 1; + orbis::g_context.regMgrInt[0x73800300] = 0; + orbis::g_context.regMgrInt[0x73800400] = 0; + orbis::g_context.regMgrInt[0x73800500] = 0; // enable log + + // user settings + orbis::g_context.regMgrInt[0x7800100] = 0; + orbis::g_context.regMgrInt[0x7810100] = 0; + orbis::g_context.regMgrInt[0x7820100] = 0; + orbis::g_context.regMgrInt[0x7830100] = 0; + orbis::g_context.regMgrInt[0x7840100] = 0; + orbis::g_context.regMgrInt[0x7850100] = 0; + orbis::g_context.regMgrInt[0x7860100] = 0; + orbis::g_context.regMgrInt[0x7870100] = 0; + orbis::g_context.regMgrInt[0x7880100] = 0; + orbis::g_context.regMgrInt[0x7890100] = 0; + orbis::g_context.regMgrInt[0x78a0100] = 0; + orbis::g_context.regMgrInt[0x78b0100] = 0; + orbis::g_context.regMgrInt[0x78c0100] = 0; + orbis::g_context.regMgrInt[0x78d0100] = 0; + orbis::g_context.regMgrInt[0x78e0100] = 0; + orbis::g_context.regMgrInt[0x78f0100] = 0; + + orbis::g_context.regMgrInt[0x2040000] = 0; // do not require initial setup + orbis::g_context.regMgrInt[0x2800600] = 0; // IDU version + orbis::g_context.regMgrInt[0x2860100] = 0; // IDU mode + orbis::g_context.regMgrInt[0x2860300] = 0; // Arcade mode + orbis::g_context.regMgrInt[0x7010000] = 0; // auto login + orbis::g_context.regMgrInt[0x9010000] = 0; // video out color effect + + if (!isSystem) { + ipmi::createMiniSysCoreObjects(initProcess); + ipmi::createSysAvControlObjects(initProcess); + ipmi::createSysCoreObjects(initProcess); + ipmi::createGnmCompositorObjects(initProcess); + ipmi::createShellCoreObjects(initProcess); + if (enableAudioIpmi) { + ipmi::createAudioSystemObjects(initProcess); + } + + // ? + ipmi::createIpmiServer(initProcess, "SceCdlgRichProf"); + ipmi::createIpmiServer(initProcess, "SceRemoteplayIpc"); + ipmi::createIpmiServer(initProcess, "SceGlsIpc"); + ipmi::createIpmiServer(initProcess, "SceImeService"); + ipmi::createIpmiServer(initProcess, "SceErrorDlgServ"); + + ipmi::createEventFlag("SceNpTusIpc_0000000a", 0x120, 0); + ipmi::createSemaphore("SceLncSuspendBlock00000000", 0x101, 1, 1); + ipmi::createSemaphore("SceNpPlusLogger 0", 0x101, 0, 0x7fffffff); + + initProcess->cwd = "/app0/"; + + if (!enableAudioIpmi) { + launchDaemon(mainThread, "/system/sys/orbis_audiod.elf", + {"/system/sys/orbis_audiod.elf"}, {}, + { + .titleId = "NPXS20973", + .unk4 = orbis::slong(0x80000000'00000000), + }); + // confirmed to work and known method of initialization since 5.05 + // version + if (orbis::g_context.fwSdkVersion >= 0x5050000) { + auto fakeIpmiThread = createGuestThread(); + ipmi::audioIpmiClient = + ipmi::createIpmiClient(fakeIpmiThread, "SceSysAudioSystemIpc"); + // HACK: here is a bug in audiod because we send this very early and + // audiod has time to reset the state due to initialization so we wait + // for a second, during this time audiod should have time to + // initialize on most systems + std::this_thread::sleep_for(std::chrono::seconds(1)); + struct Data1 { + int32_t pid = 0; + int32_t someSwitch = 0x14; // 0x14 for init, 0x19 for mute + int32_t someFlag = 0; + } data1; + data1.pid = fakeIpmiThread->tproc->pid; + struct Data2 { + void *unk0 = 0; + int32_t unk1 = 0x105; + int32_t unk2 = 0x10000; + int64_t unk3 = 0; + int32_t unk4 = 0; + int32_t unk5 = 0; + int32_t unk6 = 0; + int64_t unk7 = 0; + int32_t unk8 = 0x2; + char unk9[24]{0}; + } data2; + std::uint32_t method = orbis::g_context.fwSdkVersion >= 0x8000000 + ? 0x1234002c + : 0x1234002b; + ipmi::audioIpmiClient.sendSyncMessage(method, data1, data2); + } + } + } + + status = + ps4Exec(mainThread, execEnv, std::move(executableModule), ps4Argv, {}); + + vm::deinitialize(); + rx::thread::deinitialize(); + + return status; +} diff --git a/rpcsx-os/ops.cpp b/rpcsx/ops.cpp similarity index 96% rename from rpcsx-os/ops.cpp rename to rpcsx/ops.cpp index fe1159e..177c8d6 100644 --- a/rpcsx-os/ops.cpp +++ b/rpcsx/ops.cpp @@ -177,7 +177,7 @@ orbis::SysResult mmap(orbis::Thread *thread, orbis::caddr_t addr, orbis::size_t len, orbis::sint prot, orbis::sint flags, orbis::sint fd, orbis::off_t pos) { if (fd == -1) { - auto result = rx::vm::map(addr, len, prot, flags); + auto result = vm::map(addr, len, prot, flags); if (result == (void *)-1) { return ErrorCode::NOMEM; } @@ -226,7 +226,7 @@ orbis::SysResult dmem_mmap(orbis::Thread *thread, orbis::caddr_t addr, orbis::SysResult munmap(orbis::Thread *, orbis::ptr addr, orbis::size_t len) { - if (rx::vm::unmap(addr, len)) { + if (vm::unmap(addr, len)) { return {}; } return ErrorCode::INVAL; @@ -239,7 +239,7 @@ orbis::SysResult msync(orbis::Thread *thread, orbis::ptr addr, orbis::SysResult mprotect(orbis::Thread *thread, orbis::ptr addr, orbis::size_t len, orbis::sint prot) { - if (!rx::vm::protect((void *)addr, len, prot)) { + if (!vm::protect((void *)addr, len, prot)) { return ErrorCode::INVAL; } return {}; @@ -273,11 +273,11 @@ orbis::SysResult munlock(orbis::Thread *thread, orbis::ptr addr, orbis::SysResult virtual_query(orbis::Thread *thread, orbis::ptr addr, orbis::sint flags, orbis::ptr info, orbis::ulong infoSize) { - if (infoSize != sizeof(rx::vm::VirtualQueryInfo)) { + if (infoSize != sizeof(vm::VirtualQueryInfo)) { return ErrorCode::INVAL; } - if (!rx::vm::virtualQuery(addr, flags, (rx::vm::VirtualQueryInfo *)info)) { + if (!vm::virtualQuery(addr, flags, (vm::VirtualQueryInfo *)info)) { return ErrorCode::FAULT; } return {}; @@ -286,7 +286,7 @@ orbis::SysResult virtual_query(orbis::Thread *thread, orbis::SysResult query_memory_protection(orbis::Thread *thread, orbis::ptr address, orbis::ptr protection) { - if (rx::vm::queryProtection(address, &protection->startAddress, + if (vm::queryProtection(address, &protection->startAddress, &protection->endAddress, &protection->prot)) { return {}; } @@ -296,7 +296,7 @@ query_memory_protection(orbis::Thread *thread, orbis::ptr address, orbis::SysResult open(orbis::Thread *thread, orbis::ptr path, orbis::sint flags, orbis::sint mode, orbis::Ref *file) { - return rx::vfs::open(getAbsolutePath(path, thread), flags, mode, file, + return vfs::open(getAbsolutePath(path, thread), flags, mode, file, thread); } @@ -307,20 +307,20 @@ orbis::SysResult shm_open(orbis::Thread *thread, const char *path, return dev->open(file, path, flags, mode, thread); } orbis::SysResult unlink(orbis::Thread *thread, orbis::ptr path) { - return rx::vfs::unlink(getAbsolutePath(path, thread), thread); + return vfs::unlink(getAbsolutePath(path, thread), thread); } orbis::SysResult mkdir(Thread *thread, ptr path, sint mode) { ORBIS_LOG_TODO(__FUNCTION__, path, mode); - return rx::vfs::mkdir(getAbsolutePath(path, thread), mode, thread); + return vfs::mkdir(getAbsolutePath(path, thread), mode, thread); } orbis::SysResult rmdir(Thread *thread, ptr path) { ORBIS_LOG_TODO(__FUNCTION__, path); - return rx::vfs::rmdir(getAbsolutePath(path, thread), thread); + return vfs::rmdir(getAbsolutePath(path, thread), thread); } orbis::SysResult rename(Thread *thread, ptr from, ptr to) { ORBIS_LOG_TODO(__FUNCTION__, from, to); - return rx::vfs::rename(getAbsolutePath(from, thread), + return vfs::rename(getAbsolutePath(from, thread), getAbsolutePath(to, thread), thread); } @@ -480,7 +480,7 @@ orbis::SysResult dynlib_load_prx(orbis::Thread *thread, { orbis::Ref file; - if (auto result = rx::vfs::open(path, 0, 0, &file, thread); + if (auto result = vfs::open(path, 0, 0, &file, thread); result.isError()) { return result; } @@ -655,7 +655,7 @@ orbis::SysResult unmount(orbis::Thread *thread, orbis::ptr path, // TODO: support other that nullfs ORBIS_LOG_WARNING(__FUNCTION__, path); thread->where(); - rx::vfs::unlink(getAbsolutePath(path, thread), thread); + vfs::unlink(getAbsolutePath(path, thread), thread); return {}; } orbis::SysResult nmount(orbis::Thread *thread, orbis::ptr iovp, @@ -688,8 +688,8 @@ orbis::SysResult nmount(orbis::Thread *thread, orbis::ptr iovp, } if (fstype == "nullfs") { - rx::vfs::unlinkAll(fspath, thread); - return rx::vfs::createSymlink(target, fspath, thread); + vfs::unlinkAll(fspath, thread); + return vfs::createSymlink(target, fspath, thread); } // TODO @@ -794,8 +794,8 @@ SysResult fork(Thread *thread, slong flags) { } } - rx::vm::fork(childPid); - rx::vfs::fork(); + vm::fork(childPid); + vfs::fork(); *flag = true; @@ -881,13 +881,13 @@ SysResult execve(Thread *thread, ptr fname, ptr> argv, // } { orbis::Ref file; - auto result = rx::vfs::open(path, kOpenFlagReadOnly, 0, &file, thread); + auto result = vfs::open(path, kOpenFlagReadOnly, 0, &file, thread); if (result.isError()) { return result; } } - rx::vm::reset(); + vm::reset(); thread->tproc->nextTlsSlot = 1; for (auto [id, mod] : thread->tproc->modulesMap) { diff --git a/rpcsx-os/ops.hpp b/rpcsx/ops.hpp similarity index 100% rename from rpcsx-os/ops.hpp rename to rpcsx/ops.hpp diff --git a/rpcsx-os/orbis-kernel-config/orbis-config.hpp b/rpcsx/orbis-kernel-config/orbis-config.hpp similarity index 100% rename from rpcsx-os/orbis-kernel-config/orbis-config.hpp rename to rpcsx/orbis-kernel-config/orbis-config.hpp diff --git a/rpcsx-os/scheduler.hpp b/rpcsx/scheduler.hpp similarity index 100% rename from rpcsx-os/scheduler.hpp rename to rpcsx/scheduler.hpp diff --git a/rpcsx-os/thread.cpp b/rpcsx/thread.cpp similarity index 100% rename from rpcsx-os/thread.cpp rename to rpcsx/thread.cpp diff --git a/rpcsx-os/thread.hpp b/rpcsx/thread.hpp similarity index 100% rename from rpcsx-os/thread.hpp rename to rpcsx/thread.hpp diff --git a/rpcsx-os/vfs.cpp b/rpcsx/vfs.cpp similarity index 83% rename from rpcsx-os/vfs.cpp rename to rpcsx/vfs.cpp index 361f46c..cdbaf93 100644 --- a/rpcsx-os/vfs.cpp +++ b/rpcsx/vfs.cpp @@ -64,7 +64,7 @@ static orbis::shared_mutex gMountMtx; static std::map, std::greater<>> gMountsMap; static orbis::Ref gDevFs; -void rx::vfs::fork() { +void vfs::fork() { std::lock_guard lock(gMountMtx); // NOTE: do not decrease reference counter, it managed by parent process @@ -83,24 +83,24 @@ void rx::vfs::fork() { } } -void rx::vfs::initialize() { +void vfs::initialize() { gDevFs = orbis::knew(); gMountsMap.emplace("/dev/", gDevFs); gMountsMap.emplace("/proc/", orbis::knew()); } -void rx::vfs::deinitialize() { +void vfs::deinitialize() { gDevFs = nullptr; gMountsMap.clear(); } -void rx::vfs::addDevice(std::string name, IoDevice *device) { +void vfs::addDevice(std::string name, IoDevice *device) { std::lock_guard lock(gMountMtx); gDevFs->devices[std::move(name)] = device; } std::pair, std::string> -rx::vfs::get(const std::filesystem::path &guestPath) { +vfs::get(const std::filesystem::path &guestPath) { std::string normalPath = std::filesystem::path(guestPath).lexically_normal(); std::string_view path = normalPath; orbis::Ref device; @@ -141,8 +141,8 @@ rx::vfs::get(const std::filesystem::path &guestPath) { return {}; } -orbis::SysResult rx::vfs::mount(const std::filesystem::path &guestPath, - IoDevice *dev) { +orbis::SysResult vfs::mount(const std::filesystem::path &guestPath, + IoDevice *dev) { auto mp = guestPath.lexically_normal().string(); if (!mp.ends_with("/")) { mp += "/"; @@ -159,9 +159,9 @@ orbis::SysResult rx::vfs::mount(const std::filesystem::path &guestPath, return {}; } -orbis::SysResult rx::vfs::open(std::string_view path, int flags, int mode, - orbis::Ref *file, - orbis::Thread *thread) { +orbis::SysResult vfs::open(std::string_view path, int flags, int mode, + orbis::Ref *file, + orbis::Thread *thread) { auto [device, devPath] = get(path); if (device == nullptr) { return orbis::ErrorCode::NOENT; @@ -170,7 +170,7 @@ orbis::SysResult rx::vfs::open(std::string_view path, int flags, int mode, return device->open(file, devPath.c_str(), flags, mode, thread); } -bool rx::vfs::exists(std::string_view path, orbis::Thread *thread) { +bool vfs::exists(std::string_view path, orbis::Thread *thread) { auto [device, devPath] = get(path); if (device == nullptr) { return false; @@ -184,8 +184,8 @@ bool rx::vfs::exists(std::string_view path, orbis::Thread *thread) { return true; } -orbis::SysResult rx::vfs::mkdir(std::string_view path, int mode, - orbis::Thread *thread) { +orbis::SysResult vfs::mkdir(std::string_view path, int mode, + orbis::Thread *thread) { auto [device, devPath] = get(path); if (device == nullptr) { return orbis::ErrorCode::NOENT; @@ -193,7 +193,7 @@ orbis::SysResult rx::vfs::mkdir(std::string_view path, int mode, return device->mkdir(devPath.c_str(), mode, thread); } -orbis::SysResult rx::vfs::rmdir(std::string_view path, orbis::Thread *thread) { +orbis::SysResult vfs::rmdir(std::string_view path, orbis::Thread *thread) { auto [device, devPath] = get(path); if (device == nullptr) { return orbis::ErrorCode::NOENT; @@ -201,8 +201,8 @@ orbis::SysResult rx::vfs::rmdir(std::string_view path, orbis::Thread *thread) { return device->rmdir(devPath.c_str(), thread); } -orbis::SysResult rx::vfs::rename(std::string_view from, std::string_view to, - orbis::Thread *thread) { +orbis::SysResult vfs::rename(std::string_view from, std::string_view to, + orbis::Thread *thread) { auto [fromDevice, fromDevPath] = get(from); if (fromDevice == nullptr) { return orbis::ErrorCode::NOENT; @@ -222,7 +222,7 @@ orbis::SysResult rx::vfs::rename(std::string_view from, std::string_view to, return fromDevice->rename(fromDevPath.c_str(), toDevPath.c_str(), thread); } -orbis::ErrorCode rx::vfs::unlink(std::string_view path, orbis::Thread *thread) { +orbis::ErrorCode vfs::unlink(std::string_view path, orbis::Thread *thread) { auto [device, devPath] = get(path); if (device == nullptr) { return orbis::ErrorCode::NOENT; @@ -231,8 +231,7 @@ orbis::ErrorCode rx::vfs::unlink(std::string_view path, orbis::Thread *thread) { return device->unlink(devPath.c_str(), false, thread); } -orbis::ErrorCode rx::vfs::unlinkAll(std::string_view path, - orbis::Thread *thread) { +orbis::ErrorCode vfs::unlinkAll(std::string_view path, orbis::Thread *thread) { auto [device, devPath] = get(path); if (device == nullptr) { return orbis::ErrorCode::NOENT; @@ -241,9 +240,9 @@ orbis::ErrorCode rx::vfs::unlinkAll(std::string_view path, return device->unlink(devPath.c_str(), true, thread); } -orbis::ErrorCode rx::vfs::createSymlink(std::string_view target, - std::string_view linkPath, - orbis::Thread *thread) { +orbis::ErrorCode vfs::createSymlink(std::string_view target, + std::string_view linkPath, + orbis::Thread *thread) { auto [fromDevice, fromDevPath] = get(target); if (fromDevice == nullptr) { return orbis::ErrorCode::NOENT; diff --git a/rpcsx-os/vfs.hpp b/rpcsx/vfs.hpp similarity index 96% rename from rpcsx-os/vfs.hpp rename to rpcsx/vfs.hpp index 8884d93..b1f2395 100644 --- a/rpcsx-os/vfs.hpp +++ b/rpcsx/vfs.hpp @@ -7,7 +7,7 @@ struct IoDevice; -namespace rx::vfs { +namespace vfs { void fork(); void initialize(); void deinitialize(); @@ -27,4 +27,4 @@ orbis::ErrorCode unlinkAll(std::string_view path, orbis::Thread *thread); orbis::ErrorCode createSymlink(std::string_view target, std::string_view linkPath, orbis::Thread *thread); -} // namespace rx::vfs +} // namespace vfs diff --git a/rpcsx-os/vm.cpp b/rpcsx/vm.cpp similarity index 85% rename from rpcsx-os/vm.cpp rename to rpcsx/vm.cpp index c92962d..1065f50 100644 --- a/rpcsx-os/vm.cpp +++ b/rpcsx/vm.cpp @@ -1,18 +1,21 @@ #include "vm.hpp" -#include "bridge.hpp" +#include "gpu/Device.hpp" #include "io-device.hpp" #include "iodev/dmem.hpp" +#include "orbis/KernelContext.hpp" #include "orbis/thread/Process.hpp" #include "orbis/thread/Thread.hpp" #include "orbis/utils/Logs.hpp" #include "orbis/utils/Rc.hpp" +#include "rx/watchdog.hpp" #include #include -#include #include #include #include +#include #include +#include #include #include #include @@ -21,7 +24,7 @@ static std::mutex g_mtx; -std::string rx::vm::mapFlagsToString(std::int32_t flags) { +std::string vm::mapFlagsToString(std::int32_t flags) { std::string result; if ((flags & kMapFlagShared) == kMapFlagShared) { @@ -175,7 +178,7 @@ std::string rx::vm::mapFlagsToString(std::int32_t flags) { return result; } -std::string rx::vm::mapProtToString(std::int32_t prot) { +std::string vm::mapProtToString(std::int32_t prot) { std::string result; if ((prot & kMapProtCpuRead) == kMapProtCpuRead) { @@ -225,12 +228,12 @@ std::string rx::vm::mapProtToString(std::int32_t prot) { return result; } -static constexpr std::uint64_t kPageMask = rx::vm::kPageSize - 1; +static constexpr std::uint64_t kPageMask = vm::kPageSize - 1; static constexpr std::uint64_t kBlockShift = 32; static constexpr std::uint64_t kBlockSize = static_cast(1) << kBlockShift; static constexpr std::uint64_t kBlockMask = kBlockSize - 1; -static constexpr std::uint64_t kPagesInBlock = kBlockSize / rx::vm::kPageSize; +static constexpr std::uint64_t kPagesInBlock = kBlockSize / vm::kPageSize; static constexpr std::uint64_t kFirstBlock = 0x00; static constexpr std::uint64_t kLastBlock = 0xff; static constexpr std::uint64_t kBlockCount = kLastBlock - kFirstBlock + 1; @@ -238,7 +241,7 @@ static constexpr std::uint64_t kGroupSize = 64; static constexpr std::uint64_t kGroupMask = kGroupSize - 1; static constexpr std::uint64_t kGroupsInBlock = kPagesInBlock / kGroupSize; static constexpr std::uint64_t kMinAddress = - kFirstBlock * kBlockSize + rx::vm::kPageSize * 0x10; + kFirstBlock * kBlockSize + vm::kPageSize * 0x10; static constexpr std::uint64_t kMaxAddress = (kLastBlock + 1) * kBlockSize - 1; static constexpr std::uint64_t kMemorySize = kBlockCount * kBlockSize; @@ -255,11 +258,11 @@ struct Group { }; enum { - kReadable = rx::vm::kMapProtCpuRead, - kWritable = rx::vm::kMapProtCpuWrite, - kExecutable = rx::vm::kMapProtCpuExec, - kGpuReadable = rx::vm::kMapProtGpuRead, - kGpuWritable = rx::vm::kMapProtGpuWrite, + kReadable = vm::kMapProtCpuRead, + kWritable = vm::kMapProtCpuWrite, + kExecutable = vm::kMapProtCpuExec, + kGpuReadable = vm::kMapProtGpuRead, + kGpuWritable = vm::kMapProtGpuWrite, kAllocated = 1 << 3, kShared = 1 << 6, @@ -493,8 +496,8 @@ struct Block { std::uint64_t foundCount = 0; std::uint64_t foundPage = 0; - if (alignment < kGroupSize * rx::vm::kPageSize) { - std::uint64_t groupAlignment = alignment >> rx::vm::kPageShift; + if (alignment < kGroupSize * vm::kPageSize) { + std::uint64_t groupAlignment = alignment >> vm::kPageShift; for (std::uint64_t groupIndex = 0; groupIndex < kGroupsInBlock && foundCount < count; ++groupIndex) { @@ -586,8 +589,7 @@ struct Block { } } } else { - std::uint64_t blockAlignment = - alignment / (kGroupSize * rx::vm::kPageSize); + std::uint64_t blockAlignment = alignment / (kGroupSize * vm::kPageSize); for (std::uint64_t groupIndex = 0; groupIndex < kGroupsInBlock && foundCount < count; ++groupIndex) { @@ -624,7 +626,7 @@ struct Block { } if (foundCount >= count) { - assert(((foundPage << rx::vm::kPageShift) & (alignment - 1)) == 0); + assert(((foundPage << vm::kPageShift) & (alignment - 1)) == 0); return foundPage; } @@ -651,35 +653,36 @@ static void reserve(std::uint64_t startAddress, std::uint64_t endAddress) { assert(endAddress > startAddress); assert(blockIndex == (endAddress >> kBlockShift)); - auto firstPage = (startAddress & kBlockMask) >> rx::vm::kPageShift; - auto pagesCount = (endAddress - startAddress + (rx::vm::kPageSize - 1)) >> - rx::vm::kPageShift; + auto firstPage = (startAddress & kBlockMask) >> vm::kPageShift; + auto pagesCount = + (endAddress - startAddress + (vm::kPageSize - 1)) >> vm::kPageShift; gBlocks[blockIndex - kFirstBlock].setFlags(firstPage, pagesCount, kAllocated, false); } -void rx::vm::fork(std::uint64_t pid) { - gMemoryShm = ::shm_open(("/rpcsx-os-memory-" + std::to_string(pid)).c_str(), - O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); +void vm::fork(std::uint64_t pid) { + auto shmPath = std::format("{}/memory-{}", rx::getShmPath(), pid); + gMemoryShm = + ::open(shmPath.c_str(), O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR); (void)g_mtx.try_lock(); g_mtx.unlock(); // release mutex if (gMemoryShm == -1) { - std::fprintf(stderr, "Memory: failed to open /rpcsx-os-memory\n"); + std::println(stderr, "Memory: failed to open {}", shmPath); std::abort(); } if (::ftruncate64(gMemoryShm, kMemorySize) < 0) { - std::fprintf(stderr, "Memory: failed to allocate /rpcsx-os-memory\n"); + std::println(stderr, "Memory: failed to allocate {}", shmPath); std::abort(); } for (auto address = kMinAddress; address < kMaxAddress; address += kPageSize) { auto prot = gBlocks[(address >> kBlockShift) - kFirstBlock].getProtection( - (address & kBlockMask) >> rx::vm::kPageShift); + (address & kBlockMask) >> vm::kPageShift); if (prot & kShared) { continue; @@ -705,7 +708,7 @@ void rx::vm::fork(std::uint64_t pid) { } } -void rx::vm::reset() { +void vm::reset() { std::memset(gBlocks, 0, sizeof(gBlocks)); rx::mem::unmap(reinterpret_cast(kMinAddress), @@ -722,19 +725,20 @@ void rx::vm::reset() { kMaxAddress - kMinAddress); } -void rx::vm::initialize(std::uint64_t pid) { - std::printf("Memory: initialization\n"); +void vm::initialize(std::uint64_t pid) { + std::println("Memory: initialization"); + auto shmPath = std::format("{}/memory-{}", rx::getShmPath(), pid); - gMemoryShm = ::shm_open(("/rpcsx-os-memory-" + std::to_string(pid)).c_str(), - O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); + gMemoryShm = + ::open(shmPath.c_str(), O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR); if (gMemoryShm == -1) { - std::fprintf(stderr, "Memory: failed to open /rpcsx-os-memory\n"); + std::println(stderr, "Memory: failed to open {}", shmPath); std::abort(); } if (::ftruncate64(gMemoryShm, kMemorySize) < 0) { - std::fprintf(stderr, "Memory: failed to allocate /rpcsx-os-memory\n"); + std::println(stderr, "Memory: failed to allocate {}", shmPath); std::abort(); } @@ -742,15 +746,12 @@ void rx::vm::initialize(std::uint64_t pid) { rx::mem::reserve(reinterpret_cast(kMinAddress), kMaxAddress - kMinAddress); - - // orbis::bridge.setUpSharedMemory(kMinAddress, kMemorySize, "/orbis-memory"); } -void rx::vm::deinitialize() { - std::printf("Memory: shutdown\n"); +void vm::deinitialize() { + std::println("Memory: shutdown"); ::close(gMemoryShm); gMemoryShm = -1; - ::shm_unlink("/orbis-memory"); for (auto &block : gBlocks) { block = {}; @@ -762,14 +763,11 @@ constexpr auto kFlexibleMemorySize = 448ull * 1024 * 1024; constexpr auto kMainDirectMemorySize = kPhysicalMemorySize - kFlexibleMemorySize; -void *rx::vm::map(void *addr, std::uint64_t len, std::int32_t prot, - std::int32_t flags, std::int32_t internalFlags, - IoDevice *device, std::uint64_t offset) { - std::fprintf(stderr, - "rx::vm::map(addr = %p, len = %" PRIu64 - ", prot = %s, flags = %s)\n", - addr, len, mapProtToString(prot).c_str(), - mapFlagsToString(flags).c_str()); +void *vm::map(void *addr, std::uint64_t len, std::int32_t prot, + std::int32_t flags, std::int32_t internalFlags, IoDevice *device, + std::uint64_t offset) { + std::println(stderr, "vm::map(addr = {}, len = {}, prot = {}, flags = {})", + addr, len, mapProtToString(prot), mapFlagsToString(flags)); len = rx::alignUp(len, kPageSize); auto pagesCount = (len + (kPageSize - 1)) >> kPageShift; @@ -783,13 +781,12 @@ void *rx::vm::map(void *addr, std::uint64_t len, std::int32_t prot, } if (alignment < kPageSize) { - std::fprintf(stderr, "Memory error: wrong alignment %" PRId64 "\n", - alignment); + std::println(stderr, "Memory error: wrong alignment {}", alignment); alignment = kPageSize; } if (len > kBlockSize) { - std::fprintf(stderr, "Memory error: too big allocation %" PRId64 " pages\n", + std::println(stderr, "Memory error: too big allocation {} pages", pagesCount); return MAP_FAILED; } @@ -818,9 +815,8 @@ void *rx::vm::map(void *addr, std::uint64_t len, std::int32_t prot, auto blockIndex = address >> kBlockShift; if (blockIndex < kFirstBlock || blockIndex > kLastBlock) { - std::fprintf(stderr, - "Memory error: fixed mapping with wrong address %" PRIx64 - " pages\n", + std::println(stderr, + "Memory error: fixed mapping with wrong address {:x} pages", address); return MAP_FAILED; } @@ -829,8 +825,7 @@ void *rx::vm::map(void *addr, std::uint64_t len, std::int32_t prot, auto page = (hitAddress & kBlockMask) >> kPageShift; if (blockIndex < kFirstBlock || blockIndex > kLastBlock) { - std::fprintf(stderr, - "Memory error: wrong hit address %" PRIx64 " pages\n", + std::println(stderr, "Memory error: wrong hit address {:x} pages", hitAddress); hitAddress = 0; } else { @@ -873,20 +868,19 @@ void *rx::vm::map(void *addr, std::uint64_t len, std::int32_t prot, } if (address == 0) { - std::fprintf(stderr, - "Memory error: no free memory left for mapping of %" PRId64 - " pages\n", + std::println(stderr, + "Memory error: no free memory left for mapping of {} pages", pagesCount); return MAP_FAILED; } if (address & (alignment - 1)) { - std::fprintf(stderr, "Memory error: failed to map aligned address\n"); + std::println(stderr, "Memory error: failed to map aligned address"); std::abort(); } if (address >= kMaxAddress || address > kMaxAddress - len) { - std::fprintf(stderr, "Memory error: out of memory\n"); + std::println(stderr, "Memory error: out of memory"); std::abort(); } @@ -921,7 +915,7 @@ void *rx::vm::map(void *addr, std::uint64_t len, std::int32_t prot, } */ if (flags) { - std::fprintf(stderr, " unhandled flags 0x%" PRIx32 "\n", flags); + std::println(stderr, " unhandled flags 0x{:x}", flags); } { @@ -936,14 +930,13 @@ void *rx::vm::map(void *addr, std::uint64_t len, std::int32_t prot, gMapInfo.map(address, address + len, info); } - // if (device == nullptr) { if (auto thr = orbis::g_currentThread) { - rx::bridge.sendMapMemory(thr->tproc->pid, -1, -1, address, len, prot, - address - kMinAddress); - } else { - std::fprintf(stderr, "ignoring mapping %lx-%lx\n", address, address + len); + std::lock_guard lock(orbis::g_context.gpuDeviceMtx); + if (auto gpu = orbis::g_context.gpuDevice.staticCast()) { + gpu->submitMapMemory(thr->tproc->gfxRing, thr->tproc->pid, address, len, + -1, -1, prot, address - kMinAddress); + } } - // } if (internalFlags & kMapInternalReserveOnly) { return reinterpret_cast(address); @@ -967,26 +960,26 @@ void *rx::vm::map(void *addr, std::uint64_t len, std::int32_t prot, return result; } -bool rx::vm::unmap(void *addr, std::uint64_t size) { +bool vm::unmap(void *addr, std::uint64_t size) { size = rx::alignUp(size, kPageSize); auto pages = (size + (kPageSize - 1)) >> kPageShift; auto address = reinterpret_cast(addr); if (address < kMinAddress || address >= kMaxAddress || size > kMaxAddress || address > kMaxAddress - size) { - std::fprintf(stderr, "Memory error: unmap out of memory\n"); + std::println(stderr, "Memory error: unmap out of memory"); return false; } if ((address & kPageMask) != 0) { - std::fprintf(stderr, "Memory error: unmap unaligned address\n"); + std::println(stderr, "Memory error: unmap unaligned address"); return false; } if ((address >> kBlockShift) != ((address + size - 1) >> kBlockShift)) { - std::fprintf( + std::println( stderr, - "Memory error: unmap cross block range. address 0x%lx, size=0x%lx\n", + "Memory error: unmap cross block range. address 0x{:x}, size=0x{:x}", address, size); __builtin_trap(); } @@ -995,34 +988,37 @@ bool rx::vm::unmap(void *addr, std::uint64_t size) { gBlocks[(address >> kBlockShift) - kFirstBlock].removeFlags( (address & kBlockMask) >> kPageShift, pages, ~0); if (auto thr = orbis::g_currentThread) { - rx::bridge.sendMemoryProtect( - thr->tproc->pid, reinterpret_cast(addr), size, 0); + std::lock_guard lock(orbis::g_context.gpuDeviceMtx); + if (auto gpu = orbis::g_context.gpuDevice.staticCast()) { + gpu->submitUnmapMemory(thr->tproc->gfxRing, thr->tproc->pid, address, + size); + } } else { - std::fprintf(stderr, "ignoring mapping %lx-%lx\n", address, address + size); + std::println(stderr, "ignoring mapping {:x}-{:x}", address, address + size); } return rx::mem::unmap(addr, size); } -bool rx::vm::protect(void *addr, std::uint64_t size, std::int32_t prot) { - std::printf("rx::vm::protect(addr = %p, len = %" PRIu64 ", prot = %s)\n", - addr, size, mapProtToString(prot).c_str()); +bool vm::protect(void *addr, std::uint64_t size, std::int32_t prot) { + std::println("vm::protect(addr = {}, len = {}, prot = {})", addr, size, + mapProtToString(prot)); size = rx::alignUp(size, kPageSize); auto pages = (size + (kPageSize - 1)) >> kPageShift; auto address = reinterpret_cast(addr); if (address < kMinAddress || address >= kMaxAddress || size > kMaxAddress || address > kMaxAddress - size) { - std::fprintf(stderr, "Memory error: protect out of memory\n"); + std::println(stderr, "Memory error: protect out of memory"); return false; } if ((address & kPageMask) != 0) { - std::fprintf(stderr, "Memory error: protect unaligned address\n"); + std::println(stderr, "Memory error: protect unaligned address"); return false; } if ((address >> kBlockShift) != ((address + size - 1) >> kBlockShift)) { - std::fprintf(stderr, "Memory error: protect cross block range\n"); + std::println(stderr, "Memory error: protect cross block range"); std::abort(); } @@ -1033,23 +1029,26 @@ bool rx::vm::protect(void *addr, std::uint64_t size, std::int32_t prot) { kAllocated | (prot & (kMapProtCpuAll | kMapProtGpuAll)), false); if (auto thr = orbis::g_currentThread) { - std::printf("memory prot: %x\n", prot); - rx::bridge.sendMemoryProtect( - thr->tproc->pid, reinterpret_cast(addr), size, prot); + std::println("memory prot: {:x}", prot); + std::lock_guard lock(orbis::g_context.gpuDeviceMtx); + if (auto gpu = orbis::g_context.gpuDevice.staticCast()) { + gpu->submitProtectMemory(thr->tproc->gfxRing, thr->tproc->pid, address, + size, prot); + } } else { - std::fprintf(stderr, "ignoring mapping %lx-%lx\n", address, address + size); + std::println(stderr, "ignoring mapping {:x}-{:x}", address, address + size); } return ::mprotect(addr, size, prot & kMapProtCpuAll) == 0; } static std::int32_t getPageProtectionImpl(std::uint64_t address) { return gBlocks[(address >> kBlockShift) - kFirstBlock].getProtection( - (address & kBlockMask) >> rx::vm::kPageShift) & + (address & kBlockMask) >> vm::kPageShift) & ~kShared; } -bool rx::vm::queryProtection(const void *addr, std::uint64_t *startAddress, - std::uint64_t *endAddress, std::int32_t *prot) { +bool vm::queryProtection(const void *addr, std::uint64_t *startAddress, + std::uint64_t *endAddress, std::int32_t *prot) { auto address = reinterpret_cast(addr); if (address < kMinAddress || address >= kMaxAddress) { return false; @@ -1099,9 +1098,9 @@ bool rx::vm::queryProtection(const void *addr, std::uint64_t *startAddress, return true; } -unsigned rx::vm::getPageProtection(std::uint64_t address) { +unsigned vm::getPageProtection(std::uint64_t address) { if (address < kMinAddress || address >= kMaxAddress) { - std::fprintf(stderr, "Memory error: getPageProtection out of memory\n"); + std::println(stderr, "Memory error: getPageProtection out of memory"); return 0; } @@ -1110,8 +1109,8 @@ unsigned rx::vm::getPageProtection(std::uint64_t address) { return getPageProtectionImpl(address); } -bool rx::vm::virtualQuery(const void *addr, std::int32_t flags, - VirtualQueryInfo *info) { +bool vm::virtualQuery(const void *addr, std::int32_t flags, + VirtualQueryInfo *info) { std::lock_guard lock(g_mtx); auto address = reinterpret_cast(addr); @@ -1141,8 +1140,8 @@ bool rx::vm::virtualQuery(const void *addr, std::int32_t flags, } memoryType = dmemIt->memoryType; blockFlags = kBlockFlagDirectMemory; - std::fprintf(stderr, "virtual query %p", addr); - std::fprintf(stderr, "memory type: %u\n", memoryType); + std::print(stderr, "virtual query {}", addr); + std::println(stderr, "memory type: {}", memoryType); } // TODO } @@ -1164,8 +1163,7 @@ bool rx::vm::virtualQuery(const void *addr, std::int32_t flags, return true; } -void rx::vm::setName(std::uint64_t start, std::uint64_t size, - const char *name) { +void vm::setName(std::uint64_t start, std::uint64_t size, const char *name) { std::lock_guard lock(g_mtx); MapInfo info; @@ -1177,20 +1175,3 @@ void rx::vm::setName(std::uint64_t start, std::uint64_t size, gMapInfo.map(start, size, info); } - -void rx::vm::printHostStats() { - FILE *maps = fopen("/proc/self/maps", "r"); - - if (!maps) { - return; - } - - char *line = nullptr; - std::size_t size = 0; - while (getline(&line, &size, maps) > 0) { - std::printf("%s", line); - } - - free(line); - fclose(maps); -} diff --git a/rpcsx-os/vm.hpp b/rpcsx/vm.hpp similarity index 96% rename from rpcsx-os/vm.hpp rename to rpcsx/vm.hpp index 2b1f6c0..40134c7 100644 --- a/rpcsx-os/vm.hpp +++ b/rpcsx/vm.hpp @@ -4,7 +4,7 @@ #include #include -namespace rx::vm { +namespace vm { static constexpr std::uint64_t kPageShift = 14; static constexpr std::uint64_t kPageSize = static_cast(1) << kPageShift; @@ -39,6 +39,7 @@ enum MapFlags { enum MapProt { kMapProtCpuRead = 1, kMapProtCpuWrite = 2, + kMapProtCpuReadWrite = kMapProtCpuRead | kMapProtCpuWrite, kMapProtCpuExec = 4, kMapProtCpuAll = 0x7, kMapProtGpuRead = 0x10, @@ -66,7 +67,6 @@ static constexpr std::uint32_t kMapFlagsAlignMask = 0x1f << kMapFlagsAlignShift; std::string mapFlagsToString(std::int32_t flags); std::string mapProtToString(std::int32_t prot); -void printHostStats(); void fork(std::uint64_t pid); void reset(); void initialize(std::uint64_t pid); @@ -82,4 +82,4 @@ bool virtualQuery(const void *addr, std::int32_t flags, VirtualQueryInfo *info); bool queryProtection(const void *addr, std::uint64_t *startAddress, std::uint64_t *endAddress, std::int32_t *prot); unsigned getPageProtection(std::uint64_t address); -} // namespace rx::vm +} // namespace vm diff --git a/rx/include/rx/mem.hpp b/rx/include/rx/mem.hpp index 8a8cdd9..1e4de74 100644 --- a/rx/include/rx/mem.hpp +++ b/rx/include/rx/mem.hpp @@ -10,4 +10,5 @@ void *reserve(std::size_t size); bool reserve(void *address, std::size_t size); bool protect(void *address, std::size_t size, int prot); bool unmap(void *address, std::size_t size); +void printStats(); } // namespace rx::mem diff --git a/rx/src/mem.cpp b/rx/src/mem.cpp index 4543c5f..69afd16 100644 --- a/rx/src/mem.cpp +++ b/rx/src/mem.cpp @@ -1,11 +1,13 @@ #include "mem.hpp" +#include +#include #include #include extern const std::size_t rx::mem::pageSize = sysconf(_SC_PAGE_SIZE); -void *rx::mem::map(void *address, std::size_t size, int prot, int flags, - int fd, std::ptrdiff_t offset) { +void *rx::mem::map(void *address, std::size_t size, int prot, int flags, int fd, + std::ptrdiff_t offset) { return ::mmap(address, size, prot, flags, fd, offset); } @@ -25,3 +27,20 @@ bool rx::mem::protect(void *address, std::size_t size, int prot) { bool rx::mem::unmap(void *address, std::size_t size) { return ::munmap(address, size) == 0; } + +void rx::mem::printStats() { + FILE *maps = fopen("/proc/self/maps", "r"); + + if (!maps) { + return; + } + + char *line = nullptr; + std::size_t size = 0; + while (getline(&line, &size, maps) > 0) { + std::print("{}", line); + } + + free(line); + fclose(maps); +}