Skip to content

Commit

Permalink
mem: Improve accuracy of virtual memory
Browse files Browse the repository at this point in the history
  • Loading branch information
Macdu committed Nov 1, 2023
1 parent 784f55e commit cbc16a0
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 20 deletions.
8 changes: 5 additions & 3 deletions vita3k/mem/include/mem/functions.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ struct MemState;

typedef std::function<bool(uint8_t *addr, bool write)> AccessViolationHandler;

constexpr Address user_main_memory_start = 0x80000000U;

// Permission when protecting a memory range
// Note: WriteOnly is actually not supported (ReadWrite used instead)
enum struct MemPerm {
Expand All @@ -34,8 +36,8 @@ enum struct MemPerm {
};

bool init(MemState &state, const bool use_page_table);
Address alloc(MemState &state, uint32_t size, const char *name);
Address alloc(MemState &state, uint32_t size, const char *name, unsigned int alignment);
Address alloc(MemState &state, uint32_t size, const char *name, Address start_addr = user_main_memory_start);
Address alloc_aligned(MemState &state, uint32_t size, const char *name, unsigned int alignment, Address start_addr = user_main_memory_start);
void protect_inner(MemState &state, Address addr, uint32_t size, const MemPerm perm);
void unprotect_inner(MemState &state, Address addr, uint32_t size);
bool add_protect(MemState &state, Address addr, const uint32_t size, const MemPerm perm, ProtectCallback callback);
Expand All @@ -47,7 +49,7 @@ bool is_protecting(MemState &state, Address addr, MemPerm *perm = nullptr);
bool is_valid_addr(const MemState &state, Address addr);
bool is_valid_addr_range(const MemState &state, Address start, Address end);
bool handle_access_violation(MemState &state, uint8_t *addr, bool write) noexcept;
Block alloc_block(MemState &mem, uint32_t size, const char *name);
Block alloc_block(MemState &mem, uint32_t size, const char *name, Address start_addr = user_main_memory_start);
Address alloc_at(MemState &state, Address address, uint32_t size, const char *name);
Address try_alloc_at(MemState &state, Address address, uint32_t size, const char *name);
void free(MemState &state, Address address);
Expand Down
12 changes: 6 additions & 6 deletions vita3k/mem/src/mem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -191,13 +191,13 @@ static Address alloc_inner(MemState &state, uint32_t start_page, int page_count,
return addr;
}

Address alloc(MemState &state, uint32_t size, const char *name, unsigned int alignment) {
Address alloc_aligned(MemState &state, uint32_t size, const char *name, unsigned int alignment, Address start_addr) {
if (alignment == 0)
return alloc(state, size, name);
const std::lock_guard<std::mutex> lock(state.generation_mutex);
size += alignment;
const uint32_t page_count = align(size, state.page_size) / state.page_size;
const Address addr = alloc_inner(state, 0, page_count, name, false);
const Address addr = alloc_inner(state, start_addr / state.page_size, page_count, name, false);
const Address align_addr = align(addr, alignment);
const uint32_t page_num = addr / state.page_size;
const uint32_t align_page_num = align_addr / state.page_size;
Expand Down Expand Up @@ -490,10 +490,10 @@ void remove_external_mapping(MemState &mem, uint8_t *addr_ptr) {
}
}

Address alloc(MemState &state, uint32_t size, const char *name) {
Address alloc(MemState &state, uint32_t size, const char *name, Address start_addr) {
const std::lock_guard<std::mutex> lock(state.generation_mutex);
const uint32_t page_count = align(size, state.page_size) / state.page_size;
const Address addr = alloc_inner(state, 0, page_count, name, false);
const Address addr = alloc_inner(state, start_addr / state.page_size, page_count, name, false);
return addr;
}

Expand All @@ -517,8 +517,8 @@ Address try_alloc_at(MemState &state, Address address, uint32_t size, const char
return address;
}

Block alloc_block(MemState &mem, uint32_t size, const char *name) {
const Address address = alloc(mem, size, name);
Block alloc_block(MemState &mem, uint32_t size, const char *name, Address start_addr) {
const Address address = alloc(mem, size, name, start_addr);
return Block(address, [&mem](Address stack) {
free(mem, stack);
});
Expand Down
5 changes: 1 addition & 4 deletions vita3k/modules/SceLibc/SceLibc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -837,10 +837,7 @@ EXPORT(int, mbtowc) {

EXPORT(Ptr<void>, memalign, uint32_t alignment, uint32_t size) {
TRACY_FUNC(memalign, alignment, size);
Address address = alloc(emuenv.mem, size, "memalign", alignment);

STUBBED("No actual alignment.");
LOG_WARN_IF(address % alignment != 0, "Address {} does not fit alignment of {}.", log_hex(address), alignment);
Address address = alloc_aligned(emuenv.mem, size, "memalign", alignment);

return Ptr<void>(address);
}
Expand Down
30 changes: 23 additions & 7 deletions vita3k/modules/SceSysmem/SceSysmem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,7 @@ EXPORT(SceUID, sceKernelAllocMemBlock, const char *pName, SceKernelMemBlockType
case SCE_KERNEL_MEMBLOCK_TYPE_USER_RX:
case SCE_KERNEL_MEMBLOCK_TYPE_USER_RW:
case SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE:
// should only be 4K, but Freedom War crashes if the alignment is less than 32K...
min_alignment = 0x8000;
min_alignment = 0x1000;
break;
case SCE_KERNEL_MEMBLOCK_TYPE_USER_CDRAM_RW:
min_alignment = 0x40000;
Expand All @@ -113,18 +112,35 @@ EXPORT(SceUID, sceKernelAllocMemBlock, const char *pName, SceKernelMemBlockType

SceSize alignment = min_alignment;
if (optp && (optp->attr & SCE_KERNEL_ALLOC_MEMBLOCK_ATTR_HAS_ALIGNMENT)) {
alignment = optp->alignment;
// alignment must be a power of 2
// it should also be at least min_alignment but it looks like it is not the case in games like uncharted
// and the ps vita does not return an error
if (alignment & (alignment - 1))
if (optp->alignment & (optp->alignment - 1))
return RET_ERROR(SCE_KERNEL_ERROR_INVALID_ARGUMENT);

alignment = std::max(alignment, optp->alignment);
}

// x & -x returns the lsb of x
alignment = std::max(alignment, size & -size);

// https://wiki.henkaku.xyz/vita/SceSysmem_Types#memtype_bit_value
Address start_address;
switch (type) {
case SCE_KERNEL_MEMBLOCK_TYPE_USER_MAIN_PHYCONT_NC_RW:
start_address = 0x70000000U;
break;
case SCE_KERNEL_MEMBLOCK_TYPE_USER_CDRAM_RW:
start_address = 0x60000000U;
break;
default:
// technically should be 0x81000000 but it shouldn't make a difference
start_address = 0x80000000U;
break;
}

const auto state = emuenv.kernel.obj_store.get<SysmemState>();
const auto guard = std::lock_guard<std::mutex>(state->mutex);

Ptr<void> address = Ptr<void>(alloc(mem, size, pName, alignment));
Ptr<void> address = Ptr<void>(alloc_aligned(mem, size, pName, alignment, start_address));

if (!address) {
return RET_ERROR(SCE_KERNEL_ERROR_NO_MEMORY);
Expand Down

0 comments on commit cbc16a0

Please sign in to comment.