Compare commits

...
162 Commits
Author SHA1 Message Date
John Törnblom f5d40f0277 toolchain: set meson host_machine to freebsd (x86_64) 2026-10-10 13:18:44 +02:00
John Törnblom 1a04f75407 sce_stubs: add libSceAgc and libSceAgcDriver 2026-10-10 13:05:44 +02:00
MihawkandClaude Opus 5.5 10b539de8f include: replace the include_common link when installing over an SDK
ln -sf follows an existing link to a directory and creates the new link
inside it; -n replaces the link itself, so installing over a release
leaves the tree as a fresh install would.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 08:27:12 +02:00
John Törnblom f7fd02e6e1 add support for llvm-23 2026-09-23 22:43:31 +02:00
John Törnblom b4fcb924d6 pkg-config: improve compatibility with pkgconf-3 2026-09-23 22:38:40 +02:00
John Törnblom 3b6ea8044e libc: add killpg() 2026-09-03 20:52:10 +02:00
John Törnblom d9c9519116 crt: make payload_args->payloadout optional 2026-08-29 15:42:29 +02:00
John Törnblom 66daf51afe crt: add kernel_iommu_copyin() and some convenience functions for it 2026-08-29 13:35:04 +02:00
John Törnblom 4b86c73ab7 crt: derive iommu softc kernel address 2026-08-29 12:44:29 +02:00
John Törnblom f89a100c89 cosmetics 2026-08-29 11:59:30 +02:00
John Törnblom 8e125899b1 crt: add stubs for writing qa flags via iommu commands 2026-08-28 19:50:31 +02:00
Gezine 4eb701204f add support for firmware 13.60 2026-08-02 18:28:44 +02:00
John Törnblom 9d267a83fa crt: make sure stack is aligned (and restored on exit) 2026-08-02 17:12:35 +02:00
John Törnblom a9e742489a crt: fix potential bug in designated initializers with union members 2026-08-02 16:08:19 +02:00
John Törnblom a0d2bc60bd cosmetics 2026-07-04 00:02:52 +02:00
John Törnblom 558d2f5669 cosmetics 2026-07-03 23:45:06 +02:00
John Törnblom 4460639b2d cosmetics 2026-07-03 23:32:45 +02:00
John Törnblom 4e88ed694c cosmetics 2026-07-03 23:31:26 +02:00
John Törnblom 6d0cc823be cosmetics 2026-07-03 23:18:05 +02:00
illusiony 45fca06f9a add comment for reserved 0 write 2026-07-03 21:38:52 +02:00
illusionyandidlesauce 5184bcdfb4 crt: fix kernel rw opreations
- fixes writing at kernel address ending with `0xff` (see ps5-payload-dev/sdk issue 56)

