orbis: implement physical memory emulation level & utils improvement

fix blockpool & dmem implementation
modernize blockpool & dmem io devices
use budgets per allocation
add serialization support for MemoryTableWithPayload and AddressRange utils
add format support for EnumBitSet util
implemented trace formatter per syscall
increased allowed reference count for Ref
This commit is contained in:
DH 2025-11-30 15:46:37 +03:00
parent 479b09b2df
commit d7ad77b406
70 changed files with 4268 additions and 3160 deletions

View file

@ -9,6 +9,7 @@
#include <mutex>
#include <span>
#include <string_view>
#include <utility>
namespace orbis {
enum class BudgetResource : uint32_t {
@ -139,4 +140,44 @@ private:
BudgetList mList;
char mName[32]{};
};
class ScopedBudgetAcquire {
Budget *mBudget = nullptr;
std::uint64_t mSize = 0;
BudgetResource mResourceId = {};
public:
ScopedBudgetAcquire() = default;
ScopedBudgetAcquire(const ScopedBudgetAcquire &) = delete;
ScopedBudgetAcquire &operator=(const ScopedBudgetAcquire &) = delete;
ScopedBudgetAcquire(Budget *budget, BudgetResource resourceId,
std::uint64_t size)
: mBudget(budget), mSize(size), mResourceId(resourceId) {
if (!budget->acquire(resourceId, size)) {
mBudget = nullptr;
}
}
ScopedBudgetAcquire(ScopedBudgetAcquire &&other) noexcept {
*this = std::move(other);
}
ScopedBudgetAcquire &operator=(ScopedBudgetAcquire &&other) noexcept {
std::swap(mBudget, other.mBudget);
std::swap(mSize, other.mSize);
std::swap(mResourceId, other.mResourceId);
return *this;
}
~ScopedBudgetAcquire() {
if (mBudget) {
mBudget->release(mResourceId, mSize);
}
}
explicit operator bool() const { return mBudget != nullptr; }
void commit() { mBudget = nullptr; }
};
} // namespace orbis

View file

@ -6,6 +6,7 @@
#include "rx/EnumBitSet.hpp"
#include "rx/Rc.hpp"
#include "rx/mem.hpp"
#include "vmem.hpp"
#include <bit>
#include <type_traits>
@ -34,6 +35,8 @@ struct Process;
struct Stat;
struct StatFs;
struct IoDevice : rx::RcBase {
rx::EnumBitSet<vmem::BlockFlags> blockFlags{};
virtual ErrorCode open(rx::Ref<File> *file, const char *path,
std::uint32_t flags, std::uint32_t mode,
Thread *thread) = 0;
@ -67,14 +70,12 @@ struct IoDevice : rx::RcBase {
return ErrorCode::NOTSUP;
}
virtual ErrorCode ioctl(std::uint64_t request, orbis::ptr<void> argp,
virtual ErrorCode ioctl(std::uint64_t request, ptr<void> argp,
Thread *thread);
virtual ErrorCode map(rx::AddressRange range, std::int64_t offset,
rx::EnumBitSet<rx::mem::Protection> protection,
Process *process) {
return ErrorCode::NOTSUP;
}
rx::EnumBitSet<vmem::Protection> protection, File *file,
Process *process);
};
namespace ioctl {

View file

@ -122,8 +122,8 @@ public:
rx::Ref<EventEmitter> deviceEventEmitter;
rx::Ref<IoDevice> shmDevice;
rx::Ref<IoDevice> dmemDevice;
rx::Ref<IoDevice> blockpoolDevice;
rx::Ref<File> dmem;
rx::Ref<File> blockpool;
rx::Ref<rx::RcBase> gpuDevice;
rx::Ref<IoDevice> dceDevice;
rx::shared_mutex gpuDeviceMtx;

View file

@ -0,0 +1,12 @@
#pragma once
#include <cstdint>
namespace orbis {
enum class MemoryType : std::uint32_t {
Invalid = -1u,
WbOnion = 0, // write back, CPU bus
WCGarlic = 3, // combining, GPU bus
WbGarlic = 10, // write back, GPU bus
};
}

View file

@ -0,0 +1,32 @@
#pragma once
#include "dmem.hpp"
#include "error/ErrorCode.hpp"
#include "orbis-config.hpp"
#include "rx/AddressRange.hpp"
namespace orbis {
struct Process;
}
namespace orbis::blockpool {
#pragma pack(push, 1)
struct BlockStats {
sint availFlushedBlocks;
sint availCachedBlocks;
sint commitFlushedBlocks;
sint commitCachedBlocks;
};
static_assert(sizeof(BlockStats) == 16);
#pragma pack(pop)
void clear();
ErrorCode expand(rx::AddressRange dmemRange);
ErrorCode allocateControlBlock();
ErrorCode releaseControlBlock();
ErrorCode commit(Process *process, rx::AddressRange vmemRange, MemoryType type,
rx::EnumBitSet<orbis::vmem::Protection> protection);
void decommit(Process *process, rx::AddressRange vmemRange);
std::optional<MemoryType> getType(std::uint64_t address);
BlockStats stats();
} // namespace orbis::blockpool

View file

@ -0,0 +1,62 @@
#pragma once
#include "MemoryType.hpp"
#include "error/ErrorCode.hpp"
#include "rx/AddressRange.hpp"
#include "rx/EnumBitSet.hpp"
#include "vmem.hpp"
#include <utility>
namespace orbis {
struct Process;
struct IoDevice;
} // namespace orbis
namespace orbis::dmem {
static constexpr auto kPageSize = 64 * 1024;
enum class QueryFlags {
LowerBound,
Pooled,
bitset_last = Pooled,
};
struct QueryResult {
rx::AddressRange range;
MemoryType memoryType;
};
ErrorCode initialize();
ErrorCode clear(unsigned dmemIndex);
std::pair<std::uint64_t, ErrorCode>
allocate(unsigned dmemIndex, rx::AddressRange searchRange, std::uint64_t len,
MemoryType memoryType, std::uint64_t alignment = kPageSize,
bool pooled = false);
ErrorCode release(unsigned dmemIndex, rx::AddressRange range,
bool pooled = false);
std::pair<std::uint64_t, ErrorCode> reserveSystem(unsigned dmemIndex,
std::uint64_t size);
std::pair<std::uint64_t, ErrorCode> reservePooled(unsigned dmemIndex,
rx::AddressRange searchRange,
std::uint64_t size,
std::uint64_t alignment);
ErrorCode setType(unsigned dmemIndex, rx::AddressRange range, MemoryType type,
rx::EnumBitSet<QueryFlags> flags = {});
std::optional<QueryResult> query(unsigned dmemIndex, std::uint64_t dmemOffset,
rx::EnumBitSet<QueryFlags> flags = {});
std::uint64_t getSize(unsigned dmemIndex);
std::pair<rx::AddressRange, ErrorCode>
getAvailSize(unsigned dmemIndex, rx::AddressRange searchRange,
std::uint64_t alignment);
ErrorCode map(unsigned dmemIndex, rx::AddressRange range, std::uint64_t offset,
rx::EnumBitSet<vmem::Protection> protection);
std::pair<std::uint64_t, ErrorCode> getPmemOffset(unsigned dmemIndex,
std::uint64_t dmemOffset);
} // namespace orbis::dmem

View file

@ -4,6 +4,7 @@
#include "KernelAllocator.hpp"
#include "error/ErrorCode.hpp"
#include "note.hpp"
#include "rx/Mappable.hpp"
#include "rx/Rc.hpp"
#include "rx/SharedMutex.hpp"
#include "stat.hpp"
@ -42,12 +43,6 @@ struct FileOps {
// TODO: chown
// TODO: chmod
ErrorCode (*mmap)(File *file, void **address, std::uint64_t size,
std::int32_t prot, std::int32_t flags, std::int64_t offset,
Thread *thread) = nullptr;
ErrorCode (*munmap)(File *file, void **address, std::uint64_t size,
Thread *thread) = nullptr;
ErrorCode (*bind)(orbis::File *file, SocketAddress *address,
std::size_t addressLen, Thread *thread) = nullptr;
ErrorCode (*listen)(orbis::File *file, int backlog, Thread *thread) = nullptr;
@ -84,7 +79,7 @@ struct File : rx::RcBase {
std::uint64_t nextOff = 0;
int flags = 0;
int mode = 0;
int hostFd = -1;
rx::Mappable hostFd;
kvector<Dirent> dirEntries;
bool noBlock() const { return (flags & 4) != 0; }

View file

@ -4,13 +4,9 @@
#include "rx/AddressRange.hpp"
#include <cstdint>
namespace orbis {
struct Process;
}
namespace orbis::fmem {
ErrorCode initialize(Process *process, std::uint64_t size);
void destroy(Process *process);
std::pair<rx::AddressRange, ErrorCode> allocate(Process *process,
std::uint64_t size);
ErrorCode deallocate(Process *process, rx::AddressRange range);
ErrorCode initialize(std::uint64_t size);
void destroy();
std::pair<rx::AddressRange, ErrorCode> allocate(std::uint64_t size);
ErrorCode deallocate(rx::AddressRange range);
} // namespace orbis::fmem

View file

@ -9,30 +9,20 @@
namespace orbis {
using kernel::AllocationFlags;
struct IoDevice;
struct File;
} // namespace orbis
namespace orbis::pmem {
enum class MemoryType : std::uint32_t {
Invalid = -1u,
WbOnion = 0, // write back, CPU bus
WCGarlic = 3, // combining, GPU bus
WbGarlic = 10, // write back, GPU bus
};
struct AllocatedMemory {
rx::AddressRange range;
MemoryType memoryType;
};
ErrorCode initialize(std::uint64_t size);
void destroy();
std::pair<rx::AddressRange, ErrorCode>
allocate(std::uint64_t addressHint, std::uint64_t size, MemoryType memoryType,
allocate(std::uint64_t addressHint, std::uint64_t size,
rx::EnumBitSet<AllocationFlags> flags, std::uint64_t alignment);
ErrorCode deallocate(rx::AddressRange range);
std::optional<AllocatedMemory> query(std::uint64_t address);
std::optional<rx::AddressRange> query(std::uint64_t address);
ErrorCode map(std::uint64_t virtualAddress, rx::AddressRange range,
rx::EnumBitSet<rx::mem::Protection> protection);
std::size_t getSize();
IoDevice *getDevice();
File *getFile();
} // namespace orbis::pmem

View file

@ -1,4 +1,7 @@
#include "orbis-config.hpp"
#include "orbis/dmem.hpp"
#include "orbis/vmem.hpp"
#include "rx/EnumBitSet.hpp"
#include <orbis/Budget.hpp>
#include <orbis/error.hpp>
#include <orbis/module/ModuleHandle.hpp>
@ -18,7 +21,9 @@ using id_t = uint32_t;
struct Thread;
struct AuthInfo;
namespace vmem {
struct MemoryProtection;
}
struct ModuleInfo;
struct ModuleInfoEx;
struct KEvent;
@ -105,16 +110,16 @@ SysResult sys_execve(Thread *thread, ptr<char> fname, ptr<ptr<char>> argv,
ptr<ptr<char>> envv);
SysResult sys_umask(Thread *thread, sint newmask);
SysResult sys_chroot(Thread *thread, ptr<char> path);
SysResult sys_msync(Thread *thread, ptr<void> addr, size_t len, sint flags);
SysResult sys_msync(Thread *thread, uintptr_t addr, size_t len, sint flags);
SysResult sys_vfork(Thread *thread);
SysResult sys_sbrk(Thread *thread, sint incr);
SysResult sys_sstk(Thread *thread, sint incr);
SysResult sys_ovadvise(Thread *thread, sint anom);
SysResult sys_munmap(Thread *thread, ptr<void> addr, size_t len);
SysResult sys_mprotect(Thread *thread, ptr<const void> addr, size_t len,
sint prot);
SysResult sys_madvise(Thread *thread, ptr<void> addr, size_t len, sint behav);
SysResult sys_mincore(Thread *thread, ptr<const void> addr, size_t len,
SysResult sys_munmap(Thread *thread, uintptr_t addr, size_t len);
SysResult sys_mprotect(Thread *thread, uintptr_t addr, size_t len,
rx::EnumBitSet<vmem::Protection> prot);
SysResult sys_madvise(Thread *thread, uintptr_t addr, size_t len, sint behav);
SysResult sys_mincore(Thread *thread, uintptr_t addr, size_t len,
ptr<char> vec);
SysResult sys_getgroups(Thread *thread, uint gidsetsize, ptr<gid_t> gidset);
SysResult sys_setgroups(Thread *thread, uint gidsetsize, ptr<gid_t> gidset);
@ -198,8 +203,10 @@ SysResult sys_getrlimit(Thread *thread, uint which, ptr<struct rlimit> rlp);
SysResult sys_setrlimit(Thread *thread, uint which, ptr<struct rlimit> rlp);
SysResult sys_getdirentries(Thread *thread, sint fd, ptr<char> buf, uint count,
ptr<slong> basep);
SysResult sys_freebsd6_mmap(Thread *thread, caddr_t addr, size_t len, sint prot,
sint flags, sint fd, sint pad, off_t pos);
SysResult sys_freebsd6_mmap(Thread *thread, uintptr_t addr, size_t len,
rx::EnumBitSet<vmem::Protection> prot,
rx::EnumBitSet<vmem::MapFlags> flags, sint fd,
sint pad, off_t pos);
SysResult sys_freebsd6_lseek(Thread *thread, sint fd, sint pad, off_t offset,
sint whence);
SysResult sys_freebsd6_truncate(Thread *thread, ptr<char> path, sint pad,
@ -209,8 +216,8 @@ SysResult sys_freebsd6_ftruncate(Thread *thread, sint fd, sint pad,
SysResult sys___sysctl(Thread *thread, ptr<sint> name, uint namelen,
ptr<void> old, ptr<size_t> oldenp, ptr<void> new_,
size_t newlen);
SysResult sys_mlock(Thread *thread, ptr<const void> addr, size_t len);
SysResult sys_munlock(Thread *thread, ptr<const void> addr, size_t len);
SysResult sys_mlock(Thread *thread, uintptr_t addr, size_t len);
SysResult sys_munlock(Thread *thread, uintptr_t addr, size_t len);
SysResult sys_undelete(Thread *thread, ptr<char> path);
SysResult sys_futimes(Thread *thread, sint fd, ptr<struct timeval> tptr);
SysResult sys_getpgid(Thread *thread, pid_t pid);
@ -246,7 +253,7 @@ SysResult sys_ktimer_getoverrun(Thread *thread, sint timerid);
SysResult sys_nanosleep(Thread *thread, cptr<timespec> rqtp,
ptr<timespec> rmtp);
SysResult sys_ntp_gettime(Thread *thread, ptr<struct ntptimeval> ntvp);
SysResult sys_minherit(Thread *thread, ptr<void> addr, size_t len,
SysResult sys_minherit(Thread *thread, uintptr_t addr, size_t len,
sint inherit);
SysResult sys_rfork(Thread *thread, sint flags);
SysResult sys_openbsd_poll(Thread *thread, ptr<struct pollfd> fds, uint nfds,
@ -519,8 +526,9 @@ SysResult sys_pread(Thread *thread, sint fd, ptr<void> buf, size_t nbyte,
off_t offset);
SysResult sys_pwrite(Thread *thread, sint fd, ptr<const void> buf, size_t nbyte,
off_t offset);
SysResult sys_mmap(Thread *thread, caddr_t addr, size_t len, sint prot,
sint flags, sint fd, off_t pos);
SysResult sys_mmap(Thread *thread, uintptr_t addr, size_t len,
rx::EnumBitSet<vmem::Protection> prot,
rx::EnumBitSet<vmem::MapFlags> flags, sint fd, off_t pos);
SysResult sys_lseek(Thread *thread, sint fd, off_t offset, sint whence);
SysResult sys_truncate(Thread *thread, ptr<char> path, off_t length);
SysResult sys_ftruncate(Thread *thread, sint fd, off_t length);
@ -621,7 +629,9 @@ SysResult sys_socketex(Thread *thread, ptr<const char> name, sint domain,
SysResult sys_socketclose(Thread *thread, sint fd);
SysResult sys_netgetiflist(Thread *thread /* TODO */);
SysResult sys_kqueueex(Thread *thread, ptr<char> name, sint flags);
SysResult sys_mtypeprotect(Thread *thread /* TODO */);
SysResult sys_mtypeprotect(Thread *thread, uintptr_t addr, size_t len,
MemoryType type,
rx::EnumBitSet<vmem::Protection> prot);
SysResult sys_regmgr_call(Thread *thread, uint32_t op, uint32_t id,
ptr<void> result, ptr<void> value, uint64_t len);
SysResult sys_jitshm_create(Thread *thread /* TODO */);
@ -644,9 +654,10 @@ SysResult sys_evf_set(Thread *thread, sint id, uint64_t value);
SysResult sys_evf_clear(Thread *thread, sint id, uint64_t value);
SysResult sys_evf_cancel(Thread *thread, sint id, uint64_t value,
ptr<sint> pNumWaitThreads);
SysResult sys_query_memory_protection(Thread *thread, ptr<void> address,
ptr<MemoryProtection> protection);
SysResult sys_batch_map(Thread *thread, sint unk, sint flags,
SysResult sys_query_memory_protection(Thread *thread, uintptr_t address,
ptr<vmem::MemoryProtection> protection);
SysResult sys_batch_map(Thread *thread, sint unk,
rx::EnumBitSet<vmem::MapFlags> flags,
ptr<BatchMapEntry> entries, sint entriesCount,
ptr<sint> processedCount);
SysResult sys_osem_create(Thread *thread, ptr<const char[32]> name, uint attrs,
@ -679,7 +690,7 @@ SysResult sys_budget_delete(Thread *thread, sint budget);
SysResult sys_budget_get(Thread *thread, sint id, ptr<BudgetInfo> budgetInfo,
ptr<sint> count);
SysResult sys_budget_set(Thread *thread, sint budget);
SysResult sys_virtual_query(Thread *thread, ptr<void> addr, uint64_t unk,
SysResult sys_virtual_query(Thread *thread, uintptr_t addr, uint64_t unk,
ptr<void> info, size_t infosz);
SysResult sys_mdbg_call(Thread *thread /* TODO */);
SysResult sys_obs_sblock_create(Thread *thread /* TODO */);
@ -752,8 +763,10 @@ SysResult sys_opmc_set_hw(Thread *thread /* TODO */);
SysResult sys_opmc_get_hw(Thread *thread /* TODO */);
SysResult sys_get_cpu_usage_all(Thread *thread, uint32_t unk,
ptr<uint32_t> result);
SysResult sys_mmap_dmem(Thread *thread, caddr_t addr, size_t len,
sint memoryType, sint prot, sint flags,
SysResult sys_mmap_dmem(Thread *thread, uintptr_t addr, size_t len,
MemoryType memoryType,
rx::EnumBitSet<vmem::Protection> prot,
rx::EnumBitSet<vmem::MapFlags> flags,
off_t directMemoryStart);
SysResult sys_physhm_open(Thread *thread /* TODO */);
SysResult sys_physhm_unlink(Thread *thread /* TODO */);
@ -785,9 +798,11 @@ SysResult sys_budget_get_ptype_of_budget(Thread *thread, sint budgetId);
SysResult sys_prepare_to_resume_process(Thread *thread /* TODO */);
SysResult sys_process_terminate(Thread *thread /* TODO */);
SysResult sys_blockpool_open(Thread *thread);
SysResult sys_blockpool_map(Thread *thread, caddr_t addr, size_t len, sint prot,
sint flags);
SysResult sys_blockpool_unmap(Thread *thread, caddr_t addr, size_t len,
SysResult sys_blockpool_map(Thread *thread, uintptr_t addr, size_t len,
MemoryType type,
rx::EnumBitSet<vmem::Protection> prot,
rx::EnumBitSet<vmem::MapFlags> flags);
SysResult sys_blockpool_unmap(Thread *thread, uintptr_t addr, size_t len,
sint flags);
SysResult sys_dynlib_get_info_for_libdbg(Thread *thread /* TODO */);
SysResult sys_blockpool_batch(Thread *thread /* TODO */);

View file

@ -102,6 +102,8 @@ struct Process final {
rx::RcIdMap<Thread, lwpid_t> threadsMap;
rx::RcIdMap<orbis::File, sint> fileDescriptors;
rx::AddressRange libkernelRange;
// Named objects for debugging
rx::shared_mutex namedObjMutex;
kmap<void *, kstring> namedObjNames;
@ -109,10 +111,6 @@ struct Process final {
kmap<std::int32_t, SigAction> sigActions;
// Named memory ranges for debugging
rx::shared_mutex namedMemMutex;
kmap<NamedMemoryRange, kstring> namedMem;
// FIXME: implement process destruction
void incRef() {}
void decRef() {}
@ -126,6 +124,8 @@ struct Process final {
ref) {
return ref.get(storage);
}
Budget *getBudget() const;
};
pid_t allocatePid();

View file

@ -10,34 +10,13 @@ struct Thread;
struct Module;
struct timespec;
struct File;
namespace vmem {
struct MemoryProtection;
}
struct IoVec;
struct UContext;
struct ProcessOps {
SysResult (*mmap)(Thread *thread, caddr_t addr, size_t len, sint prot,
sint flags, sint fd, off_t pos);
SysResult (*dmem_mmap)(Thread *thread, caddr_t addr, size_t len,
sint memoryType, sint prot, sint flags,
off_t directMemoryStart);
SysResult (*munmap)(Thread *thread, ptr<void> addr, size_t len);
SysResult (*msync)(Thread *thread, ptr<void> addr, size_t len, sint flags);
SysResult (*mprotect)(Thread *thread, ptr<const void> addr, size_t len,
sint prot);
SysResult (*minherit)(Thread *thread, ptr<void> addr, size_t len,
sint inherit);
SysResult (*madvise)(Thread *thread, ptr<void> addr, size_t len, sint behav);
SysResult (*mincore)(Thread *thread, ptr<const void> addr, size_t len,
ptr<char> vec);
SysResult (*mlock)(Thread *thread, ptr<const void> addr, size_t len);
SysResult (*mlockall)(Thread *thread, sint how);
SysResult (*munlockall)(Thread *thread);
SysResult (*munlock)(Thread *thread, ptr<const void> addr, size_t len);
SysResult (*virtual_query)(Thread *thread, ptr<const void> addr, sint flags,
ptr<void> info, ulong infoSize);
SysResult (*query_memory_protection)(Thread *thread, ptr<void> address,
ptr<MemoryProtection> protection);
SysResult (*open)(Thread *thread, ptr<const char> path, sint flags, sint mode,
rx::Ref<File> *file);
SysResult (*shm_open)(Thread *thread, const char *path, sint flags, sint mode,
@ -46,10 +25,6 @@ struct ProcessOps {
SysResult (*mkdir)(Thread *thread, ptr<const char> path, sint mode);
SysResult (*rmdir)(Thread *thread, ptr<const char> path);
SysResult (*rename)(Thread *thread, ptr<const char> from, ptr<const char> to);
SysResult (*blockpool_open)(Thread *thread, rx::Ref<File> *file);
SysResult (*blockpool_map)(Thread *thread, caddr_t addr, size_t len,
sint prot, sint flags);
SysResult (*blockpool_unmap)(Thread *thread, caddr_t addr, size_t len);
SysResult (*socket)(Thread *thread, ptr<const char> name, sint domain,
sint type, sint protocol, rx::Ref<File> *file);
SysResult (*socketpair)(Thread *thread, sint domain, sint type, sint protocol,

View file

@ -32,8 +32,8 @@ struct Thread final {
uint64_t retval[2]{};
void *context{};
kvector<void *> altStack;
ptr<void> stackStart;
ptr<void> stackEnd;
uint64_t stackStart;
uint64_t stackEnd;
uint64_t fsBase{};
uint64_t gsBase{};
rx::StaticString<31> name;
@ -97,6 +97,7 @@ struct Thread final {
};
Thread *createThread(Process *process, std::string_view name);
uintptr_t getCallerAddress(Thread *thread);
extern thread_local Thread *g_currentThread;

View file

@ -1,6 +1,7 @@
#pragma once
#include "orbis-config.hpp"
#include <string>
namespace orbis {
struct Thread;
@ -9,6 +10,7 @@ using sy_call_t = SysResult(Thread *, uint64_t *);
struct sysent {
sint narg;
sy_call_t *call;
std::string (*format)(uint64_t *);
};
struct sysentvec {

View file

@ -15,7 +15,7 @@ struct rtprio {
struct thr_param {
ptr<void(void *)> start_func;
ptr<void> arg;
ptr<char> stack_base;
uint64_t stack_base;
size_t stack_size;
ptr<char> tls_base;
size_t tls_size;

View file

@ -47,7 +47,7 @@ struct MContext {
};
struct Stack {
ptr<void> sp;
uintptr_t sp;
size_t size;
sint flags;
sint align;

View file

@ -1,13 +0,0 @@
#pragma once
#include "orbis-config.hpp"
namespace orbis {
struct MemoryProtection {
uint64_t startAddress;
uint64_t endAddress;
int32_t prot;
};
static_assert(sizeof(MemoryProtection) == 24);
} // namespace orbis

View file

@ -1,21 +1,22 @@
#pragma once
#include "MemoryType.hpp"
#include "kernel/MemoryResource.hpp"
#include "orbis-config.hpp"
#include "rx/AddressRange.hpp"
#include "rx/EnumBitSet.hpp"
#include "rx/StaticString.hpp"
#include "rx/mem.hpp"
#include <string_view>
namespace orbis {
using kernel::AllocationFlags;
}
namespace orbis {
struct IoDevice;
struct File;
struct Process;
} // namespace orbis
namespace vmem {
namespace orbis::vmem {
static constexpr auto kPageSize = 16 * 1024;
enum class Protection {
@ -28,33 +29,85 @@ enum class Protection {
bitset_last = GpuWrite
};
enum class BlockFlags {
enum class BlockFlags : std::uint8_t {
FlexibleMemory,
DirectMemory,
Stack,
PooledMemory,
Commited,
Allocated,
bitset_last = Allocated
bitset_last = Commited
};
enum class BlockFlagsEx : std::uint8_t {
Allocated,
Private,
Shared,
PoolControl,
Reserved,
bitset_last = Reserved
};
enum class MapFlags {
Shared = 0,
Private = 1,
Fixed = 4,
Rename = 5,
NoReserve = 6,
NoOverwrite = 7,
Void = 8,
HasSemaphore = 9,
Stack = 10,
NoSync = 11,
Anon = 12,
System = 13,
AllAvailable = 14,
NoCore = 17,
PrefaultRead = 18,
Self = 19,
NoCoalesce = 22,
bitset_last = NoCoalesce
};
inline constexpr std::uint32_t kMapFlagsAlignShift = 24;
inline constexpr std::uint32_t kMapFlagsAlignMask = 0x1f << kMapFlagsAlignShift;
inline constexpr auto kProtCpuReadWrite =
Protection::CpuRead | Protection::CpuWrite;
inline constexpr auto kProtCpuAll =
Protection::CpuRead | Protection::CpuWrite | Protection::CpuExec;
inline constexpr auto kProtGpuAll = Protection::GpuRead | Protection::GpuWrite;
inline std::pair<std::uint64_t, rx::EnumBitSet<MapFlags>>
unpackMapFlags(rx::EnumBitSet<MapFlags> flags, std::uint64_t minAlignment) {
std::uint64_t alignment = minAlignment;
if (auto align =
(flags.toUnderlying() & kMapFlagsAlignMask) >> kMapFlagsAlignShift) {
alignment = std::uint64_t(1) << align;
flags = rx::EnumBitSet<vmem::MapFlags>::fromUnderlying(
flags.toUnderlying() & ~kMapFlagsAlignMask);
if (alignment < minAlignment) {
alignment = minAlignment;
}
}
return {alignment, flags};
}
#pragma pack(push, 1)
struct QueryResult {
uint64_t start;
uint64_t end;
uint64_t offset;
uint32_t protection;
uint32_t memoryType;
uint32_t flags;
rx::EnumBitSet<Protection> protection;
MemoryType memoryType;
rx::EnumBitSet<BlockFlags> flags;
rx::StaticCString<32> name;
uint32_t _padding;
char _padding[7];
};
static_assert(sizeof(QueryResult) == 72);
@ -69,25 +122,81 @@ struct MemoryProtection {
static_assert(sizeof(MemoryProtection) == 24);
#pragma pack(pop)
inline constexpr rx::EnumBitSet<rx::mem::Protection>
toCpuProtection(rx::EnumBitSet<Protection> prot) {
rx::EnumBitSet<rx::mem::Protection> result{};
if (prot & Protection::CpuRead) {
result |= rx::mem::Protection::R;
}
if (prot & Protection::CpuWrite) {
result |= rx::mem::Protection::W;
}
if (prot & Protection::CpuExec) {
result |= rx::mem::Protection::X;
}
return result;
}
inline constexpr rx::EnumBitSet<rx::mem::Protection>
toGpuProtection(rx::EnumBitSet<Protection> prot) {
rx::EnumBitSet<rx::mem::Protection> result{};
if (prot & Protection::GpuRead) {
result |= rx::mem::Protection::R;
}
if (prot & Protection::GpuWrite) {
result |= rx::mem::Protection::W;
}
return result;
}
void initialize(Process *process, bool force = false);
void fork(Process *process, Process *parentThread);
std::pair<rx::AddressRange, ErrorCode>
reserve(Process *process, std::uint64_t addressHint, std::uint64_t size,
rx::EnumBitSet<AllocationFlags> allocFlags);
rx::EnumBitSet<AllocationFlags> allocFlags,
rx::EnumBitSet<BlockFlagsEx> blockFlagsEx = {},
std::uint64_t alignment = kPageSize);
std::pair<rx::AddressRange, ErrorCode>
map(Process *process, std::uint64_t addressHint, std::uint64_t size,
rx::EnumBitSet<AllocationFlags> allocFlags,
rx::EnumBitSet<Protection> prot = {},
rx::EnumBitSet<BlockFlags> blockFlags = {},
std::uint64_t alignment = kPageSize, std::string_view name = {},
IoDevice *device = nullptr, std::int64_t deviceOffset = 0);
mapFile(Process *process, std::uint64_t addressHint, std::uint64_t size,
rx::EnumBitSet<AllocationFlags> allocFlags,
rx::EnumBitSet<Protection> prot, rx::EnumBitSet<BlockFlags> blockFlags,
rx::EnumBitSet<BlockFlagsEx> blockFlagsEx, File *file,
std::uint64_t fileOffset, std::string_view name = {},
std::uint64_t alignment = kPageSize,
MemoryType type = MemoryType::Invalid);
std::pair<rx::AddressRange, ErrorCode>
mapDirect(Process *process, std::uint64_t addressHint,
rx::AddressRange directRange, rx::EnumBitSet<Protection> prot,
rx::EnumBitSet<AllocationFlags> allocFlags,
std::string_view name = {}, std::uint64_t alignment = kPageSize,
MemoryType type = MemoryType::Invalid);
std::pair<rx::AddressRange, ErrorCode>
mapFlex(Process *process, std::uint64_t size, rx::EnumBitSet<Protection> prot,
std::uint64_t addressHint = 0,
rx::EnumBitSet<AllocationFlags> allocFlags = {},
rx::EnumBitSet<BlockFlags> blockFlags = {}, std::string_view name = {},
std::uint64_t alignment = kPageSize);
std::pair<rx::AddressRange, ErrorCode>
commitPooled(Process *process, rx::AddressRange addressRange, MemoryType type,
rx::EnumBitSet<Protection> prot);
ErrorCode decommitPooled(Process *process, rx::AddressRange addressRange);
ErrorCode protect(Process *process, rx::AddressRange range,
rx::EnumBitSet<Protection> prot);
ErrorCode unmap(Process *process, rx::AddressRange range);
ErrorCode setName(Process *process, rx::AddressRange range,
std::string_view name);
std::optional<QueryResult> query(Process *process, std::uint64_t address);
ErrorCode setType(Process *process, rx::AddressRange range, MemoryType type);
ErrorCode setTypeAndProtect(Process *process, rx::AddressRange range,
MemoryType type, rx::EnumBitSet<Protection> prot);
std::optional<QueryResult> query(Process *process, std::uint64_t address,
bool lowerBound = false);
std::optional<MemoryProtection> queryProtection(Process *process,
std::uint64_t address);
} // namespace vmem
} // namespace orbis
std::uint64_t address,
bool lowerBound = false);
} // namespace orbis::vmem