mirror of
https://github.com/RPCSX/rpcsx.git
synced 2026-01-04 15:50:10 +01:00
Add OS<->GPU IPC
This commit is contained in:
parent
df5f8055fa
commit
2ab5cfb1f3
|
|
@ -83,18 +83,17 @@ enum class BridgeFlags {
|
|||
PullLock = 1 << 2,
|
||||
};
|
||||
|
||||
class BridgePusher {
|
||||
BridgeHeader *buffer = nullptr;
|
||||
struct BridgePusher {
|
||||
BridgeHeader *header = nullptr;
|
||||
|
||||
public:
|
||||
BridgePusher() = default;
|
||||
BridgePusher(BridgeHeader *buffer) : buffer(buffer) {}
|
||||
BridgePusher(BridgeHeader *header) : header(header) {}
|
||||
|
||||
void setVm(std::uint64_t address, std::uint64_t size, const char *name) {
|
||||
buffer->vmAddress = address;
|
||||
buffer->vmSize = size;
|
||||
std::strncpy(buffer->vmName, name, sizeof(buffer->vmName));
|
||||
buffer->flags |= static_cast<std::uint64_t>(BridgeFlags::VmConfigured);
|
||||
header->vmAddress = address;
|
||||
header->vmSize = size;
|
||||
std::strncpy(header->vmName, name, sizeof(header->vmName));
|
||||
header->flags |= static_cast<std::uint64_t>(BridgeFlags::VmConfigured);
|
||||
}
|
||||
|
||||
void sendMemoryProtect(std::uint64_t address, std::uint64_t size,
|
||||
|
|
@ -124,7 +123,7 @@ public:
|
|||
void sendDoFlip() { sendCommand(CommandId::DoFlip, {}); }
|
||||
|
||||
void wait() {
|
||||
while (buffer->pull != buffer->push)
|
||||
while (header->pull != header->push)
|
||||
;
|
||||
}
|
||||
|
||||
|
|
@ -138,21 +137,21 @@ private:
|
|||
std::size_t cmdSize = args.size() + 1;
|
||||
std::uint64_t pos = getPushPosition(cmdSize);
|
||||
|
||||
buffer->commands[pos++] = makeCommandHeader(CommandId::Flip, cmdSize);
|
||||
header->commands[pos++] = makeCommandHeader(CommandId::Flip, cmdSize);
|
||||
for (auto arg : args) {
|
||||
buffer->commands[pos++] = arg;
|
||||
header->commands[pos++] = arg;
|
||||
}
|
||||
buffer->push = pos;
|
||||
header->push = pos;
|
||||
}
|
||||
|
||||
std::uint64_t getPushPosition(std::uint64_t cmdSize) {
|
||||
std::uint64_t position = buffer->push;
|
||||
std::uint64_t position = header->push;
|
||||
|
||||
if (position + cmdSize > buffer->size) {
|
||||
if (position < buffer->size) {
|
||||
buffer->commands[position] =
|
||||
if (position + cmdSize > header->size) {
|
||||
if (position < header->size) {
|
||||
header->commands[position] =
|
||||
static_cast<std::uint64_t>(CommandId::Nop) |
|
||||
((buffer->size - position - 1) << 32);
|
||||
((header->size - position - 1) << 32);
|
||||
}
|
||||
|
||||
position = 0;
|
||||
|
|
@ -162,44 +161,43 @@ private:
|
|||
return position;
|
||||
}
|
||||
void waitPuller(std::uint64_t pullValue) {
|
||||
while (buffer->pull < pullValue) {
|
||||
while (header->pull < pullValue) {
|
||||
;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class BridgePuller {
|
||||
BridgeHeader *buffer = nullptr;
|
||||
struct BridgePuller {
|
||||
BridgeHeader *header = nullptr;
|
||||
|
||||
public:
|
||||
BridgePuller() = default;
|
||||
BridgePuller(BridgeHeader *buffer) : buffer(buffer) {}
|
||||
BridgePuller(BridgeHeader *header) : header(header) {}
|
||||
|
||||
std::size_t pullCommands(Command *commands, std::size_t maxCount) {
|
||||
std::size_t processed = 0;
|
||||
|
||||
while (processed < maxCount) {
|
||||
if (buffer->pull == buffer->push) {
|
||||
if (header->pull == header->push) {
|
||||
break;
|
||||
}
|
||||
|
||||
auto pos = buffer->pull;
|
||||
auto cmd = buffer->commands[pos];
|
||||
auto pos = header->pull;
|
||||
auto cmd = header->commands[pos];
|
||||
CommandId cmdId = static_cast<CommandId>(cmd);
|
||||
std::uint32_t argsCount = cmd >> 32;
|
||||
|
||||
if (cmdId != CommandId::Nop) {
|
||||
commands[processed++] =
|
||||
unpackCommand(cmdId, buffer->commands + pos + 1, argsCount);
|
||||
unpackCommand(cmdId, header->commands + pos + 1, argsCount);
|
||||
}
|
||||
|
||||
auto newPull = pos + argsCount + 1;
|
||||
|
||||
if (newPull >= buffer->size) {
|
||||
if (newPull >= header->size) {
|
||||
newPull = 0;
|
||||
}
|
||||
|
||||
buffer->pull = newPull;
|
||||
header->pull = newPull;
|
||||
}
|
||||
|
||||
return processed;
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ amdgpu::bridge::createShmCommandBuffer(const char *name) {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
unlinkShm(name);
|
||||
// unlinkShm(name);
|
||||
|
||||
int fd = ::shm_open(name, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
|
||||
|
||||
|
|
@ -54,6 +54,11 @@ amdgpu::bridge::openShmCommandBuffer(const char *name) {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
if (ftruncate(fd, kShmSize) < 0) {
|
||||
::close(fd);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void *memory =
|
||||
::mmap(nullptr, kShmSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
|
||||
|
|
|
|||
|
|
@ -2,11 +2,17 @@
|
|||
#include <amdgpu/bridge/bridge.hpp>
|
||||
#include <amdgpu/device/device.hpp>
|
||||
#include <chrono>
|
||||
#include <csignal>
|
||||
#include <cstdio>
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <thread>
|
||||
#include <unistd.h>
|
||||
#include <util/VerifyVulkan.hpp>
|
||||
#include <vulkan/vulkan.h>
|
||||
#include <vulkan/vulkan_core.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <GLFW/glfw3.h> // TODO: make in optional
|
||||
|
||||
|
|
@ -262,8 +268,8 @@ int main(int argc, const char *argv[]) {
|
|||
&queueFamilyCount, nullptr);
|
||||
Verify() << (queueFamilyCount > 0);
|
||||
queueFamilyProperties.resize(queueFamilyCount);
|
||||
for (auto &propery : queueFamilyProperties) {
|
||||
propery.sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2;
|
||||
for (auto &property : queueFamilyProperties) {
|
||||
property.sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2;
|
||||
}
|
||||
|
||||
vkGetPhysicalDeviceQueueFamilyProperties2(
|
||||
|
|
@ -424,27 +430,33 @@ int main(int argc, const char *argv[]) {
|
|||
&vkDevice);
|
||||
|
||||
|
||||
std::vector<VkQueue> computeQueues;
|
||||
std::vector<VkQueue> transferQueues;
|
||||
std::vector<VkQueue> graphicsQueues;
|
||||
std::vector<std::pair<VkQueue, unsigned>> computeQueues;
|
||||
std::vector<std::pair<VkQueue, unsigned>> transferQueues;
|
||||
std::vector<std::pair<VkQueue, unsigned>> graphicsQueues;
|
||||
VkQueue presentQueue = VK_NULL_HANDLE;
|
||||
|
||||
for (auto &queueInfo : requestedQueues) {
|
||||
if (queueFamiliesWithComputeSupport.contains(queueInfo.queueFamilyIndex)) {
|
||||
for (uint32_t queueIndex = 0; queueIndex < queueInfo.queueCount; ++queueIndex) {
|
||||
vkGetDeviceQueue(vkDevice, queueInfo.queueFamilyIndex, queueIndex, &computeQueues.emplace_back());
|
||||
auto &[queue, index] = computeQueues.emplace_back();
|
||||
index = queueInfo.queueFamilyIndex;
|
||||
vkGetDeviceQueue(vkDevice, queueInfo.queueFamilyIndex, queueIndex, &queue);
|
||||
}
|
||||
}
|
||||
|
||||
if (queueFamiliesWithGraphicsSupport.contains(queueInfo.queueFamilyIndex)) {
|
||||
for (uint32_t queueIndex = 0; queueIndex < queueInfo.queueCount; ++queueIndex) {
|
||||
vkGetDeviceQueue(vkDevice, queueInfo.queueFamilyIndex, queueIndex, &graphicsQueues.emplace_back());
|
||||
auto &[queue, index] = graphicsQueues.emplace_back();
|
||||
index = queueInfo.queueFamilyIndex;
|
||||
vkGetDeviceQueue(vkDevice, queueInfo.queueFamilyIndex, queueIndex, &queue);
|
||||
}
|
||||
}
|
||||
|
||||
if (queueFamiliesWithTransferSupport.contains(queueInfo.queueFamilyIndex)) {
|
||||
for (uint32_t queueIndex = 0; queueIndex < queueInfo.queueCount; ++queueIndex) {
|
||||
vkGetDeviceQueue(vkDevice, queueInfo.queueFamilyIndex, queueIndex, &transferQueues.emplace_back());
|
||||
auto &[queue, index] = transferQueues.emplace_back();
|
||||
index = queueInfo.queueFamilyIndex;
|
||||
vkGetDeviceQueue(vkDevice, queueInfo.queueFamilyIndex, queueIndex, &queue);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -460,16 +472,56 @@ int main(int argc, const char *argv[]) {
|
|||
|
||||
amdgpu::device::setVkDevice(vkDevice, vkPhyDeviceMemoryProperties);
|
||||
|
||||
std::printf("Initialization was succesful\n");
|
||||
std::printf("Initialization was successful\n");
|
||||
|
||||
// TODO: open emulator shared memory
|
||||
auto bridge = amdgpu::bridge::createShmCommandBuffer(cmdBridgeName);
|
||||
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();
|
||||
|
||||
amdgpu::bridge::BridgePuller bridgePuller { bridge };
|
||||
amdgpu::bridge::Command commandsBuffer[32];
|
||||
|
||||
amdgpu::device::DrawContext dc{
|
||||
// TODO
|
||||
int memoryFd = ::shm_open(shmName, O_RDWR, S_IRUSR | S_IWUSR);
|
||||
|
||||
if (memoryFd < 0) {
|
||||
std::printf("failed to open shared memory\n");
|
||||
}
|
||||
|
||||
struct stat memoryStat;
|
||||
::fstat(memoryFd, &memoryStat);
|
||||
amdgpu::RemoteMemory memory {
|
||||
(char *)::mmap(nullptr, memoryStat.st_size, PROT_NONE, MAP_SHARED, memoryFd, 0)
|
||||
};
|
||||
|
||||
VkCommandPoolCreateInfo commandPoolCreateInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
|
||||
.queueFamilyIndex = graphicsQueues.front().second
|
||||
};
|
||||
|
||||
VkCommandPool commandPool;
|
||||
Verify() << vkCreateCommandPool(vkDevice, &commandPoolCreateInfo, nullptr, &commandPool);
|
||||
|
||||
VkPipelineCacheCreateInfo pipelineCacheCreateInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO,
|
||||
};
|
||||
|
||||
VkPipelineCache pipelineCache;
|
||||
Verify() << vkCreatePipelineCache(vkDevice, &pipelineCacheCreateInfo, nullptr, &pipelineCache);
|
||||
amdgpu::device::DrawContext dc{ // TODO
|
||||
.pipelineCache = pipelineCache,
|
||||
.queue = graphicsQueues.front().first,
|
||||
.commandPool = commandPool,
|
||||
};
|
||||
|
||||
amdgpu::device::AmdgpuDevice device{ dc };
|
||||
|
|
@ -484,11 +536,31 @@ int main(int argc, const char *argv[]) {
|
|||
continue;
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < pulledCount; ++i) {
|
||||
// TODO: handle command
|
||||
for (auto cmd : std::span(commandsBuffer, pulledCount)) {
|
||||
switch (cmd.id) {
|
||||
case amdgpu::bridge::CommandId::SetUpSharedMemory:
|
||||
break;
|
||||
case amdgpu::bridge::CommandId::ProtectMemory:
|
||||
break;
|
||||
case amdgpu::bridge::CommandId::CommandBuffer:
|
||||
break;
|
||||
case amdgpu::bridge::CommandId::Flip:
|
||||
break;
|
||||
case amdgpu::bridge::CommandId::DoFlip:
|
||||
break;
|
||||
case amdgpu::bridge::CommandId::SetBuffer:
|
||||
break;
|
||||
|
||||
default:
|
||||
util::unreachable("Unexpected command id %u\n", (unsigned)cmd.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bridge->pusherPid > 0) {
|
||||
kill(bridge->pusherPid, SIGINT);
|
||||
}
|
||||
|
||||
amdgpu::bridge::destroyShmCommandBuffer(bridge);
|
||||
amdgpu::bridge::unlinkShm(cmdBridgeName);
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ add_executable(rpcsx-os
|
|||
iodev/zero.cpp
|
||||
|
||||
main.cpp
|
||||
bridge.cpp
|
||||
vm.cpp
|
||||
ops.cpp
|
||||
linker.cpp
|
||||
|
|
@ -27,7 +28,7 @@ add_executable(rpcsx-os
|
|||
vfs.cpp
|
||||
)
|
||||
target_include_directories(rpcsx-os PUBLIC .)
|
||||
target_link_libraries(rpcsx-os PUBLIC orbis::kernel libcrypto unwind unwind-x86_64)
|
||||
target_link_libraries(rpcsx-os PUBLIC orbis::kernel amdgpu::bridge libcrypto unwind unwind-x86_64)
|
||||
target_link_options(rpcsx-os PUBLIC "LINKER:-Ttext-segment,0x0000010000000000")
|
||||
target_compile_options(rpcsx-os PRIVATE "-march=native")
|
||||
|
||||
|
|
|
|||
4
rpcsx-os/bridge.cpp
Normal file
4
rpcsx-os/bridge.cpp
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
#include "bridge.hpp"
|
||||
|
||||
amdgpu::bridge::BridgePusher rx::bridge;
|
||||
|
||||
7
rpcsx-os/bridge.hpp
Normal file
7
rpcsx-os/bridge.hpp
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <amdgpu/bridge/bridge.hpp>
|
||||
|
||||
namespace rx {
|
||||
extern amdgpu::bridge::BridgePusher bridge;
|
||||
}
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
#include "bridge.hpp"
|
||||
#include "io-device.hpp"
|
||||
#include <cinttypes>
|
||||
#include <cstddef>
|
||||
|
|
@ -15,54 +16,8 @@ struct VideoOutBuffer {
|
|||
|
||||
struct DceDevice : public IoDevice {};
|
||||
|
||||
// template <typename T>
|
||||
// inline bool
|
||||
// atomic_compare_exchange_weak(volatile T *ptr, T *expected, T desired,
|
||||
// int successMemOrder = __ATOMIC_SEQ_CST,
|
||||
// int failureMemOrder = __ATOMIC_SEQ_CST) {
|
||||
// return __atomic_compare_exchange_n(ptr, expected, desired, true,
|
||||
// __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
|
||||
// }
|
||||
|
||||
struct DceInstance : public IoDeviceInstance {
|
||||
VideoOutBuffer bufferAttributes{};
|
||||
|
||||
// std::uint64_t flipStatusOffset =
|
||||
// mem::allocateInternal(sizeof(liverpool::bridge::FlipStatus),
|
||||
// alignof(liverpool::bridge::FlipStatus));
|
||||
// liverpool::bridge::FlipStatus *flipStatus = new (
|
||||
// mem::mapInternal(flipStatusOffset, sizeof(liverpool::bridge::FlipStatus)))
|
||||
// liverpool::bridge::FlipStatus();
|
||||
|
||||
DceInstance() {
|
||||
// *flipStatus = {};
|
||||
// orbis::bridge.sendSetFlipStatus(flipStatusOffset);
|
||||
}
|
||||
void registerBuffer(int index, std::uint64_t address) {
|
||||
// orbis::bridge.sendSetBuffer(index, address, bufferAttributes.width,
|
||||
// bufferAttributes.height, bufferAttributes.pitch,
|
||||
// bufferAttributes.pixelFormat,
|
||||
// bufferAttributes.tilingMode);
|
||||
}
|
||||
|
||||
void flip(std::uint32_t bufferIndex, std::uint64_t flipMode,
|
||||
std::uint64_t flipArg) {
|
||||
|
||||
// orbis::bridge.sendFlip(bufferIndex, flipArg);
|
||||
// orbis::bridge.wait();
|
||||
}
|
||||
|
||||
// liverpool::bridge::FlipStatus getFlipStatus() {
|
||||
// int expected = 0;
|
||||
// while (!atomic_compare_exchange_weak(&flipStatus->locked, &expected, 1)) {
|
||||
// expected = 0;
|
||||
// }
|
||||
|
||||
// liverpool::bridge::FlipStatus result = *flipStatus;
|
||||
// flipStatus->locked = 0;
|
||||
|
||||
// return result;
|
||||
// }
|
||||
};
|
||||
|
||||
struct RegisterBuffer {
|
||||
|
|
@ -149,14 +104,13 @@ static std::int64_t dce_instance_ioctl(IoDeviceInstance *instance,
|
|||
return 0;
|
||||
}
|
||||
|
||||
// auto currentStatus = dceInstance->getFlipStatus();
|
||||
|
||||
FlipControlStatus flipStatus{};
|
||||
// flipStatus.flipArg = currentStatus.arg;
|
||||
// flipStatus.count = currentStatus.count;
|
||||
// TODO: lock bridge header
|
||||
flipStatus.flipArg = rx::bridge.header->flipArg;
|
||||
flipStatus.count = rx::bridge.header->flipCount;
|
||||
flipStatus.processTime = 0; // TODO
|
||||
flipStatus.tsc = 0; // TODO
|
||||
// flipStatus.currentBuffer = currentStatus.currentBuffer;
|
||||
flipStatus.currentBuffer = rx::bridge.header->flipBuffer;
|
||||
flipStatus.unkQueueNum = 0; // TODO
|
||||
flipStatus.gcQueueNum = 0; // TODO
|
||||
flipStatus.unk2QueueNum = 0; // TODO
|
||||
|
|
@ -196,7 +150,22 @@ static std::int64_t dce_instance_ioctl(IoDeviceInstance *instance,
|
|||
std::fprintf(stderr, "dce: RegisterBuffer(%lx, %lx, %lx, %lx)\n",
|
||||
args->attributeIndex, args->index, args->address, args->unk);
|
||||
|
||||
dceInstance->registerBuffer(args->index, args->address);
|
||||
|
||||
if (args->index >= std::size(rx::bridge.header->buffers)) {
|
||||
// TODO
|
||||
std::fprintf(stderr, "dce: out of buffers!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// TODO: lock bridge header
|
||||
rx::bridge.header->buffers[args->index] = {
|
||||
.bufferIndex = static_cast<uint32_t>(args->index),
|
||||
.width = dceInstance->bufferAttributes.width,
|
||||
.height = dceInstance->bufferAttributes.height,
|
||||
.pitch = dceInstance->bufferAttributes.pitch,
|
||||
.pixelFormat = dceInstance->bufferAttributes.pixelFormat,
|
||||
.tilingMode = dceInstance->bufferAttributes.tilingMode
|
||||
};
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -235,7 +204,7 @@ static std::int64_t dce_instance_ioctl(IoDeviceInstance *instance,
|
|||
args->arg1, args->displayBufferIndex, args->flipMode, args->flipArg,
|
||||
args->arg5, args->arg6, args->arg7, args->arg8);
|
||||
|
||||
dceInstance->flip(args->displayBufferIndex, args->flipMode, args->flipArg);
|
||||
rx::bridge.sendFlip(args->displayBufferIndex, /*args->flipMode,*/ args->flipArg);
|
||||
|
||||
if (args->flipMode == 1 || args->arg7 == 0) {
|
||||
// orbis::bridge.sendDoFlip();
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
#include "bridge.hpp"
|
||||
#include "io-device.hpp"
|
||||
#include <atomic>
|
||||
#include <cinttypes>
|
||||
|
|
@ -58,7 +59,7 @@ static std::int64_t gc_instance_ioctl(IoDeviceInstance *instance,
|
|||
std::fprintf(stderr, " unkPreservedVal = %lx\n", unkPreservedVal);
|
||||
std::fprintf(stderr, " size = %lu\n", size);
|
||||
|
||||
// orbis::bridge.sendCommandBuffer(address, size);
|
||||
rx::bridge.sendCommandBuffer(cmdId, address, size);
|
||||
}
|
||||
|
||||
break;
|
||||
|
|
@ -108,7 +109,7 @@ static std::int64_t gc_instance_ioctl(IoDeviceInstance *instance,
|
|||
std::fprintf(stderr, " unkPreservedVal = %lx\n", unkPreservedVal);
|
||||
std::fprintf(stderr, " size = %lu\n", size);
|
||||
|
||||
// orbis::bridge.sendCommandBuffer(address, size);
|
||||
rx::bridge.sendCommandBuffer(cmdId, address, size);
|
||||
}
|
||||
|
||||
//orbis::bridge.sendDoFlip();
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
#include "align.hpp"
|
||||
#include "amdgpu/bridge/bridge.hpp"
|
||||
#include "bridge.hpp"
|
||||
#include "io-device.hpp"
|
||||
#include "io-devices.hpp"
|
||||
#include "linker.hpp"
|
||||
|
|
@ -6,6 +8,8 @@
|
|||
#include "vfs.hpp"
|
||||
#include "vm.hpp"
|
||||
|
||||
#include <filesystem>
|
||||
#include <linux/limits.h>
|
||||
#include <orbis/KernelContext.hpp>
|
||||
#include <orbis/module.hpp>
|
||||
#include <orbis/module/Module.hpp>
|
||||
|
|
@ -27,6 +31,8 @@
|
|||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
static int g_gpuPid;
|
||||
|
||||
struct LibcInfo {
|
||||
std::uint64_t textBegin = ~static_cast<std::uint64_t>(0);
|
||||
std::uint64_t textSize = 0;
|
||||
|
|
@ -159,7 +165,9 @@ static void printStackTrace(ucontext_t *context, orbis::Thread *thread,
|
|||
__attribute__((no_stack_protector)) static void
|
||||
handle_signal(int sig, siginfo_t *info, void *ucontext) {
|
||||
std::uint64_t hostFs = _readgsbase_u64();
|
||||
_writefsbase_u64(hostFs);
|
||||
if (hostFs != 0) {
|
||||
_writefsbase_u64(hostFs);
|
||||
}
|
||||
|
||||
// syscall(SYS_arch_prctl, ARCH_GET_GS, &hostFs);
|
||||
// syscall(SYS_arch_prctl, ARCH_SET_FS, hostFs);
|
||||
|
|
@ -173,20 +181,32 @@ handle_signal(int sig, siginfo_t *info, void *ucontext) {
|
|||
return;
|
||||
}
|
||||
|
||||
const char message[] = "Signal handler!\n";
|
||||
write(2, message, sizeof(message) - 1);
|
||||
if (g_gpuPid > 0) {
|
||||
// stop gpu thread
|
||||
::kill(g_gpuPid, SIGINT);
|
||||
}
|
||||
|
||||
char buf[128] = "";
|
||||
int len = snprintf(buf, sizeof(buf), " [%s] %u: Signal address=%p\n",
|
||||
g_currentThread ? "guest" : "host",
|
||||
g_currentThread ? g_currentThread->tid : ::gettid(),
|
||||
info->si_addr);
|
||||
write(2, buf, len);
|
||||
if (sig != SIGINT) {
|
||||
char buf[128] = "";
|
||||
int len = snprintf(buf, sizeof(buf), " [%s] %u: Signal address=%p\n",
|
||||
g_currentThread ? "guest" : "host",
|
||||
g_currentThread ? g_currentThread->tid : ::gettid(),
|
||||
info->si_addr);
|
||||
write(2, buf, len);
|
||||
|
||||
if (std::size_t printed = printAddressLocation(
|
||||
buf, sizeof(buf), g_currentThread, (std::uint64_t)info->si_addr)) {
|
||||
printed += std::snprintf(buf + printed, sizeof(buf) - printed, "\n");
|
||||
write(2, buf, printed);
|
||||
if (std::size_t printed = printAddressLocation(
|
||||
buf, sizeof(buf), g_currentThread, (std::uint64_t)info->si_addr)) {
|
||||
printed += std::snprintf(buf + printed, sizeof(buf) - printed, "\n");
|
||||
write(2, buf, printed);
|
||||
}
|
||||
|
||||
|
||||
if (g_currentThread) {
|
||||
printStackTrace(reinterpret_cast<ucontext_t *>(ucontext), g_currentThread,
|
||||
2);
|
||||
} else {
|
||||
printStackTrace(reinterpret_cast<ucontext_t *>(ucontext), 2);
|
||||
}
|
||||
}
|
||||
|
||||
struct sigaction act {};
|
||||
|
|
@ -202,11 +222,8 @@ handle_signal(int sig, siginfo_t *info, void *ucontext) {
|
|||
std::exit(-1);
|
||||
}
|
||||
|
||||
if (g_currentThread) {
|
||||
printStackTrace(reinterpret_cast<ucontext_t *>(ucontext), g_currentThread,
|
||||
2);
|
||||
} else {
|
||||
printStackTrace(reinterpret_cast<ucontext_t *>(ucontext), 2);
|
||||
if (sig == SIGINT) {
|
||||
std::raise(SIGINT);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -260,6 +277,11 @@ static void setupSigHandlers() {
|
|||
perror("Error sigaction:");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (sigaction(SIGINT, &act, NULL)) {
|
||||
perror("Error sigaction:");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
__attribute__((no_stack_protector)) static void *
|
||||
|
|
@ -515,6 +537,72 @@ static void usage(const char *argv0) {
|
|||
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 isRpsxGpuPid(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() == "rpcsx-gpu";
|
||||
}
|
||||
static void runRpsxGpu() {
|
||||
const char *cmdBufferName = "/rpcsx-gpu-cmds";
|
||||
amdgpu::bridge::BridgeHeader *bridgeHeader = amdgpu::bridge::openShmCommandBuffer(cmdBufferName);
|
||||
|
||||
if (bridgeHeader != nullptr && bridgeHeader->pullerPid > 0 && isRpsxGpuPid(bridgeHeader->pullerPid)) {
|
||||
bridgeHeader->pusherPid = ::getpid();
|
||||
g_gpuPid = bridgeHeader->pullerPid;
|
||||
rx::bridge = bridgeHeader;
|
||||
return;
|
||||
}
|
||||
|
||||
std::printf("Starting rpcsx-gpu\n");
|
||||
|
||||
if (bridgeHeader == nullptr) {
|
||||
bridgeHeader = amdgpu::bridge::createShmCommandBuffer(cmdBufferName);
|
||||
}
|
||||
bridgeHeader->pusherPid = ::getpid();
|
||||
rx::bridge = 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<char **>(argv));
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, const char *argv[]) {
|
||||
if (argc == 2) {
|
||||
if (std::strcmp(argv[1], "-h") == 0 ||
|
||||
|
|
@ -606,6 +694,8 @@ int main(int argc, const char *argv[]) {
|
|||
}
|
||||
|
||||
rx::vm::initialize();
|
||||
runRpsxGpu();
|
||||
|
||||
// rx::vm::printHostStats();
|
||||
auto initProcess = context.createProcess(10);
|
||||
initProcess->sysent = &orbis::ps4_sysvec;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#include "vm.hpp"
|
||||
#include "align.hpp"
|
||||
#include "bridge.hpp"
|
||||
#include <bit>
|
||||
#include <cassert>
|
||||
#include <cinttypes>
|
||||
|
|
@ -596,15 +597,15 @@ static void reserve(std::uint64_t startAddress, std::uint64_t endAddress) {
|
|||
void rx::vm::initialize() {
|
||||
std::printf("Memory: initialization\n");
|
||||
|
||||
gMemoryShm = ::shm_open("/orbis-memory", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
|
||||
gMemoryShm = ::shm_open("/rpcsx-os-memory", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
|
||||
|
||||
if (gMemoryShm == -1) {
|
||||
std::printf("Memory: failed to open /orbis-memory\n");
|
||||
std::printf("Memory: failed to open /rpcsx-os-memory\n");
|
||||
std::abort();
|
||||
}
|
||||
|
||||
if (::ftruncate64(gMemoryShm, kMemorySize) < 0) {
|
||||
std::printf("Memory: failed to allocate /orbis-memory\n");
|
||||
std::printf("Memory: failed to allocate /rpcsx-os-memory\n");
|
||||
std::abort();
|
||||
}
|
||||
|
||||
|
|
@ -798,7 +799,6 @@ void *rx::vm::map(void *addr, std::uint64_t len, std::int32_t prot,
|
|||
allocInfo.flags = kBlockFlagDirectMemory; // TODO
|
||||
allocInfo.name[0] = '\0'; // TODO
|
||||
|
||||
// orbis::bridge.sendMemoryProtect(address, len, prot);
|
||||
auto result =
|
||||
utils::map(reinterpret_cast<void *>(address), len, prot & kMapProtCpuAll,
|
||||
realFlags, gMemoryShm, address - kMinAddress);
|
||||
|
|
@ -814,6 +814,7 @@ void *rx::vm::map(void *addr, std::uint64_t len, std::int32_t prot,
|
|||
}
|
||||
}
|
||||
|
||||
rx::bridge.sendMemoryProtect(address, len, prot);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -841,7 +842,7 @@ bool rx::vm::unmap(void *addr, std::uint64_t size) {
|
|||
|
||||
gBlocks[(address >> kBlockShift) - kFirstBlock].removeFlags(
|
||||
(address & kBlockMask) >> kPageShift, pages, ~0);
|
||||
// orbis::bridge.sendMemoryProtect(address, size, 0);
|
||||
rx::bridge.sendMemoryProtect(reinterpret_cast<std::uint64_t>(addr), size, 0);
|
||||
return utils::unmap(addr, size);
|
||||
}
|
||||
|
||||
|
|
@ -871,8 +872,7 @@ bool rx::vm::protect(void *addr, std::uint64_t size, std::int32_t prot) {
|
|||
(address & kBlockMask) >> kPageShift, pages,
|
||||
kAllocated | (prot & (kMapProtCpuAll | kMapProtGpuAll)));
|
||||
|
||||
// orbis::bridge.sendMemoryProtect(reinterpret_cast<std::uint64_t>(addr),
|
||||
// size, prot);
|
||||
rx::bridge.sendMemoryProtect(reinterpret_cast<std::uint64_t>(addr), size, prot);
|
||||
return ::mprotect(addr, size, prot & kMapProtCpuAll) == 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue