RPCS3: realpath from the platform layer; SDK 8160289

A title's realpath answers EPERM, even for /app0, so RPCS3's package installer
could not normalise its installation path (std::filesystem's canonical paths
are built on realpath). The title and the cores now bind realpath to
ps5_realpath (SDK 8160289).
This commit is contained in:
Mihawk committed 2026-09-28 21:51:54 -04:00
1 parent a790fb15f5
commit 9cfdbe9c7a
6 files changed
+28 -6

No files matched your search

+7 -1
View File
@@ -425,7 +425,7 @@ unloaded, so the next load finds its addresses free.
handler it replaced (the title's crash reporter), and the title's handlers
return when the core is unloaded.
**Platform gaps closed in the SDK (a9fbb6a).** Each is aliased in
**Platform gaps closed in the SDK (8160289).** Each is aliased in
`tools/core-imports.py`.
- No export at all: `accept4`, `getpagesizes`, `in6addr_any`.
@@ -437,6 +437,12 @@ return when the core is unloaded.
- Answered differently on the console: `pthread_getaffinity_np` and
`pthread_setaffinity_np` (the 64-bit mask), `sysconf` (13 CPUs, not 16),
`pthread_exit` (a thread's `thread_local` destructors first).
- Refused: `realpath` answers EPERM, even for `/app0`, so libc++'s
`std::filesystem::canonical` and `weakly_canonical` came back empty and the
package installer could not normalise its path. `ps5_realpath` makes the path
absolute, resolves `.` and `..` by name and checks each component with
`stat`; it keeps a symbolic link's name. The title links it too
(`--wrap=realpath`).
- Memory: committed ranges (`ps5_vrange_commit`), exact reservations, zeroing
of reused direct memory, and placement up to 1 TiB.
+7
View File
@@ -45,6 +45,13 @@ DIR *__wrap_fdopendir(int fd)
return ps5_fdopendir(fd);
}
/* A title's realpath is refused (EPERM); libc++'s std::filesystem canonical
* paths are built on it. */
char *__wrap_realpath(const char *path, char *resolved)
{
return ps5_realpath(path, resolved);
}
DIR *__wrap_opendir(const char *path)
{
return ps5_opendir(path);
+7 -3
View File
@@ -29,16 +29,20 @@ class CoreImports(unittest.TestCase):
self.assertIn('asm("ps5_rewinddir")', generated)
self.assertIn('asm("ps5_opendir")', generated)
def test_aligned_new_and_getcwd_bind_to_the_title(self):
def test_aligned_new_getcwd_and_realpath_bind_to_the_title(self):
# Over-aligned operator new comes from direct memory, as plain new does,
# and getcwd from the platform layer (libc's faults for a title).
# and getcwd and realpath from the platform layer (libc's fault or are
# refused for a title).
generated = imports.generate({'_ZnwmSt11align_val_t': ('FUNC', False),
'_ZnamSt11align_val_t': ('FUNC', False),
'_ZnwmSt11align_val_tRKSt9nothrow_t': ('FUNC', False),
'getcwd': ('FUNC', False)})
'getcwd': ('FUNC', False),
'realpath': ('FUNC', False)})
self.assertIn('asm("ps5_core_new_aligned")', generated)
self.assertIn('asm("ps5_core_new_aligned_nothrow")', generated)
self.assertIn('asm("ps5_getcwd")', generated)
self.assertIn('asm("ps5_realpath")', generated)
self.assertNotIn('asm("realpath")', generated)
self.assertNotIn('asm("_ZnwmSt11align_val_t")', generated)
def test_weak_only_when_every_core_imports_weakly(self):
+3
View File
@@ -274,6 +274,9 @@ PY
# payload SDK fork), and src/platform_wraps.c binds these links to it. A core's
# own imports of the same calls are bound to it by tools/core-imports.py.
directory_wrap_flags="--wrap=opendir --wrap=readdir --wrap=closedir --wrap=fdopendir --wrap=openat --wrap=unlinkat --wrap=fchmodat"
# realpath is refused to a title, so std::filesystem::canonical and
# weakly_canonical (RPCS3's package installer) came back empty.
directory_wrap_flags+=" --wrap=realpath"
# Folders the title or a core creates are 0777 and files at least 0666, so FTP,
# which runs as another user, can reach them (src/permissions_ps5.cpp).
directory_wrap_flags+=" --wrap=mkdir --wrap=open --wrap=fopen"
+3 -1
View File
@@ -98,7 +98,9 @@ def generate(imports):
# src/core_loader_ps5.cpp: the console's, plus dlopen(NULL), the
# process handle LLVM's JIT asks for.
'dlopen': 'ps5_cores_dlopen', 'dlsym': 'ps5_cores_dlsym',
'dlclose': 'ps5_cores_dlclose', 'dlerror': 'ps5_cores_dlerror'}
'dlclose': 'ps5_cores_dlclose', 'dlerror': 'ps5_cores_dlerror',
# Refused to a title (EPERM), even for /app0.
'realpath': 'ps5_realpath'}
for index, (name, (kind, weak)) in enumerate(sorted(imports.items())):
target = aliases.get(name, name)
declaration = f'void core_import_{index}()' if kind == 'FUNC' else f'char core_import_{index}[]'
+1 -1
View File
@@ -23,7 +23,7 @@ zlib_stamp="$zlib_root/.source-version"
# there). The pinned revision is exported with git archive, so a build never
# depends on the fork's working tree, and the SDK directory records it.
sdk_fork="${PS5_PAYLOAD_SDK_FORK:-$root/../PS5_PayloadSDK}"
sdk_revision=a9fbb6a9c9c67567ef5561c74075ce5e2ee9b21b
sdk_revision=8160289a132263853f4c7cff542d9d6edc0c7c12
zlib_url="https://zlib.net/fossils/zlib-$zlib_version.tar.gz"
zlib_hash="bb329a0a2cd0274d05519d61c667c062e06990d72e125ee2dfa8de64f0119d16"
skip_sdk=false