Compare commits

...

4 commits

Author SHA1 Message Date
kalaposfos13 00c55e9688
Add option to build without (read/write)(fs/gs)base instructions (#111)
Some checks failed
Formatting check / formatting-check (push) Has been cancelled
Build RPCSX / build-linux (push) Has been cancelled
Build RPCSX / build-android (arm64-v8a, armv8-a) (push) Has been cancelled
Build RPCSX / build-android (arm64-v8a, armv8.1-a) (push) Has been cancelled
Build RPCSX / build-android (arm64-v8a, armv8.2-a) (push) Has been cancelled
Build RPCSX / build-android (arm64-v8a, armv8.4-a) (push) Has been cancelled
Build RPCSX / build-android (arm64-v8a, armv8.5-a) (push) Has been cancelled
Build RPCSX / build-android (arm64-v8a, armv9-a) (push) Has been cancelled
Build RPCSX / build-android (arm64-v8a, armv9.1-a) (push) Has been cancelled
Build RPCSX / build-android (x86_64, x86-64) (push) Has been cancelled
2025-10-12 18:47:29 +03:00
DH e514fa02ff ci: do not build rpcsx 3 times 2025-10-12 18:46:32 +03:00
DH c648a13d42 orbis: Fix debug build 2025-10-12 18:01:14 +03:00
DH 0fb7aeb9b4 rx/MemoryTable: simplify map/unmap api 2025-10-12 00:04:30 +03:00
13 changed files with 93 additions and 66 deletions

View file

@ -26,9 +26,6 @@ jobs:
libsox-dev g++-14 ninja-build libasound2-dev nasm libudev-dev \
libxcb1-dev libx11-dev libwayland-dev libxkbcommon-dev libxrandr-dev \
libxinerama-dev libxcursor-dev libxi-dev libxext-dev
cmake -B build -G "Ninja" -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER=g++-14 -DCMAKE_INSTALL_PREFIX=/usr
cmake --build build -j$(($(nproc) + 2))
sudo cmake --build build
- name: Build RPCSX
run: |

View file

@ -141,6 +141,11 @@ option(WITHOUT_OPENGL "Disable OpenGL" OFF)
option(WITHOUT_OPENGLEW "Disable OpenGLEW" OFF)
option(WITHOUT_OPENAL "Disable OpenAL" OFF)
option(COMPILE_FFMPEG "Compile FFmpeg" ON)
option(USE_FS_GS_SYSCALL "Use the arch_prctl syscall to interact with fsbase and gsbase instead of x86 instructions. Used for compatibility with some systems, but comes at a performance cost." OFF)
if(USE_FS_GS_SYSCALL)
add_definitions(-DUSE_FS_GS_SYSCALL)
endif()
# rpcs3 options
option(USE_NATIVE_INSTRUCTIONS "USE_NATIVE_INSTRUCTIONS makes rpcs3 compile with -march=native, which is useful for local builds, but not good for packages." ON)

View file

@ -101,7 +101,7 @@ template <int Group> struct IoDeviceWithIoctl : IoDevice {
void addIoctl(ErrorCode (*handler)(Thread *thread, InstanceT *device,
T &arg)) {
constexpr auto id = ioctl::id(Cmd);
assert(ioctlTable[id].handler == unhandledIoctl);
assert(ioctlTable[id].handler == nullptr);
IoctlHandlerEntry &entry = ioctlTable[id];
@ -132,7 +132,7 @@ template <int Group> struct IoDeviceWithIoctl : IoDevice {
void addIoctl(ErrorCode (*handler)(Thread *thread, InstanceT *device)) {
constexpr auto id = ioctl::id(Cmd);
assert(ioctlTable[id].handler == unhandledIoctl);
assert(ioctlTable[id].handler == nullptr);
IoctlHandlerEntry &entry = ioctlTable[id];
@ -156,7 +156,7 @@ template <int Group> struct IoDeviceWithIoctl : IoDevice {
void addIoctl(std::pair<ErrorCode, T> (*handler)(Thread *thread,
InstanceT *device)) {
constexpr auto id = ioctl::id(Cmd);
assert(ioctlTable[id].handler == unhandledIoctl);
assert(ioctlTable[id].handler == nullptr);
IoctlHandlerEntry &entry = ioctlTable[id];

View file

@ -59,7 +59,9 @@ T *knew(Args &&...args) {
struct DynamicObject final : T {
using T::T;
void operator delete(void *pointer) { kfree(pointer, sizeof(T)); }
void operator delete(void *pointer) {
kfree(pointer, sizeof(DynamicObject));
}
};
auto loc = static_cast<DynamicObject *>(

View file

@ -167,8 +167,8 @@ void Cache::ShaderResources::loadResources(
rx::die("failed to evaluate pointer");
}
bufferMemoryTable.map(*pointerBase + *pointerOffset,
*pointerBase + *pointerOffset + pointer.size,
bufferMemoryTable.map(rx::AddressRange::fromBeginSize(
*pointerBase + *pointerOffset, pointer.size),
Access::Read);
resourceSlotToAddress.emplace_back(slotOffset + pointer.resourceSlot,
*pointerBase + *pointerOffset);
@ -200,8 +200,9 @@ void Cache::ShaderResources::loadResources(
it.beginAddress() == buffer.address() && it.size() == buffer.size()) {
it.get() |= bufferRes.access;
} else {
bufferMemoryTable.map(buffer.address(), buffer.address() + buffer.size(),
bufferRes.access);
bufferMemoryTable.map(
rx::AddressRange::fromBeginSize(buffer.address(), buffer.size()),
bufferRes.access);
}
resourceSlotToAddress.emplace_back(slotOffset + bufferRes.resourceSlot,
buffer.address());
@ -262,7 +263,8 @@ void Cache::ShaderResources::loadResources(
it.get().second |= imageBuffer.access;
} else {
imageMemoryTable.map(
tbuffer.address(), tbuffer.address() + info.totalTiledSize,
rx::AddressRange::fromBeginSize(tbuffer.address(),
info.totalTiledSize),
{ImageBufferKey::createFrom(tbuffer), imageBuffer.access});
}
resourceSlotToAddress.emplace_back(slotOffset + imageBuffer.resourceSlot,
@ -1489,8 +1491,7 @@ Cache::Buffer Cache::Tag::getBuffer(rx::AddressRange range, Access access) {
mParent->flushBuffers(range);
it = table.map(range.beginAddress(), range.endAddress(), nullptr, false,
true);
it = table.map(range, nullptr, false, true);
}
if (it.get() == nullptr) {
@ -1837,8 +1838,7 @@ Cache::ImageBuffer Cache::Tag::getImageBuffer(const ImageBufferKey &key,
flushed.clear();
}
auto it =
table.map(range.beginAddress(), range.endAddress(), nullptr, false, true);
auto it = table.map(range, nullptr, false, true);
if (it.get() == nullptr) {
auto cached = std::make_shared<CachedImageBuffer>();
@ -1945,8 +1945,7 @@ Cache::Image Cache::Tag::getImage(const ImageKey &key, Access access) {
flushed.clear();
}
auto it = table.map(storeRange.beginAddress(), storeRange.endAddress(),
nullptr, false, true);
auto it = table.map(storeRange, nullptr, false, true);
if (it.get() == nullptr) {
VkImageUsageFlags usage =
@ -2787,15 +2786,13 @@ void Cache::flush(Tag &tag, rx::AddressRange range) {
void Cache::trackUpdate(EntryType type, rx::AddressRange range,
std::shared_ptr<Entry> entry, TagId tagId,
bool watchChanges) {
if (auto it = mSyncTable.map(range.beginAddress(), range.endAddress(), {},
false, true);
it.get() < tagId) {
if (auto it = mSyncTable.map(range, {}, false, true); it.get() < tagId) {
it.get() = tagId;
}
entry->tagId = tagId;
auto &table = getTable(type);
table.map(range.beginAddress(), range.endAddress(), std::move(entry));
table.map(range, std::move(entry));
if (watchChanges) {
mDevice->watchWrites(mVmId, range.beginAddress(), range.size());
@ -2803,9 +2800,7 @@ void Cache::trackUpdate(EntryType type, rx::AddressRange range,
}
void Cache::trackWrite(rx::AddressRange range, TagId tagId, bool lockMemory) {
if (auto it = mSyncTable.map(range.beginAddress(), range.endAddress(), {},
false, true);
it.get() < tagId) {
if (auto it = mSyncTable.map(range, {}, false, true); it.get() < tagId) {
it.get() = tagId;
}

View file

@ -641,7 +641,7 @@ void Device::protectMemory(std::uint32_t pid, std::uint64_t address,
auto vmSlot = vmSlotIt.get();
process.vmTable.map(address, address + size,
process.vmTable.map(rx::AddressRange::fromBeginSize(address, size),
VmMapSlot{
.memoryType = vmSlot.memoryType,
.prot = static_cast<int>(prot),
@ -1004,7 +1004,7 @@ void Device::mapMemory(std::uint32_t pid, std::uint64_t address,
int prot, std::int64_t offset) {
auto &process = processInfo[pid];
process.vmTable.map(address, address + size,
process.vmTable.map(rx::AddressRange::fromBeginSize(address, size),
VmMapSlot{
.memoryType = memoryType >= 0 ? dmemIndex : -1,
.prot = prot,

View file

@ -1832,7 +1832,8 @@ gcn::deserialize(gcn::Context &context, const gcn::Environment &environment,
std::function<std::uint32_t(std::uint64_t)> readMemory) {
readMemory = [&context,
readMemory = std::move(readMemory)](std::uint64_t address) {
context.memoryMap.map(address, address + sizeof(std::uint32_t));
context.memoryMap.map(
rx::AddressRange::fromBeginSize(address, sizeof(std::uint32_t)));
return readMemory(address);
};

View file

@ -322,7 +322,7 @@ public:
auto properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
mMemory = DeviceMemory::CreateExternalHostMemory(data, size, properties);
table.map(0, size);
table.map(rx::AddressRange::fromBeginSize(0, size));
// debugName = "direct";
}
@ -337,7 +337,7 @@ public:
vkMapMemory(context->device, memory.getHandle(), 0, size, 0, &data));
mMemory = std::move(memory);
table.map(0, size);
table.map(rx::AddressRange::fromBeginSize(0, size));
mData = reinterpret_cast<char *>(data);
// debugName = "host";
}
@ -347,7 +347,7 @@ public:
auto properties = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
mMemory = DeviceMemory::Allocate(size, ~0, properties);
table.map(0, size);
table.map(rx::AddressRange::fromBeginSize(0, size));
// debugName = "local";
}
@ -397,7 +397,7 @@ public:
void deallocate(DeviceMemoryRef memory) {
std::lock_guard lock(mMtx);
table.map(memory.offset, memory.offset + memory.size);
table.map(rx::AddressRange::fromBeginSize(memory.offset, memory.size));
}
void dump() {

View file

@ -37,7 +37,7 @@ static orbis::ErrorCode blockpool_ioctl(orbis::File *file,
ORBIS_RET_ON_ERROR(
dmem->allocate(&start, args->searchEnd, args->len, 1, args->flags));
blockPool->pool.map(start, start + args->len);
blockPool->pool.map(rx::AddressRange::fromBeginSize(start, args->len));
return {};
}
}

View file

@ -144,8 +144,9 @@ static orbis::ErrorCode dmem_ioctl(orbis::File *file, std::uint64_t request,
ORBIS_LOG_WARNING("dmem releaseDirectMemory", device->index, args->address,
args->size);
device->allocations.map(args->address, args->address + args->size,
{.memoryType = -1u});
device->allocations.map(
rx::AddressRange::fromBeginSize(args->address, args->size),
{.memoryType = -1u});
return {};
}
@ -303,7 +304,7 @@ orbis::ErrorCode DmemDevice::allocate(std::uint64_t *start,
}
}
allocations.map(offset, offset + len,
allocations.map(rx::AddressRange::fromBeginSize(offset, len),
{
.memoryType = memoryType,
});
@ -319,7 +320,7 @@ orbis::ErrorCode DmemDevice::allocate(std::uint64_t *start,
}
orbis::ErrorCode DmemDevice::release(std::uint64_t start, std::uint64_t size) {
allocations.unmap(start, start + size);
allocations.unmap(rx::AddressRange::fromBeginSize(start, size));
return {};
}

View file

@ -39,9 +39,16 @@ static auto setContext = [] {
static __attribute__((no_stack_protector)) void
handleSigSys(int sig, siginfo_t *info, void *ucontext) {
#ifndef USE_FS_GS_SYSCALL
if (auto hostFs = _readgsbase_u64()) {
_writefsbase_u64(hostFs);
}
#else
uint64_t hostFs = 0;
if (syscall(SYS_arch_prctl, ARCH_GET_GS, &hostFs) == 0 && hostFs) {
syscall(SYS_arch_prctl, ARCH_SET_FS, hostFs);
}
#endif
// rx::printStackTrace(reinterpret_cast<ucontext_t *>(ucontext),
// rx::thread::g_current, 1);
@ -58,7 +65,11 @@ handleSigSys(int sig, siginfo_t *info, void *ucontext) {
thread = orbis::g_currentThread;
thread->context = prevContext;
#ifndef USE_FS_GS_SYSCALL
_writefsbase_u64(thread->fsBase);
#else
syscall(SYS_arch_prctl, ARCH_SET_FS, thread->fsBase);
#endif
}
__attribute__((no_stack_protector)) static void
@ -149,7 +160,11 @@ handleSigUser(int sig, siginfo_t *info, void *ucontext) {
}
if (inGuestCode) {
#ifndef USE_FS_GS_SYSCALL
_writefsbase_u64(thread->fsBase);
#else
syscall(SYS_arch_prctl, ARCH_SET_FS, thread->fsBase);
#endif
}
}
@ -389,6 +404,7 @@ void rx::thread::setupThisThread() {
void rx::thread::invoke(orbis::Thread *thread) {
orbis::g_currentThread = thread;
#ifndef USE_FS_GS_SYSCALL
std::uint64_t hostFs = _readfsbase_u64();
_writegsbase_u64(hostFs);
@ -397,4 +413,15 @@ void rx::thread::invoke(orbis::Thread *thread) {
::setContext(context->uc_mcontext);
_writefsbase_u64(hostFs);
#else
std::uint64_t hostFs;
syscall(SYS_arch_prctl, ARCH_GET_FS, &hostFs);
syscall(SYS_arch_prctl, ARCH_SET_GS, hostFs);
syscall(SYS_arch_prctl, ARCH_SET_FS, thread->fsBase);
auto context = reinterpret_cast<ucontext_t *>(thread->context);
::setContext(context->uc_mcontext);
syscall(SYS_arch_prctl, ARCH_SET_FS, hostFs);
#endif
}

View file

@ -776,8 +776,8 @@ constexpr auto kMainDirectMemorySize =
kPhysicalMemorySize - kFlexibleMemorySize;
void *vm::map(void *addr, std::uint64_t len, std::int32_t prot,
std::int32_t flags, std::int32_t internalFlags, orbis::IoDevice *device,
std::uint64_t offset) {
std::int32_t flags, std::int32_t internalFlags,
orbis::IoDevice *device, std::uint64_t offset) {
std::println(stderr, "vm::map(addr = {}, len = {}, prot = {}, flags = {})",
addr, len, mapProtToString(prot), mapFlagsToString(flags));
@ -966,7 +966,7 @@ void *vm::map(void *addr, std::uint64_t len, std::int32_t prot,
info.flags = flags;
info.offset = offset;
gMapInfo.map(address, address + len, info);
gMapInfo.map(rx::AddressRange::fromBeginSize(address, len), info);
}
if (auto thr = orbis::g_currentThread) {
@ -1034,7 +1034,7 @@ bool vm::unmap(void *addr, std::uint64_t size) {
std::println(stderr, "ignoring unmapping {:x}-{:x}", address,
address + size);
}
gMapInfo.unmap(address, address + size);
gMapInfo.unmap(rx::AddressRange::fromBeginSize(address, size));
return rx::mem::unmap(addr, size);
}
@ -1218,5 +1218,5 @@ void vm::setName(std::uint64_t start, std::uint64_t size, const char *name) {
std::strncpy(info.name, name, sizeof(info.name));
gMapInfo.map(start, size, info);
gMapInfo.map(rx::AddressRange::fromBeginSize(start, size), info);
}

View file

@ -66,7 +66,7 @@ public:
void clear() { mAreas.clear(); }
AreaInfo queryArea(std::uint64_t address) const {
[[nodiscard]] AreaInfo queryArea(std::uint64_t address) const {
auto it = mAreas.lower_bound(address);
assert(it != mAreas.end());
std::uint64_t endAddress = 0;
@ -84,9 +84,10 @@ public:
return {startAddress, endAddress};
}
void map(std::uint64_t beginAddress, std::uint64_t endAddress) {
auto [beginIt, beginInserted] = mAreas.emplace(beginAddress, Kind::O);
auto [endIt, endInserted] = mAreas.emplace(endAddress, Kind::X);
void map(rx::AddressRange range) {
auto [beginIt, beginInserted] =
mAreas.emplace(range.beginAddress(), Kind::O);
auto [endIt, endInserted] = mAreas.emplace(range.endAddress(), Kind::X);
if (!beginInserted) {
if (beginIt->second == Kind::X) {
@ -313,9 +314,8 @@ public:
};
template <typename T> class Payload<T *> {
static constexpr std::uintptr_t
kCloseOpenBit = alignof(T) > 1 ? 1
: (1ull << (sizeof(std::uintptr_t) * 8 - 1));
static constexpr std::uintptr_t kCloseOpenBit =
alignof(T) > 1 ? 1 : (1ull << (sizeof(std::uintptr_t) * 8 - 1));
static constexpr std::uintptr_t kClose = 0;
std::uintptr_t value = kClose;
@ -368,9 +368,8 @@ public:
};
template <typename T> class Payload<Ref<T>> {
static constexpr std::uintptr_t
kCloseOpenBit = alignof(T) > 1 ? 1
: (1ull << (sizeof(std::uintptr_t) * 8 - 1));
static constexpr std::uintptr_t kCloseOpenBit =
alignof(T) > 1 ? 1 : (1ull << (sizeof(std::uintptr_t) * 8 - 1));
static constexpr std::uintptr_t kClose = 0;
std::uintptr_t value = kClose;
@ -465,14 +464,14 @@ class MemoryTableWithPayload {
public:
class AreaInfo : public rx::AddressRange {
PayloadT &payload;
Payload<PayloadT> &payload;
public:
AreaInfo(PayloadT &payload, rx::AddressRange range)
AreaInfo(Payload<PayloadT> &payload, rx::AddressRange range)
: payload(payload), AddressRange(range) {}
PayloadT *operator->() { return &payload; }
PayloadT &get() { return payload; }
decltype(auto) operator->() { return &payload.get(); }
decltype(auto) get() { return payload.get(); }
};
class iterator {
@ -484,7 +483,7 @@ public:
iterator() = default;
iterator(map_iterator it) : it(it) {}
AreaInfo operator*() const { return {it->second.get(), range()}; }
AreaInfo operator*() const { return {it->second, range()}; }
rx::AddressRange range() const {
return rx::AddressRange::fromBeginEnd(beginAddress(), endAddress());
@ -494,8 +493,8 @@ public:
std::uint64_t endAddress() const { return std::next(it)->first; }
std::uint64_t size() const { return endAddress() - beginAddress(); }
PayloadT &get() const { return it->second.get(); }
PayloadT *operator->() const { return &it->second.get(); }
decltype(auto) get() const { return it->second.get(); }
decltype(auto) operator->() const { return &it->second.get(); }
iterator &operator++() {
++it;
@ -570,13 +569,13 @@ public:
return endAddress < address ? mAreas.end() : it;
}
iterator map(std::uint64_t beginAddress, std::uint64_t endAddress,
PayloadT payload, bool merge = true, bool noOverride = false) {
assert(beginAddress < endAddress);
iterator map(rx::AddressRange range, PayloadT payload, bool merge = true,
bool noOverride = false) {
assert(range.beginAddress() < range.endAddress());
auto [beginIt, beginInserted] =
mAreas.emplace(beginAddress, payload_type::createOpen(payload));
mAreas.emplace(range.beginAddress(), payload_type::createOpen(payload));
auto [endIt, endInserted] =
mAreas.emplace(endAddress, payload_type::createClose());
mAreas.emplace(range.endAddress(), payload_type::createClose());
bool seenOpen = false;
bool endCollision = false;
@ -685,9 +684,9 @@ public:
}
}
void unmap(std::uint64_t beginAddress, std::uint64_t endAddress) {
void unmap(rx::AddressRange range) {
// FIXME: can be optimized
unmap(map(beginAddress, endAddress, PayloadT{}, false));
unmap(map(range, PayloadT{}, false));
}
};
} // namespace rx