mirror of
https://github.com/ps5-payload-dev/sdk.git
synced 2026-10-19 10:00:59 -05:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f5d40f0277 | ||
|
|
1a04f75407 | ||
|
|
10b539de8f | ||
|
|
f7fd02e6e1 | ||
|
|
b4fcb924d6 | ||
|
|
3b6ea8044e | ||
|
|
d9c9519116 | ||
|
|
66daf51afe | ||
|
|
4b86c73ab7 | ||
|
|
f89a100c89 | ||
|
|
8e125899b1 | ||
|
|
4eb701204f | ||
|
|
9d267a83fa | ||
|
|
a9e742489a | ||
|
|
a0d2bc60bd | ||
|
|
558d2f5669 | ||
|
|
4460639b2d | ||
|
|
4e88ed694c | ||
|
|
6d0cc823be | ||
|
|
45fca06f9a | ||
|
|
5184bcdfb4 | ||
|
|
c68b1b56ae | ||
|
|
2e6fab5042 | ||
|
|
92320fbaef | ||
|
|
cf547b191d | ||
|
|
3f219cd64b | ||
|
|
4eee7ac558 | ||
|
|
d2e2e58574 | ||
|
|
9478d2baaa | ||
|
|
d77b34f88a | ||
|
|
7f30ee52cd | ||
|
|
3bede94ff9 | ||
|
|
cfbc7307ac | ||
|
|
5b73e745cb | ||
|
|
091540e1b8 | ||
|
|
1aa6d5603e | ||
|
|
9fe9f78db6 | ||
|
|
551f796331 | ||
|
|
f2e8f65dae | ||
|
|
c1e0b74f25 | ||
|
|
12433ce900 | ||
|
|
10d9163fe4 | ||
|
|
8ae0a9babf | ||
|
|
9e4b1ad764 | ||
|
|
6ab211b319 | ||
|
|
7b5caa9449 | ||
|
|
28720cfb33 | ||
|
|
13ccc2d5bf | ||
|
|
5f68a946af | ||
|
|
ed69baef16 | ||
|
|
acfd93595e | ||
|
|
6bd9c1b64f | ||
|
|
84ccd42dda | ||
|
|
b710649800 | ||
|
|
df0508f622 | ||
|
|
64e25e8359 | ||
|
|
8154f82118 | ||
|
|
9e7b5f8cca | ||
|
|
8ba558e844 | ||
|
|
d74499b738 | ||
|
|
1bd0d7bac0 | ||
|
|
5b6683374a | ||
|
|
6ae1470fd5 | ||
|
|
7dabc1bb17 | ||
|
|
1c617cac43 | ||
|
|
cca4ba3605 | ||
|
|
1da036ae2a | ||
|
|
e103138794 | ||
|
|
b58c5d94a9 | ||
|
|
8ecbe8f57f | ||
|
|
a967354f25 | ||
|
|
9deeac8bba | ||
|
|
87d19cde89 | ||
|
|
3485018172 | ||
|
|
767cf36d1f | ||
|
|
d4b272c980 | ||
|
|
9f740c433d | ||
|
|
06de6da302 | ||
|
|
b21bf9c7c5 | ||
|
|
48b3f5e838 | ||
|
|
dd333d3dcf | ||
|
|
c096b8c5fd | ||
|
|
03f75ba291 | ||
|
|
88dd7b045e | ||
|
|
51f96a350a | ||
|
|
b8504c125b | ||
|
|
6541cd1754 | ||
|
|
7428de204f | ||
|
|
d15eb41dff | ||
|
|
da9c2e1372 | ||
|
|
7d99334e9f | ||
|
|
75dbc643da | ||
|
|
b47ec1352e | ||
|
|
606319a30c | ||
|
|
9d849ebff2 | ||
|
|
eab966fd2f | ||
|
|
25ec960826 | ||
|
|
7e3b4c4df9 | ||
|
|
f4917c8892 | ||
|
|
4023167199 | ||
|
|
9f23c958eb | ||
|
|
494d9e0903 | ||
|
|
285951051f | ||
|
|
70aa9b2d97 | ||
|
|
a413a94455 | ||
|
|
b5e3004271 | ||
|
|
e7080848f5 | ||
|
|
22f11be77d | ||
|
|
4ee82db242 | ||
|
|
9832162571 | ||
|
|
1d92da40df | ||
|
|
f65522f4ab | ||
|
|
29501cbc48 | ||
|
|
81aade6f2b | ||
|
|
e3a4673f40 | ||
|
|
e15b4741b0 | ||
|
|
07ea97804c | ||
|
|
d915ad81e9 | ||
|
|
7116a650a0 | ||
|
|
3b028e7139 | ||
|
|
38e8b5b34a | ||
|
|
b79b6416e9 | ||
|
|
c028c11333 | ||
|
|
b080ed08f7 | ||
|
|
4780c3ddc9 | ||
|
|
7e9d5de599 | ||
|
|
b60dc4ff2d | ||
|
|
0760994443 | ||
|
|
124f4c1e65 | ||
|
|
b5d6a60111 | ||
|
|
ae003a47d2 | ||
|
|
9740039fba | ||
|
|
c282b54f9c | ||
|
|
b3f1da4ba2 | ||
|
|
ac172551d6 | ||
|
|
986b7c4531 | ||
|
|
1b31130d8c | ||
|
|
a7ab3e9c96 | ||
|
|
9bb7312911 | ||
|
|
9d14d05c58 | ||
|
|
8f11be6d8c | ||
|
|
5d736fede9 | ||
|
|
a45a154697 | ||
|
|
a28f7db2f3 | ||
|
|
04a8e191d1 | ||
|
|
23d5810707 | ||
|
|
c13de3c884 | ||
|
|
217e0cf252 | ||
|
|
526375d8f9 | ||
|
|
3c1cb13b0a | ||
|
|
d1d1d94e3b | ||
|
|
80724372d9 | ||
|
|
2792fe2035 | ||
|
|
ff486dcd92 | ||
|
|
46c15f0fc6 | ||
|
|
60723a29b8 | ||
|
|
66ea6b772a | ||
|
|
b4e840256d | ||
|
|
1ad6d39753 | ||
|
|
813c586bfa | ||
|
|
a373a579be | ||
|
|
1f361b6c8b |
No files matched your search
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -8,5 +8,4 @@
|
||||
nid_db.xml
|
||||
aerolib.csv
|
||||
.gdb_history
|
||||
prospero-nid
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
File diff suppressed because it is too large.
Load diff
+17
-2
@@ -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]);
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Regular → Executable
+1
-1
@@ -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
@@ -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
@@ -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}"
|
||||
Executable
+56
@@ -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]))
|
||||
@@ -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 "$@"
|
||||
@@ -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()
|
||||
@@ -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'
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
@@ -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.
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
@@ -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
|
||||
@@ -1,6 +0,0 @@
|
||||
#include <termios.h>
|
||||
|
||||
speed_t
|
||||
cfgetospeed(const struct termios *t) {
|
||||
return t->c_ospeed;
|
||||
}
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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));
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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 */
|
||||
}
|
||||
@@ -29,6 +29,8 @@ tmpfile(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
unlink(s);
|
||||
|
||||
if(!(f=fdopen(fd, "rw+b"))) {
|
||||
close(fd);
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
@@ -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
@@ -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 *)█
|
||||
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
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
}
|
||||
@@ -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)" \
|
||||
|
||||
@@ -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)" \
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
*.elf
|
||||
*.o
|
||||
*~
|
||||
|
||||
Executable → Regular
+20
-15
@@ -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"
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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}"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -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
|
||||
)
|
||||
@@ -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)" \
|
||||
|
||||
@@ -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)" \
|
||||
|
||||
@@ -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)" \
|
||||
|
||||
@@ -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)" \
|
||||
|
||||
@@ -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)" \
|
||||
|
||||
@@ -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)" \
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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)" \
|
||||
|
||||
@@ -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)" \
|
||||
|
||||
@@ -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)" \
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
@@ -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"
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
Executable
+824
@@ -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')
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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)" \
|
||||
|
||||
@@ -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)" \
|
||||
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
Reference in new issue
Block a user