mirror of
https://github.com/SpeedBreakerProject/speedbreaker.git
synced 2026-10-18 02:01:24 +02:00
Co-authored-by: Lydacious <81742991+lydacious@users.noreply.github.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
106 lines
5.3 KiB
C++
106 lines
5.3 KiB
C++
// SpeedBreaker runtime. GPL-3.0-or-later (see COPYING).
|
|
//
|
|
// Whether the game got the memory it needs, and what to tell the player when
|
|
// it didn't. The recompiled code addresses guest memory as base + a 32-bit
|
|
// guest address, so the game needs one contiguous 4 GB of host address space
|
|
// (kernel/memory.cpp), with the 360's 512 MB of physical memory mapped three
|
|
// times inside it (0xA0000000, 0xC0000000, 0xE0000000). There is no smaller
|
|
// layout: the game's heaps reach 0x7EFFFFFF, its image sits at 0x82000000 and
|
|
// the three physical windows end at 0xFFFFFFFF.
|
|
//
|
|
// iOS limits an app's address space to 17.4 GB on a device with more than
|
|
// 3 GB of memory, about 5 GB of it free in one piece above the system's
|
|
// shared region, unless it has Extended Virtual Addressing (then the 4 GB
|
|
// lands at 0x7000000000) or Increased Memory Limit on a device that supports
|
|
// it (63 GB since iOS 16: xnu's kern_exec.c). Increased Memory Limit also
|
|
// raises the memory limit (about 3.3 GB -> 6 GB on an 8 GB iPhone), which the
|
|
// game's peak footprint (about 2.5-3 GB, scripts/ios/README.md, "Memory")
|
|
// needs on smaller devices. scripts/ios/SpeedBreaker/SpeedBreaker.entitlements
|
|
// asks for both. A sideloaded copy (the IPA, scripts/ios/make_ipa.sh) is
|
|
// re-signed with the player's own Apple Account: a free one never gets
|
|
// Extended Virtual Addressing, and keeps Increased Memory Limit only with
|
|
// some tools. When the 4 GB can't be had the game can't start: main.cpp shows
|
|
// StartupFailure() on screen instead of quitting. With a low memory limit it
|
|
// starts, and LowMemoryNotice() says iOS may close it.
|
|
//
|
|
// Everything here is pure (tests/memory_status_test.cpp) except Gather(),
|
|
// which reads the device.
|
|
#pragma once
|
|
#include <cstdint>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
namespace memstatus
|
|
{
|
|
// Which step of Memory::Memory() failed (kernel/memory.h: failedStep).
|
|
enum class Failure : uint8_t { None, AddressSpace, PhysicalMemory };
|
|
|
|
// From the app's own code signature (platform/code_signature.h):
|
|
// Unknown when it couldn't be read (or isn't iOS's concern).
|
|
enum class Flag : uint8_t { Unknown, No, Yes };
|
|
|
|
struct Status
|
|
{
|
|
Failure failure = Failure::None;
|
|
int error = 0; // errno for the reservation, a kern_return_t for the mirrors
|
|
std::string errorText; // strerror / mach_error_string
|
|
uint64_t base = 0; // host address of the guest's 4 GB (0: none)
|
|
Flag extendedVirtualAddressing = Flag::Unknown;
|
|
Flag increasedMemoryLimit = Flag::Unknown;
|
|
bool signatureRead = false; // the entitlements above come from the signature
|
|
int64_t memoryLimitMB = -1; // iOS: footprint + os_proc_available_memory() at startup; -1 unknown
|
|
// iOS: the top of the app's address space (task_vm_info's
|
|
// max_address), which shows whether the entitlements took effect:
|
|
// 0xFC0000000 (63 GB) or more with them, 0x458000000 (17.4 GB)
|
|
// without on a device with more than 3 GB; 0 unknown.
|
|
uint64_t addressSpaceTop = 0;
|
|
bool ios = false;
|
|
};
|
|
|
|
// The game's peak memory footprint with room to spare (measured 2.2 GB
|
|
// in a race at 1x on a Mac, about 2.5 GB expected in an iPhone's free
|
|
// roam: scripts/ios/README.md, "Memory"): below this limit iOS may
|
|
// close the game in a busy scene.
|
|
constexpr int64_t kPeakFootprintMB = 3072;
|
|
// An address space that ends below this (MACH_VM_JUMBO_ADDRESS, 63 GB)
|
|
// is iOS's default one: neither entitlement took effect, and the game's
|
|
// 4 GB plus the 3 GB or so it needs besides (the graphics driver's,
|
|
// its heaps) must fit in the 7 GB or so iOS leaves an app.
|
|
constexpr uint64_t kLargeAddressSpace = 0xFC0000000;
|
|
|
|
// The log's line: "[memory] guest 4 GB at 0x7000000000; ...".
|
|
std::string LogLine(const Status& status);
|
|
|
|
// The system summary's Memory item (the same facts, without the prefix).
|
|
std::string SummaryItem(const Status& status);
|
|
|
|
struct Message
|
|
{
|
|
std::string title;
|
|
std::vector<std::string> paragraphs; // the first says what happened, the rest what to do
|
|
std::string details; // small print: the error and the entitlements
|
|
};
|
|
// What the player sees when the game can't start (failure != None).
|
|
Message StartupFailure(const Status& status);
|
|
|
|
// A one-line notice (a toast) when the game started but iOS may close
|
|
// it: iOS's default address space (below kLargeAddressSpace), or a
|
|
// memory limit below kPeakFootprintMB. "" otherwise (and off iOS).
|
|
std::string LowMemoryNotice(const Status& status);
|
|
|
|
// The device's side (iOS): the entitlements from the app's signature,
|
|
// the memory limit and the address space's top; elsewhere only the
|
|
// error's text (NFSMW_TEST_MEMORY_IOS=1: the iOS wording); `base`, the
|
|
// failure and its error come from g_memory. Main thread, once, early.
|
|
void Gather(Status& status);
|
|
|
|
// iOS, main thread, every frame (video::RunFrame): once a minute a log
|
|
// line with the app's memory footprint, its peak and what is left before
|
|
// iOS's limit ("[memory] footprint 2410 MB, peak 2511 MB, 3626 MB left"),
|
|
// so a log cut short by iOS closing the game shows how close it was.
|
|
// Nothing elsewhere.
|
|
void Poll();
|
|
|
|
const char* FlagName(Flag flag); // "yes", "no", "unknown"
|
|
}
|