Co-Authored-By: idlesauce <148508202+idlesauce@users.noreply.github.com>
2026-07-03 21:38:52 +02:00
John Törnblom c68b1b56ae kernel_virt2phys: fix overflow in page table hierarchy traversal 2026-07-02 23:28:02 +02:00
John Törnblom 2e6fab5042 crt: align the internal declaration of KERNEL_OFFSET_PROC_P_VMSPACE 2026-07-01 21:22:39 +02:00
John Törnblom 92320fbaef crt: add kernel procio functions that operate on pmap entries when mdbg is unavailable 2026-07-01 21:14:36 +02:00
Gezine cf547b191d add support for firmware 13.42 2026-07-01 21:14:25 +02:00
John Törnblom 3f219cd64b cosmetics 2026-06-30 22:14:28 +02:00
John Törnblom 4eee7ac558 kernel: add KERNEL_OFFSET_VMSPACE_VM_PMAP 2026-06-30 22:12:58 +02:00
alex-free d2e2e58574 improve deps 2026-06-28 17:33:42 +02:00
John Törnblom 9478d2baaa cosmetics 2026-06-28 17:28:26 +02:00
John Törnblom d77b34f88a libc: add stubs for getgrnam_r and getgrgid_r 2026-06-28 17:28:18 +02:00
John Törnblom 7f30ee52cd cosmetics 2026-06-25 19:29:38 +02:00
John Törnblom 3bede94ff9 cosmetics 2026-06-25 19:28:24 +02:00
John Törnblom cfbc7307ac kernel: change prototype for kernel_<get/set>_ucred_attrs so more attrs are exposed via api 2026-06-25 18:49:49 +02:00
John Törnblom 5b73e745cb cosmetics 2026-06-21 22:13:14 +02:00
John Törnblom 091540e1b8 add support for llvm-22 2026-06-21 22:13:14 +02:00
alex-free 1aa6d5603e update readme to specify which commands require root privileges 2026-06-21 22:09:26 +02:00
John Törnblom 9fe9f78db6 cosmetics 2026-06-21 22:07:17 +02:00
John Törnblom 551f796331 cosmetics 2026-06-21 22:06:19 +02:00
John Törnblom f2e8f65dae cosmetics 2026-06-21 21:51:43 +02:00
Aleksei Kulaev c1e0b74f25 Fix program path issue during lld invocation 2026-06-21 21:31:42 +02:00
Aleksei Kulaev 12433ce900 Fix issue with ld from Homebrew on MacOS 2026-06-21 21:31:42 +02:00
Aleksei Kulaev 10d9163fe4 Deduplicate code in makefiles 2026-06-21 21:31:42 +02:00
John Törnblom 8ae0a9babf sce stubs: add sceFsCreatePprPfsSaveDataImage 2026-06-10 21:24:54 +02:00
John Törnblom 9e4b1ad764 cosmetics 2026-06-05 21:25:45 +02:00
John Törnblom 6ab211b319 cosmetics 2026-06-05 21:05:22 +02:00
illusiony 7b5caa9449 crt: obtain sdk version from libc 2026-06-05 20:56:16 +02:00
Gezine 28720cfb33 add support for firmware 13.40 2026-06-05 20:51:39 +02:00
John Törnblom 13ccc2d5bf cosmetics 2026-05-22 19:47:47 +02:00
John Törnblom 5f68a946af fix linking with libdl and libpthread 2026-05-22 19:35:03 +02:00
John Törnblom ed69baef16 cosmetics 2026-05-22 18:49:56 +02:00
John Törnblom acfd93595e sce_stubs: fixes 2026-05-21 23:42:04 +02:00
John Törnblom 6bd9c1b64f toolchain: improve support for objective-c 2026-05-19 22:28:10 +02:00
John Törnblom 84ccd42dda cosmetics 2026-05-17 14:49:13 +02:00
John Törnblom b710649800 crt: use kernel_get_ucred_prison to resolve KERNEL_ADDRESS_PRISON0 2026-05-13 20:19:41 +02:00
John Törnblom df0508f622 add kernel_get_ucred_prison() and kernel_set_ucred_prison() 2026-05-13 20:19:41 +02:00
illusiony 64e25e8359 CMake: add PAYLOAD_DEPLOY 2026-05-12 18:30:07 +02:00
Echo Stretch 8154f82118 Added Support For 13.00/13.20 2026-05-03 22:50:31 +02:00
John Törnblom 9e7b5f8cca libc: add getloadavg() 2026-04-18 13:22:40 +02:00
John Törnblom 8ba558e844 samples: add example for relocatable linking 2026-04-17 18:53:19 +02:00
rrooij d74499b738 Omit PIE when -r is present
The options are incompatible with each other. Ran into this
when cross compiling some projects.
2026-04-17 18:47:44 +02:00
John Törnblom 1bd0d7bac0 libc: add nftw() 2026-04-09 14:28:17 +02:00
Echo Stretch 5b6683374a Add 11.xx and 12.xx offsets 2026-04-01 05:15:18 +02:00
Echo Stretch 6ae1470fd5 Adjust KERNEL_ADDRESS_TEXT_BASE offsets 2026-03-21 22:11:42 +01:00
Echo Stretch 7dabc1bb17 Added 11.xx and 12.xx Offsets 2026-03-21 22:11:42 +01:00
ItsJokerZz 1c617cac43 Added Mono Stubs
Tested and working- if within the ShellUI obviously.
2026-03-08 14:47:55 +01:00
Echo Stretch cca4ba3605 Fix KERNEL_OFFSET_VMSPACE_P_ROOT value 2026-03-01 23:12:31 +01:00
John Törnblom 1da036ae2a libufs: initial commit 2026-02-23 19:09:52 +01:00
John Törnblom e103138794 stubs: add libSceFsInternalForVsh 2026-02-19 16:27:18 +01:00
John Törnblom b58c5d94a9 stubs: add libSceHttp 2026-02-19 16:26:42 +01:00
John Törnblom 8ecbe8f57f samples: add hello_argv 2026-02-13 19:02:29 +01:00
John Törnblom a967354f25 deploy: add support for URIs (file://, http:// and https://) 2026-02-12 23:06:13 +01:00
John Törnblom 9deeac8bba cosmetics 2026-02-02 23:23:54 +01:00
John Törnblom 87d19cde89 prospero-nid: implement in python to simplify binary distribution 2026-02-02 23:00:01 +01:00
John Törnblom 3485018172 cosmetics 2026-02-02 22:08:19 +01:00
John Törnblom 767cf36d1f add support for llvm-21 2026-02-01 14:12:47 +01:00
John Törnblom d4b272c980 cosmetics 2026-01-25 22:00:05 +01:00
John Törnblom 9f740c433d cosmetics 2026-01-25 22:00:05 +01:00
John Törnblom 06de6da302 kernel: set errno when some errors occurs 2026-01-25 22:00:05 +01:00
danilaltd b21bf9c7c5 stubs: add libSceGnmDriverForNeoMode 2026-01-24 15:36:34 +01:00
John Törnblom 48b3f5e838 rtld: add support for loading system sprx files when payload is jailed 2026-01-18 20:12:39 +01:00
John Törnblom dd333d3dcf cosmetics 2026-01-18 20:09:07 +01:00
John Törnblom c096b8c5fd locale: use freebsd struct for localeconv 2025-12-31 16:29:18 +01:00
John Törnblom 03f75ba291 crt: use syscall function specifically defined for the crt 2025-12-31 16:28:21 +01:00
John Törnblom 88dd7b045e samples: exemplify how to install fake SELFs to the ShellUI dashboard 2025-12-20 21:11:55 +01:00
John Törnblom 51f96a350a lld: fix compatibility with older versions of ld.lld 2025-12-20 16:46:18 +01:00
John Törnblom b8504c125b lld: allow overriding default linker script 2025-12-20 12:31:11 +01:00
John Törnblom 6541cd1754 lld: disable -pie when --static is used 2025-12-20 12:29:52 +01:00
John Törnblom 7428de204f example: add debug notification example 2025-12-15 21:16:30 +01:00
John Törnblom d15eb41dff cosmetics 2025-12-15 21:02:46 +01:00
LM da9c2e1372 fix spaceing 2025-12-15 20:56:20 +01:00
LM 7d99334e9f add json as a global 2025-12-15 20:56:20 +01:00
LM 75dbc643da Change json_payload to static and simplify usage 2025-12-15 20:56:20 +01:00
LM b47ec1352e Update Notify sample 2025-12-15 20:56:20 +01:00
John Törnblom 606319a30c rtld: change search order for dynlibs so cwd is considered last 2025-12-15 20:54:31 +01:00
John Törnblom 9d849ebff2 cosmetics 2025-12-15 20:51:49 +01:00
John Törnblom eab966fd2f add kernel_get_ucred_svgid() 2025-12-15 20:50:30 +01:00
John Törnblom 25ec960826 add kernel_get_ucred_rgid() 2025-12-15 20:50:05 +01:00
John Törnblom 7e3b4c4df9 add kernel_get_ucred_svuid() 2025-12-15 20:49:43 +01:00
John Törnblom f4917c8892 add kernel_get_ucred_ruid() 2025-12-15 20:49:12 +01:00
John Törnblom 4023167199 add kernel_get_ucred_uid() 2025-12-15 20:48:42 +01:00
John Törnblom 9f23c958eb libc: unlink file in tmpfile() 2025-11-18 16:11:34 +01:00
John Törnblom 494d9e0903 kernel: kernel_get_proc_thread() 2025-11-08 20:55:24 +01:00
John Törnblom 285951051f ci: fix typos 2025-10-18 14:53:57 +02:00
John Törnblom 70aa9b2d97 ci: cosmetics 2025-10-18 14:39:15 +02:00
John Törnblom a413a94455 ci: add macos target 2025-10-18 14:38:43 +02:00
John Törnblom b5e3004271 make a couple of shell scripts work on macos 2025-10-18 14:38:04 +02:00
John Törnblom e7080848f5 llvm-config: pass args to llvm-config if LLVM_CONFIG is set 2025-10-17 22:36:55 +02:00
John Törnblom 22f11be77d cosmetics 2025-10-17 21:59:04 +02:00
John Törnblom 4ee82db242 cosmetics 2025-10-17 21:49:15 +02:00
John Törnblom 9832162571 readme: update macos instructions 2025-10-17 21:41:43 +02:00
John Törnblom 1d92da40df libcxx: bump to version 18.1.8 2025-10-17 21:40:55 +02:00
John Törnblom f65522f4ab readme: cosmetics 2025-10-17 21:40:30 +02:00
John Törnblom 29501cbc48 readme: cosmetics 2025-10-17 21:35:00 +02:00
John Törnblom 81aade6f2b readme: use llvm-18 as prerequisites instead of llvm-15 2025-10-17 21:33:27 +02:00
John Törnblom e3a4673f40 cosmetics 2025-10-17 21:32:26 +02:00
John Törnblom e15b4741b0 cosmetics 2025-10-17 19:33:44 +02:00
John Törnblom 07ea97804c meson: improve shell compatibility 2025-10-17 18:56:42 +02:00
John Törnblom d915ad81e9 cosmetics 2025-10-17 18:55:48 +02:00
John Törnblom 7116a650a0 libc: set errno when mount, nmount and umount fails 2025-10-03 19:41:37 +02:00
buzzer-re 3b028e7139 fix cmake-bin-wrapper script for macOS shell, libcxx is compiled normally 2025-10-01 19:21:41 +02:00
buzzer-re 38e8b5b34a Add instructions for build on macOS (M* Chips) 2025-10-01 19:21:41 +02:00
Echo Stretch b79b6416e9 revert offset change 2025-09-15 12:06:21 +02:00
John Törnblom c028c11333 cosmetics 2025-08-30 18:08:01 +02:00
John Törnblom b080ed08f7 cosmetics 2025-08-30 18:00:34 +02:00
Echo Stretch 4780c3ddc9 Fixed 1.00 - 270 Offsets 2025-08-30 17:03:22 +02:00
John Törnblom 7e9d5de599 include: sce libs use utf-16 for wchar_t 2025-08-30 14:26:06 +02:00
John Törnblom b60dc4ff2d deploy: make port argument optional (and default to 9021) 2025-08-28 14:13:01 +02:00
John Törnblom 0760994443 cosmetics 2025-08-28 13:58:07 +02:00
John Törnblom 124f4c1e65 crt: fix potential infloops 2025-08-28 13:57:29 +02:00
John Törnblom b5d6a60111 libc: add some more termios functions 2025-08-10 20:03:06 +02:00
John Törnblom ae003a47d2 libc: add _setjmp and _longjmp 2025-08-10 17:27:44 +02:00
John Törnblom 9740039fba libc: add recvmmsg and sendmmsg 2025-08-10 17:27:05 +02:00
John Törnblom c282b54f9c libc: add scandir and alphasort 2025-08-09 15:38:17 +02:00
John Törnblom b3f1da4ba2 lld: enforce mulated-tls when using lto 2025-08-07 22:55:09 +02:00
John Törnblom ac172551d6 libc: add hstrerror 2025-07-29 18:38:54 +02:00
John Törnblom 986b7c4531 samples: bump minimum version of hello_cmake 2025-07-23 13:35:50 +02:00
John Törnblom 1b31130d8c samples: add vscode code completion and debugging configurations to hello_cmake 2025-07-23 13:34:37 +02:00
John Törnblom a7ab3e9c96 samples: use gdb-multiarch for debug targets, allowing debugging on non-x86_64 hosts 2025-07-23 00:04:29 +02:00
John Törnblom 9bb7312911 cosmetics 2025-07-15 23:32:11 +02:00
John Törnblom 9d14d05c58 prospero-deploy: only read from /dev/stdin if interactive mode (-i) is enabled 2025-07-15 23:31:59 +02:00
John Törnblom 8f11be6d8c prospero-deploy: redirect stdin to the payload 2025-07-15 20:09:19 +02:00
John Törnblom 5d736fede9 cmake: fix lto linking 2025-07-12 15:04:28 +02:00
John Törnblom a45a154697 lld: ensure --hash-style is the last argument 2025-06-29 16:30:09 +02:00
John Törnblom a28f7db2f3 lld: ensure GNU hash style in symbol tables 2025-06-29 16:09:46 +02:00
John Törnblom 04a8e191d1 samples: improve coverage of test_privileges 2025-06-27 23:11:24 +02:00
John Törnblom 23d5810707 kernel: add api for reading and writing vmem protection flags 2025-06-27 22:03:23 +02:00
John Törnblom c13de3c884 revert some aspects of commit 3c1cb13b0a.
This fixes kernel panics on fw 10.01 when launching homebrew via websrv
2025-06-27 00:35:41 +02:00
John Törnblom 217e0cf252 ci: create a pre-release on tags 2025-06-22 20:44:42 +02:00
John Törnblom 526375d8f9 cosmetics 2025-06-22 20:44:36 +02:00
John Törnblom 3c1cb13b0a cosmetics 2025-06-22 14:35:43 +02:00
John Törnblom d1d1d94e3b cosmetics 2025-06-22 14:04:05 +02:00
John Törnblom 80724372d9 cosmetics 2025-06-22 13:48:21 +02:00
Echo Stretch 2792fe2035 Fixed 8.00+ Offsets 2025-06-08 18:56:15 +02:00
Echo Stretch ff486dcd92 Fix Base ?? 2025-06-08 18:56:15 +02:00
n0llptr 46c15f0fc6 Fix 9.00 security flags offset 2025-06-02 19:54:13 +02:00
John Törnblom 60723a29b8 crt: avoid using mdbg 2025-06-01 18:17:28 +02:00
John Törnblom 66ea6b772a patch: improve error logging 2025-06-01 13:39:57 +02:00
John Törnblom b4e840256d cosmetics 2025-06-01 13:18:43 +02:00
John Törnblom 1ad6d39753 samples: improve coverage of test_privileges 2025-06-01 13:18:09 +02:00
John Törnblom 813c586bfa ci: build test cases 2025-05-31 20:29:44 +02:00
John Törnblom a373a579be samples: add test cases for mdbg and ptrace 2025-05-31 20:10:59 +02:00
John Törnblom 1f361b6c8b ci: bump host llvm+clang to v18 2025-05-31 19:12:34 +02:00
120 changed files with 13010 additions and 1223 deletions

No files matched your search

+60
View File
@@ -0,0 +1,60 @@
name: macos-latest
on:
push:
paths-ignore:
- "**/*.md"
- "**/*.txt"
pull_request:
paths-ignore:
- "**/*.md"
- "**/*.txt"
workflow_dispatch:
jobs:
build:
runs-on: macos-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Install prerequisites
run: |
brew update
brew install llvm@18 meson cmake
- name: Build SDK
run: |
make install
./libcxx.sh
env:
LLVM_CONFIG: /opt/homebrew/opt/llvm@18/bin/llvm-config
DESTDIR: ${{ runner.tool_cache }}/ps5-payload-sdk
PS5_PAYLOAD_SDK: ${{ runner.tool_cache }}/ps5-payload-sdk
- name: Build samples
run: |
source $PS5_PAYLOAD_SDK/toolchain/prospero.sh
$MAKE -C samples/arbitrary_syscall
$MAKE -C samples/browser
$MAKE -C samples/hello_argv
$MAKE -C samples/hello_cxx
$MAKE -C samples/hello_cxx23
$MAKE -C samples/hello_dlfcn
$MAKE -C samples/hello_kenv
$MAKE -C samples/hello_sprx
$MAKE -C samples/hello_stdio
$MAKE -C samples/hello_world
$MAKE -C samples/hwinfo
$MAKE -C samples/list_files
$MAKE -C samples/mntinfo
$MAKE -C samples/notify
$MAKE -C samples/notify_debug
$MAKE -C samples/ps
$CMAKE -S samples/hello_cmake -B samples/hello_cmake/build
$CMAKE --build samples/hello_cmake/build
$MESON setup samples/hello_meson samples/hello_meson/build
$MESON compile -C samples/hello_meson/build
env:
LLVM_CONFIG: /opt/homebrew/opt/llvm@18/bin/llvm-config
PS5_PAYLOAD_SDK: ${{ runner.tool_cache }}/ps5-payload-sdk
-45
View File
@@ -1,45 +0,0 @@
name: CI
on:
push:
paths-ignore:
- "**/*.md"
- '**/*.txt'
pull_request:
paths-ignore:
- "**/*.md"
- '**/*.txt'
workflow_dispatch:
concurrency:
group: ${{ github.ref }}-${{ github.event_name }}
cancel-in-progress: true
jobs:
build:
runs-on: ubuntu-24.04
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup
run: |
sudo apt update
sudo apt install bash clang-15 lld-15 pkg-config cmake meson socat mingw-w64
- name: Build
run: |
make WIN=1 DESTDIR=${{ runner.tool_cache }}/ps5-payload-sdk install
PS5_PAYLOAD_SDK=${{ runner.tool_cache }}/ps5-payload-sdk ./libcxx.sh
cd ${{ runner.tool_cache }}
zip -r $GITHUB_WORKSPACE/ps5-payload-sdk.zip ps5-payload-sdk
- name: Upload
uses: actions/upload-artifact@v4
with:
name: SDK
include-hidden-files: true
path: ./ps5-payload-sdk.zip
if-no-files-found: error
+98
View File
@@ -0,0 +1,98 @@
name: ubuntu-latest
on:
push:
paths-ignore:
- "**/*.md"
- '**/*.txt'
pull_request:
paths-ignore:
- "**/*.md"
- '**/*.txt'
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Install prerequisites
run: |
sudo apt update
sudo apt install clang-18 lld-18 mingw-w64 cmake meson
- name: Build SDK
run: |
make install
./libcxx.sh
cd ${{ runner.tool_cache }}
zip -r $GITHUB_WORKSPACE/ps5-payload-sdk.zip ps5-payload-sdk
cd -
env:
DESTDIR: ${{ runner.tool_cache }}/ps5-payload-sdk
PS5_PAYLOAD_SDK: ${{ runner.tool_cache }}/ps5-payload-sdk
WIN: 1
- name: Bundle SDK
run: |
cd ${{ runner.tool_cache }}
zip -r $GITHUB_WORKSPACE/ps5-payload-sdk.zip ps5-payload-sdk
cd -
- name: Build samples
run: |
source $PS5_PAYLOAD_SDK/toolchain/prospero.sh
$MAKE -C samples/arbitrary_syscall
$MAKE -C samples/browser
$MAKE -C samples/hello_argv
$MAKE -C samples/hello_cxx
$MAKE -C samples/hello_cxx23
$MAKE -C samples/hello_dlfcn
$MAKE -C samples/hello_kenv
$MAKE -C samples/hello_sprx
$MAKE -C samples/hello_stdio
$MAKE -C samples/hello_world
$MAKE -C samples/hwinfo
$MAKE -C samples/list_files
$MAKE -C samples/mntinfo
$MAKE -C samples/notify
$MAKE -C samples/notify_debug
$MAKE -C samples/ps
$CMAKE -S samples/hello_cmake -B samples/hello_cmake/build
$CMAKE --build samples/hello_cmake/build
$MESON setup samples/hello_meson samples/hello_meson/build
$MESON compile -C samples/hello_meson/build
env:
PS5_PAYLOAD_SDK: ${{ runner.tool_cache }}/ps5-payload-sdk
- name: Upload SDK
uses: actions/upload-artifact@v4
with:
name: SDK
include-hidden-files: true
path: ./ps5-payload-sdk.zip
if-no-files-found: error
release:
needs: build
permissions:
contents: write
if: startsWith(github.ref, 'refs/tags/')
runs-on: ubuntu-latest
steps:
- name: Download artifacts
uses: actions/download-artifact@v4
with:
name: SDK
path: .
- name: Create GitHub Release (pre-release)
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ github.ref_name }}
prerelease: true
files: ps5-payload-sdk.zip
-1
View File
@@ -8,5 +8,4 @@
nid_db.xml
aerolib.csv
.gdb_history
prospero-nid
+2 -3
View File
@@ -14,11 +14,10 @@
# along with this program; see the file COPYING. If not see
# <http://www.gnu.org/licenses/>.
MAKE ?= make
DESTDIR ?= /opt/ps5-payload-sdk
include Makefile.inc
TOPTARGETS := all clean install
SUBDIRS := crt sce_stubs libc include host
SUBDIRS := crt sce_stubs libc libufs include host
ifdef WIN
SUBDIRS += host/win
+52
View File
@@ -0,0 +1,52 @@
# Copyright (C) 2026 John Törnblom
# Copyright (C) 2026 Aleksei Kulaev
#
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; see the file COPYING. If not see
# <http://www.gnu.org/licenses/>.
MAKE ?= make
PYTHON ?= python3
DESTDIR ?= /opt/ps5-payload-sdk
LLVM_CONFIG_CANDIDATES := llvm-config-23 llvm-config-22 llvm-config-21 \
llvm-config-20 llvm-config-19 llvm-config-18 \
llvm-config-17 llvm-config-16 llvm-config-15 \
llvm-config
LLVM_CONFIG_CANDIDATES := $(foreach LCC,$(LLVM_CONFIG_CANDIDATES), \
$(if $(shell command -v $(LCC) 2>/dev/null), $(LCC)))
LLVM_CONFIG ?= $(firstword $(LLVM_CONFIG_CANDIDATES))
ifndef LLVM_CONFIG
$(error Unable to find llvm-config)
endif
LLVM_BINDIR := $(shell $(LLVM_CONFIG) --bindir)
CC := $(LLVM_BINDIR)/clang
AR := $(LLVM_BINDIR)/llvm-ar
LD := $(LLVM_BINDIR)/ld.lld
# When using macos with brew, lld-19 and above are not installed in the standard
# llvm bindir directory, compensate for that here.
ifeq ($(shell command -v $(LD) 2>/dev/null),)
OS := $(shell uname -s)
ifeq ($(OS),Darwin)
BREW := $(shell command -v brew 2>/dev/null)
ifneq ($(BREW),)
LD := $(shell $(BREW) --prefix lld 2>/dev/null)/bin/ld.lld
else
$(error Unable to find brew)
endif
endif
endif
+28 -18
View File
@@ -4,40 +4,42 @@ known to work include:
- [ps5-payload-elfldr][elfldr]
- [ps5-payload-websrv][websrv]
- [bdj-ipv6-hen][bdj-ipv6-hen]
- [elfloader][elfloader] for BD-J [ps5-jar-loader]
- [elfloader][elfloader] via [ps5-jar-loader]
- [remote_lua_loader][remote_lua_loader]
Several artifacts in this repository originate from the [PS5SDK][PS5SDK] project.
## Prerequisites
On Debian-flavored operating systems, you can invoke the following command to
On Debian-flavored operating systems, you can invoke the following commands to
install dependencies used by the SDK.
```console
john@localhost:ps5-payload-dev/sdk$ sudo apt-get update && sudo apt-get upgrade # optional
john@localhost:ps5-payload-dev/sdk$ sudo apt-get install bash clang-15 lld-15 # required
john@localhost:ps5-payload-dev/sdk$ sudo apt-get install socat cmake meson pkg-config # optional
john@localhost:ps5-payload-dev/sdk$ sudo apt-get install bash clang-18 lld-18 wget # required
john@localhost:ps5-payload-dev/sdk$ sudo apt-get install socat cmake meson pkg-config python3 python3-pyelftools # optional
```
If you are using Fedora, you can install dependencies as follows (tested with version 41):
```console
john@localhost:ps5-payload-dev/sdk$ sudo dnf install bash llvm-devel clang lld # required
john@localhost:ps5-payload-dev/sdk$ sudo dnf install socat cmake meson pkg-config # optional
john@localhost:ps5-payload-dev/sdk$ sudo dnf install bash llvm-devel clang lld wget # required
john@localhost:ps5-payload-dev/sdk$ sudo dnf install socat cmake meson pkg-config python3 python3-pyelftools # optional
```
If you are using macOS, you can install them using the [Homebrew Package Manager][macos-brew] (tested with macOS Sequoia):
```console
john@localhost:ps5-payload-dev/sdk$ brew install llvm@18 wget # required
john@localhost:ps5-payload-dev/sdk$ export LLVM_CONFIG=/opt/homebrew/opt/llvm@18/bin/llvm-config # required
john@localhost:ps5-payload-dev/sdk$ brew install socat cmake meson python && pip3 install pyelftools # optional
```
## Quick-start
To download and install a binary distribution for GNU/Linux:
You can download a binary distribution of the SDK from [the latest release page][latest-rel],
then install it to your local storage, e.g,
```console
john@localhost:tmp$ wget https://github.com/ps5-payload-dev/sdk/releases/latest/download/ps5-payload-sdk.zip
john@localhost:tmp$ sudo unzip -d /opt ps5-payload-sdk.zip
```
## Building
```console
john@localhost:ps5-payload-dev/sdk$ make
john@localhost:ps5-payload-dev/sdk$ make DESTDIR=/opt/ps5-payload-sdk install
john@localhost:ps5-payload-dev/sdk$ export PS5_PAYLOAD_SDK=/opt/ps5-payload-sdk
john@localhost:ps5-payload-dev/sdk$ ./libcxx.sh # fetch, build, and install libcxx
```
Assuming you have all the prerequisites and you are on a POSIX system,
the binary distribution should work regardless of CPU architecture, e.g., x86_64, aarch64.
## Usage
```console
@@ -47,14 +49,20 @@ john@localhost:ps5-payload-dev/sdk$ export PS5_HOST=ps5; export PS5_PORT=9021
john@localhost:ps5-payload-dev/sdk$ make -C samples/hello_world test
```
## Building the SDK
```console
john@localhost:ps5-payload-dev/sdk$ sudo make DESTDIR=/opt/ps5-payload-sdk install
john@localhost:ps5-payload-dev/sdk$ export PS5_PAYLOAD_SDK=/opt/ps5-payload-sdk
john@localhost:ps5-payload-dev/sdk$ sudo -E ./libcxx.sh # fetch, build, and install libcxx
```
## Adding new SCE Libs
If you have decrypted sprx files that you would like to interact with, you can
build stubs for them as follows:
build stubs for them as follows (Make sure you have already installed the optional dependencies for your OS):
```console
john@localhost:ps5-payload-dev/sdk$ sudo apt-get install wget python3 python3-pyelftools
john@localhost:ps5-payload-dev/sdk$ ln -s /path/to/sprx/libSceXYZ.sprx sce_stubs/libSceXYZ.sprx
john@localhost:ps5-payload-dev/sdk$ make -C sce_stubs stubs
john@localhost:ps5-payload-dev/sdk$ make DESTDIR=/opt/ps5-payload-sdk install
john@localhost:ps5-payload-dev/sdk$ sudo make DESTDIR=/opt/ps5-payload-sdk install
```
## Reporting Bugs
@@ -69,6 +77,7 @@ Unless otherwhise explicitly stated inside a file, the rest are licensed under
the GPLv3+.
[issues]: https://github.com/ps5-payload-dev/sdk/issues/new
[latest-rel]: https://github.com/ps5-payload-dev/sdk/releases/latest
[elfldr]: https://github.com/ps5-payload-dev/elfldr
[websrv]: https://github.com/ps5-payload-dev/websrv
[bdj-ipv6-hen]: https://github.com/ps5-payload-dev/bdj-ipv6-hen
@@ -76,3 +85,4 @@ the GPLv3+.
[elfloader]: https://github.com/cryonumb/elfloader
[ps5-jar-loader]: https://github.com/hammer-83/ps5-jar-loader
[PS5SDK]: https://github.com/PS5Dev/PS5SDK
[macos-brew]: https://brew.sh
+5 -1
View File
@@ -27,6 +27,7 @@ $SCRIPTDIR/libcxx.sh || exit 1
MAKE_SAMPLES=("arbitrary_syscall"
"browser"
"hello_argv"
"hello_cxx"
"hello_cxx23"
"hello_dlfcn"
@@ -35,10 +36,13 @@ MAKE_SAMPLES=("arbitrary_syscall"
"hello_stdio"
"hello_world"
"hwinfo"
"install_app"
"list_files"
"mntinfo"
"notify"
"ps")
"notify_debug"
"ps"
"relocatable_linking")
CMAKE_SAMPLES=("hello_cmake"
)
+6 -23
View File
@@ -14,28 +14,7 @@
# along with this program; see the file COPYING. If not see
# <http://www.gnu.org/licenses/>.
DESTDIR ?= /opt/ps5-payload-sdk
CCS := clang-20 clang-19 clang-18 clang-17 clang-16 clang-15 clang
CCS := $(foreach CC,$(CCS),$(if $(shell command -v $(CC) 2> /dev/null),$(CC)))
CC := $(firstword $(CCS))
ifndef CC
$(error No suitable compiler found)
endif
LDS := ld.lld-20 ld.lld-19 ld.lld-18 ld.lld-17 ld.lld-16 ld.lld-15 ld.lld ld
LDS := $(foreach LD,$(LDS),$(if $(shell command -v $(LD) 2> /dev/null),$(LD)))
LD := $(firstword $(LDS))
ifndef LD
$(error No suitable linker found)
endif
ARS := llvm-ar-20 llvm-ar-19 llvm-ar-18 llvm-ar-17 llvm-ar-16 llvm-ar-15 llvm-ar ar
ARS := $(foreach AR,$(ARS),$(if $(shell command -v $(AR) 2> /dev/null),$(AR)))
AR := $(firstword $(ARS))
ifndef AR
$(error No suitable archiver found)
endif
include ../Makefile.inc
CFLAGS += -ffreestanding -fno-builtin -nostdlib -fPIC
CFLAGS += -target x86_64-sie-ps5 -fno-plt -fno-stack-protector
@@ -44,7 +23,8 @@ CFLAGS += -fms-extensions -Wno-microsoft-anon-tag
CFLAGS += -O1
OBJ := crt.o syscall.o klog.o nid.o kernel.o rtld.o rtld_so.o rtld_sprx.o \
rtld_payload.o rtld_dlfcn.o mdbg.o patch.o
rtld_payload.o rtld_dlfcn.o mdbg.o patch.o kernel_procio.o \
kernel_iommu.o _start.o
.PHONY: all clean install
@@ -74,6 +54,9 @@ crt1.o: $(OBJ)
%.o: %.c
$(CC) -c $(CFLAGS) -o $@ $^
%.o: %.S
$(CC) -c $(CFLAGS) -masm=intel -o $@ $^
clean:
rm -f *.o *.a
+37
View File
@@ -0,0 +1,37 @@
/* Copyright (C) 2026 John Törnblom
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 3, or (at your option) any
later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>. */
.intel_syntax noprefix
.data
.local __crt_reg_backup
.type __crt_reg_backup, @object
__crt_reg_backup:
.quad 0
.text
.extern __crt_start
.type __crt_start, @function
.text
.global _start
.type _start, @function
_start:
mov [__crt_reg_backup + rip], rsp
and rsp, -16
call __crt_start
mov rsp, [__crt_reg_backup + rip]
ret
+23 -8
View File
@@ -52,7 +52,7 @@ payload_init(payload_args_t *args) {
int *__isthreaded = 0;
int error = 0;
if((error=__syscall_init(args))) {
if((error=__crt_syscall_init(args))) {
return error;
}
if((error=__kernel_init(args))) {
@@ -131,7 +131,10 @@ payload_run(void) {
}
// run the actual payload
*payload_args->payloadout = main(argc, argv, environ);
err = main(argc, argv, environ);
if(payload_args->payloadout) {
*payload_args->payloadout = err;
}
// run .fini destructors
if((err=__rtld_lib_fini(lib))) {
@@ -153,15 +156,20 @@ payload_run(void) {
static int
payload_terminate(void) {
void (*exit)(int) = 0;
int exit_code = 0;
// we are running inside a hijacked process, just return
if(kernel_dynlib_dlsym(-1, 0x2001, "sceKernelDlsym")) {
return 0;
return exit_code;
}
if(payload_args->payloadout) {
exit_code = *payload_args->payloadout;
}
// resolve and run exit
if(KERNEL_DLSYM(0x2, exit)) {
exit(*payload_args->payloadout);
exit(exit_code);
}
// should not happend
@@ -176,7 +184,9 @@ payload_terminate(void) {
**/
void
payload_exit(int exit_code) {
*payload_args->payloadout = exit_code;
if(payload_args->payloadout) {
*payload_args->payloadout = exit_code;
}
__builtin_longjmp(jmpbuf, 1);
}
@@ -194,7 +204,7 @@ payload_get_args(void) {
* Entry-point invoked by the ELF loader.
**/
int
_start(payload_args_t *args) {
__crt_start(payload_args_t *args) {
int err;
// clear .bss section
@@ -205,14 +215,19 @@ _start(payload_args_t *args) {
payload_args = args;
// init payload runtime
if((*args->payloadout=payload_init(args))) {
if((err=payload_init(args))) {
if(args->payloadout) {
*args->payloadout = err;
}
return payload_terminate();
}
// run payload
if(!__builtin_setjmp(jmpbuf)) {
if((err=payload_run())) {
*payload_args->payloadout = err;
if(args->payloadout) {
*args->payloadout = err;
}
}
}
+606 -150
View File
File diff suppressed because it is too large. Load diff
+17 -2
View File
@@ -128,15 +128,30 @@ typedef struct dynlib_obj {
} dynlib_obj_t;
extern const unsigned long KERNEL_OFFSET_PROC_P_VMSPACE;
extern unsigned long KERNEL_OFFSET_VMSPACE_VM_PMAP;
extern unsigned long KERNEL_ADDRESS_DMAP_BASE;
extern unsigned long KERNEL_ADDRESS_IOMMU_SOFTC;
int kernel_copyout(unsigned long kaddr, void *uaddr, unsigned long len);
int kernel_copyin(const void *uaddr, unsigned long kaddr, unsigned long len);
unsigned long kernel_get_proc(int pid);
int kernel_proc_getpaddr(int pid, unsigned long vaddr,
unsigned long *paddr, unsigned long *plen);
unsigned long kernel_get_ucred_authid(int pid);
int kernel_set_ucred_authid(int pid, unsigned long authid);
unsigned long kernel_get_ucred_attrs(int pid);
int kernel_set_ucred_attrs(int pid, unsigned long attrs);
int kernel_get_ucred_attrs(int pid, unsigned char attrs[32]);
int kernel_set_ucred_attrs(int pid, const unsigned char attrs[32]);
unsigned long kernel_get_ucred_prison(int pid);
int kernel_set_ucred_prison(int pid, unsigned long prison);
int kernel_get_ucred_caps(int pid, unsigned char caps[16]);
int kernel_set_ucred_caps(int pid, const unsigned char caps[16]);
+252
View File
@@ -0,0 +1,252 @@
/* Copyright (C) 2026 John Törnblom
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 3, or (at your option) any
later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>. */
#include "kernel.h"
#include "kernel_iommu.h"
/**
* Physical base address of the AMD IOMMU MMIO region.
**/
#define IOMMU_MMIO_BASE 0xfdd80000UL
/**
* MMIO register offsets for the IOMMU command buffer.
**/
#define IOMMU_MMIO_CB3_HEAD 0xe000
#define IOMMU_MMIO_CB3_TAIL 0xe008
/**
* IOMMU command buffer ring constants.
**/
#define IOMMU_CB_SIZE 0x2000
#define IOMMU_CB_MASK (IOMMU_CB_SIZE - 1)
#define IOMMU_CMD_SIZE 0x10
/**
* Field offsets within the IOMMU softc data structure.
**/
#define IOMMU_SC_CB3_PTR 0x80
#define IOMMU_SC_CB3_INDEX 0x88
/**
* Global state that is initialised on first call.
**/
static unsigned long iommu_mmio_kaddr = 0;
static unsigned long iommu_cb_base = 0;
static unsigned long iommu_cb_index = 0;
/**
* Initialize the global state.
**/
static int
iommu_init(void) {
if(iommu_mmio_kaddr) {
return 0;
}
if(!KERNEL_ADDRESS_IOMMU_SOFTC) {
return -1;
}
iommu_mmio_kaddr = KERNEL_ADDRESS_DMAP_BASE + IOMMU_MMIO_BASE;
if(kernel_copyout(KERNEL_ADDRESS_IOMMU_SOFTC + IOMMU_SC_CB3_PTR,
&iommu_cb_base, sizeof(iommu_cb_base))) {
iommu_mmio_kaddr = 0;
return -1;
}
iommu_cb_index = KERNEL_ADDRESS_IOMMU_SOFTC + IOMMU_SC_CB3_INDEX;
if(!iommu_cb_base) {
iommu_mmio_kaddr = 0;
return -1;
}
return 0;
}
/**
* Submit a command to the IOMMU command queue.
**/
static int
iommu_submit_cmd(const void *cmd) {
unsigned long curr_tail;
unsigned long next_tail;
unsigned long head;
unsigned long tail;
if(kernel_copyout(iommu_mmio_kaddr + IOMMU_MMIO_CB3_TAIL,
&curr_tail, sizeof(curr_tail))) {
return -1;
}
next_tail = (curr_tail + IOMMU_CMD_SIZE) & IOMMU_CB_MASK;
if(kernel_copyin(cmd, iommu_cb_base + curr_tail, IOMMU_CMD_SIZE)) {
return -1;
}
if(kernel_copyin(&next_tail, iommu_mmio_kaddr + IOMMU_MMIO_CB3_TAIL,
sizeof(next_tail))) {
return -1;
}
if(kernel_copyin(&next_tail, iommu_cb_index, sizeof(next_tail))) {
return -1;
}
while(1) {
if(kernel_copyout(iommu_mmio_kaddr + IOMMU_MMIO_CB3_HEAD, &head, sizeof(head))) {
return -1;
}
if(kernel_copyout(iommu_mmio_kaddr + IOMMU_MMIO_CB3_TAIL, &tail, sizeof(tail))) {
return -1;
}
if(head == tail) {
return 0;
}
}
}
/**
* Submit a write command to IOMMU command queue.
**/
static int
iommu_write8(unsigned long paddr, unsigned long val) {
unsigned int cmd[4];
cmd[0] = (unsigned int)(paddr & 0xFFFFFFF8) | 0x05;
cmd[1] = (unsigned int)((paddr >> 32) & 0xFFFFF) | 0x10000000;
cmd[2] = (unsigned int)(val);
cmd[3] = (unsigned int)(val >> 32);
return iommu_submit_cmd(cmd);
}
/**
* Copy byte values into a word.
**/
static unsigned long
iommu_patch_word(unsigned long word, const unsigned char *src,
unsigned int off, unsigned int n) {
unsigned char *b = (unsigned char*)&word;
for(unsigned int i=0; i<n; i++) {
b[off+i] = src[i];
}
return word;
}
int
kernel_iommu_copyin(const void *uaddr, unsigned long kaddr, unsigned long len) {
const unsigned char *src = (const unsigned char*)uaddr;
unsigned long paddr;
unsigned long chunk;
unsigned long curr;
unsigned long plen;
unsigned long coff;
unsigned int head;
unsigned long off;
unsigned long val;
if(!uaddr || !kaddr || !len) {
return -1;
}
if(iommu_init()) {
return -1;
}
for(off=0; off<len; off+=chunk) {
if(kernel_proc_getpaddr(0, kaddr+off, &paddr, &plen)) {
return -1;
}
chunk = len - off;
if(chunk > plen) {
chunk = plen;
}
coff = 0;
if(paddr & 7) {
head = (unsigned int)(8 - (paddr & 7));
if(head > (unsigned int)chunk) {
head = (unsigned int)chunk;
}
if(kernel_copyout(KERNEL_ADDRESS_DMAP_BASE + (paddr & ~7UL),
&curr, sizeof(curr))) {
return -1;
}
curr = iommu_patch_word(curr, src+off, (unsigned int)(paddr & 7), head);
if(iommu_write8(paddr & ~7UL, curr)) {
return -1;
}
coff += head;
}
while(coff+8 <= chunk) {
val = 0;
for(int i=0; i<8; i++) {
val |= (unsigned long)src[off+coff+i] << (i*8);
}
iommu_write8(paddr+coff, val);
coff += 8;
}
if(coff < chunk) {
if(kernel_copyout(KERNEL_ADDRESS_DMAP_BASE+paddr+coff, &curr,
sizeof(curr))) {
return -1;
}
curr = iommu_patch_word(curr, src+off+coff, 0, (unsigned int)(chunk-coff));
if(iommu_write8(paddr+coff, curr)) {
return -1;
}
}
}
return 0;
}
int
kernel_iommu_setlong(unsigned long kaddr, unsigned long val) {
return kernel_iommu_copyin(&val, kaddr, sizeof(val));
}
int
kernel_iommu_setint(unsigned long kaddr, unsigned int val) {
return kernel_iommu_copyin(&val, kaddr, sizeof(val));
}
int
kernel_iommu_setshort(unsigned long kaddr, unsigned short val) {
return kernel_iommu_copyin(&val, kaddr, sizeof(val));
}
int
kernel_iommu_setchar(unsigned long kaddr, unsigned char val) {
return kernel_iommu_copyin(&val, kaddr, sizeof(val));
}
+22
View File
@@ -0,0 +1,22 @@
/* Copyright (C) 2026 John Törnblom
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 3, or (at your option) any
later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>. */
#pragma once
int kernel_iommu_copyin(const void *uaddr, unsigned long kaddr,
unsigned long len);
+212
View File
@@ -0,0 +1,212 @@
/* Copyright (C) 2026 John Törnblom, idlesauce, and sleirsgoevy
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 3, or (at your option) any
later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>. */
#include "kernel.h"
#include "mdbg.h"
#define X86_PG_V 0x01
#define X86_PG_PS 0x80
#define PG_FRAME (0xffffffffff000ul)
/**
* Walk the page table hierarchy (9 bit indices in 4 levels) to find the
* entry of the physical address mapped to the vaddr of the given process.
**/
int
kernel_proc_getpaddr(int pid, unsigned long vaddr, unsigned long* paddr,
unsigned long* plen) {
unsigned long table_offset;
unsigned long table_index;
unsigned long vmspace;
unsigned long pml4u;
unsigned long proc;
unsigned long cr3;
unsigned long pte;
if(!KERNEL_OFFSET_VMSPACE_VM_PMAP) {
return -1;
}
if(!(proc=kernel_get_proc(pid))) {
return -1;
}
if(kernel_copyout(proc + KERNEL_OFFSET_PROC_P_VMSPACE,
&vmspace, sizeof(vmspace))) {
return -1;
}
if(kernel_copyout(vmspace + KERNEL_OFFSET_VMSPACE_VM_PMAP + 0x20,
&pml4u, sizeof(pml4u))) {
return -1;
}
if(kernel_copyout(vmspace + KERNEL_OFFSET_VMSPACE_VM_PMAP + 0x28,
&cr3, sizeof(cr3))) {
return -1;
}
pte = cr3;
for(long bitpos=39; bitpos>=12; bitpos-=9) {
table_index = (vaddr >> bitpos) & ((1ull << 9) - 1);
table_offset = table_index * 8;
pte &= PG_FRAME;
if(kernel_copyout(pml4u-cr3 + table_offset + pte, &pte, sizeof(pte))) {
return -1;
}
// check entry validity
if(!(pte & X86_PG_V)) {
return -1;
}
// check if the entry is flagged as large or if we reached the last level
if((pte & X86_PG_PS) || bitpos == 12) {
*paddr = pte;
*paddr &= (1ul << 52) - (1ul << bitpos);
*paddr |= vaddr & ((1ul << bitpos) - 1);
*plen = (*paddr | ((1ul << bitpos) - 1)) + 1 - *paddr;
return 0;
}
}
return -1;
}
int
kernel_proc_copyin(int pid, const void *buf, unsigned long addr,
unsigned long len) {
unsigned long paddr;
unsigned long plen;
// lets see if we can just use mdbg
if(!mdbg_copyin(pid, buf, addr, len)) {
return 0;
}
for(unsigned long i=0; i<len; i+=plen) {
if(kernel_proc_getpaddr(pid, addr + i, &paddr, &plen)) {
return -1;
}
if(plen > len) {
plen = len;
}
if(kernel_copyin(((unsigned char*)buf) + i,
KERNEL_ADDRESS_DMAP_BASE + paddr, plen)) {
return -1;
}
}
return 0;
}
int
kernel_proc_copyout(int pid, unsigned long addr, void *buf,
unsigned long len) {
unsigned long paddr;
unsigned long plen;
// lets see if we can just use mdbg
if(!mdbg_copyout(pid, addr, buf, len)) {
return 0;
}
for(unsigned long i=0; i<len; i+=plen) {
if(kernel_proc_getpaddr(pid, addr + i, &paddr, &plen)) {
return -1;
}
if(plen > len) {
plen = len;
}
if(kernel_copyout(KERNEL_ADDRESS_DMAP_BASE + paddr,
((unsigned char*)buf) + i, plen)) {
return -1;
}
}
return 0;
}
int
kernel_proc_setchar(int pid, unsigned long addr, char val) {
return kernel_proc_copyin(pid, &val, addr, sizeof(val));
}
int
kernel_proc_setshort(int pid, unsigned long addr, short val) {
return kernel_proc_copyin(pid, &val, addr, sizeof(val));
}
int
kernel_proc_setint(int pid, unsigned long addr, int val) {
return kernel_proc_copyin(pid, &val, addr, sizeof(val));
}
int
kernel_proc_setlong(int pid, unsigned long addr, long val) {
return kernel_proc_copyin(pid, &val, addr, sizeof(val));
}
char
kernel_proc_getchar(int pid, unsigned long addr) {
char val = 0;
kernel_proc_copyout(pid, addr, &val, sizeof(val));
return val;
}
short
kernel_proc_getshort(int pid, unsigned long addr) {
short val = 0;
kernel_proc_copyout(pid, addr, &val, sizeof(val));
return val;
}
int
kernel_proc_getint(int pid, unsigned long addr) {
int val = 0;
kernel_proc_copyout(pid, addr, &val, sizeof(val));
return val;
}
long
kernel_proc_getlong(int pid, unsigned long addr) {
long val = 0;
kernel_proc_copyout(pid, addr, &val, sizeof(val));
return val;
}
+5 -5
View File
@@ -30,10 +30,10 @@ static int* (*__error)(void) = 0;
**/
static char*
klog_label(char *buf, unsigned long size) {
int pid = __syscall(SYS_getpid);
int pid = __crt_syscall(SYS_getpid);
buf[0] = 0;
__syscall(0x268, pid, buf, size);
__crt_syscall(0x268, pid, buf, size);
if(buf[0] == 0) {
snprintf(buf, size, "pid:%d", pid);
@@ -56,7 +56,7 @@ klog_printf(const char *fmt, ...) {
snprintf(buf, sizeof buf, "<118>[%s] %s", klog_label(lbl, sizeof(lbl)), sargs);
return (int)__syscall(0x259, 7, buf, 0);
return (int)__crt_syscall(0x259, 7, buf, 0);
}
@@ -67,7 +67,7 @@ klog_puts(const char *s) {
snprintf(buf, sizeof buf, "<118>[%s] %s\n", klog_label(lbl, sizeof(lbl)), s);
return (int)__syscall(0x259, 7, buf, 0);
return (int)__crt_syscall(0x259, 7, buf, 0);
}
@@ -79,7 +79,7 @@ klog_perror(const char *s) {
snprintf(buf, sizeof buf, "<118>[%s] %s: %s\n",
klog_label(lbl, sizeof(lbl)), s, strerror(*__error()));
return (int)__syscall(0x259, 7, buf, 0);
return (int)__crt_syscall(0x259, 7, buf, 0);
}
+2 -2
View File
@@ -69,7 +69,7 @@ static int
mdbg_memop(int memop, mdbg_memop_args_t *args) {
static const unsigned char privcaps[16] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
int pid = (int)__syscall(SYS_getpid);
int pid = (int)__crt_syscall(SYS_getpid);
mdbg_cmd_t cmd = {1, memop};
unsigned char caps[16];
unsigned long authid;
@@ -98,7 +98,7 @@ mdbg_memop(int memop, mdbg_memop_args_t *args) {
do {
res.len = res.status = 0;
if((err=__syscall(SYS_mdbg_call, &cmd, args, &res)) == -1) {
if((err=__crt_syscall(SYS_mdbg_call, &cmd, args, &res)) == -1) {
break;
}
args->src += res.len;
+5 -64
View File
@@ -16,68 +16,16 @@ along with this program; see the file COPYING. If not, see
#include "kernel.h"
#include "klog.h"
#include "mdbg.h"
#include "payload.h"
#include "syscall.h"
/**
* Patch retail distributions of sceKernelSpawn() that ignore the dbg parameter.
*
* At offset 52, replace 0x00000000a845c748l with 0x90909090a8758948l, i.e.,
*
* mov QWORD PTR [rbp-0x58],0x0
* becomes
* mov QWORD PTR [rbp-0x58],rsi
* nop
* nop
* nop
* nop
**/
static int
patch_sceKernelSpawn(void) {
unsigned long loc;
unsigned long val;
if(!(loc=kernel_dynlib_dlsym(-1, 0x1, "sceKernelSpawn"))) {
if(!(loc=kernel_dynlib_dlsym(-1, 0x2001, "sceKernelSpawn"))) {
// nothing to patch
klog_puts("patch_sceKernelSpawn: unable to resolve sceKernelSpawn");
return 0;
}
}
loc += 52;
if(mdbg_copyout(-1, loc, &val, sizeof(val))) {
klog_perror("mdbg_copyout");
return -1;
}
// sanity checks
if(val == 0x90909090a8758948l) {
return 0;
} else if(val != 0x00000000a845c748l) {
klog_puts("patch_sceKernelSpawn: wrong offset");
return -1;
}
val = 0x90909090a8758948l;
if(mdbg_copyin(-1, &val, loc, sizeof(val))) {
klog_perror("mdbg_copyin");
return -1;
}
return 0;
}
/**
* Patch syscall permissions of the currently running process.
**/
static int
patch_syscall_permissions(void) {
int pid = __syscall(SYS_getpid);
int pid = __crt_syscall(SYS_getpid);
unsigned long kproc;
unsigned long kaddr;
unsigned long uaddr;
@@ -111,30 +59,26 @@ patch_syscall_permissions(void) {
**/
static int
patch_kernel_ucred(void) {
int pid = __syscall(SYS_getpid);
int pid = __crt_syscall(SYS_getpid);
unsigned char attrs[32];
unsigned char caps[16];
unsigned long attrs;
if(kernel_get_ucred_caps(pid, caps)) {
klog_puts("kernel_get_ucred_caps failed");
return -1;
}
if(!(attrs=kernel_get_ucred_attrs(pid))) {
klog_puts("kernel_get_ucred_attrs failed");
if(kernel_get_ucred_attrs(pid, attrs)) {
return -1;
}
caps[5] = 0x1c; // ??
caps[7] = 0x40; // jail related?
caps[15] |= 0x40; // jitshm
attrs |= 0x80; // ptrace
attrs[3] |= 0x80; // ptrace
if(kernel_set_ucred_caps(pid, caps)) {
klog_puts("kernel_set_ucred_caps failed");
return -1;
}
if(kernel_set_ucred_attrs(pid, attrs)) {
klog_puts("kernel_set_ucred_attrs failed");
return -1;
}
@@ -146,9 +90,6 @@ int
__patch_init(void) {
int error;
if((error=patch_sceKernelSpawn())) {
return error;
}
if((error=patch_kernel_ucred())) {
return error;
}
+39 -20
View File
@@ -158,6 +158,8 @@ __rtld_lib_soname2lib(rtld_lib_t* ctx, const char *soname) {
int
__rtld_find_file(const char *name, char* path) {
unsigned long random_word_len = 0xff;
char random_word[0xff];
unsigned long off = 0;
const char *ldpaths;
char buf[0x100];
@@ -170,43 +172,54 @@ __rtld_find_file(const char *name, char* path) {
path[0] = 0;
if(name[0] == '/') {
if(!(err=__syscall(SYS_stat, name, buf))) {
if(!(err=__crt_syscall(SYS_stat, name, buf))) {
strcpy(path, name);
}
return err;
}
cwd[0] = 0;
__syscall(SYS___getcwd, cwd, sizeof(cwd));
if(cwd[0]) {
strcpy(path, cwd);
strcat(path, "/");
strcat(path, name);
if(!__syscall(SYS_stat, path, buf)) {
return 0;
}
}
sprintf(path, "/system/priv/lib/%s", name);
if(!__syscall(SYS_stat, path, buf)) {
if(!__crt_syscall(SYS_stat, path, buf)) {
return 0;
}
sprintf(path, "/system/common/lib/%s", name);
if(!__syscall(SYS_stat, path, buf)) {
if(!__crt_syscall(SYS_stat, path, buf)) {
return 0;
}
sprintf(path, "/system_ex/priv_ex/lib/%s", name);
if(!__syscall(SYS_stat, path, buf)) {
if(!__crt_syscall(SYS_stat, path, buf)) {
return 0;
}
sprintf(path, "/system_ex/common_ex/lib/%s", name);
if(!__syscall(SYS_stat, path, buf)) {
if(!__crt_syscall(SYS_stat, path, buf)) {
return 0;
}
if(!__crt_syscall(SYS_randomized_path, 0, &random_word, &random_word_len)) {
sprintf(path, "/%s/priv/lib/%s", random_word, name);
if(!__crt_syscall(SYS_stat, path, buf)) {
return 0;
}
sprintf(path, "/%s/common/lib/%s", random_word, name);
if(!__crt_syscall(SYS_stat, path, buf)) {
return 0;
}
sprintf(path, "/%s/priv_ex/lib/%s", random_word, name);
if(!__crt_syscall(SYS_stat, path, buf)) {
return 0;
}
sprintf(path, "/%s/common_ex/lib/%s", random_word, name);
if(!__crt_syscall(SYS_stat, path, buf)) {
return 0;
}
}
if((ldpaths=getenv("LD_LIBRARY_PATH"))) {
for(int i=0; ldpaths[i]; i++) {
path[off++] = ldpaths[i];
@@ -215,18 +228,24 @@ __rtld_find_file(const char *name, char* path) {
path[off+1] = 0;
strcat(path, name);
off = 0;
if(!__syscall(SYS_stat, path, buf)) {
if(!__crt_syscall(SYS_stat, path, buf)) {
return 0;
}
}
}
}
strcpy(path, "/user/homebrew/lib/");
strcat(path, name);
if(!__syscall(SYS_stat, path, buf)) {
sprintf(path, "/user/homebrew/lib/%s", name);
if(!__crt_syscall(SYS_stat, path, buf)) {
return 0;
}
if(! __crt_syscall(SYS___getcwd, cwd, sizeof(cwd))) {
sprintf(path, "%s/%s", cwd, name);
if(!__crt_syscall(SYS_stat, path, buf)) {
return 0;
}
}
path[0] = 0;
return -1;
+7 -7
View File
@@ -136,13 +136,13 @@ int __rtld_init(void);
*
* The search order is as follows:
* 1 - absolute path
* 2 - current work dir
* 3 - /system/priv/lib/
* 4 - /system/common/lib/
* 5 - /system_ex/priv_ex/lib/
* 6 - /system_ex/common_ex/lib/
* 7 - paths in the env var LD_LIBRARY_PATH
* 8 - /user/homebrew/lib/
* 2 - /system/priv/lib/
* 3 - /system/common/lib/
* 4 - /system_ex/priv_ex/lib/
* 5 - /system_ex/common_ex/lib/
* 6 - paths in the env var LD_LIBRARY_PATH
* 7 - /user/homebrew/lib/
* 8 - current work dir
**/
int __rtld_find_file(const char *name, char* path);
+2 -2
View File
@@ -400,7 +400,7 @@ payload_destroy(rtld_lib_t* ctx) {
rtld_lib_t*
__rtld_payload_new(const char *soname) {
rtld_payload_lib_t* lib = calloc(1, sizeof(rtld_payload_lib_t));
int pid = __syscall(SYS_getpid);
int pid = __crt_syscall(SYS_getpid);
lib->open = payload_open;
lib->init = payload_init;
@@ -414,7 +414,7 @@ __rtld_payload_new(const char *soname) {
lib->mapsize = __image_end - __image_start;
strcpy(lib->soname, soname);
__syscall(0x268, pid, lib->soname, 1024);
__crt_syscall(0x268, pid, lib->soname, 1024);
return (rtld_lib_t*)lib;
}
+12 -12
View File
@@ -95,7 +95,7 @@ typedef struct rtld_so_lib {
static void*
mmap(void* addr, unsigned long len, int prot, int flags, int fd,
unsigned long offset) {
return (void*)__syscall(SYS_mmap, addr, len, prot, flags, fd, offset);
return (void*)__crt_syscall(SYS_mmap, addr, len, prot, flags, fd, offset);
}
@@ -107,7 +107,7 @@ mprotect(void* addr, unsigned long size, int prot) {
if((prot & PROT_EXEC)) {
return kernel_mprotect(-1, (unsigned long)addr, size, prot);
} else {
return (int)__syscall(SYS_mprotect, addr, size, prot);
return (int)__crt_syscall(SYS_mprotect, addr, size, prot);
}
}
@@ -117,7 +117,7 @@ mprotect(void* addr, unsigned long size, int prot) {
**/
static int
munmap(void* addr, unsigned long len) {
return (int)__syscall(SYS_munmap, addr, len);
return (int)__crt_syscall(SYS_munmap, addr, len);
}
@@ -130,37 +130,37 @@ readfile(const char* path) {
long len;
int fd;
if((fd=(int)__syscall(SYS_open, path, 0)) < 0) {
if((fd=(int)__crt_syscall(SYS_open, path, 0)) < 0) {
klog_perror("open");
return 0;
}
if((len=__syscall(SYS_lseek, fd, 0, SEEK_END)) < 0) {
if((len=__crt_syscall(SYS_lseek, fd, 0, SEEK_END)) < 0) {
klog_perror("lseek");
__syscall(SYS_close, fd);
__crt_syscall(SYS_close, fd);
return 0;
}
if(__syscall(SYS_lseek, fd, 0, SEEK_SET) < 0) {
if(__crt_syscall(SYS_lseek, fd, 0, SEEK_SET) < 0) {
klog_perror("lseek");
__syscall(SYS_close, fd);
__crt_syscall(SYS_close, fd);
return 0;
}
if(!(buf=malloc(len))) {
klog_perror("malloc");
__syscall(SYS_close, fd);
__crt_syscall(SYS_close, fd);
return 0;
}
if(__syscall(SYS_read, fd, buf, len) != len) {
if(__crt_syscall(SYS_read, fd, buf, len) != len) {
klog_perror("read");
free(buf);
__syscall(SYS_close, fd);
__crt_syscall(SYS_close, fd);
return 0;
}
if(__syscall(SYS_close, fd) < 0) {
if(__crt_syscall(SYS_close, fd) < 0) {
klog_perror("close");
free(buf);
return 0;
+3 -2
View File
@@ -19,7 +19,8 @@ along with this program; see the file COPYING. If not, see
static __attribute__ ((used)) long ptr_syscall = 0;
void __syscall() {
void
__crt_syscall() {
asm(".intel_syntax noprefix\n"
" mov rax, rdi\n"
" mov rdi, rsi\n"
@@ -34,7 +35,7 @@ void __syscall() {
int
__syscall_init(payload_args_t *args) {
__crt_syscall_init(payload_args_t *args) {
int (*sceKernelDlsym)(int, const char*, void*) = 0;
if(args->sys_dynlib_dlsym(0x1, "sceKernelDlsym", &sceKernelDlsym)) {
+22 -20
View File
@@ -22,33 +22,35 @@ along with this program; see the file COPYING. If not, see
/**
* syscall number definitions.
**/
#define SYS_read 3
#define SYS_write 4
#define SYS_open 5
#define SYS_close 6
#define SYS_getpid 20
#define SYS_access 33
#define SYS_munmap 73
#define SYS_mprotect 74
#define SYS_setsockopt 105
#define SYS_stat 188
#define SYS_sysctl 202
#define SYS___getcwd 326
#define SYS_mmap 477
#define SYS_lseek 478
#define SYS_mdbg_call 573
#define SYS_sprx_dlsym 591
#define SYS_sprx_load 594
#define SYS_sprx_unload 595
#define SYS_read 3
#define SYS_write 4
#define SYS_open 5
#define SYS_close 6
#define SYS_getpid 20
#define SYS_access 33
#define SYS_munmap 73
#define SYS_mprotect 74
#define SYS_setsockopt 105
#define SYS_stat 188
#define SYS_sysctl 202
#define SYS___getcwd 326
#define SYS_mmap 477
#define SYS_lseek 478
#define SYS_mdbg_call 573
#define SYS_sprx_dlsym 591
#define SYS_sprx_load 594
#define SYS_sprx_unload 595
#define SYS_randomized_path 602
#define SYS_dynlib_get_obj_member 649
/**
* Make a syscall.
**/
long __syscall(long sysno, ...);
long __crt_syscall(long sysno, ...);
/**
* Initialize the syscall function.
**/
int __syscall_init(payload_args_t* args);
int __crt_syscall_init(payload_args_t* args);
+19 -22
View File
@@ -21,10 +21,10 @@ TOOLCHAINS := toolchain/prospero.sh \
toolchain/prospero.cmake \
toolchain/prospero.ini
TOOLS := bin/cmake-bin-wrapper \
bin/llvm-bin-wrapper \
bin/meson-bin-wrapper \
bin/llvm-config \
TOOLS := bin/prospero-cmake \
bin/prospero-llvm \
bin/prospero-meson \
bin/prospero-llvm-config \
bin/prospero-clang \
bin/prospero-clang++ \
bin/prospero-deploy \
@@ -38,17 +38,12 @@ LDSCRIPTS := elf_x86_64.x
.PHONY: all clean install
all: bin/prospero-nid
clean:
rm -f bin/prospero-nid
bin/prospero-nid: bin/prospero-nid.c
$(CC) -o $@ $<
all:
install: install-tools install-symlinks install-ldscripts install-toolchains
install-ldscripts: $(LDSCRIPTS)
install -d $(DESTDIR)
install -d $(DESTDIR)/ldscripts
install $^ $(DESTDIR)/ldscripts
install -d $(DESTDIR)/target/lib
@@ -56,25 +51,27 @@ install-ldscripts: $(LDSCRIPTS)
ln -sf ../../ldscripts/elf_x86_64.x $(DESTDIR)/target/lib/prx.script
install-toolchains: $(TOOLCHAINS)
install -d $(DESTDIR)
install -d $(DESTDIR)/toolchain
install $^ $(DESTDIR)/toolchain
install-tools: $(TOOLS)
install -d $(DESTDIR)
install -d $(DESTDIR)/bin
install $^ $(DESTDIR)/bin
install-symlinks:
ln -sf llvm-bin-wrapper $(DESTDIR)/bin/llvm-ar
ln -sf llvm-bin-wrapper $(DESTDIR)/bin/llvm-nm
ln -sf llvm-bin-wrapper $(DESTDIR)/bin/llvm-objcopy
ln -sf llvm-bin-wrapper $(DESTDIR)/bin/llvm-ranlib
ln -sf llvm-bin-wrapper $(DESTDIR)/bin/llvm-strip
ln -sf llvm-bin-wrapper $(DESTDIR)/bin/clang
ln -sf llvm-bin-wrapper $(DESTDIR)/bin/clang++
ln -sf llvm-bin-wrapper $(DESTDIR)/bin/clang-cpp
ln -sf llvm-bin-wrapper $(DESTDIR)/bin/ld.lld
ln -sf cmake-bin-wrapper $(DESTDIR)/bin/prospero-cmake
ln -sf meson-bin-wrapper $(DESTDIR)/bin/prospero-meson
install -d $(DESTDIR)
install -d $(DESTDIR)/bin
ln -sf prospero-llvm $(DESTDIR)/bin/llvm-ar
ln -sf prospero-llvm $(DESTDIR)/bin/llvm-nm
ln -sf prospero-llvm $(DESTDIR)/bin/llvm-objcopy
ln -sf prospero-llvm $(DESTDIR)/bin/llvm-ranlib
ln -sf prospero-llvm $(DESTDIR)/bin/llvm-strip
ln -sf prospero-llvm $(DESTDIR)/bin/clang
ln -sf prospero-llvm $(DESTDIR)/bin/clang++
ln -sf prospero-llvm $(DESTDIR)/bin/clang-cpp
ln -sf prospero-llvm $(DESTDIR)/bin/ld.lld
ln -sf llvm-ar $(DESTDIR)/bin/prospero-ar
ln -sf llvm-nm $(DESTDIR)/bin/prospero-nm
ln -sf llvm-objcopy $(DESTDIR)/bin/prospero-objcopy
+1 -1
View File
@@ -58,7 +58,7 @@ fi
# clang-20 started appending crt objects when linking
if [[ $($SCRIPT_DIR/llvm-config --version | cut -d. -f1) -ge 20 ]]; then
if [[ $($SCRIPT_DIR/prospero-llvm-config --version | cut -d. -f1) -ge 20 ]]; then
export SCE_PROSPERO_SDK_DIR="${PS5_PAYLOAD_SDK}"
LIBS_CRT=""
fi
+1 -1
View File
@@ -63,7 +63,7 @@ if [[ "${TU}" == "" ]]; then
fi
# clang++-20 started appending crt objects when linking
if [[ $($SCRIPT_DIR/llvm-config --version | cut -d. -f1) -ge 20 ]]; then
if [[ $($SCRIPT_DIR/prospero-llvm-config --version | cut -d. -f1) -ge 20 ]]; then
export SCE_PROSPERO_SDK_DIR="${PS5_PAYLOAD_SDK}/"
LIBS_CRT=""
fi
+1 -1
View File
@@ -19,7 +19,7 @@ SCRIPT_PATH="${BASH_SOURCE[0]}"
SCRIPT_NAME="$(basename "${SCRIPT_PATH}")"
SCRIPT_DIR="$(dirname "${SCRIPT_PATH}")"
TOOLCHAIN="${SCRIPT_NAME::-6}"
TOOLCHAIN=$(echo "$SCRIPT_NAME" | sed 's/......$//')
export CMAKE_TOOLCHAIN_FILE="${SCRIPT_DIR}/../toolchain/${TOOLCHAIN}.cmake"
+55 -10
View File
@@ -15,23 +15,68 @@
# along with this program; see the file COPYING. If not see
# <http://www.gnu.org/licenses/>
PS5_HOST=""
PS5_PORT=""
PS5_PAYLOAD=""
HOST=$PS5_HOST
PORT=$PS5_PORT
while getopts "h:p:" opt; do
PAYLOAD=""
INTERACTIVE=""
show_help() {
cat <<EOF
Usage: $(basename "$0") -h HOST [-p PORT] [-i] PAYLOAD_PATH_OR_URI
Options:
-h HOST Set the host address (defaults to \$PS5_HOST)
-p PORT Set the port (defaults to \$PS5_PORT if set, else 9021)
-i Enable interactive mode (append /dev/stdin to payload)
-H, --help Show this help message and exit
Arguments:
PAYLOAD_PATH Path or URI to the payload
EOF
}
if [ -z "$PORT" ]; then
PORT=9021
fi
for arg in "$@"; do
case "$arg" in
--help)
show_help
exit 0
;;
esac
done
while getopts "h:p:i" opt; do
case ${opt} in
h) PS5_HOST=$OPTARG;;
p) PS5_PORT=$OPTARG;;
h) HOST=$OPTARG;;
p) PORT=$OPTARG;;
i) INTERACTIVE="1";;
esac
done
shift $((OPTIND -1))
if [[ -z $PS5_HOST || -z $PS5_PORT || -z $1 ]]; then
echo "Usage: $(basename $0) -h HOST -p PORT PAYLOAD_PATH" >&2
if [[ -z $HOST || -z $PORT || -z $1 ]]; then
echo "Usage: $(basename $0) -h HOST [-p PORT] [-i] PAYLOAD_PATH" >&2
exit 1
fi
PS5_PAYLOAD=$1
socat -t 99999999 - TCP:$PS5_HOST:$PS5_PORT < "$PS5_PAYLOAD"
if [[ -z $INTERACTIVE ]]; then
if [ -e "$1" ]; then
socat -t 9999999 - TCP:$HOST:$PORT < $1
else
echo "$1" | socat -t 9999999 - TCP:$HOST:$PORT
fi
else
if [ -e "$1" ]; then
{ cat "$1" && cat /dev/stdin; } | socat - TCP:$HOST:$PORT
else
{ echo "$1" && cat /dev/stdin; } | socat - TCP:$HOST:$PORT
fi
fi
+32 -8
View File
@@ -1,5 +1,6 @@
#!/usr/bin/env bash
# Copyright (C) 2024 John Törnblom
# Copyright (C) 2026 Aleksei Kulaev
#
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
@@ -21,19 +22,42 @@ SCRIPT_DIR="$(dirname "${SCRIPT_PATH}")"
PS5_PAYLOAD_SDK="$(realpath "${SCRIPT_DIR}/..")"
PS5_PAYLOAD_HBROOT="${PS5_PAYLOAD_SDK}/target/user/homebrew"
LLVM_CONFIG="${SCRIPT_DIR}/llvm-config"
LLVM_BINDIR=$("${LLVM_CONFIG}" --bindir)
PIE="-pie"
LDSCRIPT="-T${PS5_PAYLOAD_SDK}/ldscripts/elf_x86_64.x"
for ARG in "$@"; do
if [[ "$ARG" == "--shared" ]]; then
PIE=""
PIE=""
fi
if [[ "$ARG" == "-r" ]]; then
PIE=""
fi
if [[ "$ARG" == "--static" ]]; then
PIE=""
fi
if [[ "$ARG" == "--script" || "$ARG" == "-T" ]]; then
LDSCRIPT=""
fi
done
LLVM_BINDIR=$("${SCRIPT_DIR}/prospero-llvm-config" --bindir)
BIN_PATH="${LLVM_BINDIR}/ld.lld"
# When using macos with brew, lld-19 and above are not installed in the standard
# llvm bindir directory, compensate for that here.
if ! command -v "${BIN_PATH}" >/dev/null 2>&1; then
if [ "$(uname -s)" = "Darwin" ]; then
BREW="$(command -v brew 2>/dev/null)"
if [ -n "${BREW}" ]; then
BIN_PATH="$("${BREW}" --prefix lld 2>/dev/null)/bin/ld.lld"
else
echo "Unable to find brew" >&2
exit 1
fi
fi
fi
exec "${BIN_PATH}" \
-m elf_x86_64 $PIE --eh-frame-hdr \
-z max-page-size=0x4000 \
-T "${PS5_PAYLOAD_SDK}/ldscripts/elf_x86_64.x" \
"$@"
-m elf_x86_64 $PIE $LDSCRIPT --eh-frame-hdr \
-z max-page-size=0x4000 -mllvm -emulated-tls \
"$@" --hash-style=gnu
@@ -20,8 +20,7 @@ SCRIPT_NAME="$(basename "${SCRIPT_PATH}")"
SCRIPT_DIR="$(dirname "${SCRIPT_PATH}")"
# check if script name matches an llvm tool
LLVM_CONFIG="${SCRIPT_DIR}/llvm-config"
LLVM_BINDIR=$("${LLVM_CONFIG}" --bindir)
LLVM_BINDIR=$("${SCRIPT_DIR}/prospero-llvm-config" --bindir)
BIN_PATH="${LLVM_BINDIR}/${SCRIPT_NAME}"
if [ -f "${BIN_PATH}" ]; then
exec "${BIN_PATH}" "$@"
@@ -30,7 +29,7 @@ fi
# check if symlink points to this script
SCRIPT_LINK="$(readlink "${SCRIPT_PATH}")"
SCRIPT_LINK="$(basename "${SCRIPT_LINK}")"
if [ "$SCRIPT_LINK" = "llvm-bin-wrapper" ]; then
if [ "$SCRIPT_LINK" = "prospero-llvm" ]; then
BIN_NAME=$(echo $SCRIPT_NAME | rev | cut -d'-' -f1 | rev)
BIN_PATH="${LLVM_BINDIR}/${BIN_NAME}"
exec -a "${SCRIPT_NAME}" "${BIN_PATH}" "$@"
@@ -40,6 +39,9 @@ fi
if [ "$SCRIPT_LINK" = "" ]; then
BIN_NAME=$(echo $SCRIPT_NAME | rev | cut -d'-' -f1 | rev)
BIN_PATH="${LLVM_BINDIR}/llvm-${BIN_NAME}"
if [ "$BIN_NAME" = "llvm" ]; then
exit 1
fi
exec -a "${SCRIPT_NAME}" "${BIN_PATH}" "$@"
fi
@@ -15,20 +15,30 @@
# along with this program; see the file COPYING. If not see
# <http://www.gnu.org/licenses/>.
SCRIPT_PATH="${BASH_SOURCE[0]}"
SCRIPT_PATH="$(readlink -f "$SCRIPT_PATH")"
if [ -x "$(command -v "${LLVM_CONFIG}")" ]; then
exec "${LLVM_CONFIG}"
LLVM_CONFIG="$(readlink -f "$LLVM_CONFIG")"
if [ "$LLVM_CONFIG" != "$SCRIPT_PATH" ]; then
exec "${LLVM_CONFIG}" "$@"
fi
fi
CANDIDATES=("llvm-config-20"
"llvm-config-19"
"llvm-config-18"
CANDIDATES=("llvm-config-23"
"llvm-config-22"
"llvm-config-21"
"llvm-config-20"
"llvm-config-19"
"llvm-config-18"
"llvm-config-17"
"llvm-config-16"
"llvm-config-15")
"llvm-config-15"
"llvm-config")
for LLVM_CONFIG in "${CANDIDATES[@]}"; do
if [ -x "$(command -v "${LLVM_CONFIG}")" ]; then
exec "${LLVM_CONFIG}" "$@"
for CMD in "${CANDIDATES[@]}"; do
if [ -x "$(command -v "${CMD}")" ]; then
exec "${CMD}" "$@"
fi
done
@@ -19,7 +19,7 @@ SCRIPT_PATH="${BASH_SOURCE[0]}"
SCRIPT_NAME="$(basename "${SCRIPT_PATH}")"
SCRIPT_DIR="$(dirname "${SCRIPT_PATH}")"
TOOLCHAIN="${SCRIPT_NAME::-6}"
TOOLCHAIN=$(echo "$SCRIPT_NAME" | sed 's/......$//')
if [[ "$1" = "setup" ]]; then
ARGS="setup --cross-file=${SCRIPT_DIR}/../toolchain/${TOOLCHAIN}.ini ${@:2}"
+56
View File
@@ -0,0 +1,56 @@
#!/usr/bin/env python3
# encoding: utf-8
# Copyright (C) 2026 John Törnblom
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; see the file COPYING. If not see
# <http://www.gnu.org/licenses/>.
import hashlib
import struct
import sys
def nid_encode(sym):
charset = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-'
salt = b'\x51\x8d\x64\xa6\x35\xde\xd8\xc1\xe6\xb0\x39\xb1\xc3\xe5\x52\x30'
sha1 = hashlib.sha1()
sha1.update(sym.encode('utf-8'))
sha1.update(salt)
digest = bytearray(sha1.digest())
value = struct.unpack('>Q', digest[0:8])[0]
digest[0:8] = struct.pack('<Q', value)
digest[8:16] = b'\x00' * 8
nid = []
for i in range(0, 11, 3):
a = digest[i]
b = digest[i+1]
c = digest[i+2]
abc = (a << 16) | (b << 8) | c
nid.append(charset[(abc >> 18) & 0x3F])
nid.append(charset[(abc >> 12) & 0x3F])
nid.append(charset[(abc >> 6) & 0x3F])
nid.append(charset[abc & 0x3F])
return ''.join(nid[:11])
if __name__ == '__main__':
if len(sys.argv) < 2:
print('Usage: %s <SYMBOL_NAME>' % sys.argv[0])
sys.exit(1)
print(nid_encode(sys.argv[1]))
+3
View File
@@ -26,4 +26,7 @@ export PKG_CONFIG_SYSROOT_DIR=${PS5_PAYLOAD_SDK}/target
export PKG_CONFIG_LIBDIR=${PKG_CONFIG_SYSROOT_DIR}/user/homebrew/lib/pkgconfig
export PKG_CONFIG_PATH=${PKG_CONFIG_SYSROOT_DIR}/user/homebrew/libdata/pkgconfig
# Needed by pkgconf-3, see https://man.archlinux.org/man/pkgconf.1.en#DESTDIR
unset DESTDIR
exec -a "${SCRIPT_NAME}" pkg-config --static "$@"
+9 -1
View File
@@ -66,9 +66,17 @@ else()
set(CMAKE_LINKER ${PS5_PAYLOAD_SDK}/bin/prospero-lld CACHE PATH "")
set(CMAKE_AR ${PS5_PAYLOAD_SDK}/bin/prospero-ar CACHE PATH "")
set(CMAKE_STRIP ${PS5_PAYLOAD_SDK}/bin/prospero-strip CACHE PATH "")
set(CMAKE_C_COMPILER_AR ${PS5_PAYLOAD_SDK}/bin/prospero-ar CACHE PATH "")
set(CMAKE_CXX_COMPILER_AR ${PS5_PAYLOAD_SDK}/bin/prospero-ar CACHE PATH "")
set(CMAKE_RANLIB ${PS5_PAYLOAD_SDK}/bin/prospero-ranlib CACHE PATH "")
set(CMAKE_C_COMPILER_RANLIB ${PS5_PAYLOAD_SDK}/bin/prospero-ranlib CACHE PATH "")
set(CMAKE_CXX_COMPILER_RANLIB ${PS5_PAYLOAD_SDK}/bin/prospero-ranlib CACHE PATH "")
set(CMAKE_STRIP ${PS5_PAYLOAD_SDK}/bin/prospero-strip CACHE PATH "")
set(PKG_CONFIG_EXECUTABLE ${PS5_PAYLOAD_SDK}/bin/prospero-pkg-config CACHE PATH "")
set(CMAKE_FIND_PACKAGE_PREFER_CONFIG TRUE)
set(PS5_DEPLOY ${PS5_PAYLOAD_SDK}/bin/prospero-deploy CACHE PATH "")
set(PAYLOAD_DEPLOY ${PS5_DEPLOY})
endif()
+3 -1
View File
@@ -1,13 +1,15 @@
[binaries]
c = '@DIRNAME@/../bin/prospero-clang'
cpp = '@DIRNAME@/../bin/prospero-clang++'
objc = '@DIRNAME@/../bin/prospero-clang'
objcpp = '@DIRNAME@/../bin/prospero-clang++'
ld = '@DIRNAME@/../bin/prospero-lld'
ar = '@DIRNAME@/../bin/prospero-ar'
strip = '@DIRNAME@/../bin/prospero-strip'
cmake = '@DIRNAME@/../bin/prospero-cmake'
pkg-config = '@DIRNAME@/../bin/prospero-pkg-config'
[target_machine]
[host_machine]
system = 'freebsd'
cpu_family = 'x86_64'
cpu = 'x86_64'
+2
View File
@@ -26,6 +26,8 @@ PS5_DEPLOY := $(PS5_PAYLOAD_SDK)/bin/prospero-deploy
AS := $(PS5_PAYLOAD_SDK)/bin/prospero-as
CC := $(PS5_PAYLOAD_SDK)/bin/prospero-clang
CXX := $(PS5_PAYLOAD_SDK)/bin/prospero-clang++
OBJC := $(PS5_PAYLOAD_SDK)/bin/prospero-clang
OBJCXX := $(PS5_PAYLOAD_SDK)/bin/prospero-clang++
LD := $(PS5_PAYLOAD_SDK)/bin/prospero-lld
PKG_CONFIG := $(PS5_PAYLOAD_SDK)/bin/prospero-pkg-config
AR := $(PS5_PAYLOAD_SDK)/bin/prospero-ar
+2
View File
@@ -33,6 +33,8 @@ export PS5_CROSS_FIX_ROOT=${PS5_PAYLOAD_SDK}/bin/prospero-cross-fix-root
export AS=${PS5_PAYLOAD_SDK}/bin/prospero-as
export CC=${PS5_PAYLOAD_SDK}/bin/prospero-clang
export CXX=${PS5_PAYLOAD_SDK}/bin/prospero-clang++
export OBJC=${PS5_PAYLOAD_SDK}/bin/prospero-clang
export OBJCXX=${PS5_PAYLOAD_SDK}/bin/prospero-clang++
export LD=${PS5_PAYLOAD_SDK}/bin/prospero-lld
export AR=${PS5_PAYLOAD_SDK}/bin/prospero-ar
+1 -1
View File
@@ -29,4 +29,4 @@ install:
cp -r ps5/. $(DESTDIR)/target/include/ps5
install -d $(DESTDIR)/target/user/homebrew/include
ln -sf user/homebrew/include $(DESTDIR)/target/include_common
ln -sfn user/homebrew/include $(DESTDIR)/target/include_common
+7
View File
@@ -146,10 +146,17 @@ typedef __uint32_t __vm_paddr_t;
#endif
typedef __uint32_t __vm_size_t;
#endif
#ifdef __SCE__
typedef unsigned short ___wchar_t;
#define __WCHAR_MIN 0 /* min value for a wchar_t */
#define __WCHAR_MAX 0xffff /* max value for a wchar_t */
#else
typedef int ___wchar_t;
#define __WCHAR_MIN __INT_MIN /* min value for a wchar_t */
#define __WCHAR_MAX __INT_MAX /* max value for a wchar_t */
#endif
/*
* Unusual type definitions.
+42
View File
@@ -0,0 +1,42 @@
/* Copyright (C) 2026 John Törnblom
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 3, or (at your option) any
later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>. */
#pragma once
#include <sys/cdefs.h>
#include <stdint.h>
__BEGIN_DECLS
/**
* Copy data into the kernel via iommu write commands, thus bypassing some of
* the write permission checks when going via the CPU.
**/
int kernel_iommu_copyin(const void *buf, intptr_t kaddr, size_t len);
/**
* Convenience functions for common uses of kernel_iommu_copyin().
**/
int kernel_iommu_setchar(intptr_t kaddr, char val);
int kernel_iommu_setshort(intptr_t kaddr, short val);
int kernel_iommu_setint(intptr_t kaddr, int val);
int kernel_iommu_setlong(intptr_t kaddr, long val);
__END_DECLS
+39 -9
View File
@@ -21,7 +21,7 @@ along with this program; see the file COPYING. If not, see
__BEGIN_DECLS
// Absolute kernel pointers
// absolute kernel pointers
extern const intptr_t KERNEL_ADDRESS_TEXT_BASE;
extern const intptr_t KERNEL_ADDRESS_DATA_BASE;
extern const intptr_t KERNEL_ADDRESS_ALLPROC;
@@ -33,13 +33,13 @@ extern const intptr_t KERNEL_ADDRESS_QA_FLAGS;
extern const intptr_t KERNEL_ADDRESS_TARGETID;
extern const intptr_t KERNEL_ADDRESS_BUS_DATA_DEVICES;
// Proc field offsets
// struct proc field offsets
extern const off_t KERNEL_OFFSET_PROC_P_UCRED;
extern const off_t KERNEL_OFFSET_PROC_P_FD;
extern const off_t KERNEL_OFFSET_PROC_P_PID;
extern const off_t KERNEL_OFFSET_PROC_P_VMSPACE;
// Ucred field offsets
// struct ucred field offsets
extern const off_t KERNEL_OFFSET_UCRED_CR_UID;
extern const off_t KERNEL_OFFSET_UCRED_CR_RUID;
extern const off_t KERNEL_OFFSET_UCRED_CR_SVUID;
@@ -48,15 +48,18 @@ extern const off_t KERNEL_OFFSET_UCRED_CR_SCEAUTHID;
extern const off_t KERNEL_OFFSET_UCRED_CR_SCECAPS;
extern const off_t KERNEL_OFFSET_UCRED_CR_SCEATTRS;
// Filedesc field offsets
// struct filedesc field offsets
extern const off_t KERNEL_OFFSET_FILEDESC_FD_RDIR;
extern const off_t KERNEL_OFFSET_FILEDESC_FD_JDIR;
// struct vmspace field offsets
extern const off_t KERNEL_OFFSET_VMSPACE_VM_PMAP;
uint32_t kernel_get_fw_version(void);
int32_t kernel_copyin(const void *udaddr, intptr_t kaddr, size_t len);
int32_t kernel_copyout(intptr_t kaddr, void *udaddr, size_t len);
int32_t kernel_copyin(const void *udaddr, intptr_t kaddr, size_t len);
int32_t kernel_copyout(intptr_t kaddr, void *udaddr, size_t len);
int32_t kernel_setlong(intptr_t addr, uint64_t val);
int32_t kernel_setint(intptr_t addr, uint32_t val);
@@ -69,15 +72,31 @@ uint16_t kernel_getshort(intptr_t addr);
uint8_t kernel_getchar(intptr_t addr);
intptr_t kernel_get_proc(pid_t pid);
intptr_t kernel_get_proc_thread(pid_t pid, pid_t tid);
intptr_t kernel_get_proc_ucred(pid_t pid);
intptr_t kernel_get_proc_filedesc(pid_t pid);
intptr_t kernel_get_proc_file(pid_t pid, int fd);
int kernel_proc_copyin(pid_t pid, const void *buf, intptr_t addr, size_t len);
int kernel_proc_copyout(pid_t pid, intptr_t addr, void *buf, size_t len);
uint64_t kernel_proc_getlong(pid_t pid, intptr_t addr);
uint32_t kernel_proc_getint(pid_t pid, intptr_t addr);
uint16_t kernel_proc_getshort(pid_t pid, intptr_t addr);
uint8_t kernel_proc_getchar(pid_t pid, intptr_t addr);
int kernel_proc_setchar(pid_t pid, intptr_t addr, char val);
int kernel_proc_setshort(pid_t pid, intptr_t addr, short val);
int kernel_proc_setint(pid_t pid, intptr_t addr, int val);
int kernel_proc_setlong(pid_t pid, intptr_t addr, long val);
int kernel_get_vmem_protection(pid_t pid, intptr_t addr, size_t len);
int kernel_set_vmem_protection(pid_t pid, intptr_t addr, size_t len, int prot);
int kernel_mprotect(pid_t pid, intptr_t addr, size_t size, int prot);
int kernel_overlap_sockets(pid_t pid, int master_sock, int victim_sock);
int kernel_dynlib_handle(pid_t pid, const char* basename, uint32_t *handle);
int kernel_dynlib_handle(pid_t pid, const char* basename, uint32_t *handle);
intptr_t kernel_dynlib_dlsym(pid_t pid, uint32_t handle, const char *sym);
intptr_t kernel_dynlib_resolve(pid_t pid, uint32_t handle, const char *nid);
intptr_t kernel_dynlib_mapbase_addr(pid_t pid, uint32_t handle);
@@ -91,8 +110,8 @@ int32_t kernel_set_ucred_authid(pid_t pid, uint64_t authid);
int32_t kernel_get_ucred_caps(pid_t pid, uint8_t caps[16]);
int32_t kernel_set_ucred_caps(pid_t pid, const uint8_t caps[16]);
uint64_t kernel_get_ucred_attrs(pid_t pid);
int32_t kernel_set_ucred_attrs(pid_t pid, uint64_t attr);
int32_t kernel_get_ucred_attrs(pid_t pid, uint8_t attrs[32]);
int32_t kernel_set_ucred_attrs(pid_t pid, const uint8_t attrs[32]);
int32_t kernel_get_qaflags(uint8_t qaflags[16]);
int32_t kernel_set_qaflags(uint8_t const qaflags[16]);
@@ -105,12 +124,23 @@ int32_t kernel_set_proc_rootdir(pid_t pid, intptr_t vnode);
intptr_t kernel_get_proc_jaildir(pid_t pid);
int32_t kernel_set_proc_jaildir(pid_t pid, intptr_t vnode);
uid_t kernel_get_ucred_uid(pid_t pid);
int32_t kernel_set_ucred_uid(pid_t pid, uid_t uid);
uid_t kernel_get_ucred_ruid(pid_t pid);
int32_t kernel_set_ucred_ruid(pid_t pid, uid_t ruid);
uid_t kernel_get_ucred_svuid(pid_t pid);
int32_t kernel_set_ucred_svuid(pid_t pid, uid_t svuid);
gid_t kernel_get_ucred_rgid(pid_t pid);
int32_t kernel_set_ucred_rgid(pid_t pid, gid_t rgid);
gid_t kernel_get_ucred_svgid(pid_t pid);
int32_t kernel_set_ucred_svgid(pid_t pid, gid_t svgid);
intptr_t kernel_get_ucred_prison(pid_t pid);
int kernel_set_ucred_prison(pid_t pid, intptr_t prison);
__END_DECLS
+16 -22
View File
@@ -14,42 +14,36 @@
# along with this program; see the file COPYING. If not see
# <http://www.gnu.org/licenses/>.
DESTDIR ?= /opt/ps5-payload-sdk
CCS := clang-20 clang-19 clang-18 clang-17 clang-16 clang-15 clang
CCS := $(foreach CC,$(CCS),$(if $(shell command -v $(CC) 2> /dev/null),$(CC)))
CC := $(firstword $(CCS))
ifndef CC
$(error No suitable compiler found)
endif
ARS := llvm-ar-20 llvm-ar-19 llvm-ar-18 llvm-ar-17 llvm-ar-16 llvm-ar-15 llvm-ar ar
ARS := $(foreach AR,$(ARS),$(if $(shell command -v $(AR) 2> /dev/null),$(AR)))
AR := $(firstword $(ARS))
ifndef AR
$(error No suitable archiver found)
endif
include ../Makefile.inc
CFLAGS := -target x86_64-sie-ps5 -fPIC -fno-plt -fno-stack-protector
CFLAGS += -nobuiltininc -isystem ../include/freebsd
CFLAGS += -fvisibility-nodllstorageclass=default
CFLAGS += -O1
SRCS := $(wildcard *.c)
OBJS := $(SRCS:.c=.o)
ASFLAGS := $(CFLAGS)
ARCHIVE := libc.a
SRCS := $(wildcard *.c)
OBJS := $(SRCS:.c=.o) _setjmp.o
.PHONY: all clean install
all: $(ARCHIVE)
all: libc.a libdl.a libpthread.a
$(ARCHIVE): $(OBJS)
libc.a: $(OBJS)
$(AR) -rsc $@ $^
libdl.a:
$(AR) -rsc $@
libpthread.a:
$(AR) -rsc $@
clean:
rm -f *.a *.o
install: $(ARCHIVE)
install: libc.a libdl.a libpthread.a
install -d $(DESTDIR)/target/lib
install $^ $(DESTDIR)/target/lib
install libc.a $(DESTDIR)/target/lib
install libdl.a $(DESTDIR)/target/lib
install libpthread.a $(DESTDIR)/target/lib
+95
View File
@@ -0,0 +1,95 @@
/*-
* Copyright (c) 1990 The Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* William Jolitz.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
.asciz "@(#)_setjmp.s 5.1 (Berkeley) 4/23/90"
#endif /* LIBC_SCCS and not lint */
#include <machine/asm.h>
__FBSDID("$FreeBSD$");
/*
* C library -- _setjmp, _longjmp
*
* _longjmp(a,v)
* will generate a "return(v)" from the last call to
* _setjmp(a)
* by restoring registers from the environment 'a'.
* The previous signal state is NOT restored.
*/
ENTRY(_setjmp)
movq %rdi,%rax
movq 0(%rsp),%rdx /* retval */
movq %rdx, 0(%rax) /* 0; retval */
movq %rbx, 8(%rax) /* 1; rbx */
movq %rsp,16(%rax) /* 2; rsp */
movq %rbp,24(%rax) /* 3; rbp */
movq %r12,32(%rax) /* 4; r12 */
movq %r13,40(%rax) /* 5; r13 */
movq %r14,48(%rax) /* 6; r14 */
movq %r15,56(%rax) /* 7; r15 */
fnstcw 64(%rax) /* 8; fpu cw */
stmxcsr 68(%rax) /* and mxcsr */
xorq %rax,%rax
ret
END(_setjmp)
WEAK_REFERENCE(___longjmp, _longjmp)
ENTRY(___longjmp)
movq %rdi,%rdx
/* Restore the mxcsr, but leave exception flags intact. */
stmxcsr -4(%rsp)
movl 68(%rdx),%eax
andl $0xffffffc0,%eax
movl -4(%rsp),%edi
andl $0x3f,%edi
xorl %eax,%edi
movl %edi,-4(%rsp)
ldmxcsr -4(%rsp)
movq %rsi,%rax /* retval */
movq 0(%rdx),%rcx
movq 8(%rdx),%rbx
movq 16(%rdx),%rsp
movq 24(%rdx),%rbp
movq 32(%rdx),%r12
movq 40(%rdx),%r13
movq 48(%rdx),%r14
movq 56(%rdx),%r15
fldcw 64(%rdx)
testq %rax,%rax
jnz 1f
incq %rax
1: movq %rcx,0(%rsp)
ret
END(___longjmp)
.section .note.GNU-stack,"",%progbits
-6
View File
@@ -1,6 +0,0 @@
#include <termios.h>
speed_t
cfgetospeed(const struct termios *t) {
return t->c_ospeed;
}
+67
View File
@@ -0,0 +1,67 @@
/*-
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)getloadavg.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/sysctl.h>
#include <vm/vm_param.h>
#include <stdlib.h>
/*
* getloadavg() -- Get system load averages.
*
* Put `nelem' samples into `loadavg' array.
* Return number of samples retrieved, or -1 on error.
*/
int
getloadavg(double loadavg[], int nelem)
{
struct loadavg loadinfo;
int i, mib[2];
size_t size;
mib[0] = CTL_VM;
mib[1] = VM_LOADAVG;
size = sizeof(loadinfo);
if (sysctl(mib, 2, &loadinfo, &size, NULL, 0) < 0)
return (-1);
nelem = MIN(nelem, sizeof(loadinfo.ldavg) / sizeof(fixpt_t));
for (i = 0; i < nelem; i++)
loadavg[i] = (double) loadinfo.ldavg[i] / loadinfo.fscale;
return (nelem);
}
+19 -1
View File
@@ -14,9 +14,10 @@ You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>. */
#include <sys/types.h>
#include <errno.h>
#include <grp.h>
#include <sys/types.h>
struct group*
getgrnam(const char *name) {
@@ -31,3 +32,20 @@ getgrgid(gid_t gid) {
return 0;
}
int
getgrnam_r(const char *name, struct group *grp, char* buf, size_t buflen,
struct group **result) {
#warning "getgrnam_r() not implemented"
*result = 0;
return ENOSYS;
}
int
getgrgid_r(gid_t gid, struct group *grp, char *buf, size_t buflen,
struct group **result) {
#warning "getgrgid_r() not implemented"
*result = 0;
return ENOSYS;
}
+51
View File
@@ -0,0 +1,51 @@
/*
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)killpg.c 8.1 (Berkeley) 6/2/93";
#endif /* LIBC_SCCS and not lint */
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/types.h>
#include <signal.h>
#include <errno.h>
/*
* Backwards-compatible killpg().
*/
int
killpg(pid_t pgid, int sig)
{
if (pgid == 1) {
errno = ESRCH;
return (-1);
}
return (kill(-pgid, sig));
}
+80
View File
@@ -0,0 +1,80 @@
/* Copyright (C) 2025 John Törnblom
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 3, or (at your option) any
later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>. */
#include <errno.h>
#include <unistd.h>
#include <sys/mount.h>
#include <sys/syscall.h>
static long
__syscall6(long n, long a1, long a2, long a3, long a4, long a5, long a6) {
unsigned long ret;
char iserror;
register long r10 __asm__("r10") = a4;
register long r8 __asm__("r8") = a5;
register long r9 __asm__("r9") = a6;
__asm__ __volatile__(
"syscall" : "=a"(ret), "=@ccc"(iserror), "+r"(r10), "+r"(r8), "+r"(r9) :
"a"(n), "D"(a1), "S"(a2), "d"(a3) :
"rcx", "r11", "memory"
);
return iserror ? -ret : ret;
}
int
mount(const char *type, const char *dir, int flags, void *data) {
long ret;
if((ret=__syscall6(SYS_mount, (long)type, (long)dir, flags, (long)data, 0, 0)) < 0) {
errno = -ret;
return -1;
}
return 0;
}
int
nmount(struct iovec *iov, unsigned int niov, int flags) {
long ret;
if((ret=__syscall6(SYS_nmount, (long)iov, niov, flags, 0, 0, 0)) < 0) {
errno = -ret;
return -1;
}
return 0;
}
int
unmount(const char *dir, int flags) {
long ret;
if((ret=__syscall6(SYS_unmount, (long)dir, flags, 0, 0, 0, 0)) < 0) {
errno = -ret;
return -1;
}
return 0;
}
+15 -1
View File
@@ -80,11 +80,25 @@ static struct protoent g_protent[] = {
const char*
gai_strerror(int err) {
static char buf[50];
if(0 <= err && err < EAI_MAX) {
return g_errlist[err];
}
return "Unknown network error";
sprintf(buf, "Unknown network error code 0x%08x", err);
return buf;
}
const char*
hstrerror(int herr) {
static char buf[50];
sprintf(buf, "Unknown network error code 0x%08x", herr);
return buf;
}
+109
View File
@@ -0,0 +1,109 @@
/* $OpenBSD: nftw.c,v 1.7 2006/03/31 19:41:44 millert Exp $ */
/*
* Copyright (c) 2003, 2004 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Sponsored in part by the Defense Advanced Research Projects
* Agency (DARPA) and Air Force Research Laboratory, Air Force
* Materiel Command, USAF, under agreement number F39502-99-1-0512.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fts.h>
#include <ftw.h>
int
nftw(const char *path, int (*fn)(const char *, const struct stat *, int,
struct FTW *), int nfds, int ftwflags)
{
char * const paths[2] = { (char *)path, NULL };
struct FTW ftw;
FTSENT *cur;
FTS *ftsp;
int error = 0, ftsflags, fnflag, postorder, sverrno;
/* XXX - nfds is currently unused */
if (nfds < 1) {
errno = EINVAL;
return (-1);
}
ftsflags = FTS_COMFOLLOW;
if (!(ftwflags & FTW_CHDIR))
ftsflags |= FTS_NOCHDIR;
if (ftwflags & FTW_MOUNT)
ftsflags |= FTS_XDEV;
if (ftwflags & FTW_PHYS)
ftsflags |= FTS_PHYSICAL;
else
ftsflags |= FTS_LOGICAL;
postorder = (ftwflags & FTW_DEPTH) != 0;
ftsp = fts_open(paths, ftsflags, NULL);
if (ftsp == NULL)
return (-1);
while ((cur = fts_read(ftsp)) != NULL) {
switch (cur->fts_info) {
case FTS_D:
if (postorder)
continue;
fnflag = FTW_D;
break;
case FTS_DC:
continue;
case FTS_DNR:
fnflag = FTW_DNR;
break;
case FTS_DP:
if (!postorder)
continue;
fnflag = FTW_DP;
break;
case FTS_F:
case FTS_DEFAULT:
fnflag = FTW_F;
break;
case FTS_NS:
case FTS_NSOK:
fnflag = FTW_NS;
break;
case FTS_SL:
fnflag = FTW_SL;
break;
case FTS_SLNONE:
fnflag = FTW_SLN;
break;
default:
error = -1;
goto done;
}
ftw.base = cur->fts_pathlen - cur->fts_namelen;
ftw.level = cur->fts_level;
error = fn(cur->fts_path, cur->fts_statp, fnflag, &ftw);
if (error != 0)
break;
}
done:
sverrno = errno;
if (fts_close(ftsp) != 0 && error == 0)
error = -1;
else
errno = sverrno;
return (error);
}
+35
View File
@@ -15,6 +15,7 @@ along with this program; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>. */
#include <ctype.h>
#include <limits.h>
#include <locale.h>
#include <stdarg.h>
#include <stdio.h>
@@ -229,6 +230,40 @@ const _RuneLocale _DefaultRuneLocale = {
};
static const struct lconv posix_lconv = {
.decimal_point = ".",
.thousands_sep = "",
.grouping = "",
.int_curr_symbol = "",
.currency_symbol = "",
.mon_decimal_point = "",
.mon_thousands_sep = "",
.mon_grouping = "",
.positive_sign = "",
.negative_sign = "",
.int_frac_digits = CHAR_MAX,
.frac_digits = CHAR_MAX,
.p_cs_precedes = CHAR_MAX,
.p_sep_by_space = CHAR_MAX,
.n_cs_precedes = CHAR_MAX,
.n_sep_by_space = CHAR_MAX,
.p_sign_posn = CHAR_MAX,
.n_sign_posn = CHAR_MAX,
.int_p_cs_precedes = CHAR_MAX,
.int_p_sep_by_space = CHAR_MAX,
.int_n_cs_precedes = CHAR_MAX,
.int_n_sep_by_space = CHAR_MAX,
.int_p_sign_posn = CHAR_MAX,
.int_n_sign_posn = CHAR_MAX,
};
struct lconv*
localeconv(void) {
return (void*)&posix_lconv;
}
int
asprintf_l(char **strp, locale_t loc, const char *fmt, ...) {
va_list args;
+107
View File
@@ -0,0 +1,107 @@
/*
* Copyright (c) 2016 Boris Astardzhiev, Smartcom-Bulgaria AD
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice(s), this list of conditions and the following disclaimer as
* the first lines of this file unmodified other than the possible
* addition of one or more copyright notices.
* 2. Redistributions in binary form must reproduce the above copyright
* notice(s), this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/syscall.h>
#include <errno.h>
#include <poll.h>
#include <stddef.h>
//#include "libc_private.h"
__attribute__((weak)) long __syscall(long n, ...);
static ssize_t
__sys_recvmsg(int sockfd, struct msghdr *msg, int flags) {
return __syscall(SYS_recvmsg, sockfd, msg, flags);
}
ssize_t
recvmmsg(int s, struct mmsghdr *__restrict msgvec, size_t vlen, int flags,
const struct timespec *__restrict timeout)
{
struct pollfd pfd[1];
size_t i, rcvd;
ssize_t ret;
int res;
short ev;
if (timeout != NULL) {
pfd[0].fd = s;
pfd[0].revents = 0;
pfd[0].events = ev = POLLIN | POLLRDNORM | POLLRDBAND |
POLLPRI;
res = ppoll(&pfd[0], 1, timeout, NULL);
if (res == -1 || res == 0)
return (res);
if (pfd[0].revents & POLLNVAL) {
errno = EBADF;
return (-1);
}
if ((pfd[0].revents & ev) == 0) {
errno = ETIMEDOUT;
return (-1);
}
}
ret = __sys_recvmsg(s, &msgvec[0].msg_hdr, flags);
if (ret == -1)
return (ret);
msgvec[0].msg_len = ret;
/*
* Do non-blocking receive for second and later messages if
* WAITFORONE is set.
*/
if (flags & MSG_WAITFORONE)
flags |= MSG_DONTWAIT;
rcvd = 1;
for (i = rcvd; i < vlen; i++, rcvd++) {
ret = __sys_recvmsg(s, &msgvec[i].msg_hdr, flags);
if (ret == -1) {
/* We have received messages. Let caller know
* about the data received, socket error is
* returned on next invocation.
*/
return (rcvd);
}
/* Save received bytes. */
msgvec[i].msg_len = ret;
}
return (rcvd);
}
+166
View File
@@ -0,0 +1,166 @@
/*
* Copyright (c) 1983, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)scandir.c 8.3 (Berkeley) 1/2/94";
#endif /* LIBC_SCCS and not lint */
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
/*
* Scan the directory dirname calling select to make a list of selected
* directory entries then sort using qsort and compare routine dcomp.
* Returns the number of entries and a pointer to a list of pointers to
* struct dirent (through namelist). Returns -1 if there were any errors.
*/
#include "namespace.h"
#include <dirent.h>
#include <stdlib.h>
#include <string.h>
#include "un-namespace.h"
#ifdef I_AM_SCANDIR_B
#include "block_abi.h"
#define SELECT(x) CALL_BLOCK(select, x)
#ifndef __BLOCKS__
void
qsort_b(void *, size_t, size_t, void*);
#endif
#else
#define SELECT(x) select(x)
#endif
static int alphasort_thunk(void *thunk, const void *p1, const void *p2);
/*
* The DIRSIZ macro is the minimum record length which will hold the directory
* entry. This requires the amount of space in struct dirent without the
* d_name field, plus enough space for the name and a terminating nul byte
* (dp->d_namlen + 1), rounded up to a 4 byte boundary.
*/
#undef DIRSIZ
#define DIRSIZ(dp) \
((sizeof(struct dirent) - sizeof(dp)->d_name) + \
(((dp)->d_namlen + 1 + 3) &~ 3))
int
#ifdef I_AM_SCANDIR_B
scandir_b(const char *dirname, struct dirent ***namelist,
DECLARE_BLOCK(int, select, const struct dirent *),
DECLARE_BLOCK(int, dcomp, const struct dirent **, const struct dirent **))
#else
scandir(const char *dirname, struct dirent ***namelist,
int (*select)(const struct dirent *), int (*dcomp)(const struct dirent **,
const struct dirent **))
#endif
{
struct dirent *d, *p, **names = NULL;
size_t arraysz, numitems;
DIR *dirp;
if ((dirp = opendir(dirname)) == NULL)
return(-1);
numitems = 0;
arraysz = 32; /* initial estimate of the array size */
names = (struct dirent **)malloc(arraysz * sizeof(struct dirent *));
if (names == NULL)
goto fail;
while ((d = readdir(dirp)) != NULL) {
if (select != NULL && !SELECT(d))
continue; /* just selected names */
/*
* Make a minimum size copy of the data
*/
p = (struct dirent *)malloc(DIRSIZ(d));
if (p == NULL)
goto fail;
p->d_fileno = d->d_fileno;
p->d_type = d->d_type;
p->d_reclen = d->d_reclen;
p->d_namlen = d->d_namlen;
bcopy(d->d_name, p->d_name, p->d_namlen + 1);
/*
* Check to make sure the array has space left and
* realloc the maximum size.
*/
if (numitems >= arraysz) {
struct dirent **names2;
names2 = reallocarray(names, arraysz,
2 * sizeof(struct dirent *));
if (names2 == NULL) {
free(p);
goto fail;
}
names = names2;
arraysz *= 2;
}
names[numitems++] = p;
}
closedir(dirp);
if (numitems && dcomp != NULL)
#ifdef I_AM_SCANDIR_B
qsort_b(names, numitems, sizeof(struct dirent *), (void*)dcomp);
#else
qsort_r(names, numitems, sizeof(struct dirent *),
&dcomp, alphasort_thunk);
#endif
*namelist = names;
return (numitems);
fail:
while (numitems > 0)
free(names[--numitems]);
free(names);
closedir(dirp);
return (-1);
}
/*
* Alphabetic order comparison routine for those who want it.
* POSIX 2008 requires that alphasort() uses strcoll().
*/
int
alphasort(const struct dirent **d1, const struct dirent **d2)
{
return (strcoll((*d1)->d_name, (*d2)->d_name));
}
static int
alphasort_thunk(void *thunk, const void *p1, const void *p2)
{
int (*dc)(const struct dirent **, const struct dirent **);
dc = *(int (**)(const struct dirent **, const struct dirent **))thunk;
return (dc((const struct dirent **)p1, (const struct dirent **)p2));
}
+74
View File
@@ -0,0 +1,74 @@
/*
* Copyright (c) 2016 Boris Astardzhiev, Smartcom-Bulgaria AD
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice(s), this list of conditions and the following disclaimer as
* the first lines of this file unmodified other than the possible
* addition of one or more copyright notices.
* 2. Redistributions in binary form must reproduce the above copyright
* notice(s), this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/syscall.h>
//#include "libc_private.h"
__attribute__((weak)) long __syscall(long n, ...);
static ssize_t
__sys_sendmsg(int sockfd, struct msghdr *msg, int flags) {
return __syscall(SYS_sendmsg, sockfd, msg, flags);
}
ssize_t
sendmmsg(int s, struct mmsghdr *__restrict msgvec, size_t vlen, int flags)
{
size_t i, sent;
ssize_t ret;
sent = 0;
for (i = 0; i < vlen; i++, sent++) {
ret = __sys_sendmsg(s, &msgvec[i].msg_hdr, flags);
if (ret == -1) {
if (sent != 0) {
/*
* We have sent messages. Let caller
* know about the data sent, socket
* error is returned on next
* invocation.
*/
return (sent);
}
return (ret);
}
/* Save sent bytes. */
msgvec[i].msg_len = ret;
}
return (sent);
}
+15 -29
View File
@@ -30,6 +30,21 @@ syscall() {
);
}
void
__syscall() {
asm(".intel_syntax noprefix\n"
" mov rax, rdi\n"
" mov rdi, rsi\n"
" mov rsi, rdx\n"
" mov rdx, rcx\n"
" mov r10, r8\n"
" mov r8, r9\n"
" mov r9, qword ptr [rsp + 8]\n"
" syscall\n"
" ret\n"
);
}
void
fork() {
asm(".intel_syntax noprefix\n"
@@ -91,26 +106,6 @@ chown() {
}
void
mount() {
asm(".intel_syntax noprefix\n"
" mov rax, 21\n"
" mov r10, rcx\n"
" syscall\n"
" ret\n"
);
}
void
unmount() {
asm(".intel_syntax noprefix\n"
" mov rax, 22\n"
" mov r10, rcx\n"
" syscall\n"
" ret\n"
);
}
void
ptrace() {
asm(".intel_syntax noprefix\n"
@@ -1181,15 +1176,6 @@ afs3_syscall() {
);
}
void
nmount() {
asm(".intel_syntax noprefix\n"
" mov rax, 378\n"
" mov r10, rcx\n"
" syscall\n"
" ret\n"
);
}
void
__mac_get_proc() {
+269
View File
@@ -0,0 +1,269 @@
/*-
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)termios.c 8.2 (Berkeley) 2/21/94";
#endif /* LIBC_SCCS and not lint */
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "namespace.h"
#include <sys/types.h>
#include <sys/fcntl.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <sys/syscall.h>
#include <errno.h>
#include <string.h>
#define TTYDEFCHARS
#include <termios.h>
#include <unistd.h>
#include "un-namespace.h"
//#include "libc_private.h"
__attribute__((weak)) long __syscall(long n, ...);
int
tcgetattr(int fd, struct termios *t)
{
return (_ioctl(fd, TIOCGETA, t));
}
int
tcsetattr(int fd, int opt, const struct termios *t)
{
struct termios localterm;
if (opt & TCSASOFT) {
localterm = *t;
localterm.c_cflag |= CIGNORE;
t = &localterm;
}
switch (opt & ~TCSASOFT) {
case TCSANOW:
return (_ioctl(fd, TIOCSETA, t));
case TCSADRAIN:
return (_ioctl(fd, TIOCSETAW, t));
case TCSAFLUSH:
return (_ioctl(fd, TIOCSETAF, t));
default:
errno = EINVAL;
return (-1);
}
}
int
tcsetpgrp(int fd, pid_t pgrp)
{
int s;
s = pgrp;
return (_ioctl(fd, TIOCSPGRP, &s));
}
pid_t
tcgetpgrp(int fd)
{
int s;
if (_ioctl(fd, TIOCGPGRP, &s) < 0)
return ((pid_t)-1);
return ((pid_t)s);
}
pid_t
tcgetsid(int fd)
{
int s;
if (_ioctl(fd, TIOCGSID, &s) < 0)
return ((pid_t)-1);
return ((pid_t)s);
}
int
tcsetsid(int fd, pid_t pid)
{
if (pid != getsid(0)) {
errno = EINVAL;
return (-1);
}
return (_ioctl(fd, TIOCSCTTY, NULL));
}
speed_t
cfgetospeed(const struct termios *t)
{
return (t->c_ospeed);
}
speed_t
cfgetispeed(const struct termios *t)
{
return (t->c_ispeed);
}
int
cfsetospeed(struct termios *t, speed_t speed)
{
t->c_ospeed = speed;
return (0);
}
int
cfsetispeed(struct termios *t, speed_t speed)
{
t->c_ispeed = speed;
return (0);
}
int
cfsetspeed(struct termios *t, speed_t speed)
{
t->c_ispeed = t->c_ospeed = speed;
return (0);
}
/*
* Make a pre-existing termios structure into "raw" mode: character-at-a-time
* mode with no characters interpreted, 8-bit data path.
*/
void
cfmakeraw(struct termios *t)
{
t->c_iflag &= ~(IMAXBEL|IXOFF|INPCK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON|IGNPAR);
t->c_iflag |= IGNBRK;
t->c_oflag &= ~OPOST;
t->c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL|ICANON|ISIG|IEXTEN|NOFLSH|TOSTOP|PENDIN);
t->c_cflag &= ~(CSIZE|PARENB);
t->c_cflag |= CS8|CREAD;
t->c_cc[VMIN] = 1;
t->c_cc[VTIME] = 0;
}
/*
* Obtain a termios structure which is similar to the one provided by
* the kernel.
*/
void
cfmakesane(struct termios *t)
{
t->c_cflag = TTYDEF_CFLAG;
t->c_iflag = TTYDEF_IFLAG;
t->c_lflag = TTYDEF_LFLAG;
t->c_oflag = TTYDEF_OFLAG;
t->c_ispeed = TTYDEF_SPEED;
t->c_ospeed = TTYDEF_SPEED;
memcpy(&t->c_cc, ttydefchars, sizeof ttydefchars);
}
int
tcsendbreak(int fd, int len __unused)
{
struct timeval sleepytime;
sleepytime.tv_sec = 0;
sleepytime.tv_usec = 400000;
if (_ioctl(fd, TIOCSBRK, 0) == -1)
return (-1);
(void)__syscall(SYS_select, 0, 0, 0, 0, &sleepytime);
if (_ioctl(fd, TIOCCBRK, 0) == -1)
return (-1);
return (0);
}
int
tcdrain(int fd)
{
return (_ioctl(fd, TIOCDRAIN, 0));
}
int
tcflush(int fd, int which)
{
int com;
switch (which) {
case TCIFLUSH:
com = FREAD;
break;
case TCOFLUSH:
com = FWRITE;
break;
case TCIOFLUSH:
com = FREAD | FWRITE;
break;
default:
errno = EINVAL;
return (-1);
}
return (_ioctl(fd, TIOCFLUSH, &com));
}
int
tcflow(int fd, int action)
{
struct termios term;
u_char c;
switch (action) {
case TCOOFF:
return (_ioctl(fd, TIOCSTOP, 0));
case TCOON:
return (_ioctl(fd, TIOCSTART, 0));
case TCION:
case TCIOFF:
if (tcgetattr(fd, &term) == -1)
return (-1);
c = term.c_cc[action == TCIOFF ? VSTOP : VSTART];
if (c != _POSIX_VDISABLE && _write(fd, &c, sizeof(c)) == -1)
return (-1);
return (0);
default:
errno = EINVAL;
return (-1);
}
/* NOTREACHED */
}
+2
View File
@@ -29,6 +29,8 @@ tmpfile(void) {
return 0;
}
unlink(s);
if(!(f=fdopen(fd, "rw+b"))) {
close(fd);
}
+1 -1
View File
@@ -16,7 +16,7 @@
# <http://www.gnu.org/licenses/>.
LLVM_URL="https://github.com/llvm/llvm-project/releases/download"
LLVM_VER="17.0.6"
LLVM_VER="18.1.8"
if [[ -z "$PS5_PAYLOAD_SDK" ]]; then
echo "error: PS5_PAYLOAD_SDK is not set"
+43
View File
@@ -0,0 +1,43 @@
# Copyright (C) 2026 John Törnblom
#
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; see the file COPYING. If not see
# <http://www.gnu.org/licenses/>.
include ../Makefile.inc
CFLAGS := -target x86_64-sie-ps5 -fPIC -fno-plt -fno-stack-protector
CFLAGS += -nobuiltininc -isystem ../include/freebsd
CFLAGS += -fvisibility-nodllstorageclass=default
CFLAGS += -O1 -D_LIBUFS
ASFLAGS := $(CFLAGS)
SRCS := $(wildcard *.c)
OBJS := $(SRCS:.c=.o)
ARCHIVE := libufs.a
.PHONY: all clean install
all: $(ARCHIVE)
$(ARCHIVE): $(OBJS)
$(AR) -rsc $@ $^
clean:
rm -f *.a *.o
install: $(ARCHIVE)
install -d $(DESTDIR)/target/lib
install $^ $(DESTDIR)/target/lib
+201
View File
@@ -0,0 +1,201 @@
/*
* Copyright (c) 2002 Juli Mallett. All rights reserved.
*
* This software was written by Juli Mallett <jmallett@FreeBSD.org> for the
* FreeBSD project. Redistribution and use in source and binary forms, with
* or without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistribution of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/mount.h>
#include <sys/disk.h>
#include <sys/disklabel.h>
#include <sys/stat.h>
#include <ufs/ufs/ufsmount.h>
#include <ufs/ufs/dinode.h>
#include <ufs/ffs/fs.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <libufs.h>
ssize_t
bread(struct uufsd *disk, ufs2_daddr_t blockno, void *data, size_t size)
{
void *p2;
ssize_t cnt;
ERROR(disk, NULL);
p2 = data;
/*
* XXX: various disk controllers require alignment of our buffer
* XXX: which is stricter than struct alignment.
* XXX: Bounce the buffer if not 64 byte aligned.
* XXX: this can be removed if/when the kernel is fixed
*/
if (((intptr_t)data) & 0x3f) {
p2 = malloc(size);
if (p2 == NULL) {
ERROR(disk, "allocate bounce buffer");
goto fail;
}
}
cnt = pread(disk->d_fd, p2, size, (off_t)(blockno * disk->d_bsize));
if (cnt == -1) {
ERROR(disk, "read error from block device");
goto fail;
}
if (cnt == 0) {
ERROR(disk, "end of file from block device");
goto fail;
}
if ((size_t)cnt != size) {
ERROR(disk, "short read or read error from block device");
goto fail;
}
if (p2 != data) {
memcpy(data, p2, size);
free(p2);
}
return (cnt);
fail: memset(data, 0, size);
if (p2 != data) {
free(p2);
}
return (-1);
}
ssize_t
bwrite(struct uufsd *disk, ufs2_daddr_t blockno, const void *data, size_t size)
{
ssize_t cnt;
int rv;
void *p2 = NULL;
ERROR(disk, NULL);
rv = ufs_disk_write(disk);
if (rv == -1) {
ERROR(disk, "failed to open disk for writing");
return (-1);
}
/*
* XXX: various disk controllers require alignment of our buffer
* XXX: which is stricter than struct alignment.
* XXX: Bounce the buffer if not 64 byte aligned.
* XXX: this can be removed if/when the kernel is fixed
*/
if (((intptr_t)data) & 0x3f) {
p2 = malloc(size);
if (p2 == NULL) {
ERROR(disk, "allocate bounce buffer");
return (-1);
}
memcpy(p2, data, size);
data = p2;
}
cnt = pwrite(disk->d_fd, data, size, (off_t)(blockno * disk->d_bsize));
if (p2 != NULL)
free(p2);
if (cnt == -1) {
ERROR(disk, "write error to block device");
return (-1);
}
if ((size_t)cnt != size) {
ERROR(disk, "short write to block device");
return (-1);
}
return (cnt);
}
#ifdef __FreeBSD_kernel__
static int
berase_helper(struct uufsd *disk, ufs2_daddr_t blockno, ufs2_daddr_t size)
{
off_t ioarg[2];
ioarg[0] = blockno * disk->d_bsize;
ioarg[1] = size;
return (ioctl(disk->d_fd, DIOCGDELETE, ioarg));
}
#else
static int
berase_helper(struct uufsd *disk, ufs2_daddr_t blockno, ufs2_daddr_t size)
{
char *zero_chunk;
off_t offset, zero_chunk_size, pwrite_size;
int rv;
offset = blockno * disk->d_bsize;
zero_chunk_size = 65536 * disk->d_bsize;
zero_chunk = calloc(1, zero_chunk_size);
if (zero_chunk == NULL) {
ERROR(disk, "failed to allocate memory");
return (-1);
}
while (size > 0) {
pwrite_size = size;
if (pwrite_size > zero_chunk_size)
pwrite_size = zero_chunk_size;
rv = pwrite(disk->d_fd, zero_chunk, pwrite_size, offset);
if (rv == -1) {
ERROR(disk, "failed writing to disk");
break;
}
size -= rv;
offset += rv;
rv = 0;
}
free(zero_chunk);
return (rv);
}
#endif
int
berase(struct uufsd *disk, ufs2_daddr_t blockno, ufs2_daddr_t size)
{
int rv;
ERROR(disk, NULL);
rv = ufs_disk_write(disk);
if (rv == -1) {
ERROR(disk, "failed to open disk for writing");
return(rv);
}
return (berase_helper(disk, blockno, size));
}
+223
View File
@@ -0,0 +1,223 @@
/*
* Copyright (c) 2003 Juli Mallett. All rights reserved.
*
* This software was written by Juli Mallett <jmallett@FreeBSD.org> for the
* FreeBSD project. Redistribution and use in source and binary forms, with
* or without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistribution of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/mount.h>
#include <sys/disklabel.h>
#include <sys/stat.h>
#include <ufs/ufs/ufsmount.h>
#include <ufs/ufs/dinode.h>
#include <ufs/ffs/fs.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <libufs.h>
ufs2_daddr_t
cgballoc(struct uufsd *disk)
{
u_int8_t *blksfree;
struct cg *cgp;
struct fs *fs;
long bno;
fs = &disk->d_fs;
cgp = &disk->d_cg;
blksfree = cg_blksfree(cgp);
for (bno = 0; bno < fs->fs_fpg / fs->fs_frag; bno++)
if (ffs_isblock(fs, blksfree, bno))
goto gotit;
return (0);
gotit:
fs->fs_cs(fs, cgp->cg_cgx).cs_nbfree--;
ffs_clrblock(fs, blksfree, (long)bno);
ffs_clusteracct(fs, cgp, bno, -1);
cgp->cg_cs.cs_nbfree--;
fs->fs_cstotal.cs_nbfree--;
fs->fs_fmod = 1;
return (cgbase(fs, cgp->cg_cgx) + blkstofrags(fs, bno));
}
int
cgbfree(struct uufsd *disk, ufs2_daddr_t bno, long size)
{
u_int8_t *blksfree;
struct fs *fs;
struct cg *cgp;
ufs1_daddr_t fragno, cgbno;
int i, cg, blk, frags, bbase;
fs = &disk->d_fs;
cg = dtog(fs, bno);
if (cgread1(disk, cg) != 1)
return (-1);
cgp = &disk->d_cg;
cgbno = dtogd(fs, bno);
blksfree = cg_blksfree(cgp);
if (size == fs->fs_bsize) {
fragno = fragstoblks(fs, cgbno);
ffs_setblock(fs, blksfree, fragno);
ffs_clusteracct(fs, cgp, fragno, 1);
cgp->cg_cs.cs_nbfree++;
fs->fs_cstotal.cs_nbfree++;
fs->fs_cs(fs, cg).cs_nbfree++;
} else {
bbase = cgbno - fragnum(fs, cgbno);
/*
* decrement the counts associated with the old frags
*/
blk = blkmap(fs, blksfree, bbase);
ffs_fragacct(fs, blk, cgp->cg_frsum, -1);
/*
* deallocate the fragment
*/
frags = numfrags(fs, size);
for (i = 0; i < frags; i++)
setbit(blksfree, cgbno + i);
cgp->cg_cs.cs_nffree += i;
fs->fs_cstotal.cs_nffree += i;
fs->fs_cs(fs, cg).cs_nffree += i;
/*
* add back in counts associated with the new frags
*/
blk = blkmap(fs, blksfree, bbase);
ffs_fragacct(fs, blk, cgp->cg_frsum, 1);
/*
* if a complete block has been reassembled, account for it
*/
fragno = fragstoblks(fs, bbase);
if (ffs_isblock(fs, blksfree, fragno)) {
cgp->cg_cs.cs_nffree -= fs->fs_frag;
fs->fs_cstotal.cs_nffree -= fs->fs_frag;
fs->fs_cs(fs, cg).cs_nffree -= fs->fs_frag;
ffs_clusteracct(fs, cgp, fragno, 1);
cgp->cg_cs.cs_nbfree++;
fs->fs_cstotal.cs_nbfree++;
fs->fs_cs(fs, cg).cs_nbfree++;
}
}
return cgwrite(disk);
}
ino_t
cgialloc(struct uufsd *disk)
{
struct ufs2_dinode *dp2;
u_int8_t *inosused;
struct cg *cgp;
struct fs *fs;
ino_t ino;
int i;
fs = &disk->d_fs;
cgp = &disk->d_cg;
inosused = cg_inosused(cgp);
for (ino = 0; ino < fs->fs_ipg; ino++)
if (isclr(inosused, ino))
goto gotit;
return (0);
gotit:
if (fs->fs_magic == FS_UFS2_MAGIC &&
ino + INOPB(fs) > cgp->cg_initediblk &&
cgp->cg_initediblk < cgp->cg_niblk) {
char block[MAXBSIZE];
bzero(block, (int)fs->fs_bsize);
dp2 = (struct ufs2_dinode *)&block;
for (i = 0; i < INOPB(fs); i++) {
dp2->di_gen = arc4random();
dp2++;
}
if (bwrite(disk, ino_to_fsba(fs,
cgp->cg_cgx * fs->fs_ipg + cgp->cg_initediblk),
block, fs->fs_bsize))
return (0);
cgp->cg_initediblk += INOPB(fs);
}
setbit(inosused, ino);
cgp->cg_irotor = ino;
cgp->cg_cs.cs_nifree--;
fs->fs_cstotal.cs_nifree--;
fs->fs_cs(fs, cgp->cg_cgx).cs_nifree--;
fs->fs_fmod = 1;
return (ino + (cgp->cg_cgx * fs->fs_ipg));
}
int
cgread(struct uufsd *disk)
{
return (cgread1(disk, disk->d_ccg++));
}
int
cgread1(struct uufsd *disk, int c)
{
struct fs *fs;
fs = &disk->d_fs;
if ((unsigned)c >= fs->fs_ncg) {
return (0);
}
if (bread(disk, fsbtodb(fs, cgtod(fs, c)), disk->d_cgunion.d_buf,
fs->fs_bsize) == -1) {
ERROR(disk, "unable to read cylinder group");
return (-1);
}
disk->d_lcg = c;
return (1);
}
int
cgwrite(struct uufsd *disk)
{
return (cgwrite1(disk, disk->d_lcg));
}
int
cgwrite1(struct uufsd *disk, int c)
{
struct fs *fs;
fs = &disk->d_fs;
if (bwrite(disk, fsbtodb(fs, cgtod(fs, c)),
disk->d_cgunion.d_buf, fs->fs_bsize) == -1) {
ERROR(disk, "unable to write cylinder group");
return (-1);
}
return (0);
}
+119
View File
@@ -0,0 +1,119 @@
/*
* Copyright (c) 2002 Juli Mallett. All rights reserved.
*
* This software was written by Juli Mallett <jmallett@FreeBSD.org> for the
* FreeBSD project. Redistribution and use in source and binary forms, with
* or without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistribution of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/mount.h>
#include <sys/disklabel.h>
#include <sys/stat.h>
#include <ufs/ufs/ufsmount.h>
#include <ufs/ufs/dinode.h>
#include <ufs/ffs/fs.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <libufs.h>
int
getino(struct uufsd *disk, void **dino, ino_t inode, int *mode)
{
ino_t min, max;
caddr_t inoblock;
struct ufs1_dinode *dp1;
struct ufs2_dinode *dp2;
struct fs *fs;
ERROR(disk, NULL);
fs = &disk->d_fs;
if (inode >= (ino_t)fs->fs_ipg * fs->fs_ncg) {
ERROR(disk, "inode number out of range");
return (-1);
}
inoblock = disk->d_inoblock;
min = disk->d_inomin;
max = disk->d_inomax;
if (inoblock == NULL) {
inoblock = malloc(fs->fs_bsize);
if (inoblock == NULL) {
ERROR(disk, "unable to allocate inode block");
return (-1);
}
disk->d_inoblock = inoblock;
}
if (inode >= min && inode < max)
goto gotit;
bread(disk, fsbtodb(fs, ino_to_fsba(fs, inode)), inoblock,
fs->fs_bsize);
disk->d_inomin = min = inode - (inode % INOPB(fs));
disk->d_inomax = max = min + INOPB(fs);
gotit: switch (disk->d_ufs) {
case 1:
dp1 = &((struct ufs1_dinode *)inoblock)[inode - min];
if (mode != NULL)
*mode = dp1->di_mode & IFMT;
if (dino != NULL)
*dino = dp1;
return (0);
case 2:
dp2 = &((struct ufs2_dinode *)inoblock)[inode - min];
if (mode != NULL)
*mode = dp2->di_mode & IFMT;
if (dino != NULL)
*dino = dp2;
return (0);
default:
break;
}
ERROR(disk, "unknown UFS filesystem type");
return (-1);
}
int
putino(struct uufsd *disk)
{
struct fs *fs;
fs = &disk->d_fs;
if (disk->d_inoblock == NULL) {
ERROR(disk, "No inode block allocated");
return (-1);
}
if (bwrite(disk, fsbtodb(fs, ino_to_fsba(&disk->d_fs, disk->d_inomin)),
disk->d_inoblock, disk->d_fs.fs_bsize) <= 0)
return (-1);
return (0);
}
+149
View File
@@ -0,0 +1,149 @@
/*
* Copyright (c) 2002 Juli Mallett. All rights reserved.
*
* This software was written by Juli Mallett <jmallett@FreeBSD.org> for the
* FreeBSD project. Redistribution and use in source and binary forms, with
* or without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistribution of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD$
*/
#ifndef __LIBUFS_H__
#define __LIBUFS_H__
/*
* libufs structures.
*/
/*
* userland ufs disk.
*/
struct uufsd {
const char *d_name; /* disk name */
int d_ufs; /* decimal UFS version */
int d_fd; /* raw device file descriptor */
long d_bsize; /* device bsize */
ufs2_daddr_t d_sblock; /* superblock location */
struct csum *d_sbcsum; /* Superblock summary info */
caddr_t d_inoblock; /* inode block */
ino_t d_inomin; /* low inode */
ino_t d_inomax; /* high inode */
union {
struct fs d_fs; /* filesystem information */
char d_sb[MAXBSIZE];
/* superblock as buffer */
} d_sbunion;
union {
struct cg d_cg; /* cylinder group */
char d_buf[MAXBSIZE];
/* cylinder group storage */
} d_cgunion;
int d_ccg; /* current cylinder group */
int d_lcg; /* last cylinder group (in d_cg) */
const char *d_error; /* human readable disk error */
int d_mine; /* internal flags */
#define d_fs d_sbunion.d_fs
#define d_sb d_sbunion.d_sb
#define d_cg d_cgunion.d_cg
};
/*
* libufs macros (internal, non-exported).
*/
#ifdef _LIBUFS
/*
* Trace steps through libufs, to be used at entry and erroneous return.
*/
static inline void
ERROR(struct uufsd *u, const char *str)
{
#ifdef _LIBUFS_DEBUGGING
if (str != NULL) {
fprintf(stderr, "libufs: %s", str);
if (errno != 0)
fprintf(stderr, ": %s", strerror(errno));
fprintf(stderr, "\n");
}
#endif
if (u != NULL)
u->d_error = str;
}
#endif /* _LIBUFS */
__BEGIN_DECLS
/*
* libufs prototypes.
*/
/*
* block.c
*/
ssize_t bread(struct uufsd *, ufs2_daddr_t, void *, size_t);
ssize_t bwrite(struct uufsd *, ufs2_daddr_t, const void *, size_t);
int berase(struct uufsd *, ufs2_daddr_t, ufs2_daddr_t);
/*
* cgroup.c
*/
ufs2_daddr_t cgballoc(struct uufsd *);
int cgbfree(struct uufsd *, ufs2_daddr_t, long);
ino_t cgialloc(struct uufsd *);
int cgread(struct uufsd *);
int cgread1(struct uufsd *, int);
int cgwrite(struct uufsd *);
int cgwrite1(struct uufsd *, int);
/*
* inode.c
*/
int getino(struct uufsd *, void **, ino_t, int *);
int putino(struct uufsd *);
/*
* sblock.c
*/
int sbread(struct uufsd *);
int sbwrite(struct uufsd *, int);
/*
* type.c
*/
int ufs_disk_close(struct uufsd *);
int ufs_disk_fillout(struct uufsd *, const char *);
int ufs_disk_fillout_blank(struct uufsd *, const char *);
int ufs_disk_write(struct uufsd *);
/*
* ffs_subr.c
*/
void ffs_clrblock(struct fs *, u_char *, ufs1_daddr_t);
void ffs_clusteracct(struct fs *, struct cg *, ufs1_daddr_t, int);
void ffs_fragacct(struct fs *, int, int32_t [], int);
int ffs_isblock(struct fs *, u_char *, ufs1_daddr_t);
int ffs_isfreeblock(struct fs *, u_char *, ufs1_daddr_t);
void ffs_setblock(struct fs *, u_char *, ufs1_daddr_t);
__END_DECLS
#endif /* __LIBUFS_H__ */
+169
View File
@@ -0,0 +1,169 @@
/*
* Copyright (c) 2002 Juli Mallett. All rights reserved.
*
* This software was written by Juli Mallett <jmallett@FreeBSD.org> for the
* FreeBSD project. Redistribution and use in source and binary forms, with
* or without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistribution of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/mount.h>
#include <sys/disklabel.h>
#include <sys/stat.h>
#include <ufs/ufs/ufsmount.h>
#include <ufs/ufs/dinode.h>
#include <ufs/ffs/fs.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <libufs.h>
static int superblocks[] = SBLOCKSEARCH;
int
sbread(struct uufsd *disk)
{
uint8_t block[MAXBSIZE];
struct fs *fs;
int sb, superblock;
int i, size, blks;
uint8_t *space;
ERROR(disk, NULL);
fs = &disk->d_fs;
superblock = superblocks[0];
for (sb = 0; (superblock = superblocks[sb]) != -1; sb++) {
if (bread(disk, superblock, disk->d_sb, SBLOCKSIZE) == -1) {
ERROR(disk, "non-existent or truncated superblock");
return (-1);
}
if (fs->fs_magic == FS_UFS1_MAGIC)
disk->d_ufs = 1;
if (fs->fs_magic == FS_UFS2_MAGIC &&
fs->fs_sblockloc == superblock)
disk->d_ufs = 2;
if (fs->fs_bsize <= MAXBSIZE &&
(size_t)fs->fs_bsize >= sizeof(*fs)) {
if (disk->d_ufs)
break;
}
disk->d_ufs = 0;
}
if (superblock == -1 || disk->d_ufs == 0) {
/*
* Other error cases will result in errno being set, here we
* must set it to indicate no superblock could be found with
* which to associate this disk/filesystem.
*/
ERROR(disk, "no usable known superblock found");
errno = ENOENT;
return (-1);
}
disk->d_bsize = fs->fs_fsize / fsbtodb(fs, 1);
disk->d_sblock = superblock / disk->d_bsize;
/*
* Read in the superblock summary information.
*/
size = fs->fs_cssize;
blks = howmany(size, fs->fs_fsize);
size += fs->fs_ncg * sizeof(int32_t);
space = malloc(size);
if (space == NULL) {
ERROR(disk, "failed to allocate space for summary information");
return (-1);
}
fs->fs_csp = (struct csum *)space;
for (i = 0; i < blks; i += fs->fs_frag) {
size = fs->fs_bsize;
if (i + fs->fs_frag > blks)
size = (blks - i) * fs->fs_fsize;
if (bread(disk, fsbtodb(fs, fs->fs_csaddr + i), block, size)
== -1) {
ERROR(disk, "Failed to read sb summary information");
free(fs->fs_csp);
return (-1);
}
bcopy(block, space, size);
space += size;
}
fs->fs_maxcluster = (uint32_t *)space;
disk->d_sbcsum = fs->fs_csp;
return (0);
}
int
sbwrite(struct uufsd *disk, int all)
{
struct fs *fs;
int blks, size;
uint8_t *space;
unsigned i;
ERROR(disk, NULL);
fs = &disk->d_fs;
if (!disk->d_sblock) {
disk->d_sblock = disk->d_fs.fs_sblockloc / disk->d_bsize;
}
if (bwrite(disk, disk->d_sblock, fs, SBLOCKSIZE) == -1) {
ERROR(disk, "failed to write superblock");
return (-1);
}
/*
* Write superblock summary information.
*/
blks = howmany(fs->fs_cssize, fs->fs_fsize);
space = (uint8_t *)disk->d_sbcsum;
for (i = 0; i < blks; i += fs->fs_frag) {
size = fs->fs_bsize;
if (i + fs->fs_frag > blks)
size = (blks - i) * fs->fs_fsize;
if (bwrite(disk, fsbtodb(fs, fs->fs_csaddr + i), space, size)
== -1) {
ERROR(disk, "Failed to write sb summary information");
return (-1);
}
space += size;
}
if (all) {
for (i = 0; i < fs->fs_ncg; i++)
if (bwrite(disk, fsbtodb(fs, cgsblock(fs, i)),
fs, SBLOCKSIZE) == -1) {
ERROR(disk, "failed to update a superblock");
return (-1);
}
}
return (0);
}
+200
View File
@@ -0,0 +1,200 @@
/*
* Copyright (c) 2002 Juli Mallett. All rights reserved.
*
* This software was written by Juli Mallett <jmallett@FreeBSD.org> for the
* FreeBSD project. Redistribution and use in source and binary forms, with
* or without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistribution of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/mount.h>
#include <sys/disklabel.h>
#include <sys/stat.h>
#include <ufs/ufs/ufsmount.h>
#include <ufs/ufs/dinode.h>
#include <ufs/ffs/fs.h>
#include <errno.h>
#include <fcntl.h>
#include <fstab.h>
#include <paths.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <libufs.h>
/* Internally, track the 'name' value, it's ours. */
#define MINE_NAME 0x01
/* Track if its fd points to a writable device. */
#define MINE_WRITE 0x02
int
ufs_disk_close(struct uufsd *disk)
{
ERROR(disk, NULL);
close(disk->d_fd);
disk->d_fd = -1;
if (disk->d_inoblock != NULL) {
free(disk->d_inoblock);
disk->d_inoblock = NULL;
}
if (disk->d_mine & MINE_NAME) {
free((char *)(uintptr_t)disk->d_name);
disk->d_name = NULL;
}
if (disk->d_sbcsum != NULL) {
free(disk->d_sbcsum);
disk->d_sbcsum = NULL;
}
return (0);
}
int
ufs_disk_fillout(struct uufsd *disk, const char *name)
{
if (ufs_disk_fillout_blank(disk, name) == -1) {
return (-1);
}
if (sbread(disk) == -1) {
ERROR(disk, "could not read superblock to fill out disk");
return (-1);
}
return (0);
}
int
ufs_disk_fillout_blank(struct uufsd *disk, const char *name)
{
struct stat st;
struct fstab *fs;
struct statfs sfs;
const char *oname;
char dev[MAXPATHLEN];
int fd, ret;
ERROR(disk, NULL);
oname = name;
again: if ((ret = stat(name, &st)) < 0) {
if (*name != '/') {
snprintf(dev, sizeof(dev), "%s%s", _PATH_DEV, name);
name = dev;
goto again;
}
/*
* The given object doesn't exist, but don't panic just yet -
* it may be still mount point listed in /etc/fstab, but without
* existing corresponding directory.
*/
name = oname;
}
if (ret >= 0 && S_ISREG(st.st_mode)) {
/* Possibly a disk image, give it a try. */
;
} else if (ret >= 0 && S_ISCHR(st.st_mode)) {
/* This is what we need, do nothing. */
;
} else if (0/*(fs = getfsfile(name)) != NULL*/) {
/*
* The given mount point is listed in /etc/fstab.
* It is possible that someone unmounted file system by hand
* and different file system is mounted on this mount point,
* but we still prefer /etc/fstab entry, because on the other
* hand, there could be /etc/fstab entry for this mount
* point, but file system is not mounted yet (eg. noauto) and
* statfs(2) will point us at different file system.
*/
name = fs->fs_spec;
} else if (ret >= 0 && S_ISDIR(st.st_mode)) {
/*
* The mount point is not listed in /etc/fstab, so it may be
* file system mounted by hand.
*/
if (statfs(name, &sfs) < 0) {
ERROR(disk, "could not find special device");
return (-1);
}
strlcpy(dev, sfs.f_mntfromname, sizeof(dev));
name = dev;
} else {
ERROR(disk, "could not find special device");
return (-1);
}
fd = open(name, O_RDONLY);
if (fd == -1) {
ERROR(disk, "could not open special device");
return (-1);
}
disk->d_bsize = 1;
disk->d_ccg = 0;
disk->d_fd = fd;
disk->d_inoblock = NULL;
disk->d_inomin = 0;
disk->d_inomax = 0;
disk->d_lcg = 0;
disk->d_mine = 0;
disk->d_ufs = 0;
disk->d_error = NULL;
disk->d_sbcsum = NULL;
if (oname != name) {
name = strdup(name);
if (name == NULL) {
ERROR(disk, "could not allocate memory for disk name");
return (-1);
}
disk->d_mine |= MINE_NAME;
}
disk->d_name = name;
return (0);
}
int
ufs_disk_write(struct uufsd *disk)
{
int fd;
ERROR(disk, NULL);
if (disk->d_mine & MINE_WRITE)
return (0);
fd = open(disk->d_name, O_RDWR);
if (fd < 0) {
ERROR(disk, "failed to open disk for writing");
return (-1);
}
close(disk->d_fd);
disk->d_fd = fd;
disk->d_mine |= MINE_WRITE;
return (0);
}
+2 -1
View File
@@ -39,7 +39,8 @@ test: $(ELF)
$(PS5_DEPLOY) -h $(PS5_HOST) -p $(PS5_PORT) $^
debug: $(ELF)
gdb \
gdb-multiarch \
-ex "set architecture i386:x86-64" \
-ex "target extended-remote $(PS5_HOST):2159" \
-ex "file $(ELF)" \
-ex "remote put $(ELF) /data/$(ELF)" \
+2 -1
View File
@@ -41,7 +41,8 @@ test: $(ELF)
$(PS5_DEPLOY) -h $(PS5_HOST) -p $(PS5_PORT) $^
debug: $(ELF)
gdb \
gdb-multiarch \
-ex "set architecture i386:x86-64" \
-ex "target extended-remote $(PS5_HOST):2159" \
-ex "file $(ELF)" \
-ex "remote put $(ELF) /data/$(ELF)" \
+4
View File
@@ -0,0 +1,4 @@
*.elf
*.o
*~
+20 -15
View File
@@ -1,5 +1,4 @@
#!/usr/bin/env bash
# Copyright (C) 2024 John Törnblom
# Copyright (C) 2026 John Törnblom
#
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
@@ -15,21 +14,27 @@
# along with this program; see the file COPYING. If not see
# <http://www.gnu.org/licenses/>.
SCRIPTDIR="${BASH_SOURCE[0]}"
SCRIPTDIR="$(dirname "${SCRIPTDIR}")"
PS5_HOST ?= ps5
PS5_PORT ?= 9021
DISTDIR="${PWD}"
VER=$(git describe --abbrev=10 --dirty --always --tags)
ifdef PS5_PAYLOAD_SDK
include $(PS5_PAYLOAD_SDK)/toolchain/prospero.mk
else
$(error PS5_PAYLOAD_SDK is undefined)
endif
export TEMPDIR=$(mktemp -d)
trap 'rm -rf -- "$TEMPDIR"' EXIT
ELF := hello_argv.elf
export DESTDIR="${TEMPDIR}/ps5-payload-sdk-${VER}"
export PS5_PAYLOAD_SDK=$DESTDIR
export WIN=1 # also build windows tools
CFLAGS := -Wall -Werror -g
make clean install || exit 1
"${SCRIPTDIR}/libcxx.sh" || exit 1
all: $(ELF)
cd "${TEMPDIR}"
zip -r "${DISTDIR}/ps5-payload-sdk-${VER}.zip" "ps5-payload-sdk-${VER}"
$(ELF): main.c
$(CC) $(CFLAGS) -o $@ $^
clean:
rm -f $(ELF)
test: $(ELF)
curl -T $(ELF) ftp://$(PS5_HOST):2121/user/temp/
$(PS5_DEPLOY) -h $(PS5_HOST) -p $(PS5_PORT) "file:/user/temp/$(ELF)?args=Hello%2C%5C%20world%21"
+28
View File
@@ -0,0 +1,28 @@
/* Copyright (C) 2026 John Törnblom
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 3, or (at your option) any
later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>. */
#include <stdio.h>
int
main(int argc, char* argv[]) {
for(int i=1; i<argc; i++) {
puts(argv[i]);
}
return 0;
}
+12
View File
@@ -0,0 +1,12 @@
{
"configurations": [
{
"name": "ps5-payload-sdk",
"compilerPath": "${env:PS5_PAYLOAD_SDK}/bin/prospero-clang++",
"intelliSenseMode": "clang-x64",
"cStandard": "c17",
"cppStandard": "c++17"
}
],
"version": 4
}
+27
View File
@@ -0,0 +1,27 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "ps5-payload-sdk",
"type": "cppdbg",
"request": "launch",
"program": "${command:cmake.launchTargetPath}",
"cwd": "${workspaceFolder}",
"targetArchitecture": "x64",
"MIMode": "gdb",
"miDebuggerPath": "/usr/bin/gdb-multiarch",
"miDebuggerServerAddress": "${env:PS5_HOST}:2159",
"useExtendedRemote": true,
"postRemoteConnectCommands": [
{
"description": "Trasfer the executable to the remote gdb server",
"text": "remote put ${command:cmake.launchTargetPath} /user/temp/${command:cmake.launchTargetName}"
}
{
"description": "Set path to the executable on the remote gdb server",
"text": "set remote exec-file /user/temp/${command:cmake.launchTargetName}"
}
]
}
]
}
+13 -1
View File
@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.5)
cmake_minimum_required(VERSION 3.10)
project(hello_cmake C CXX)
add_executable(hello_c main.c)
@@ -6,3 +6,15 @@ add_executable(hello_cpp main.cpp)
set_target_properties(hello_c PROPERTIES OUTPUT_NAME hello_c.elf)
set_target_properties(hello_cpp PROPERTIES OUTPUT_NAME hello_cpp.elf)
add_custom_target(test_c
USES_TERMINAL
COMMAND ${PS5_DEPLOY} hello_c.elf
DEPENDS hello_c
)
add_custom_target(test_cpp
USES_TERMINAL
COMMAND ${PS5_DEPLOY} hello_cpp.elf
DEPENDS hello_cpp
)
+2 -1
View File
@@ -39,7 +39,8 @@ test: $(ELF)
$(PS5_DEPLOY) -h $(PS5_HOST) -p $(PS5_PORT) $^
debug: $(ELF)
gdb \
gdb-multiarch \
-ex "set architecture i386:x86-64" \
-ex "target extended-remote $(PS5_HOST):2159" \
-ex "file $(ELF)" \
-ex "remote put $(ELF) /data/$(ELF)" \
+2 -1
View File
@@ -39,7 +39,8 @@ test: $(ELF)
$(PS5_DEPLOY) -h $(PS5_HOST) -p $(PS5_PORT) $^
debug: $(ELF)
gdb \
gdb-multiarch \
-ex "set architecture i386:x86-64" \
-ex "target extended-remote $(PS5_HOST):2159" \
-ex "file $(ELF)" \
-ex "remote put $(ELF) /data/$(ELF)" \
+2 -1
View File
@@ -39,7 +39,8 @@ test: $(ELF)
$(PS5_DEPLOY) -h $(PS5_HOST) -p $(PS5_PORT) $^
debug: $(ELF)
gdb \
gdb-multiarch \
-ex "set architecture i386:x86-64" \
-ex "target extended-remote $(PS5_HOST):2159" \
-ex "file $(ELF)" \
-ex "remote put $(ELF) /data/$(ELF)" \
+2 -1
View File
@@ -39,7 +39,8 @@ test: $(ELF)
$(PS5_DEPLOY) -h $(PS5_HOST) -p $(PS5_PORT) $^
debug: $(ELF)
gdb \
gdb-multiarch \
-ex "set architecture i386:x86-64" \
-ex "target extended-remote $(PS5_HOST):2159" \
-ex "file $(ELF)" \
-ex "remote put $(ELF) /data/$(ELF)" \
+2 -1
View File
@@ -39,7 +39,8 @@ test: $(ELF)
$(PS5_DEPLOY) -h $(PS5_HOST) -p $(PS5_PORT) $^
debug: $(ELF)
gdb \
gdb-multiarch \
-ex "set architecture i386:x86-64" \
-ex "target extended-remote $(PS5_HOST):2159" \
-ex "file $(ELF)" \
-ex "remote put $(ELF) /data/$(ELF)" \
+3 -2
View File
@@ -36,10 +36,11 @@ clean:
rm -f $(ELF)
test: $(ELF)
$(PS5_DEPLOY) -h $(PS5_HOST) -p $(PS5_PORT) $^
echo "$(USER)" | $(PS5_DEPLOY) -i -h $(PS5_HOST) -p $(PS5_PORT) $^
debug: $(ELF)
gdb \
gdb-multiarch \
-ex "set architecture i386:x86-64" \
-ex "target extended-remote $(PS5_HOST):2159" \
-ex "file $(ELF)" \
-ex "remote put $(ELF) /data/$(ELF)" \
+8 -1
View File
@@ -17,6 +17,13 @@ along with this program; see the file COPYING. If not, see
#include <stdio.h>
int main() {
printf("Hello, world!\n");
char buf[255] = "anonymous";
fprintf(stdout, "enter name\n");
fflush(stdout);
fgets(buf, sizeof(buf), stdin);
fprintf(stdout, "Hello, %s", buf);
return 0;
}
+2 -1
View File
@@ -39,7 +39,8 @@ test: $(ELF)
$(PS5_DEPLOY) -h $(PS5_HOST) -p $(PS5_PORT) $^
debug: $(ELF)
gdb \
gdb-multiarch \
-ex "set architecture i386:x86-64" \
-ex "target extended-remote $(PS5_HOST):2159" \
-ex "file $(ELF)" \
-ex "remote put $(ELF) /data/$(ELF)" \
+2 -1
View File
@@ -39,7 +39,8 @@ test: $(ELF)
$(PS5_DEPLOY) -h $(PS5_HOST) -p $(PS5_PORT) $^
debug: $(ELF)
gdb \
gdb-multiarch \
-ex "set architecture i386:x86-64" \
-ex "target extended-remote $(PS5_HOST):2159" \
-ex "file $(ELF)" \
-ex "remote put $(ELF) /data/$(ELF)" \
+2 -5
View File
@@ -38,12 +38,9 @@ clean:
test: $(ELF)
$(PS5_DEPLOY) -h $(PS5_HOST) -p $(PS5_PORT) $^
install: $(ELF)
install -d $(DESTDIR)/$(PREFIX)/bin
install $^ $(DESTDIR)/$(PREFIX)/bin/hwinfo
debug: $(ELF)
gdb \
gdb-multiarch \
-ex "set architecture i386:x86-64" \
-ex "target extended-remote $(PS5_HOST):2159" \
-ex "file $(ELF)" \
-ex "remote put $(ELF) /data/$(ELF)" \
+2
View File
@@ -0,0 +1,2 @@
*.bin
Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

@@ -0,0 +1,10 @@
{
"applicationCategoryType": 0,
"localizedParameters": {
"defaultLanguage": "en-US",
"en-US": {
"titleName": "FAKE02932"
}
},
"titleId": "FAKE02932"
}
@@ -0,0 +1,10 @@
{
"applicationCategoryType": 33554432,
"localizedParameters": {
"defaultLanguage": "en-US",
"en-US": {
"titleName": "FAKE02932"
}
},
"titleId": "FAKE02932"
}
+84
View File
@@ -0,0 +1,84 @@
# Copyright (C) 2025 John Törnblom
#
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; see the file COPYING. If not see
# <http://www.gnu.org/licenses/>.
PS5_HOST ?= ps5
PS5_PORT ?= 9021
FTP_URL := ftp://$(PS5_HOST):2121
ifdef PS5_PAYLOAD_SDK
include $(PS5_PAYLOAD_SDK)/toolchain/prospero.mk
else
$(error PS5_PAYLOAD_SDK is undefined)
endif
ELF2SELF := ./make_fself.py
TITLE_ID := FAKE02932
CFLAGS := -Wall -Werror -g -DTITLE_ID=\"$(TITLE_ID)\"
LDADD := -lSceIpmi -lSceAppInstUtil -lSceUserService -lSceSystemService
PS4_SDK_VERSION ?= 0x07590001
AUTHID := 0x3800000000000022
AUTHINFO := 00 00 00 00 00 00 00 00 00 00 00 00 00 1C 00 40 00 FF 00 00 00 00 \
00 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80 \
00 40 00 40 00 00 00 00 00 00 00 80 00 00 00 00 00 00 00 08 00 40 \
FF FF 00 00 00 F0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \
00 00 00 00
.INTERMEDIATE: eboot.elf
all: payload.elf $(TITLE_ID)/eboot.bin
payload.elf: payload.c
$(CC) $(CFLAGS) $(LDADD) -o $@ $^
eboot.o: eboot.c
$(CC) -c $(CFLAGS) -o $@ $^
eboot.elf: eboot.o
$(LD) --static -T eboot.x -o $@ $^
$(TITLE_ID)/eboot.bin: eboot.elf
$(ELF2SELF) --ptype fake --paid $(AUTHID) \
--auth-info "$(AUTHINFO)" \
--app-version $(PS4_SDK_VERSION) \
--fw-version $(PS4_SDK_VERSION) $^ $@
$(TITLE_ID)/icon0.png:
convert -size 512x512 -gravity center label:'$(TITLE_ID)' $@
clean:
rm -f *.o *.elf $(TITLE_ID)/eboot.bin
test: $(TITLE_ID)/eboot.bin $(TITLE_ID)/icon0.png payload.elf
curl -Q "MTRW" $(FTP_URL) > /dev/null
curl -Q "MKD /system_ex/app/$(TITLE_ID)" $(FTP_URL) > /dev/null || true
curl -Q "MKD /system_ex/app/$(TITLE_ID)/sce_sys" $(FTP_URL) > /dev/null || true
curl -Q "MKD /user/app/$(TITLE_ID)" $(FTP_URL) > /dev/null || true
curl -Q "MKD /user/app/$(TITLE_ID)/sce_sys" $(FTP_URL) > /dev/null || true
curl -T "$(TITLE_ID)/eboot.bin" "$(FTP_URL)/system_ex/app/$(TITLE_ID)/"
curl -T "$(TITLE_ID)/sce_sys/param.json" "$(FTP_URL)/user/app/$(TITLE_ID)/sce_sys/"
curl -T "$(TITLE_ID)/icon0.png" "$(FTP_URL)/user/app/$(TITLE_ID)/sce_sys/"
$(PS5_DEPLOY) -h $(PS5_HOST) -p $(PS5_PORT) payload.elf
curl -T "$(TITLE_ID)/sce_sys/param.json.system" "$(FTP_URL)/system_ex/app/$(TITLE_ID)/sce_sys/param.json"
+64
View File
@@ -0,0 +1,64 @@
/* Copyright (C) 2025 John Törnblom
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 3, or (at your option) any
later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>. */
long
__syscall(long n, ...) {
long a1 = 0, a2 = 0, a3 = 0, a4 = 0, a5 = 0, a6 = 0;
__builtin_va_list ap;
unsigned long ret;
char iserror;
__builtin_va_start(ap, n);
a1 = __builtin_va_arg(ap, long);
a2 = __builtin_va_arg(ap, long);
a3 = __builtin_va_arg(ap, long);
a4 = __builtin_va_arg(ap, long);
a5 = __builtin_va_arg(ap, long);
a6 = __builtin_va_arg(ap, long);
__builtin_va_end(ap);
register long r10 __asm__("r10") = a4;
register long r8 __asm__("r8") = a5;
register long r9 __asm__("r9") = a6;
__asm__ __volatile__("syscall"
: "=a"(ret), "=@ccc"(iserror), "+r"(r10), "+r"(r8), "+r"(r9)
: "a"(n), "D"(a1), "S"(a2), "d"(a3)
: "rcx", "r11", "memory");
return iserror ? -ret : ret;
}
int
klog(const char *s) {
return __syscall(0x259, 7, s, 0);
}
int
main(void) {
klog("Hello, world!\n");
return 0;
}
void
_start(void) {
__syscall(1, main()); // exit
__builtin_trap();
}
+51
View File
@@ -0,0 +1,51 @@
/* Copyright (C) 2025 John Törnblom
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 3, or (at your option) any
later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>. */
OUTPUT_FORMAT("elf64-x86-64")
OUTPUT_ARCH(i386:x86-64)
PHDRS {
ph_text PT_LOAD FLAGS(0x1);
ph_rodata PT_LOAD FLAGS(0x4);
ph_data PT_LOAD FLAGS(0x6);
ph_sce_procparam 0x61000001 FLAGS(0x4);
}
SECTIONS {
. = CONSTANT(MAXPAGESIZE);
.text : ALIGN(CONSTANT(MAXPAGESIZE)) {
__text_start__ = .;
*(.text .text.*)
__text_end__ = .;
} : ph_text
.rodata : ALIGN(CONSTANT(MAXPAGESIZE)) {
__rodata_start__ = .;
*(.rodata .rodata.*)
__rodata_end__ = .;
}: ph_rodata
.data : ALIGN(CONSTANT(MAXPAGESIZE)) {
__data_start__ = .;
*(.data .data.*)
__data_end__ = .;
} : ph_data
.sce_process_param : ALIGN(32) {
KEEP(*(.sce_process_param))
} : ph_sce_procparam
}
+824
View File
@@ -0,0 +1,824 @@
#!/usr/bin/env python3
import sys, os, struct, traceback
import hashlib, hmac
import argparse, re, string
def int_with_base_type(val):
return int(val, 0)
def try_parse_int(x, base=0):
try:
return int(x, base) if isinstance(x, str) else int(x)
except:
return None
def align_up(x, alignment):
return (x + (alignment - 1)) & ~(alignment - 1)
def align_down(x, alignment):
return x & ~(alignment - 1)
def ilog2(x):
if x <= 0:
raise ValueError('math domain error')
return len(bin(x)) - 3
def is_intervals_overlap(p1, p2):
return p1[0] <= p2[1] and p1[1] <= p2[0]
def check_file_magic(f, expected_magic):
old_offset = f.tell()
try:
magic = f.read(len(expected_magic))
except:
return False
finally:
f.seek(old_offset)
return magic == expected_magic
def parse_version(version):
major, minor, patch = (version >> 8) & 0xFF, version & 0xFF, 0 # FIXME
major = 10 * (major >> 4) + (major & 0xF)
minor = 10 * (minor >> 4) + (minor & 0xF)
return '{0:d}.{1:02d}.{2:03d}'.format(major, minor, patch)
def sha256(data):
return hashlib.sha256(data).digest()
def hmac_sha256(key, data):
return hmac.new(key=key, msg=data, digestmod=hashlib.sha256).digest()
class ElfError(Exception):
def __init__(self, msg):
self.msg = msg
def __str__(self):
return repr(self.msg)
class ElfEHdr(object):
FMT = '<4s5B6xB'
EX_FMT = '<2HI3QI6H'
MAGIC = b'\x7FELF'
CLASS64 = 0x2
DATA2LSB = 0x1
EM_X86_64 = 0x3E
EV_CURRENT = 0x1
ET_EXEC = 0x2
ET_SCE_EXEC = 0xFE00
ET_SCE_EXEC_ASLR = 0xFE10
ET_SCE_DYNAMIC = 0xFE18
def __init__(self):
self.magic = None
self.machine_class = None
self.data_encoding = None
self.version = None
self.os_abi = None
self.abi_version = None
self.nident_size = None
self.type = None
self.machine = None
self.version = None
self.entry = None
self.phoff = None
self.shoff = None
self.flags = None
self.ehsize = None
self.phentsize = None
self.phnum = None
self.shentsize = None
self.shnum = None
self.shstridx = None
def load(self, f):
if not check_file_magic(f, ElfEHdr.MAGIC):
raise ElfError('Invalid magic.')
self.magic, self.machine_class, self.data_encoding, self.version, self.os_abi, self.abi_version, self.nident_size = struct.unpack(ElfEHdr.FMT, f.read(struct.calcsize(ElfEHdr.FMT)))
if self.machine_class != ElfEHdr.CLASS64 or self.data_encoding != ElfEHdr.DATA2LSB:
raise ElfError('Unsupported class or data encoding.')
self.type, self.machine, self.version, self.entry, self.phoff, self.shoff, self.flags, self.ehsize, self.phentsize, self.phnum, self.shentsize, self.shnum, self.shstridx = struct.unpack(ElfEHdr.EX_FMT, f.read(struct.calcsize(ElfEHdr.EX_FMT)))
if self.machine != ElfEHdr.EM_X86_64 or self.version != ElfEHdr.EV_CURRENT:
raise ElfError('Unsupported machine type or version.')
if self.phentsize != struct.calcsize(ElfPHdr.FMT) or (self.shentsize > 0 and self.shentsize != struct.calcsize(ElfSHdr.FMT)):
raise ElfError('Unsupported header entry size.')
if self.type not in [ElfEHdr.ET_EXEC, ElfEHdr.ET_SCE_EXEC, ElfEHdr.ET_SCE_EXEC_ASLR, ElfEHdr.ET_SCE_DYNAMIC]:
raise ElfError('Unsupported type.')
def save(self, f):
f.write(struct.pack(ElfEHdr.FMT, self.magic, self.machine_class, self.data_encoding, self.version, self.os_abi, self.abi_version, self.nident_size))
f.write(struct.pack(ElfEHdr.EX_FMT, self.type, self.machine, self.version, self.entry, self.phoff, self.shoff, self.flags, self.ehsize, self.phentsize, self.phnum, self.shentsize, self.shnum, self.shstridx))
def has_segments(self):
return self.phentsize > 0 and self.phnum > 0
def has_sections(self):
return self.shentsize > 0 and self.shnum > 0
class ElfPHdr(object):
FMT = '<2I6Q'
PT_LOAD = 0x1
PT_DYNAMIC = 0x2
PT_INTERP = 0x3
PT_TLS = 0x7
PT_GNU_EH_FRAME = 0x6474E550
PT_GNU_STACK = 0x6474E551
PT_SCE_RELA = 0x60000000,
PT_SCE_DYNLIBDATA = 0x61000000
PT_SCE_PROCPARAM = 0x61000001
PT_SCE_MODULE_PARAM = 0x61000002
PT_SCE_RELRO = 0x61000010
PT_SCE_COMMENT = 0x6FFFFF00
PT_SCE_VERSION = 0x6FFFFF01
PF_EXEC = 0x1
PF_WRITE = 0x2
PF_READ = 0x4
PF_READ_EXEC = PF_READ | PF_EXEC
PF_READ_WRITE = PF_READ | PF_WRITE
def __init__(self, idx):
self.idx = idx
self.type = None
self.flags = None
self.offset = None
self.vaddr = None
self.paddr = None
self.filesz = None
self.memsz = None
self.align = None
def load(self, f):
self.type, self.flags, self.offset, self.vaddr, self.paddr, self.filesz, self.memsz, self.align = struct.unpack(ElfPHdr.FMT, f.read(struct.calcsize(ElfPHdr.FMT)))
def save(self, f):
f.write(struct.pack(ElfPHdr.FMT, self.type, self.flags, self.offset, self.vaddr, self.paddr, self.filesz, self.memsz, self.align))
def name(self):
if self.type == ElfPHdr.PT_LOAD:
if (self.flags & ElfPHdr.PF_READ_EXEC) == ElfPHdr.PF_READ_EXEC:
return '.text'
elif (self.flags & ElfPHdr.PF_READ_WRITE) == ElfPHdr.PF_READ_WRITE:
return '.data'
else:
return '.load_{0:02}'.format(self.idx)
else:
return {
ElfPHdr.PT_DYNAMIC: '.dynamic',
ElfPHdr.PT_INTERP: '.interp',
ElfPHdr.PT_TLS: '.tls',
ElfPHdr.PT_GNU_EH_FRAME: '.eh_frame_hdr',
ElfPHdr.PT_SCE_DYNLIBDATA: '.sce_dynlib_data',
ElfPHdr.PT_SCE_PROCPARAM: '.sce_process_param',
ElfPHdr.PT_SCE_MODULE_PARAM: '.sce_module_param',
ElfPHdr.PT_SCE_COMMENT: '.sce_comment',
}.get(self.type, None)
def class_name(self):
if (self.flags & ElfPHdr.PF_READ_EXEC) == ElfPHdr.PF_READ_EXEC:
return 'CODE'
else:
return 'DATA'
class ElfSHdr(object):
FMT = '<2I4Q2I2Q'
def __init__(self, idx):
self.idx = idx
self.name = None
self.type = None
self.flags = None
self.addr = None
self.offset = None
self.size = None
self.link = None
self.info = None
self.align = None
self.entsize = None
def load(self, f):
self.name, self.type, self.flags, self.addr, self.offset, self.size, self.link, self.info, self.align, self.entsize = struct.unpack(ElfSHdr.FMT, f.read(struct.calcsize(ElfSHdr.FMT)))
def save(self, f):
f.write(struct.pack(ElfSHdr.FMT, self.name, self.type, self.flags, self.addr, self.offset, self.size, self.link, self.info, self.align, self.entsize))
class ElfFile(object):
def __init__(self, **kwargs):
self.ehdr = None
self.phdrs = None
self.shdrs = None
self.file_size = None
self.digest = None
self.segments = None
self.sections = None
self.ignore_shdrs = 'ignore_shdrs' in kwargs and kwargs['ignore_shdrs']
def load(self, f):
start_offset = f.tell()
data = f.read()
self.file_size = len(data)
self.digest = sha256(data)
f.seek(start_offset)
self.ehdr = ElfEHdr()
self.ehdr.load(f)
if self.ignore_shdrs:
self.ehdr.shnum = 0
self.phdrs = []
self.segments = []
if self.ehdr.has_segments():
for i in range(self.ehdr.phnum):
f.seek(start_offset + self.ehdr.phoff + i * self.ehdr.phentsize)
phdr = ElfPHdr(i)
phdr.load(f)
self.phdrs.append(phdr)
if phdr.filesz > 0:
f.seek(start_offset + phdr.offset)
data = f.read(phdr.filesz)
else:
data = b''
self.segments.append(data)
self.shdrs = []
self.sections = []
if self.ehdr.has_sections():
for i in range(self.ehdr.shnum):
f.seek(start_offset + self.ehdr.shoff + i * self.ehdr.shentsize)
shdr = ElfSHdr(i)
shdr.load(f)
self.shdrs.append(shdr)
if phdr.filesz > 0:
f.seek(start_offset + shdr.offset)
data = f.read(phdr.filesz)
else:
data = b''
self.sections.append(data)
def save(self, f, no_sections=False):
start_offset = f.tell()
self.ehdr.save(f)
if not no_sections:
if self.ehdr.has_sections():
for i in range(self.ehdr.shnum):
f.seek(start_offset + self.ehdr.shoff + i * self.ehdr.shentsize)
shdr = self.shdrs[i]
shdr.save(f)
if self.ehdr.has_segments():
for i in range(self.ehdr.phnum):
f.seek(start_offset + self.ehdr.phoff + i * self.ehdr.phentsize)
phdr = self.phdrs[i]
phdr.save(f)
DIGEST_SIZE = 0x20
SIGNATURE_SIZE = 0x100
BLOCK_SIZE = 0x4000
DEFAULT_BLOCK_SIZE = 0x1000
SELF_CONTROL_BLOCK_TYPE_NPDRM = 0x3
SELF_NPDRM_CONTROL_BLOCK_CONTENT_ID_SIZE = 0x13
SELF_NPDRM_CONTROL_BLOCK_RANDOM_PAD_SIZE = 0xD
EMPTY_DIGEST = b'\0' * DIGEST_SIZE
EMPTY_SIGNATURE = b'\0' * SIGNATURE_SIZE
class SignedElfEntry(object):
FMT = '<4Q'
PROPS_ORDER_SHIFT = 0
PROPS_ORDER_MASK = 0x1
PROPS_ENCRYPTED_SHIFT = 1
PROPS_ENCRYPTED_MASK = 0x1
PROPS_SIGNED_SHIFT = 2
PROPS_SIGNED_MASK = 0x1
PROPS_COMPRESSED_SHIFT = 3
PROPS_COMPRESSED_MASK = 0x1
PROPS_WINDOW_BITS_SHIFT = 8
PROPS_WINDOW_BITS_MASK = 0x7
PROPS_HAS_BLOCKS_SHIFT = 11
PROPS_HAS_BLOCKS_MASK = 0x1
PROPS_BLOCK_SIZE_SHIFT = 12
PROPS_BLOCK_SIZE_MASK = 0xF
PROPS_HAS_DIGESTS_SHIFT = 16
PROPS_HAS_DIGESTS_MASK = 0x1
PROPS_HAS_EXTENTS_SHIFT = 17
PROPS_HAS_EXTENTS_MASK = 0x1
PROPS_HAS_META_SEGMENT_SHIFT = 20
PROPS_HAS_META_SEGMENT_MASK = 0x1
PROPS_SEGMENT_INDEX_SHIFT = 20
PROPS_SEGMENT_INDEX_MASK = 0xFFFF
PROPS_DEFAULT_BLOCK_SIZE = 0x1000
PROPS_META_SEGMENT_MASK = 0xF0000
def __init__(self, index):
self.index = index
self.props = None
self.offset = None
self.filesz = None
self.memsz = None
self.data = None
def save(self, f):
f.write(struct.pack(SignedElfEntry.FMT, self.props, self.offset, self.filesz, self.memsz))
@property
def order(self):
return (self.props >> SignedElfEntry.PROPS_ORDER_SHIFT) & SignedElfEntry.PROPS_ORDER_MASK
@order.setter
def order(self, value):
self.props &= ~(SignedElfEntry.PROPS_ORDER_MASK << SignedElfEntry.PROPS_ORDER_SHIFT)
self.props |= (value & SignedElfEntry.PROPS_ORDER_MASK) << SignedElfEntry.PROPS_ORDER_SHIFT
@property
def encrypted(self):
return ((self.props >> SignedElfEntry.PROPS_ENCRYPTED_SHIFT) & SignedElfEntry.PROPS_ENCRYPTED_MASK) != 0
@encrypted.setter
def encrypted(self, value):
self.props &= ~(SignedElfEntry.PROPS_ENCRYPTED_MASK << SignedElfEntry.PROPS_ENCRYPTED_SHIFT)
if value:
self.props |= SignedElfEntry.PROPS_ENCRYPTED_MASK << SignedElfEntry.PROPS_ENCRYPTED_SHIFT
@property
def signed(self):
return ((self.props >> SignedElfEntry.PROPS_SIGNED_SHIFT) & SignedElfEntry.PROPS_SIGNED_MASK) != 0
@signed.setter
def signed(self, value):
self.props &= ~(SignedElfEntry.PROPS_SIGNED_MASK << SignedElfEntry.PROPS_SIGNED_SHIFT)
if value:
self.props |= SignedElfEntry.PROPS_SIGNED_MASK << SignedElfEntry.PROPS_SIGNED_SHIFT
@property
def compressed(self):
return ((self.props >> SignedElfEntry.PROPS_COMPRESSED_SHIFT) & SignedElfEntry.PROPS_COMPRESSED_MASK) != 0
@compressed.setter
def compressed(self, value):
self.props &= ~(SignedElfEntry.PROPS_COMPRESSED_MASK << SignedElfEntry.PROPS_COMPRESSED_SHIFT)
if value:
self.props |= SignedElfEntry.PROPS_COMPRESSED_MASK << SignedElfEntry.PROPS_COMPRESSED_SHIFT
@property
def has_blocks(self):
return ((self.props >> SignedElfEntry.PROPS_HAS_BLOCKS_SHIFT) & SignedElfEntry.PROPS_HAS_BLOCKS_MASK) != 0
@has_blocks.setter
def has_blocks(self, value):
self.props &= ~(SignedElfEntry.PROPS_HAS_BLOCKS_MASK << SignedElfEntry.PROPS_HAS_BLOCKS_SHIFT)
if value:
self.props |= SignedElfEntry.PROPS_HAS_BLOCKS_MASK << SignedElfEntry.PROPS_HAS_BLOCKS_SHIFT
@property
def has_digests(self):
return ((self.props >> SignedElfEntry.PROPS_HAS_DIGESTS_SHIFT) & SignedElfEntry.PROPS_HAS_DIGESTS_MASK) != 0
@has_digests.setter
def has_digests(self, value):
self.props &= ~(SignedElfEntry.PROPS_HAS_DIGESTS_MASK << SignedElfEntry.PROPS_HAS_DIGESTS_SHIFT)
if value:
self.props |= SignedElfEntry.PROPS_HAS_DIGESTS_MASK << SignedElfEntry.PROPS_HAS_DIGESTS_SHIFT
@property
def has_extents(self):
return ((self.props >> SignedElfEntry.PROPS_HAS_EXTENTS_SHIFT) & SignedElfEntry.PROPS_HAS_EXTENTS_MASK) != 0
@has_extents.setter
def has_extents(self, value):
self.props &= ~(SignedElfEntry.PROPS_HAS_EXTENTS_MASK << SignedElfEntry.PROPS_HAS_EXTENTS_SHIFT)
if value:
self.props |= SignedElfEntry.PROPS_HAS_EXTENTS_MASK << SignedElfEntry.PROPS_HAS_EXTENTS_SHIFT
@property
def has_meta_segment(self):
return ((self.props >> SignedElfEntry.PROPS_HAS_META_SEGMENT_SHIFT) & SignedElfEntry.PROPS_HAS_META_SEGMENT_MASK) != 0
@has_meta_segment.setter
def has_meta_segment(self, value):
self.props &= ~(SignedElfEntry.PROPS_HAS_META_SEGMENT_MASK << SignedElfEntry.PROPS_HAS_META_SEGMENT_SHIFT)
if value:
self.props |= SignedElfEntry.PROPS_HAS_META_SEGMENT_MASK << SignedElfEntry.PROPS_HAS_META_SEGMENT_SHIFT
@property
def wbits(self):
return (self.props >> SignedElfEntry.PROPS_WINDOW_BITS_SHIFT) & SignedElfEntry.PROPS_WINDOW_BITS_MASK
@wbits.setter
def wbits(self, value):
self.props &= ~(SignedElfEntry.PROPS_WINDOW_BITS_MASK << SignedElfEntry.PROPS_WINDOW_BITS_SHIFT)
self.props |= (value & SignedElfEntry.PROPS_WINDOW_BITS_MASK) << SignedElfEntry.PROPS_WINDOW_BITS_SHIFT
@property
def block_size(self):
if self.has_blocks:
return 1 << (12 + (self.props >> SignedElfEntry.PROPS_BLOCK_SIZE_SHIFT) & SignedElfEntry.PROPS_BLOCK_SIZE_MASK)
else:
return DEFAULT_BLOCK_SIZE
@block_size.setter
def block_size(self, value):
self.props &= ~(SignedElfEntry.PROPS_BLOCK_SIZE_MASK << SignedElfEntry.PROPS_BLOCK_SIZE_SHIFT)
if self.has_blocks:
value = ilog2(value) - 12
else:
value = 0 # TODO: check
self.props |= (value & SignedElfEntry.PROPS_BLOCK_SIZE_MASK) << SignedElfEntry.PROPS_BLOCK_SIZE_SHIFT
@property
def segment_index(self):
return (self.props >> SignedElfEntry.PROPS_SEGMENT_INDEX_SHIFT) & SignedElfEntry.PROPS_SEGMENT_INDEX_MASK
@wbits.setter
def segment_index(self, value):
self.props &= ~(SignedElfEntry.PROPS_SEGMENT_INDEX_MASK << SignedElfEntry.PROPS_SEGMENT_INDEX_SHIFT)
self.props |= (value & SignedElfEntry.PROPS_SEGMENT_INDEX_MASK) << SignedElfEntry.PROPS_SEGMENT_INDEX_SHIFT
def is_meta_segment(self): # TODO: check
return (self.props & SignedElfEntry.PROPS_META_SEGMENT_MASK) != 0
def __repr__(self):
return 'prs:0x{0:X} ofs:0x{1:X} fsz:0x{2:X} msz:0x{3:X}'.format(self.props, self.offset, self.filesz, self.memsz)
class SignedElfExInfo(object):
FMT = '<4Q32s'
PTYPE_FAKE = 0x1
PTYPE_NPDRM_EXEC = 0x4
PTYPE_NPDRM_DYNLIB = 0x5
PTYPE_SYSTEM_EXEC = 0x8
PTYPE_SYSTEM_DYNLIB = 0x9 # including Mono binaries
PTYPE_HOST_KERNEL = 0xC
PTYPE_SECURE_MODULE = 0xE
PTYPE_SECURE_KERNEL = 0xF
def __init__(self):
self.paid = None
self.ptype = None
self.app_version = None
self.fw_version = None
self.digest = None
def save(self, f):
f.write(struct.pack(SignedElfExInfo.FMT, self.paid, self.ptype, self.app_version, self.fw_version, self.digest))
class SignedElfNpdrmControlBlock(object):
FMT = '<H14x19s13s'
def __init__(self):
self.type = SELF_CONTROL_BLOCK_TYPE_NPDRM
self.content_id = None
self.random_pad = None
def save(self, f):
f.write(struct.pack(SignedElfNpdrmControlBlock.FMT, self.type, self.content_id, self.random_pad))
class SignedElfMetaBlock(object):
FMT = '<80x'
def __init__(self):
pass
def save(self, f):
f.write(struct.pack(SignedElfMetaBlock.FMT))
class SignedElfMetaFooter(object):
FMT = '<48xI28x'
def __init__(self):
self.unk1 = None
def save(self, f):
f.write(struct.pack(SignedElfMetaFooter.FMT, self.unk1))
class SignedElfFile(object):
COMMON_HEADER_FMT = '<4s4B'
EXT_HEADER_FMT = '<I2HQ2H4x'
MAGIC = b'\x4F\x15\x3D\x1D'
VERSION = 0x00
MODE = 0x01
ENDIAN = 0x01
ATTRIBS = 0x12
KEY_TYPE = 0x101
FLAGS_SEGMENT_SIGNED_SHIFT = 4
FLAGS_SEGMENT_SIGNED_MASK = 0x7
HAS_NPDRM = 1
def __init__(self, elf, **kwargs):
self.elf = elf
self.magic = None
self.version = None
self.mode = None
self.endian = None
self.attribs = None
self.key_type = None
self.header_size = None
self.meta_size = None
self.file_size = None
self.num_entries = None
self.flags = None
self.entries = None
self.ex_info = None
self.npdrm_control_block = None
self.meta_blocks = None
self.meta_footer = None
self.signature = None
self.version_data = None
self.paid = kwargs['paid'] if 'paid' in kwargs and not kwargs['paid'] is None else 0x3100000000000002
self.ptype = kwargs['ptype'] if 'ptype' in kwargs and not kwargs['ptype'] is None else SignedElfExInfo.PTYPE_FAKE
self.app_version = kwargs['app_version'] if 'app_version' in kwargs and not kwargs['app_version'] is None else 0
self.fw_version = kwargs['fw_version'] if 'fw_version' in kwargs and not kwargs['fw_version'] is None else 0
self.auth_info = kwargs['auth_info'] if 'auth_info' in kwargs and not kwargs['auth_info'] is None else None
def _prepare(self):
self.magic = SignedElfFile.MAGIC
self.version = SignedElfFile.VERSION
self.mode = SignedElfFile.MODE
self.endian = SignedElfFile.ENDIAN
self.attribs = SignedElfFile.ATTRIBS
self.key_type = SignedElfFile.KEY_TYPE
self.flags = 0x2
signed_block_count = 2
self.flags |= (signed_block_count & SignedElfFile.FLAGS_SEGMENT_SIGNED_MASK) << SignedElfFile.FLAGS_SEGMENT_SIGNED_SHIFT
self.entries = []
entry_idx = 0
for i in range(self.elf.ehdr.phnum):
phdr = self.elf.phdrs[i]
if phdr.type == ElfPHdr.PT_SCE_VERSION:
self.version_data = self.elf.segments[i]
if not phdr.type in [ElfPHdr.PT_LOAD, ElfPHdr.PT_SCE_RELRO, ElfPHdr.PT_SCE_DYNLIBDATA, ElfPHdr.PT_SCE_COMMENT]:
continue
meta_entry = SignedElfEntry(entry_idx)
meta_entry.props = 0
meta_entry.encrypted = False
meta_entry.signed = True
meta_entry.has_digests = True
meta_entry.segment_index = entry_idx + 1
self.entries.append(meta_entry)
data_entry = SignedElfEntry(entry_idx + 1)
data_entry.props = 0
data_entry.encrypted = False
data_entry.signed = True
data_entry.has_blocks = True
data_entry.block_size = BLOCK_SIZE
data_entry.segment_index = i
self.entries.append(data_entry)
entry_idx += 2
self.num_entries = len(self.entries)
self.ex_info = SignedElfExInfo()
self.ex_info.paid = self.paid
self.ex_info.ptype = self.ptype
self.ex_info.app_version = self.app_version
self.ex_info.fw_version = self.fw_version
self.ex_info.digest = self.elf.digest
if SignedElfFile.HAS_NPDRM:
self.npdrm_control_block = SignedElfNpdrmControlBlock()
self.npdrm_control_block.content_id = b'\0' * SELF_NPDRM_CONTROL_BLOCK_CONTENT_ID_SIZE
self.npdrm_control_block.random_pad = b'\0' * SELF_NPDRM_CONTROL_BLOCK_RANDOM_PAD_SIZE
self.header_size = struct.calcsize(SignedElfFile.COMMON_HEADER_FMT) + struct.calcsize(SignedElfFile.EXT_HEADER_FMT)
self.header_size += self.num_entries * struct.calcsize(SignedElfEntry.FMT)
self.header_size += max(self.elf.ehdr.ehsize, self.elf.ehdr.phoff + self.elf.ehdr.phentsize * self.elf.ehdr.phnum)
self.header_size = align_up(self.header_size, 16)
self.header_size += struct.calcsize(SignedElfExInfo.FMT)
if SignedElfFile.HAS_NPDRM:
self.header_size += struct.calcsize(SignedElfNpdrmControlBlock.FMT)
self.meta_size = self.num_entries * struct.calcsize(SignedElfMetaBlock.FMT) + struct.calcsize(SignedElfMetaFooter.FMT) + SIGNATURE_SIZE
print("meta block", self.num_entries, self.num_entries * struct.calcsize(SignedElfMetaBlock.FMT));
print("footer", struct.calcsize(SignedElfMetaFooter.FMT));
print("signature",SIGNATURE_SIZE);
self.meta_blocks = []
for i in range(self.num_entries):
meta_block = SignedElfMetaBlock()
self.meta_blocks.append(meta_block)
self.meta_footer = SignedElfMetaFooter()
self.meta_footer.unk1 = 0x10000
if not self.auth_info is None:
self.signature = (struct.pack('<QQ', len(self.auth_info), self.ex_info.paid) + self.auth_info[8:]).ljust(SIGNATURE_SIZE, b'\0')
else:
self.signature = EMPTY_SIGNATURE
entry_idx = 0
offset = self.header_size + self.meta_size
for i in range(self.elf.ehdr.phnum):
phdr = self.elf.phdrs[i]
if not phdr.type in [ElfPHdr.PT_LOAD, ElfPHdr.PT_SCE_RELRO, ElfPHdr.PT_SCE_DYNLIBDATA, ElfPHdr.PT_SCE_COMMENT]:
continue
print('processing segment #{0:02}...'.format(i))
meta_entry, data_entry = self.entries[entry_idx], self.entries[entry_idx + 1]
num_blocks = align_up(phdr.filesz, BLOCK_SIZE) // BLOCK_SIZE
meta_entry.data = EMPTY_DIGEST * num_blocks
meta_entry.offset = offset
meta_entry.memsz = meta_entry.filesz = len(meta_entry.data)
offset += meta_entry.filesz
offset = align_up(offset, 16)
data_entry.data = self.elf.segments[i]
data_entry.offset = offset
data_entry.memsz = data_entry.filesz = phdr.filesz
offset += data_entry.filesz
offset = align_up(offset, 16)
entry_idx += 2
self.file_size = offset
def save(self, f):
start_offset = f.tell()
# calculate neccessary fields
self._prepare()
# write common header
f.write(struct.pack(SignedElfFile.COMMON_HEADER_FMT, self.magic, self.version, self.mode, self.endian, self.attribs))
# write extended header
f.write(struct.pack(SignedElfFile.EXT_HEADER_FMT, self.key_type, self.header_size, self.meta_size, self.file_size, self.num_entries, self.flags))
# write entries
for entry in self.entries:
entry.save(f)
# write elf headers
elf_offset = f.tell()
elf_header_size = max(self.elf.ehdr.ehsize, self.elf.ehdr.phoff + self.elf.ehdr.phentsize * self.elf.ehdr.phnum)
elf_header_size = align_up(elf_header_size, 16)
self.elf.save(f, True)
f.seek(elf_offset + elf_header_size)
# write extended info
self.ex_info.save(f)
# write npdrm control block
if SignedElfFile.HAS_NPDRM:
self.npdrm_control_block.save(f)
# write meta blocks
for meta_block in self.meta_blocks:
meta_block.save(f)
# write meta footer
self.meta_footer.save(f)
# write signature
f.write(self.signature)
# write segments
for entry in self.entries:
f.seek(start_offset + entry.offset)
f.write(entry.data)
if f.tell() < self.file_size:
f.seek(self.file_size-1)
f.write(b"\x00")
# write version
if not self.version_data is None:
f.write(self.version_data)
def ensure_hex_string(val, **kwargs):
exact_size = int(kwargs['exact_size']) if 'exact_size' in kwargs else None
min_size = int(kwargs['min_size']) if 'min_size' in kwargs else None
max_size = int(kwargs['max_size']) if 'max_size' in kwargs else None
val = re.sub(r'\s+', '', val)
val_size = len(val)
if val_size > 0:
if val.startswith('0x') or val.startswith('0X'):
val = val[2:]
if len(val) % 2 != 0 or not all(x in string.hexdigits for x in val):
return None
val = bytes.fromhex(val)
val_size = len(val)
if not exact_size is None and val_size != exact_size:
return None
else:
if not min_size is None and val_size < min_size:
return None
if not max_size is None and val_size > max_size:
return None
return val
def input_file_type(val):
if not os.access(val, os.F_OK | os.R_OK) or not os.path.isfile(val):
raise argparse.ArgumentTypeError('invalid input file: {0}'.format(val))
return val
def output_file_type(val):
if os.access(val, os.F_OK) and (not os.path.isfile(val) or not os.access(val, os.F_OK | os.W_OK)):
raise argparse.ArgumentTypeError('invalid output file: {0}'.format(val))
return val
def auth_info_type(val):
new_val = ensure_hex_string(val, exact_size=0x88)
if new_val is None:
raise argparse.ArgumentTypeError('invalid auth info: {0}'.format(val))
return new_val
class MyParser(argparse.ArgumentParser):
def error(self, message):
self.print_help()
sys.stderr.write('\nerror: {0}\n'.format(message))
sys.exit(2)
if __name__ == '__main__':
parser = MyParser(description='fake signed elf maker')
parser.add_argument('input', type=input_file_type, default=None, help='elf/prx file path')
parser.add_argument('output', type=output_file_type, default=None, help='self/sprx file path')
parser.add_argument('--paid', type=int_with_base_type, default=0x3100000000000002, help='program authentication id')
parser.add_argument('--ptype', default=None, help='program type {fake, npdrm_exec, npdrm_dynlib, system_exec, system_dynlib, host_kernel, secure_module, secure_kernel}')
parser.add_argument('--app-version', type=int_with_base_type, default=0, help='application version')
parser.add_argument('--fw-version', type=int_with_base_type, default=0, help='firmware version')
parser.add_argument('--auth-info', type=auth_info_type, default=None, help='authentication info')
if len(sys.argv) == 1:
parser.print_usage()
sys.exit(1)
args = parser.parse_args()
paid = args.paid
if not (0 <= paid <= 0xFFFFFFFFFFFFFFFF):
parser.error('invalid program authentication id: 0x{0:016X}'.format(paid))
ptype = SignedElfExInfo.PTYPE_FAKE
if not args.ptype is None:
ptype = {
'fake': SignedElfExInfo.PTYPE_FAKE,
'npdrm_exec': SignedElfExInfo.PTYPE_NPDRM_EXEC,
'npdrm_dynlib': SignedElfExInfo.PTYPE_NPDRM_DYNLIB,
'system_exec': SignedElfExInfo.PTYPE_SYSTEM_EXEC,
'system_dynlib': SignedElfExInfo.PTYPE_SYSTEM_DYNLIB,
'host_kernel': SignedElfExInfo.PTYPE_HOST_KERNEL,
'secure_module': SignedElfExInfo.PTYPE_SECURE_MODULE,
'secure_kernel': SignedElfExInfo.PTYPE_SECURE_KERNEL,
}.get(args.ptype.strip().lower(), None)
if ptype is None:
ptype = try_parse_int(args.ptype)
if ptype is None:
parser.error('invalid program type: 0x{0:016X}'.format(ptype))
if not (0 <= ptype <= 0xFFFFFFFFFFFFFFFF):
parser.error('invalid program type: 0x{0:016X}'.format(ptype))
app_version = args.app_version
if not (0 <= app_version <= 0xFFFFFFFFFFFFFFFF):
parser.error('invalid application version: 0x{0:016X}'.format(app_version))
fw_version = args.fw_version
if not (0 <= fw_version <= 0xFFFFFFFFFFFFFFFF):
parser.error('invalid firmware version: 0x{0:016X}'.format(fw_version))
auth_info = args.auth_info
elf_file_path = args.input
fself_file_path = args.output
print('loading elf file: {0}'.format(elf_file_path))
try:
with open(elf_file_path, 'rb') as f:
elf_file = ElfFile(ignore_shdrs=True)
elf_file.load(f)
except Exception as err:
traceback.print_exc()
print('')
parser.error('unable to load elf file: {0} ({1})'.format(elf_file_path, err))
print('saving fake signed elf file: {0}'.format(fself_file_path))
try:
with open(fself_file_path, 'wb') as f:
self_file = SignedElfFile(elf_file, paid=paid, ptype=ptype, app_version=app_version, fw_version=fw_version, auth_info=auth_info)
self_file.save(f)
except Exception as err:
traceback.print_exc()
print('')
parser.error('unable to save fself file: {0} ({1})'.format(elf_file_path, err))
print('done')
+39
View File
@@ -0,0 +1,39 @@
/* Copyright (C) 2025 John Törnblom
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 3, or (at your option) any
later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>. */
#include <stdio.h>
int sceAppInstUtilInitialize(void);
int sceAppInstUtilAppInstallTitleDir(const char*, const char*, void*);
int
main(int argc, char *argv[]) {
int err;
if((err=sceAppInstUtilInitialize())) {
printf("sceAppInstUtilInitialize: %x\n", err);
return -1;
}
if((err=sceAppInstUtilAppInstallTitleDir(TITLE_ID, "/user/app/", 0))) {
printf("sceAppInstUtilAppInstallTitleDir: %x\n", err);
return -1;
}
return 0;
}
+2 -1
View File
@@ -39,7 +39,8 @@ test: $(ELF)
$(PS5_DEPLOY) -h $(PS5_HOST) -p $(PS5_PORT) $^
debug: $(ELF)
gdb \
gdb-multiarch \
-ex "set architecture i386:x86-64" \
-ex "target extended-remote $(PS5_HOST):2159" \
-ex "file $(ELF)" \
-ex "remote put $(ELF) /data/$(ELF)" \
+2 -1
View File
@@ -39,7 +39,8 @@ test: $(ELF)
$(PS5_DEPLOY) -h $(PS5_HOST) -p $(PS5_PORT) $^
debug: $(ELF)
gdb \
gdb-multiarch \
-ex "set architecture i386:x86-64" \
-ex "target extended-remote $(PS5_HOST):2159" \
-ex "file $(ELF)" \
-ex "remote put $(ELF) /data/$(ELF)" \
+3 -2
View File
@@ -25,7 +25,7 @@ endif
ELF := notify.elf
CFLAGS := -Wall -Werror -g
CFLAGS := -Wall -Werror -g -lSceNotification
all: $(ELF)
@@ -39,7 +39,8 @@ test: $(ELF)
$(PS5_DEPLOY) -h $(PS5_HOST) -p $(PS5_PORT) $^
debug: $(ELF)
gdb \
gdb-multiarch \
-ex "set architecture i386:x86-64" \
-ex "target extended-remote $(PS5_HOST):2159" \
-ex "file $(ELF)" \
-ex "remote put $(ELF) /data/$(ELF)" \
+61 -17
View File
@@ -1,4 +1,4 @@
/* Copyright (C) 2023 John Törnblom
/* Copyright (C) 2025 LightningMods
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
@@ -16,28 +16,72 @@ along with this program; see the file COPYING. If not, see
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
typedef struct notify_request {
char useless1[45];
char message[3075];
} notify_request_t;
#define SCE_NOTIFICATION_LOCAL_USER_ID_SYSTEM 0xFE
int sceKernelSendNotificationRequest(int, notify_request_t*, size_t, int);
int sceNotificationSend(int userId, bool isLogged, const char* payload);
static const char toast_tmpl[] =
"{\n"
" \"rawData\": {\n"
" \"viewTemplateType\": \"InteractiveToastTemplateB\",\n"
" \"channelType\": \"Downloads\",\n"
" \"useCaseId\": \"IDC\",\n"
" \"toastOverwriteType\": \"No\",\n"
" \"isImmediate\": true,\n"
" \"priority\": 100,\n"
" \"viewData\": {\n"
" \"icon\": {\n"
" \"type\": \"Url\",\n"
" \"parameters\": {\n"
" \"url\": \"/path/to/icon.png\"\n"
" }\n"
" },\n"
" \"message\": {\n"
" \"body\": \"Hello World!\"\n"
" },\n"
" \"subMessage\": {\n"
" \"body\": \"notify sample\"\n"
" },\n"
" \"actions\": [\n"
" {\n"
" \"actionName\": \"Go to debug settings\",\n"
" \"actionType\": \"DeepLink\",\n"
" \"defaultFocus\": true,\n"
" \"parameters\": {\n"
" \"actionUrl\": \"pssettings:play?function=debug_settings\"\n"
" }\n"
" }\n"
" ]\n"
" },\n"
" \"platformViews\": {\n"
" \"previewDisabled\": {\n"
" \"viewData\": {\n"
" \"icon\": {\n"
" \"type\": \"Predefined\",\n"
" \"parameters\": {\n"
" \"icon\": \"download\"\n"
" }\n"
" },\n"
" \"message\": {\n"
" \"body\": \"notify sample is running\"\n"
" }\n"
" }\n"
" }\n"
" }\n"
" },\n"
" \"createdDateTime\": \"2025-12-14T03:14:51.473Z\",\n"
" \"localNotificationId\": \"588193127\"\n"
"}";
int
main(int argc, char *argv[]) {
notify_request_t req;
bzero(&req, sizeof req);
if(argc == 1) {
snprintf(req.message, sizeof req.message, "%s", argv[0]);
} else if(argc >= 2) {
snprintf(req.message, sizeof req.message, "%s: %s", argv[0], argv[1]);
}
return sceKernelSendNotificationRequest(0, &req, sizeof req, 0);
main(void) {
return sceNotificationSend(SCE_NOTIFICATION_LOCAL_USER_ID_SYSTEM,
true, toast_tmpl);
}
+4
View File
@@ -0,0 +1,4 @@
*.elf
*.o
*~
Loaded 100 of 120 files, more files were not shown because too many files have changed in this diff. Show more