Files
PS5_RetroArch/tests/test_core_imports.py
T
MihawkandClaude Opus 5.5 564d5555e4 Rebuild PPSSPP from v1.20.4 on the Vulkan renderer: God of War boots
The core is rebuilt from the v1.20.4 release as one patch
(patches/ppsspp/ps5-port.patch; tools/build-ppsspp.sh, PPSSPP_DEV=1 builds
the tree as it stands). Vulkan through the frontend's device (no GL, no
GLEW), the x86-64 JIT, and FFmpeg 3.0.2 cross-built from the tree's own
submodule for video. In the core: executable memory is mapped read-write
then made executable (the console's working order), guest memory is an
anonymous shared object mapped into a 4 GiB reserved range at
0x6_0000_0000 (outside the GPU's window at high word 2), the fault
handler reads the console's machine context six words past the SDK
header's, and the libretro surface path is VK_KHR_display.

In the title, what a core needs that the console did not give it:
- core thread creation and thread-specific data go through title frames
  (src/core_threads_ps5.cpp): libkernel resolves the caller to a module
  and faults on the core's anonymous mapping. Core threads get a 2 MiB
  minimum stack (glslang's parser overflowed the default).
- a core allocates from an overflow heap in direct memory first
  (src/overflow_heap.c, dlmalloc 2.8.6 MIT, 32-byte aligned as the
  target's default new alignment): PPSSPP filled libc's small heap, after
  which libkernel's own condition variables and sceAgcInit failed.
- gmtime_r and arc4random shims (src/libc_shims.c).
- a crash report in trace.txt (rip, rsp, return address, stack words).
- patch 0087: the log file is line-buffered, so a fault keeps its lines.

Console: GoW boots, loads, plays its intro video and menu and renders its
real-time intro cutscene correctly at 60 FPS content; the menu's
background still renders wrong (driver depth sampling is the lead).
Driver ../PS5_Vulkan 8d61168. verify.sh PASS (patch count 193 -> 194).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 22:52:08 -04:00

42 lines
2.1 KiB
Python

"""Multiple cores share bindings without losing object imports or adapters."""
import importlib.util
from pathlib import Path
import unittest
from unittest.mock import patch
ROOT = Path(__file__).resolve().parent.parent
spec = importlib.util.spec_from_file_location('core_imports', ROOT / 'tools/core-imports.py')
imports = importlib.util.module_from_spec(spec)
spec.loader.exec_module(imports)
class CoreImports(unittest.TestCase):
def test_union_deduplicates_and_preserves_runtime_adapters(self):
first = '''1: 00000000 0 FUNC GLOBAL DEFAULT UND malloc
2: 00000000 0 OBJECT GLOBAL DEFAULT UND __isthreaded
3: 00000000 0 FUNC GLOBAL DEFAULT UND opendir'''
second = '''1: 00000000 0 FUNC GLOBAL DEFAULT UND malloc
2: 00000000 0 NOTYPE GLOBAL DEFAULT UND localtime_r
3: 00000000 0 FUNC GLOBAL DEFAULT UND rewinddir'''
with patch.object(imports.subprocess, 'check_output', side_effect=[first, second]):
collected = imports.collect_imports(['one.so', 'two.so'])
self.assertEqual(len(collected), 5)
generated = imports.generate(collected)
# A core's malloc is the title's overflow-first allocator (src/memory_ps5.cpp).
self.assertEqual(generated.count('asm("ps5_core_malloc")'), 1)
self.assertIn('[] asm("__isthreaded")', generated)
self.assertIn('asm("rtime_localtime")', generated)
self.assertIn('asm("ps5_rewinddir")', generated)
self.assertIn('asm("ps5_opendir")', generated)
def test_reject_conflicting_types_and_tls(self):
with patch.object(imports.subprocess, 'check_output', side_effect=[
'1: 0 0 FUNC GLOBAL DEFAULT UND symbol',
'1: 0 0 OBJECT GLOBAL DEFAULT UND symbol']):
with self.assertRaisesRegex(ValueError, 'Conflicting'):
imports.collect_imports(['one.so', 'two.so'])
with patch.object(imports.subprocess, 'check_output', return_value=
'1: 0 0 TLS GLOBAL DEFAULT UND variable'):
with self.assertRaisesRegex(ValueError, 'Unsupported'):
imports.collect_imports(['tls.so'])