flexible address in mmap

This commit is contained in:
AlpinDale 2025-12-09 00:33:28 +04:30
parent 513bc203df
commit 1c0617146c

View File

@ -532,56 +532,41 @@ struct AddressSpace::Impl {
user_base = reinterpret_cast<u8*>(
mmap(reinterpret_cast<void*>(USER_MIN), user_size, protection_flags, map_flags, -1, 0));
#elif defined(ARCH_ARM64)
// On ARM64 macOS, MAP_FIXED may not work at these addresses due to system restrictions.
// We need these exact addresses for the PS4 memory layout, so we try multiple approaches.
int map_flags_fixed = MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE | MAP_FIXED;
// On ARM64 macOS, MAP_FIXED doesn't work at low addresses (0x400000) due to system restrictions.
// Map memory wherever possible and use offset calculations. This is a temporary solution
// until proper address translation is implemented for ARM64.
// Note: This means the PS4 virtual addresses won't match host addresses, so instruction
// translation/JIT will need to handle the offset.
constexpr int map_flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE;
// Map the three regions separately, but let the system choose addresses
system_managed_base =
reinterpret_cast<u8*>(mmap(reinterpret_cast<void*>(SYSTEM_MANAGED_MIN),
system_managed_size, protection_flags, map_flags_fixed, -1, 0));
reinterpret_cast<u8*>(mmap(nullptr, system_managed_size, protection_flags, map_flags, -1, 0));
if (system_managed_base == MAP_FAILED) {
// Try without MAP_NORESERVE
int map_flags_noreserve = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED;
system_managed_base =
reinterpret_cast<u8*>(mmap(reinterpret_cast<void*>(SYSTEM_MANAGED_MIN),
system_managed_size, protection_flags, map_flags_noreserve, -1, 0));
if (system_managed_base == MAP_FAILED) {
LOG_CRITICAL(Kernel_Vmm, "mmap failed for system_managed_base at {}: {}. "
"ARM64 macOS does not allow mapping at address 0x400000. "
"The PS4 memory layout requires exact addresses. "
"Consider using x86_64 mode or implementing address translation for ARM64.",
fmt::ptr(reinterpret_cast<void*>(SYSTEM_MANAGED_MIN)), strerror(errno));
throw std::bad_alloc{};
}
LOG_CRITICAL(Kernel_Vmm, "mmap failed for system_managed_base: {}", strerror(errno));
throw std::bad_alloc{};
}
system_reserved_base =
reinterpret_cast<u8*>(mmap(reinterpret_cast<void*>(SYSTEM_RESERVED_MIN),
system_reserved_size, protection_flags, map_flags_fixed, -1, 0));
reinterpret_cast<u8*>(mmap(nullptr, system_reserved_size, protection_flags, map_flags, -1, 0));
if (system_reserved_base == MAP_FAILED) {
int map_flags_noreserve = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED;
system_reserved_base =
reinterpret_cast<u8*>(mmap(reinterpret_cast<void*>(SYSTEM_RESERVED_MIN),
system_reserved_size, protection_flags, map_flags_noreserve, -1, 0));
if (system_reserved_base == MAP_FAILED) {
LOG_CRITICAL(Kernel_Vmm, "mmap failed for system_reserved_base at {}: {}",
fmt::ptr(reinterpret_cast<void*>(SYSTEM_RESERVED_MIN)), strerror(errno));
throw std::bad_alloc{};
}
LOG_CRITICAL(Kernel_Vmm, "mmap failed for system_reserved_base: {}", strerror(errno));
throw std::bad_alloc{};
}
user_base = reinterpret_cast<u8*>(
mmap(reinterpret_cast<void*>(USER_MIN), user_size, protection_flags, map_flags_fixed, -1, 0));
mmap(nullptr, user_size, protection_flags, map_flags, -1, 0));
if (user_base == MAP_FAILED) {
int map_flags_noreserve = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED;
user_base = reinterpret_cast<u8*>(
mmap(reinterpret_cast<void*>(USER_MIN), user_size, protection_flags, map_flags_noreserve, -1, 0));
if (user_base == MAP_FAILED) {
LOG_CRITICAL(Kernel_Vmm, "mmap failed for user_base at {}: {}",
fmt::ptr(reinterpret_cast<void*>(USER_MIN)), strerror(errno));
throw std::bad_alloc{};
}
LOG_CRITICAL(Kernel_Vmm, "mmap failed for user_base: {}", strerror(errno));
throw std::bad_alloc{};
}
LOG_WARNING(Kernel_Vmm, "ARM64 macOS: Using flexible memory layout. "
"PS4 addresses will be offset from host addresses. "
"system_managed: {} (expected {}), system_reserved: {} (expected {}), user: {} (expected {})",
fmt::ptr(system_managed_base), fmt::ptr(reinterpret_cast<void*>(SYSTEM_MANAGED_MIN)),
fmt::ptr(system_reserved_base), fmt::ptr(reinterpret_cast<void*>(SYSTEM_RESERVED_MIN)),
fmt::ptr(user_base), fmt::ptr(reinterpret_cast<void*>(USER_MIN)));
#endif
#else
const auto virtual_size = system_managed_size + system_reserved_size + user_size;
@ -618,7 +603,7 @@ struct AddressSpace::Impl {
fmt::ptr(user_base + user_size - 1));
const VAddr system_managed_addr = reinterpret_cast<VAddr>(system_managed_base);
const VAddr system_reserved_addr = reinterpret_cast<VAddr>(system_managed_base);
const VAddr system_reserved_addr = reinterpret_cast<VAddr>(system_reserved_base);
const VAddr user_addr = reinterpret_cast<VAddr>(user_base);
m_free_regions.insert({system_managed_addr, system_managed_addr + system_managed_size});
m_free_regions.insert({system_reserved_addr, system_reserved_addr + system_reserved_size});