mirror of
https://github.com/RPCSX/rpcsx.git
synced 2026-01-24 01:20:44 +01:00
orbis: fix fork, fixed base elf support & dmem::release
This commit is contained in:
parent
e661de9ad7
commit
d8b7826c9c
|
|
@ -167,7 +167,8 @@ inline bool validateProtection(rx::EnumBitSet<Protection> &prot) {
|
|||
inline bool validateMemoryType(MemoryType type,
|
||||
rx::EnumBitSet<Protection> prot) {
|
||||
if (type == MemoryType::WbGarlic) {
|
||||
if (prot & (Protection::CpuWrite | Protection::GpuWrite)) {
|
||||
if ((prot & (Protection::CpuWrite | Protection::GpuWrite)) ==
|
||||
(Protection::CpuWrite | Protection::GpuWrite)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ struct DirectMemoryAllocation {
|
|||
[[nodiscard]] bool isAllocated() const { return (type & kAllocatedBit) != 0; }
|
||||
[[nodiscard]] bool isRelated(const DirectMemoryAllocation &other,
|
||||
rx::AddressRange, rx::AddressRange) const {
|
||||
return type == other.type;
|
||||
return false;
|
||||
}
|
||||
|
||||
[[nodiscard]] DirectMemoryAllocation
|
||||
|
|
@ -249,11 +249,20 @@ static void dmemDump(unsigned dmemIndex, std::string_view message = {}) {
|
|||
|
||||
rx::ScopedFileLock lock(stderr);
|
||||
|
||||
rx::println(stderr, "dmem0 {}", message);
|
||||
rx::println(stderr, "dmem{} {}", dmemIndex, message);
|
||||
for (auto alloc : *dmem) {
|
||||
rx::println(stderr, " {:012x}-{:012x}: {}{} {}", alloc.beginAddress(),
|
||||
alloc.endAddress(), "_A"[alloc->isAllocated()],
|
||||
"_P"[alloc->isPooled()], alloc->getMemoryType());
|
||||
for (auto &map : alloc->mappings) {
|
||||
auto dmemRange =
|
||||
rx::AddressRange::fromBeginSize(map.dmemOffset, map.vmRange.size());
|
||||
|
||||
rx::println(stderr, " {:#x}-{:#x} -> {:#x}-{:#x} pid {}",
|
||||
dmemRange.beginAddress(), dmemRange.endAddress(),
|
||||
map.vmRange.beginAddress(), map.vmRange.endAddress(),
|
||||
map.process->pid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -278,7 +287,8 @@ orbis::dmem::allocate(unsigned dmemIndex, rx::AddressRange searchRange,
|
|||
alignment = alignment == 0 ? kPageSize : alignment;
|
||||
len = rx::alignUp(len, dmem::kPageSize);
|
||||
|
||||
if (searchRange.endAddress() == 0) {
|
||||
if (searchRange.endAddress() == 0 ||
|
||||
searchRange.endAddress() > dmem->dmemTotalSize - dmem->dmemReservedSize) {
|
||||
searchRange = rx::AddressRange::fromBeginEnd(searchRange.beginAddress(),
|
||||
dmem->dmemTotalSize -
|
||||
dmem->dmemReservedSize);
|
||||
|
|
@ -732,6 +742,10 @@ orbis::ErrorCode orbis::dmem::map(orbis::Process *process, unsigned dmemIndex,
|
|||
}
|
||||
|
||||
if (offset + range.size() > dmem->dmemTotalSize - dmem->dmemReservedSize) {
|
||||
dmemDump(dmemIndex,
|
||||
rx::format("map out of memory {:x}-{:x}, dmem size {:x}",
|
||||
range.beginAddress(), range.endAddress(),
|
||||
dmem->dmemTotalSize - dmem->dmemReservedSize));
|
||||
return orbis::ErrorCode::ACCES;
|
||||
}
|
||||
|
||||
|
|
@ -746,10 +760,17 @@ orbis::ErrorCode orbis::dmem::map(orbis::Process *process, unsigned dmemIndex,
|
|||
auto endIt = beginIt;
|
||||
while (endIt != dmem->end() && endIt.beginAddress() < offset + range.size()) {
|
||||
if (!endIt->isAllocated() || endIt->isPooled()) {
|
||||
dmemDump(dmemIndex,
|
||||
rx::format("attempt to map unallocated or pulled memory "
|
||||
"{:x}-{:x}, dmem size {:x}",
|
||||
range.beginAddress(), range.endAddress(),
|
||||
dmem->dmemTotalSize - dmem->dmemReservedSize));
|
||||
return orbis::ErrorCode::ACCES;
|
||||
}
|
||||
|
||||
if (!vmem::validateMemoryType(endIt->getMemoryType(), protection)) {
|
||||
dmemDump(dmemIndex, rx::format("invalid protection {} for memory type {}",
|
||||
protection, endIt->getMemoryType()));
|
||||
return ErrorCode::ACCES;
|
||||
}
|
||||
|
||||
|
|
@ -761,20 +782,33 @@ orbis::ErrorCode orbis::dmem::map(orbis::Process *process, unsigned dmemIndex,
|
|||
}
|
||||
|
||||
if (auto last = endIt; (--last).endAddress() < offset + range.size()) {
|
||||
dmemDump(dmemIndex,
|
||||
rx::format("map out of memory {:x}-{:x}, dmem size {:x}",
|
||||
range.beginAddress(), range.endAddress(),
|
||||
dmem->dmemTotalSize - dmem->dmemReservedSize));
|
||||
return orbis::ErrorCode::ACCES;
|
||||
}
|
||||
|
||||
auto dmemRange = rx::AddressRange::fromBeginSize(offset, range.size());
|
||||
|
||||
for (auto it = beginIt; it != endIt; ++it) {
|
||||
auto itRange = it.range();
|
||||
auto mappingRange = range.intersection(itRange);
|
||||
auto mappingDmemRange = dmemRange.intersection(itRange);
|
||||
auto mappingVmemRange = rx::AddressRange::fromBeginSize(
|
||||
range.beginAddress() + (mappingDmemRange.beginAddress() - offset),
|
||||
mappingDmemRange.size());
|
||||
|
||||
it->mappings.push_back({
|
||||
.process = process,
|
||||
.vmRange = mappingRange,
|
||||
.dmemOffset =
|
||||
offset + (mappingRange.beginAddress() - itRange.beginAddress()),
|
||||
.vmRange = mappingVmemRange,
|
||||
.dmemOffset = mappingDmemRange.beginAddress(),
|
||||
});
|
||||
}
|
||||
|
||||
dmemDump(dmemIndex,
|
||||
rx::format("map {:#x}-{:#x} -> {:#x}-{:#x} pid {}",
|
||||
dmemRange.beginAddress(), dmemRange.endAddress(),
|
||||
range.beginAddress(), range.endAddress(), process->pid));
|
||||
auto physicalRange =
|
||||
rx::AddressRange::fromBeginSize(dmem->pmemOffset + offset, range.size());
|
||||
|
||||
|
|
@ -805,6 +839,9 @@ orbis::ErrorCode orbis::dmem::notifyUnmap(orbis::Process *process,
|
|||
++it;
|
||||
}
|
||||
|
||||
dmemDump(dmemIndex, rx::format("unmap {:#x}-{:#x}", range.beginAddress(),
|
||||
range.endAddress()));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -118,6 +118,13 @@ struct VirtualMemoryAllocation {
|
|||
orbis::vmem::BlockFlags::FlexibleMemory;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool isCommited() const {
|
||||
return (flags & orbis::vmem::BlockFlags::Commited) ==
|
||||
orbis::vmem::BlockFlags::Commited;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool isFlexCommited() const { return isFlex() && isCommited(); }
|
||||
|
||||
[[nodiscard]] bool isDirect() const {
|
||||
return (flags & orbis::vmem::BlockFlags::DirectMemory) ==
|
||||
orbis::vmem::BlockFlags::DirectMemory;
|
||||
|
|
@ -400,7 +407,43 @@ void orbis::vmem::initialize(Process *process, bool force) {
|
|||
}
|
||||
|
||||
void orbis::vmem::fork(Process *process, Process *parentThread) {
|
||||
// FIXME: implement
|
||||
auto vmem = process->get(g_vmInstance);
|
||||
auto parentVmem = parentThread->get(g_vmInstance);
|
||||
|
||||
std::lock_guard lock(*parentVmem);
|
||||
|
||||
std::vector<std::byte> tmpData;
|
||||
|
||||
for (auto alloc : parentVmem->allocations) {
|
||||
if (alloc->isAllocated() && alloc->isFlexCommited()) {
|
||||
auto clonedAllocation = alloc.get();
|
||||
auto [flexRange, errc] = fmem::allocate(alloc.size());
|
||||
|
||||
rx::dieIf(errc != ErrorCode{}, "fork: fmem allocation failed: {}", errc);
|
||||
clonedAllocation.deviceOffset = flexRange.beginAddress();
|
||||
auto cpuProt = toCpuProtection(alloc->prot);
|
||||
tmpData.resize(alloc.size());
|
||||
std::memcpy(tmpData.data(), std::bit_cast<void *>(alloc.beginAddress()),
|
||||
alloc.size());
|
||||
|
||||
pmem::map(alloc.beginAddress(), flexRange, cpuProt);
|
||||
vmem->allocations.map(alloc, clonedAllocation);
|
||||
|
||||
if (!(cpuProt & rx::mem::Protection::W)) {
|
||||
rx::mem::protect(alloc, cpuProt | rx::mem::Protection::W);
|
||||
}
|
||||
|
||||
std::memcpy(std::bit_cast<void *>(alloc.beginAddress()), tmpData.data(),
|
||||
tmpData.size());
|
||||
|
||||
if (!(cpuProt & rx::mem::Protection::W)) {
|
||||
rx::mem::protect(alloc, cpuProt);
|
||||
}
|
||||
|
||||
} else {
|
||||
vmem->allocations.map(alloc, alloc.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<rx::AddressRange, orbis::ErrorCode> orbis::vmem::reserve(
|
||||
|
|
@ -826,6 +869,18 @@ std::pair<rx::AddressRange, orbis::ErrorCode> orbis::vmem::mapFlex(
|
|||
alignment);
|
||||
|
||||
if (prot) {
|
||||
auto cpuProt = toCpuProtection(prot);
|
||||
if (!(cpuProt & rx::mem::Protection::W)) {
|
||||
rx::mem::protect(vmemRange, cpuProt | rx::mem::Protection::W);
|
||||
}
|
||||
|
||||
std::memset(std::bit_cast<void *>(vmemRange.beginAddress()), 0,
|
||||
vmemRange.size());
|
||||
|
||||
if (!(cpuProt & rx::mem::Protection::W)) {
|
||||
rx::mem::protect(vmemRange, cpuProt);
|
||||
}
|
||||
|
||||
amdgpu::mapMemory(process->pid, vmemRange, MemoryType::WbOnion, prot,
|
||||
allocationInfo.deviceOffset);
|
||||
}
|
||||
|
|
@ -1143,11 +1198,24 @@ orbis::ErrorCode orbis::vmem::protect(Process *process, rx::AddressRange range,
|
|||
rx::dieIf(errc != ErrorCode{},
|
||||
"failed to allocate flexible memory");
|
||||
|
||||
errc = pmem::map(range.beginAddress(), pmemRange,
|
||||
toCpuProtection(blockProt));
|
||||
alloc.deviceOffset = pmemRange.beginAddress();
|
||||
|
||||
auto cpuProt = toCpuProtection(blockProt);
|
||||
errc = pmem::map(range.beginAddress(), pmemRange, cpuProt);
|
||||
|
||||
rx::dieIf(errc != ErrorCode{}, "failed to map flexible memory");
|
||||
|
||||
if (!(cpuProt & rx::mem::Protection::W)) {
|
||||
rx::mem::protect(range, cpuProt | rx::mem::Protection::W);
|
||||
}
|
||||
|
||||
std::memset(std::bit_cast<void *>(range.beginAddress()), 0,
|
||||
range.size());
|
||||
|
||||
if (!(cpuProt & rx::mem::Protection::W)) {
|
||||
rx::mem::protect(range, cpuProt);
|
||||
}
|
||||
|
||||
amdgpu::mapMemory(process->pid, range, MemoryType::WbOnion,
|
||||
prot, pmemRange.beginAddress());
|
||||
} else if (!blockProt && alloc.prot) {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
#include "orbis/IoDevice.hpp"
|
||||
#include "orbis/KernelAllocator.hpp"
|
||||
#include "orbis/KernelObject.hpp"
|
||||
#include "orbis/fmem.hpp"
|
||||
#include "orbis/module/Module.hpp"
|
||||
#include "orbis/pmem.hpp"
|
||||
#include "orbis/stat.hpp"
|
||||
|
|
@ -12,7 +11,6 @@
|
|||
#include "rx/AddressRange.hpp"
|
||||
#include "rx/SharedMutex.hpp"
|
||||
#include "rx/StrUtil.hpp"
|
||||
#include "rx/debug.hpp"
|
||||
#include "rx/die.hpp"
|
||||
#include "rx/format.hpp"
|
||||
#include "rx/mem.hpp"
|
||||
|
|
@ -519,7 +517,7 @@ static auto g_elfDevice = orbis::createGlobalObject<ElfDevice>();
|
|||
|
||||
static rx::Ref<orbis::Module> loadModule(ElfFile *elf, orbis::Process *process,
|
||||
std::string_view name) {
|
||||
rx::Ref<orbis::Module> result{orbis::knew<orbis::Module>()};
|
||||
rx::Ref result{orbis::knew<orbis::Module>()};
|
||||
|
||||
Elf64_Ehdr header;
|
||||
std::memcpy(&header, elf->image.data(), sizeof(Elf64_Ehdr));
|
||||
|
|
@ -1079,10 +1077,10 @@ static rx::Ref<orbis::Module> loadModule(ElfFile *elf, orbis::Process *process,
|
|||
phdr.p_type == kElfProgramTypeGnuRelRo) {
|
||||
// map anonymous memory, copy segment data
|
||||
|
||||
auto [vmem, vmemErrc] =
|
||||
orbis::vmem::mapFlex(process, segmentRange.size(), protFlags,
|
||||
imageRange.beginAddress() + segmentBegin,
|
||||
orbis::AllocationFlags::Fixed, {}, mapName);
|
||||
auto [vmem, vmemErrc] = orbis::vmem::mapFlex(
|
||||
process, segmentRange.size(), protFlags,
|
||||
imageRange.beginAddress() + segmentBegin - baseAddress,
|
||||
orbis::AllocationFlags::Fixed, {}, mapName);
|
||||
|
||||
rx::dieIf(vmemErrc != orbis::ErrorCode{},
|
||||
"elf: failed to map flexible to virtual memory {}",
|
||||
|
|
@ -1093,8 +1091,8 @@ static rx::Ref<orbis::Module> loadModule(ElfFile *elf, orbis::Process *process,
|
|||
rx::mem::Protection::R | rx::mem::Protection::W);
|
||||
}
|
||||
|
||||
std::memcpy(imageBase + phdr.p_vaddr, elf->image.data() + phdr.p_offset,
|
||||
phdr.p_filesz);
|
||||
std::memcpy(imageBase + phdr.p_vaddr - baseAddress,
|
||||
elf->image.data() + phdr.p_offset, phdr.p_filesz);
|
||||
|
||||
rx::println(stderr, "{}: RW segment {:x}-{:x}, {}", result->moduleName,
|
||||
segmentRange.beginAddress(), segmentRange.endAddress(),
|
||||
|
|
@ -1114,28 +1112,29 @@ static rx::Ref<orbis::Module> loadModule(ElfFile *elf, orbis::Process *process,
|
|||
std::lock_guard lock(elf->mtx);
|
||||
if (!elf->initialized) {
|
||||
auto [vmem, vmemErrc] = orbis::vmem::mapFile(
|
||||
process, imageRange.beginAddress() + segmentBegin,
|
||||
process, imageRange.beginAddress() + segmentBegin - baseAddress,
|
||||
segmentRange.size(), orbis::AllocationFlags::Fixed,
|
||||
protFlags | orbis::vmem::Protection::CpuWrite, {}, {}, elf,
|
||||
segmentBegin, mapName);
|
||||
segmentBegin - baseAddress, mapName);
|
||||
|
||||
rx::dieIf(vmemErrc != orbis::ErrorCode{},
|
||||
"elf: failed to map elf to virtual memory {}", vmemErrc);
|
||||
|
||||
std::memset(imageBase + phdr.p_vaddr + phdr.p_filesz, 0,
|
||||
phdr.p_memsz - phdr.p_filesz);
|
||||
std::memcpy(imageBase + phdr.p_vaddr,
|
||||
std::memset(imageBase + phdr.p_vaddr + phdr.p_filesz - baseAddress,
|
||||
0, phdr.p_memsz - phdr.p_filesz);
|
||||
std::memcpy(imageBase + phdr.p_vaddr - baseAddress,
|
||||
elf->image.data() + phdr.p_offset, phdr.p_filesz);
|
||||
elf->initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
auto [vmem, vmemErrc] = orbis::vmem::mapFile(
|
||||
process, imageRange.beginAddress() + segmentBegin,
|
||||
process, imageRange.beginAddress() + segmentBegin - baseAddress,
|
||||
segmentRange.size(), orbis::AllocationFlags::Fixed, protFlags,
|
||||
orbis::vmem::BlockFlags::FlexibleMemory |
|
||||
orbis::vmem::BlockFlags::Commited,
|
||||
orbis::vmem::BlockFlagsEx::Shared, elf, segmentBegin, mapName);
|
||||
orbis::vmem::BlockFlagsEx::Shared, elf, segmentBegin - baseAddress,
|
||||
mapName);
|
||||
|
||||
rx::dieIf(vmemErrc != orbis::ErrorCode{},
|
||||
"elf: failed to map elf to virtual memory {}", (int)vmemErrc);
|
||||
|
|
@ -1153,7 +1152,7 @@ static rx::Ref<orbis::Module> loadModule(ElfFile *elf, orbis::Process *process,
|
|||
rx::println(stderr, "elf: corrupted, segment {} overriding. {}",
|
||||
segmentIndex, name);
|
||||
} else {
|
||||
segment.addr = imageBase + segmentBegin;
|
||||
segment.addr = imageBase + segmentBegin - baseAddress;
|
||||
segment.size = phdr.p_memsz;
|
||||
segment.prot = protFlags.toUnderlying();
|
||||
result->segmentCount = std::max(segmentIndex + 1, result->segmentCount);
|
||||
|
|
|
|||
|
|
@ -1212,14 +1212,89 @@ int main(int argc, const char *argv[]) {
|
|||
},
|
||||
};
|
||||
|
||||
orbis::BudgetInfo systemBudgetInfo[]{
|
||||
{
|
||||
.resourceId = orbis::BudgetResource::Dmem,
|
||||
.flags = 0,
|
||||
.item =
|
||||
{
|
||||
.total = 0x1'8000'0000,
|
||||
},
|
||||
},
|
||||
{
|
||||
.resourceId = orbis::BudgetResource::Vmem,
|
||||
.flags = 0,
|
||||
.item =
|
||||
{
|
||||
.total = 2ul * 1024 * 1024 * 1024,
|
||||
},
|
||||
},
|
||||
{
|
||||
.resourceId = orbis::BudgetResource::Fmem,
|
||||
.flags = 0,
|
||||
.item =
|
||||
{
|
||||
.total = 2ul * 1024 * 1024 * 1024,
|
||||
},
|
||||
},
|
||||
{
|
||||
.resourceId = orbis::BudgetResource::CpuSet,
|
||||
.flags = 0,
|
||||
.item =
|
||||
{
|
||||
.total = 8,
|
||||
},
|
||||
},
|
||||
{
|
||||
.resourceId = orbis::BudgetResource::File,
|
||||
.flags = 0,
|
||||
.item =
|
||||
{
|
||||
.total = 4096,
|
||||
},
|
||||
},
|
||||
{
|
||||
.resourceId = orbis::BudgetResource::Socket,
|
||||
.flags = 0,
|
||||
.item =
|
||||
{
|
||||
.total = 4096,
|
||||
},
|
||||
},
|
||||
{
|
||||
.resourceId = orbis::BudgetResource::Equeue,
|
||||
.flags = 0,
|
||||
.item =
|
||||
{
|
||||
.total = 4096,
|
||||
},
|
||||
},
|
||||
{
|
||||
.resourceId = orbis::BudgetResource::Pipe,
|
||||
.flags = 0,
|
||||
.item =
|
||||
{
|
||||
.total = 4096,
|
||||
},
|
||||
},
|
||||
{
|
||||
.resourceId = orbis::BudgetResource::Device,
|
||||
.flags = 0,
|
||||
.item =
|
||||
{
|
||||
.total = 4096,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
auto bigAppBudget = orbis::g_context->createProcessTypeBudget(
|
||||
orbis::Budget::ProcessType::BigApp, "big app budget", bigAppBudgetInfo);
|
||||
|
||||
// FIXME: define following budgets
|
||||
orbis::g_context->createProcessTypeBudget(
|
||||
orbis::Budget::ProcessType::MiniApp, "mini-app budget", bigAppBudgetInfo);
|
||||
orbis::g_context->createProcessTypeBudget(orbis::Budget::ProcessType::System,
|
||||
"system budget", bigAppBudgetInfo);
|
||||
auto systemBudget = orbis::g_context->createProcessTypeBudget(
|
||||
orbis::Budget::ProcessType::System, "system budget", systemBudgetInfo);
|
||||
orbis::g_context->createProcessTypeBudget(
|
||||
orbis::Budget::ProcessType::NonGameMiniApp, "non-game mini-app budget",
|
||||
bigAppBudgetInfo);
|
||||
|
|
@ -1251,6 +1326,7 @@ int main(int argc, const char *argv[]) {
|
|||
-1ul,
|
||||
}};
|
||||
initProcess->budgetProcessType = orbis::Budget::ProcessType::System;
|
||||
initProcess->budgetId = orbis::g_context->budgets.insert(systemBudget);
|
||||
initProcess->isInSandbox = false;
|
||||
} else {
|
||||
initProcess->authInfo = {
|
||||
|
|
|
|||
|
|
@ -647,6 +647,9 @@ SysResult fork(Thread *thread, slong flags) {
|
|||
process->authInfo = thread->tproc->authInfo;
|
||||
process->sdkVersion = thread->tproc->sdkVersion;
|
||||
process->type = thread->tproc->type;
|
||||
process->budgetProcessType = thread->tproc->budgetProcessType;
|
||||
process->budgetId = thread->tproc->budgetId;
|
||||
|
||||
for (auto [id, mod] : thread->tproc->modulesMap) {
|
||||
if (!process->modulesMap.insert(id, mod)) {
|
||||
std::abort();
|
||||
|
|
|
|||
Loading…
Reference in a new issue