shadPS4/src/core/memory.h

129 lines
3.1 KiB
C
Raw Normal View History

// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <string_view>
#include <vector>
#include <boost/icl/split_interval_map.hpp>
#include "common/enum.h"
#include "common/singleton.h"
#include "common/types.h"
#include "core/address_space.h"
namespace Core {
enum class MemoryProt : u32 {
NoAccess = 0,
CpuRead = 1,
CpuReadWrite = 2,
GpuRead = 16,
GpuWrite = 32,
GpuReadWrite = 38,
};
enum class MemoryMapFlags : u32 {
NoFlags = 0,
Fixed = 0x10,
NoOverwrite = 0x0080,
NoCoalesce = 0x400000,
};
DECLARE_ENUM_FLAG_OPERATORS(MemoryMapFlags)
enum class VMAType : u32 {
Free = 0,
Reserved = 1,
Direct = 2,
Flexible = 3,
Pooled = 4,
Stack = 5,
};
struct DirectMemoryArea {
PAddr base = 0;
size_t size = 0;
int memory_type = 0;
};
struct VirtualMemoryArea {
VAddr base = 0;
size_t size = 0;
PAddr phys_base = 0;
VMAType type = VMAType::Free;
MemoryProt prot = MemoryProt::NoAccess;
bool disallow_merge = false;
std::string name = "";
bool CanMergeWith(const VirtualMemoryArea& next) const {
if (disallow_merge || next.disallow_merge) {
return false;
}
if (base + size != next.base) {
return false;
}
if (type == VMAType::Direct && phys_base + size != next.phys_base) {
return false;
}
if (prot != next.prot || type != next.type) {
return false;
}
return true;
}
};
constexpr VAddr SYSTEM_RESERVED = 0x800000000u;
constexpr VAddr CODE_BASE_OFFSET = 0x100000000u;
constexpr VAddr SYSTEM_MANAGED_MIN = 0x0000040000u;
constexpr VAddr SYSTEM_MANAGED_MAX = 0x07FFFFBFFFu;
constexpr VAddr USER_MIN = 0x1000000000u;
constexpr VAddr USER_MAX = 0xFBFFFFFFFFu;
class MemoryManager {
using VMAMap = std::map<VAddr, VirtualMemoryArea>;
using VMAHandle = VMAMap::iterator;
public:
explicit MemoryManager();
~MemoryManager();
PAddr Allocate(PAddr search_start, PAddr search_end, size_t size, u64 alignment,
int memory_type);
void Free(PAddr phys_addr, size_t size);
int MapMemory(void** out_addr, VAddr virtual_addr, size_t size, MemoryProt prot,
MemoryMapFlags flags, VMAType type, std::string_view name = "",
PAddr phys_addr = 0, u64 alignment = 0);
void UnmapMemory(VAddr virtual_addr, size_t size);
private:
bool HasOverlap(VAddr addr, size_t size) const {
return vma_map.find(addr) != vma_map.end();
}
VMAHandle FindVMA(VAddr target) {
// Return first the VMA with base >= target.
const auto it = vma_map.lower_bound(target);
if (it->first == target) {
return it;
}
return std::prev(it);
}
VirtualMemoryArea& AddMapping(VAddr virtual_addr, size_t size);
VMAHandle Split(VMAHandle vma_handle, u32 offset_in_vma);
VMAHandle MergeAdjacent(VMAHandle iter);
private:
AddressSpace impl;
std::vector<DirectMemoryArea> allocations;
VMAMap vma_map;
};
using Memory = Common::Singleton<MemoryManager>;
} // namespace Core