mirror of
https://github.com/ps5-linux/ps5-linux-loader.git
synced 2026-05-13 18:22:00 +00:00
Compare commits
21 Commits
65961996d7
...
dev-wifi-f
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
01436f0a6b | ||
|
|
8e60126031 | ||
|
|
7617090c6c | ||
|
|
f017958451 | ||
|
|
d5e1702917 | ||
|
|
1be941e9bd | ||
|
|
28e2ccd35a | ||
|
|
4355489449 | ||
|
|
c5154ba567 | ||
|
|
29a0d28c69 | ||
|
|
7a58386b98 | ||
|
|
dcb60beef2 | ||
|
|
9f1d4f683d | ||
|
|
235ad43eb5 | ||
|
|
9d0bfe00b9 | ||
|
|
b9e4b36688 | ||
|
|
5ae9c4de79 | ||
|
|
aedd5e3b38 | ||
|
|
b45045217f | ||
|
|
c602ff8063 | ||
|
|
6ac9bab944 |
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
bin/
|
||||
shellcode_kernel/shellcode_kernel.h
|
||||
shellcode_hypervisor/shellcode_hypervisor.h
|
||||
*.elf
|
||||
*.bin
|
||||
*.o
|
||||
114
README.md
114
README.md
@@ -1,6 +1,6 @@
|
||||
# ps5-linux
|
||||
|
||||
**ps5-linux** leverages a patched HV vulnerability to transform your PS5 Phat console running **3.xx or 4.xx firmwares** into a highly capable Linux PC, unlocking its full hardware potential for desktop use. Powered by 8 CPU cores (16 threads) at **3.5 GHz** and a GPU at **2.23 GHz**, it provides enough performance to run Steam games and various emulators with impressive fluidity. It supports HDMI 4K60 video and audio output. Furthermore, it allows you to utilize an **M.2 SSD** as a dedicated Linux partition, as well as all USB ports on the console.
|
||||
**ps5-linux** leverages a patched HV vulnerability to transform your PS5 Phat console running **3.xx or 4.xx firmwares** (and soon also on **firmware 6.02**) into a highly capable Linux PC, unlocking its full hardware potential for desktop use. Powered by 8 CPU cores (16 threads) at **3.5 GHz** and a GPU at **2.23 GHz**, it provides enough performance to run Steam games and various emulators with impressive fluidity. It supports HDMI 4K60 video and audio output. Furthermore, it allows you to utilize an **M.2 SSD** as a dedicated Linux partition, as well as all USB ports on the console.
|
||||
|
||||

|
||||
|
||||
@@ -8,14 +8,13 @@
|
||||
|
||||
*ps5-linux* is currently only supported on PS5 Phat on 3.xx and 4.xx firmwares.
|
||||
|
||||
- **3.00**, **3.10**, **3.20**, **3.21**, without M.2 support
|
||||
- **3.00**, **3.10**, **3.20**, **3.21** without M.2 support
|
||||
- **4.00**, **4.02**, **4.03**, **4.50**, **4.51** with M.2 support
|
||||
- **Soon: 6.02** with M2 support
|
||||
|
||||
Support for 1.xx and 2.xx firmwares may be added in the future, but we will not prioritize this effort.
|
||||
|
||||
Support for 5.xx firmwares may be added in the future, but for those firmwares, Linux will run within the GameOS VM, thus it will have less features (still unknown what limitations there will be) and it may not perform as good.
|
||||
|
||||
If you want to update to a specific firmware, [download the correct PUP](https://darthsternie.net/ps5-firmwares/) and follow the [official guide](https://www.playstation.com/en-us/support/hardware/reinstall-playstation-system-software-safe-mode) to upgrade your PS5.
|
||||
If you want to update to a specific firmware, [download the correct PUP](https://darthsternie.net/ps5-firmwares/) and follow the [official guide](https://www.playstation.com/en-us/support/hardware/reinstall-playstation-system-software-safe-mode) to upgrade your PS5. Obviously you cannot downgrade.
|
||||
|
||||
## Hardwares
|
||||
|
||||
@@ -30,21 +29,34 @@ To run *ps5-linux*, you need some required and optional hardwares:
|
||||
|
||||
## Configure PS5 settings
|
||||
|
||||
- **Required**: Enable Rest Mode features:
|
||||
- **VERY IMPORTANT**: Enable Rest Mode features:
|
||||
- Go to `Settings` → `System` → `Power Saving` → `Features Available in Rest Mode` and set `Supply Power to USB Ports` to `Always`.
|
||||
- **Required**: Disable HDMI Device Link:
|
||||
- **VERY IMPORTANT**: Disable HDMI Device Link:
|
||||
- Go to `Settings` → `HDMI` → `Enable HDMI Device Link`
|
||||
- *Recommended*: Disable automatic updates:
|
||||
- Go to `Settings` → `System Software` → `System Software Update and Settings`
|
||||
- *Recommended*: Disable automatic error reporting:
|
||||
- Go to `Settings` → `System Software` → `Report System Software Errors Automatically`
|
||||
|
||||
If you reset your PS5 settings or reinstall the FW, you need to reapply these settings again.
|
||||
|
||||
## Installation
|
||||
|
||||
### 1. Get a Linux image
|
||||
|
||||
#### Linux/macOS:
|
||||
|
||||
Install docker:
|
||||
|
||||
```bash
|
||||
sudo apt update
|
||||
sudo apt install docker.io -y
|
||||
sudo service docker start
|
||||
sudo usermod -aG docker $USER
|
||||
```
|
||||
|
||||
Restart the terminal.
|
||||
|
||||
```bash
|
||||
git clone https://github.com/ps5-linux/ps5-linux-image
|
||||
cd ps5-linux-image
|
||||
@@ -99,36 +111,7 @@ sudo dd if=output/ps5-ubuntu2604.img of=/dev/sdX bs=4M status=progress conv=fsyn
|
||||
|
||||
#### Windows (Balena Etcher):
|
||||
|
||||
Download Balena Etcher, select the .img file, select your USB drive, click Flash.
|
||||
|
||||
#### Windows (WSL2 + usbipd):
|
||||
|
||||
Install usbipd in PowerShell as administrator:
|
||||
|
||||
```bash
|
||||
winget install usbipd
|
||||
```
|
||||
|
||||
Plug in your USB drive, list devices and find the busid of your drive:
|
||||
|
||||
```bash
|
||||
usbipd list
|
||||
```
|
||||
|
||||
Bind and attach it to WSL (replace 5-3 with your busid):
|
||||
|
||||
```bash
|
||||
usbipd bind --busid 5-3
|
||||
usbipd attach --busid 5-3 --wsl
|
||||
```
|
||||
|
||||
Then flash from WSL:
|
||||
|
||||
```bash
|
||||
lsblk # confirm the drive appeared, e.g. /dev/sdb
|
||||
sudo wipefs -a /dev/sdX
|
||||
sudo dd if=output/ps5-ubuntu2604.img of=/dev/sdX bs=4M status=progress
|
||||
```
|
||||
Download [Balena Etcher](https://etcher.balena.io/), select the `.img` file, select your USB drive, click Flash.
|
||||
|
||||
### 3. Plug the USB drive into your PS5
|
||||
|
||||
@@ -157,6 +140,12 @@ cd ps5-linux-loader
|
||||
make
|
||||
```
|
||||
|
||||
If you're on ARM64 Linux, then additionall install the x86-64 cross-compilation tools before:
|
||||
|
||||
```bash
|
||||
sudo apt install gcc-x86-64-linux-gnu binutils-x86-64-linux-gnu
|
||||
```
|
||||
|
||||
Find your PS5 IP at `Settings → Network → View Connection Status`.
|
||||
|
||||
```bash
|
||||
@@ -167,11 +156,13 @@ If all is successful, the payload will automatically go into rest mode. Wait unt
|
||||
|
||||
If the LED is white, but you still have a blackscreen then:
|
||||
|
||||
- Try removing `video=DP-1:1920x1080@60` line in cmdline.txt.
|
||||
- Try different monitors or capture cards, ideally with different resolutions. Currently, some monitors have issues.
|
||||
- Try setting `amdgpu.force_1080p=1` in `cmdline.txt` in the FAT32 partition of the USB drive.
|
||||
|
||||
If none of this helps, please report the issue in our [Discord server](https://discord.gg/PeMGVB7BAm) and provide your EDID information.
|
||||
|
||||
|
||||
## First Boot
|
||||
|
||||
Configure your system and memorize your login password.
|
||||
@@ -182,36 +173,51 @@ Then, there are certain settings and commands we recommend doing:
|
||||
|
||||
2. Possibly, you have to disable and reenable your Wired/WLAN connection to get internet connection.
|
||||
|
||||
3. Install Firefox:
|
||||
3. Hold packages to prevent updating the kernel when doing `apt upgrade`:
|
||||
```bash
|
||||
sudo apt-mark hold linux-generic linux-generic-hwe-24.04 linux-generic-hwe-26.04 linux-image-generic linux-image-generic-hwe-24.04 linux-image-generic-hwe-26.04 linux-headers-generic linux-headers-generic-hwe-24.04 linux-headers-generic-hwe-26.04
|
||||
```
|
||||
|
||||
4. Install Firefox:
|
||||
|
||||
```bash
|
||||
sudo snap install firefox
|
||||
sudo snap refresh mesa-2404 --channel=latest/edge
|
||||
```
|
||||
|
||||
4. Clone our [ps5-linux-tools](https://github.com/ps5-linux/ps5-linux-tools):
|
||||
5. Update mesa:
|
||||
|
||||
```bash
|
||||
sudo snap refresh mesa-2404 --channel=latest/edge
|
||||
sudo add-apt-repository ppa:kisak/kisak-mesa
|
||||
sudo apt update
|
||||
sudo apt upgrade
|
||||
```
|
||||
|
||||
6. Clone our [ps5-linux-tools](https://github.com/ps5-linux/ps5-linux-tools):
|
||||
|
||||
```bash
|
||||
sudo apt install zlib1g-dev
|
||||
git clone https://github.com/ps5-linux/ps5-linux-tools
|
||||
cd ps5-linux-tools
|
||||
make
|
||||
```
|
||||
|
||||
## M.2 installation
|
||||
|
||||
You can use a M.2 SSD exclusively for Linux (which means you cannot use it for PS5 game storage).
|
||||
|
||||
1. Attach the M.SSD and format it on your PS5.
|
||||
2. Boot Linux on your PS5 and run these commands to initialize your M.2:
|
||||
1. Attach the M.2 SSD by following the [official guide](https://www.playstation.com/en-us/support/hardware/ps5-install-m2-ssd).
|
||||
2. **VERY IMPORTANT**: If you used the M2. SSD for games before, reformat it on the PS5 under `Settings` → `Storage` → `M.2 SSD Storage`.
|
||||
3. Boot Linux on your PS5 and run these commands to initialize your M.2:
|
||||
|
||||
```bash
|
||||
sudo apt install zlib1g-dev
|
||||
cd ps5-linux-tools
|
||||
gcc -o m2_init m2_init.c -lz
|
||||
sudo ./m2_init
|
||||
```
|
||||
|
||||
3. Reboot via `sudo reboot`. If your PS5 asks you to format your M.2 again, please report this issue to us in our [Discord server](https://discord.gg/PeMGVB7BAm) and provide your M.2 model and storage size.
|
||||
4. Relaunch Linux on your PS5.
|
||||
5. Copy the `ps5-ubuntu2604.img` image that you built during installation or rebuild it on your PS5. Then, install it onto your M.2:
|
||||
4. Reboot via `sudo reboot`. If your PS5 asks you to format your M.2 again, please report this issue to us in our [Discord server](https://discord.gg/PeMGVB7BAm) and provide your M.2 model and storage size.
|
||||
5. Relaunch Linux on your PS5.
|
||||
6. Copy the `ps5-ubuntu2604.img` image that you built during installation or rebuild it on your PS5. Then, install it onto your M.2:
|
||||
|
||||
```bash
|
||||
cd ps5-linux-tools
|
||||
@@ -227,7 +233,9 @@ chmod +x ./m2_exec.sh
|
||||
sudo ./m2_exec.sh
|
||||
```
|
||||
|
||||
In order to always boot Linux from your M.2, you can edit the label at `/boot/efi/cmdline.txt` from `root=LABEL=ubuntu2604` to `root=LABEL=ubuntu2604-m2`.
|
||||
Then follow the same instructions again as the previous section.
|
||||
|
||||
In order to always boot Linux from your M.2, you can edit the label at `/boot/efi/cmdline.txt` from `root=LABEL=ubuntu2604` to `root=LABEL=ubuntu2604-m2`. You will still require a USB drive with the FAT32, but you can reformat the ext4 partition.
|
||||
|
||||
## Fan & boost control
|
||||
|
||||
@@ -235,7 +243,6 @@ We provide a simple tool that allows you to boost your CPU to 3500Mhz and GPU to
|
||||
|
||||
```bash
|
||||
cd ps5-linux-tools
|
||||
gcc -o ps5_control ps5_control.c
|
||||
sudo ./ps5_control --fan on
|
||||
sudo ./ps5_control --boost on
|
||||
```
|
||||
@@ -248,24 +255,27 @@ Always turn on fan when your turn on boost, as this is what the official PS5 OS
|
||||
- A: No, this is a soft-mod. You need to re-run the exploit in order to boot into Linux.
|
||||
- Q: Can I put Linux into standby and resume?
|
||||
- A: No, this is not supported. We may however add a shutdown feature that puts your PS5 into rest-mode allowing you to relaunch Linux when powering up again.
|
||||
|
||||
- Q: Can I continue using my PS5 if I install Linux?
|
||||
- A: Yes, the internal SSD is not modified
|
||||
- Q: Can I use the PS5's NIC/WLAN module in Linux?
|
||||
- A: In theory yes, but someone needs to write or adapt drivers to use them.
|
||||
- Q: Will higher >=6.xx firmwares be supported?
|
||||
- Q: Will higher >=6.50 firmwares be supported?
|
||||
- A: No.
|
||||
- Q: Does the DualSense controller work?
|
||||
- A: Via a Bluetooth dongle. Built-in Bluetooth is not yet supported.
|
||||
- Q: What resolutions and refresh rates are supported?
|
||||
- A: So far only 1080p, 1440p and 2160p at 60Hz. 120Hz or 30Hz may be added in the future.
|
||||
- A: 1080p, 1440p and 2160p at 60Hz are broadly supported. 1440p@120Hz has been the only confirmed working on the DELL S3225QC yet. 120Hz or 30Hz may be added in the future.
|
||||
|
||||
|
||||
## Tips and tricks
|
||||
|
||||
- If you see graphical issues in your games, add the environment variable `RADV_DEBUG=nohiz` as [recommended for BC250](https://elektricm.github.io/amd-bc250-docs/drivers/environment/#critical-environment-variables) as well.
|
||||
- You can adjust the kernel cmdline in `cmdline.txt` in the FAT32 partition.
|
||||
- You can adjust the VRAM size in `vram.txt` in the FAT32 partition. By default, it uses 512MB (0x20000000) which enables [Dynamic VRAM allocation](https://elektricm.github.io/amd-bc250-docs/bios/flashing/#why-flash-the-bios).
|
||||
- Monitor hotswap may work, but it will not change resolution automatically.
|
||||
- Some monitors have a black screen if a video=DP-1: parameter is set in `cmdline.txt`. Confirmed working without `video=DP-1:1920x1080@60` on:
|
||||
- MSI MAG274Q QD E2, DELL S2721DGF, DELL U2515H (1440p@60Hz)
|
||||
- Possibly also: LG 27GL850, Lenovo Legion Y27q, ViewSonic Elite XG270QG
|
||||
|
||||
Many configurations, tips and tricks from the [AMD BC250 Documentation](https://elektricm.github.io/amd-bc250-docs/) also apply to PS5.
|
||||
|
||||
|
||||
6
include/firmware.h
Normal file
6
include/firmware.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#ifndef FIRMWARE_H
|
||||
#define FIRMWARE_H
|
||||
|
||||
int dump_device_firmwares(const char *boot_file_path);
|
||||
|
||||
#endif
|
||||
@@ -1,3 +1,6 @@
|
||||
#ifndef LOADER_H
|
||||
#define LOADER_H
|
||||
|
||||
#include "utils.h"
|
||||
#include <stdint.h>
|
||||
|
||||
@@ -8,3 +11,5 @@ void pte_store(uintptr_t ptep, uint64_t pte);
|
||||
int read_file(const char *path, void *buf, size_t bufsize);
|
||||
void trim_newline(char *s);
|
||||
int fetch_linux(struct linux_info *info);
|
||||
|
||||
#endif
|
||||
@@ -1,8 +0,0 @@
|
||||
#ifndef MAIN_H
|
||||
#define MAIN_H
|
||||
|
||||
int main(void);
|
||||
int setup_env(void);
|
||||
int prepare_resume(void);
|
||||
|
||||
#endif
|
||||
@@ -35,6 +35,8 @@ typedef struct _offset_list {
|
||||
uint64_t KERNEL_UART_OVERRIDE;
|
||||
uint64_t KERNEL_DEBUG_PATCH;
|
||||
uint64_t KERNEL_CFI_CHECK;
|
||||
uint64_t PS5_WIFI_FW_OFFSET;
|
||||
uint64_t PS5_WIFI_FW_SIZE;
|
||||
} offset_list;
|
||||
|
||||
extern offset_list off_0300;
|
||||
@@ -47,4 +49,4 @@ extern offset_list off_0403;
|
||||
extern offset_list off_0450;
|
||||
extern offset_list off_0451;
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
12
include/prepare_resume.h
Normal file
12
include/prepare_resume.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#ifndef PREPARE_RESUME_H
|
||||
#define PREPARE_RESUME_H
|
||||
#include "utils.h"
|
||||
|
||||
extern struct linux_info linux_i;
|
||||
|
||||
int prepare_resume(void);
|
||||
int update_sck_data_ptr (void* sc, uint64_t dest_text, uint64_t dest_data);
|
||||
void hook_call_near(uint64_t hook, uint64_t dst);
|
||||
void prepare_sck_args(uint64_t dest_data);
|
||||
|
||||
#endif
|
||||
@@ -42,6 +42,7 @@ struct linux_info {
|
||||
size_t initrd_size;
|
||||
size_t vram_size;
|
||||
char cmdline[2048];
|
||||
int kit_type;
|
||||
uintptr_t linux_info; // PA of linux_info
|
||||
};
|
||||
|
||||
@@ -55,6 +56,18 @@ extern uint32_t fw; // Defined on utils.c
|
||||
extern uint64_t vmcb_pa[16]; // Defined on hv_defeat.c
|
||||
extern struct linux_info linux_i; // Declared on main.c
|
||||
|
||||
int setup_env(void);
|
||||
|
||||
static inline void kwrite_large(uint64_t ka, void* src, uint64_t len) {
|
||||
uint32_t CHUNK = 0x1000;
|
||||
uint64_t written = 0;
|
||||
while (written < len) {
|
||||
uint32_t n = (len - written > CHUNK) ? CHUNK : (uint32_t)(len - written);
|
||||
kernel_copyin(src + written, ka + written, n);
|
||||
written += n;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void kwrite(uint64_t ka, void *src, uint64_t len) {
|
||||
kernel_copyin(src, ka, len);
|
||||
}
|
||||
@@ -156,4 +169,17 @@ void enter_rest_mode(void);
|
||||
#define DEBUG_PRINT(fmt, ...)
|
||||
#endif
|
||||
|
||||
|
||||
bool if_exists(const char* path);
|
||||
bool sceKernelIsTestKit(void);
|
||||
bool sceKernelIsDevKit(void);
|
||||
|
||||
enum kit_type {
|
||||
KIT_RETAIL,
|
||||
KIT_TESTKIT,
|
||||
KIT_DEVKIT
|
||||
};
|
||||
|
||||
enum kit_type get_kit_type(void);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -3,9 +3,16 @@ ifndef PS5_PAYLOAD_SDK
|
||||
endif
|
||||
|
||||
# 1. Variables
|
||||
ifeq ($(shell uname -m),aarch64)
|
||||
CC = x86_64-linux-gnu-gcc
|
||||
LD = x86_64-linux-gnu-ld
|
||||
OBJCOPY = x86_64-linux-gnu-objcopy
|
||||
else
|
||||
CC = gcc
|
||||
LD = ld
|
||||
CFLAGS = -O2 -fno-stack-protector -ffreestanding -nostdlib -fcf-protection=none -I$(PS5_PAYLOAD_SDK)/target/include
|
||||
OBJCOPY = objcopy
|
||||
endif
|
||||
CFLAGS = -O2 -fno-stack-protector -ffreestanding -nostdlib -fcf-protection=none -m64 -I$(PS5_PAYLOAD_SDK)/target/include
|
||||
LDFLAGS = -T linker.ld
|
||||
TARGET = shellcode_hypervisor.elf
|
||||
TEXT_BIN = shellcode_hypervisor.bin
|
||||
@@ -23,7 +30,7 @@ $(TARGET): $(OBJ)
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
$(TEXT_BIN): $(TARGET)
|
||||
objcopy -O binary -j .shell_code $(TARGET) $(TEXT_BIN)
|
||||
$(OBJCOPY) -O binary -j .shell_code $(TARGET) $(TEXT_BIN)
|
||||
|
||||
clean:
|
||||
rm -f $(OBJ) $(TARGET) $(TEXT_BIN) $(dump)
|
||||
|
||||
@@ -12,6 +12,7 @@ struct linux_info {
|
||||
size_t initrd_size;
|
||||
size_t vram_size;
|
||||
char cmdline[2048];
|
||||
int kit_type;
|
||||
};
|
||||
|
||||
static struct linux_info info;
|
||||
@@ -88,8 +89,16 @@ static void e820_memory_setup(struct boot_params *bp) {
|
||||
append_e820_table(bp, 0x0f0000000, 0x0f8000000, E820_TYPE_RESERVED);
|
||||
append_e820_table(bp, 0x100000000, VRAM_BASE, E820_TYPE_RAM);
|
||||
append_e820_table(bp, VRAM_BASE, 0x470000000, E820_TYPE_RESERVED); // VRAM
|
||||
append_e820_table(bp, 0x470000000, 0x47f300000, E820_TYPE_RAM);
|
||||
append_e820_table(bp, 0x47f300000, 0x480000000, E820_TYPE_RESERVED);
|
||||
|
||||
// DevKits have 32GB
|
||||
if (info.kit_type != KIT_DEVKIT) {
|
||||
append_e820_table(bp, 0x470000000, 0x47f300000, E820_TYPE_RAM);
|
||||
append_e820_table(bp, 0x47f300000, 0x480000000, E820_TYPE_RESERVED);
|
||||
}
|
||||
else {
|
||||
append_e820_table(bp, 0x470000000, 0x87f300000, E820_TYPE_RAM);
|
||||
append_e820_table(bp, 0x87f300000, 0x880000000, E820_TYPE_RESERVED);
|
||||
}
|
||||
}
|
||||
|
||||
void boot_linux(void) {
|
||||
@@ -124,7 +133,7 @@ void boot_linux(void) {
|
||||
|
||||
memcpy((void *)kernel_pa, (void *)(info.bzimage + setup_size), kernel_size);
|
||||
|
||||
// printf("This is kernel_pa: "); print_val64(kernel_pa); printf("\n");
|
||||
|
||||
void (*startup_64)(uint64_t physaddr, struct boot_params *bp) =
|
||||
(void *)(kernel_pa + 0x200);
|
||||
startup_64(kernel_pa, bp);
|
||||
@@ -159,7 +168,7 @@ void entry(void) {
|
||||
}
|
||||
|
||||
// Disable IOMMU.
|
||||
*(volatile uint64_t *)0xfdd80018 &= ~1;
|
||||
*(volatile uint64_t *)(AMDIOMMU_MMIO_BASE + AMDIOMMU_CTRL) &= ~1;
|
||||
|
||||
memcpy(&info, (void *)(cave_linux_info), sizeof(struct linux_info));
|
||||
|
||||
|
||||
@@ -37,7 +37,16 @@
|
||||
#define DCHUBBUB_WHITELIST_BASE_ADDR_0 0x24878
|
||||
#define DCHUBBUB_WHITELIST_TOP_ADDR_0 0x2487c
|
||||
|
||||
#define AMDIOMMU_MMIO_BASE 0xfdd80000
|
||||
#define AMDIOMMU_CTRL 0x18
|
||||
|
||||
#define MAXCPU 16
|
||||
|
||||
void entry(void);
|
||||
void boot_linux(void);
|
||||
void boot_linux(void);
|
||||
|
||||
enum kit_type {
|
||||
KIT_RETAIL,
|
||||
KIT_TESTKIT,
|
||||
KIT_DEVKIT
|
||||
};
|
||||
@@ -6,8 +6,6 @@
|
||||
|
||||
__attribute__((section(".entry_point"), naked)) uint32_t main(void) {
|
||||
|
||||
// We enter this function after CR3 was updated to 1:1 mapping
|
||||
// We need to point RSP/RBP to a good known valid address
|
||||
uint32_t ebax, ebx, ecx, edx;
|
||||
uint32_t cpu_id;
|
||||
|
||||
@@ -17,12 +15,10 @@ __attribute__((section(".entry_point"), naked)) uint32_t main(void) {
|
||||
|
||||
cpu_id = (ebx >> 24) & 0xFF;
|
||||
|
||||
// We point to a location after the main linux boot code
|
||||
// Each CPU should have a different location
|
||||
// Each CPU should have a different stack
|
||||
uintptr_t new_rsp =
|
||||
(uintptr_t)hv_base_rsp + ((uint64_t)(cpu_id)*hv_stack_size);
|
||||
|
||||
// WARNING: This invalidates current local variables
|
||||
__asm__ volatile("movq %0, %%rsp \n\t"
|
||||
"movq %%rsp, %%rbp \n\t"
|
||||
:
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
// This file is shared between kernel shellcode and hypervisor shellcode
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct {
|
||||
uint64_t bzimage_pa; // Already relocated by Kernel shellcode
|
||||
uint64_t initrd_pa; // Already relocated by Kernel shellcode
|
||||
uint64_t linux_info_pa; // Already relocated by Kernel shellcode
|
||||
uint64_t bzimage_pa;
|
||||
uint64_t initrd_pa;
|
||||
uint64_t linux_info_pa;
|
||||
} shellcode_hypervisor_args;
|
||||
@@ -96,12 +96,10 @@ void wrmsr(uint32_t msr, uint64_t val) {
|
||||
__asm__ __volatile__("wrmsr" : : "a"(low), "d"(high), "c"(msr));
|
||||
}
|
||||
|
||||
// Map FreeBSD atomic_add_32 to GCC builtin
|
||||
void atomic_add_32(volatile uint32_t *p, uint32_t v) {
|
||||
__sync_fetch_and_add(p, v);
|
||||
}
|
||||
|
||||
// Map FreeBSD atomic_cmpset_32 to GCC builtin
|
||||
int atomic_cmpset_32(volatile uint32_t *dst, uint32_t exp, uint32_t src) {
|
||||
return __sync_bool_compare_and_swap(dst, exp, src);
|
||||
}
|
||||
|
||||
@@ -3,9 +3,16 @@ ifndef PS5_PAYLOAD_SDK
|
||||
endif
|
||||
|
||||
|
||||
ifeq ($(shell uname -m),aarch64)
|
||||
CC = x86_64-linux-gnu-gcc
|
||||
LD = x86_64-linux-gnu-ld
|
||||
OBJCOPY = x86_64-linux-gnu-objcopy
|
||||
else
|
||||
CC = gcc
|
||||
LD = ld
|
||||
CFLAGS = -O2 -fno-stack-protector -ffreestanding -nostdlib -I$(PS5_PAYLOAD_SDK)/target/include
|
||||
OBJCOPY = objcopy
|
||||
endif
|
||||
CFLAGS = -O2 -fno-stack-protector -ffreestanding -nostdlib -m64 -I$(PS5_PAYLOAD_SDK)/target/include
|
||||
LDFLAGS = -T linker.ld
|
||||
TARGET = shellcode_kernel.elf
|
||||
TEXT_BIN = shellcode_text.bin
|
||||
@@ -24,7 +31,7 @@ $(TARGET): $(OBJ)
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
$(TEXT_BIN): $(TARGET)
|
||||
objcopy -O binary -j .text $(TARGET) $(TEXT_BIN)
|
||||
$(OBJCOPY) -O binary -j .text $(TARGET) $(TEXT_BIN)
|
||||
|
||||
clean:
|
||||
rm -f $(OBJ) $(TARGET) $(TEXT_BIN) $(dump)
|
||||
|
||||
@@ -9,11 +9,11 @@
|
||||
#define TRANSMITTER_CONTROL_ENABLE 1
|
||||
#define TRANSMITTER_CONTROL_SET_VOLTAGE_AND_PREEMPASIS 11
|
||||
|
||||
int (*transmitter_control)(int cmd, void *control) = NULL; // Filled by main.c
|
||||
int (*mp3_initialize)(int vmid) = NULL; // Filled by main.c
|
||||
int (*mp3_invoke)(int cmd_id, void *req, void *rsp) = NULL; // Filled by main.c
|
||||
int (*transmitter_control)(int cmd, void *control) = NULL;
|
||||
int (*mp3_initialize)(int vmid) = NULL;
|
||||
int (*mp3_invoke)(int cmd_id, void *req, void *rsp) = NULL;
|
||||
|
||||
uint64_t g_vbios; // Filled by main.c
|
||||
uint64_t g_vbios;
|
||||
|
||||
typedef struct {
|
||||
uint8_t lanenum;
|
||||
@@ -46,6 +46,7 @@ struct linux_info {
|
||||
size_t initrd_size;
|
||||
size_t vram_size;
|
||||
char cmdline[2048];
|
||||
int kit_type;
|
||||
};
|
||||
|
||||
static struct linux_info info;
|
||||
@@ -94,39 +95,31 @@ static int mp3_enable_output(int be, int mode) {
|
||||
|
||||
static void patch_hv(void) {
|
||||
|
||||
// Install identity map for HV
|
||||
// HV Shellcode 1 it's updating CR3
|
||||
uint64_t identity_cr3 = cave_hv_paging; // P, RW, US=0
|
||||
uint64_t identity_pml4_0 =
|
||||
identity_cr3 +
|
||||
0x1003ULL; // P, RW, US=0 - 512GB // offset 0 +0x1000 from PML4
|
||||
uint64_t l40_l3_addr = PAGE_PA(identity_pml4_0); // addr PML4[0]
|
||||
uint64_t identity_cr3 = cave_hv_paging;
|
||||
uint64_t identity_pml4_0 = identity_cr3 + 0x1003ULL;
|
||||
uint64_t l40_l3_addr = PAGE_PA(identity_pml4_0);
|
||||
uint64_t identity_pml40_l3[] = {
|
||||
0x0000000000000083, // P, RW, US=0 - 0 GB to 1 GB
|
||||
0x0000000040000083, // P, RW, US=0 - 1 GB to 2 GB
|
||||
0x0000000080000083, // P, RW, US=0 - 3 GB to 3 GB
|
||||
0x00000000C0000083, // P, RW, US=0 - 4 GB to 4 GB
|
||||
0x0000000100000083 // P, RW, US=0 - 5 GB to 6 GB --> Our paging structure
|
||||
0x0000000000000083,
|
||||
0x0000000040000083,
|
||||
0x0000000080000083,
|
||||
0x00000000C0000083,
|
||||
0x0000000100000083
|
||||
};
|
||||
uint64_t l3_size = sizeof(identity_pml40_l3) / sizeof(identity_pml40_l3[0]);
|
||||
|
||||
// Create the map in memory
|
||||
*(uint64_t *)PHYS_TO_DMAP(identity_cr3) = identity_pml4_0;
|
||||
for (uint64_t i = 0; i < l3_size; i++) {
|
||||
*(uint64_t *)PHYS_TO_DMAP(l40_l3_addr + i * 8) = identity_pml40_l3[i];
|
||||
}
|
||||
|
||||
// Install hv_shellcode 2
|
||||
memcpy((void *)PHYS_TO_DMAP(cave_hv_code), shellcode_hypervisor,
|
||||
shellcode_hypervisor_len);
|
||||
|
||||
// Jump to shellcode final identity mapping
|
||||
uint8_t shellcode_jmp[] = {
|
||||
0x48, 0xC7, 0xC0, 0x00, 0x6F, 0x80, 0x62, // mov rax, 0x62806f00
|
||||
0xFF, 0xE0, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, // jmp rax
|
||||
0x48, 0xC7, 0xC0, 0x00, 0x6F, 0x80, 0x62,
|
||||
0xFF, 0xE0, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3,
|
||||
0xC3, 0xC3};
|
||||
|
||||
// Update code cave in hv 1:1 region
|
||||
*(uint32_t *)(&shellcode_jmp[3]) = (uint32_t)args.hv_code_cave_pa;
|
||||
|
||||
// Just patch the VMEXIT handler directly, avoiding all checks
|
||||
@@ -142,12 +135,9 @@ static void patch_hv(void) {
|
||||
0xFF, 0xE0 // jmp rax
|
||||
};
|
||||
|
||||
// Update CR3 PA (from config)
|
||||
*(uint64_t *)(&shellcode_identity_and_jmp[2]) = cave_hv_paging;
|
||||
// Update HV shellcode cave
|
||||
*(uint64_t *)(&shellcode_identity_and_jmp[15]) = cave_hv_code;
|
||||
|
||||
// Install shellcode 1 to update CR3 and jump to main HV shellcode
|
||||
memcpy((void *)PHYS_TO_DMAP(args.hv_code_cave_pa), shellcode_identity_and_jmp,
|
||||
sizeof(shellcode_identity_and_jmp));
|
||||
}
|
||||
|
||||
@@ -3,19 +3,11 @@
|
||||
#include "utils.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#define MSR_EFER 0xC0000080
|
||||
shellcode_kernel_args args = {0};
|
||||
|
||||
shellcode_kernel_args args = {
|
||||
.fw_version = 0xDEADBEEF, .fun_printf = 0x0, .vmcb = {0}};
|
||||
|
||||
// We are being called instead of AcpiSetFirmwareWakingVector from
|
||||
// acpi_wakeup_machdep
|
||||
__attribute__((section(".entry_point"))) uint32_t main(uint64_t add1,
|
||||
uint64_t add2) {
|
||||
|
||||
// We will do main checks on .text only with a reference to .data to avoid
|
||||
// fixed offsets first After NPTs are disabled, we can continue nornmally
|
||||
// using all the variables in .data that are embedded in shellcode
|
||||
volatile shellcode_kernel_args *args_ptr =
|
||||
(volatile shellcode_kernel_args
|
||||
*)0x11AA11AA11AA11AA; // To be replaced with proper address in .kdata
|
||||
@@ -24,12 +16,10 @@ __attribute__((section(".entry_point"))) uint32_t main(uint64_t add1,
|
||||
// "Hide" the pointer from the optimizer
|
||||
__asm__ volatile("" : "+r"(args_ptr));
|
||||
|
||||
// We don't have required information - Abort
|
||||
if ((args_ptr->fun_printf & 0xFFFF) == 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
// Activate UART on Kernel
|
||||
uint32_t *uart_va = (uint32_t *)(args_ptr->dmap_base + 0xC0115110ULL);
|
||||
*uart_va &= ~0x200;
|
||||
uint32_t *override_char_va = (uint32_t *)args_ptr->kernel_uart_override;
|
||||
@@ -45,7 +35,6 @@ __attribute__((section(".entry_point"))) uint32_t main(uint64_t add1,
|
||||
uint64_t unk;
|
||||
int n_devices;
|
||||
|
||||
// Reconfigure IOMMU calling the HV
|
||||
int ret = ((uint64_t(*)(uint64_t, uint64_t, uint64_t, uint64_t,
|
||||
int *))args_ptr->fun_hv_iommu_set_buffers)(
|
||||
iommu_cb2_pa, iommu_cb3_pa, iommu_eb_pa, (uint64_t) &unk, &n_devices);
|
||||
@@ -65,7 +54,6 @@ __attribute__((section(".entry_point"))) uint32_t main(uint64_t add1,
|
||||
goto out;
|
||||
}
|
||||
|
||||
// Wait for completion
|
||||
ret = ((uint64_t(*)(void))args_ptr->fun_hv_iommu_wait_completion)();
|
||||
|
||||
if (ret == 0) {
|
||||
@@ -83,7 +71,6 @@ __attribute__((section(".entry_point"))) uint32_t main(uint64_t add1,
|
||||
putc_uart(args_ptr->dmap_base, 'K');
|
||||
putc_uart(args_ptr->dmap_base, '\n');
|
||||
|
||||
// Allow R/W on HV and Kernel area
|
||||
if (tmr_disable(args_ptr->dmap_base)) {
|
||||
|
||||
putc_uart(args_ptr->dmap_base, 'T');
|
||||
@@ -104,7 +91,6 @@ __attribute__((section(".entry_point"))) uint32_t main(uint64_t add1,
|
||||
putc_uart(args_ptr->dmap_base, 'K');
|
||||
putc_uart(args_ptr->dmap_base, '\n');
|
||||
|
||||
// Patch HV
|
||||
patch_vmcb(args_ptr);
|
||||
|
||||
putc_uart(args_ptr->dmap_base, 'V');
|
||||
@@ -145,9 +131,6 @@ __attribute__((section(".entry_point"))) uint32_t main(uint64_t add1,
|
||||
boot_linux();
|
||||
printf("Linux prepared OK\n");
|
||||
|
||||
// Activate HV UART - Not really needed but good for debugging
|
||||
// *(uint32_t*)PHYS_TO_DMAP(args.hv_uart_override_pa) = 0x0;
|
||||
|
||||
printf("Calling smp_rendezvous to exit all cores to HV with ptr: %016lx\n",
|
||||
(uint64_t)vmmcall_dummy);
|
||||
printf("Good Bye VM :)\n");
|
||||
@@ -186,36 +169,28 @@ __attribute__((noinline, optimize("O0"), naked)) void vmmcall_dummy(void) {
|
||||
|
||||
void halt(void) { __asm__ __volatile__("hlt"); }
|
||||
|
||||
// Submit a single 16-byte command and wait for completion
|
||||
__attribute__((noinline, optimize("O0"))) void
|
||||
iommu_submit_cmd(volatile shellcode_kernel_args *args_ptr, uint64_t *cmd) {
|
||||
// Read the offset of current tail of command list
|
||||
|
||||
uint64_t curr_tail = *(
|
||||
(uint64_t *)args_ptr->iommu_mmio_va +
|
||||
IOMMU_MMIO_CB_TAIL /
|
||||
8); // Offset in IOMMU Command Buffer - Downscale the size of the ptr
|
||||
uint64_t next_tail = (curr_tail + IOMMU_CMD_ENTRY_SIZE) &
|
||||
IOMMU_CB_MASK; // Offset in IOMMU Command Buffer
|
||||
IOMMU_MMIO_CB_TAIL / 8);
|
||||
uint64_t next_tail = (curr_tail + IOMMU_CMD_ENTRY_SIZE) & IOMMU_CB_MASK;
|
||||
|
||||
// We write the command in the current empty entry
|
||||
uint64_t *cmd_buffer =
|
||||
(uint64_t *)args_ptr->iommu_cb2_va + curr_tail / 8; // Downscale the size of the ptr
|
||||
// Copy 0x10 bytes (CMD Size)
|
||||
(uint64_t *)args_ptr->iommu_cb2_va + curr_tail / 8;
|
||||
cmd_buffer[0] = cmd[0];
|
||||
cmd_buffer[1] = cmd[1];
|
||||
|
||||
__asm__ volatile("" : : : "memory"); // Prevent reordering
|
||||
*((uint64_t *)args_ptr->iommu_mmio_va + IOMMU_MMIO_CB_TAIL / 8) =
|
||||
next_tail; // Indicate the IOMMU that there is a CMD - Downscale the size
|
||||
// of the ptr
|
||||
next_tail;
|
||||
|
||||
// Wait CMD processing completion - Head will be the Tail
|
||||
while (*((uint64_t *)args_ptr->iommu_mmio_va + IOMMU_MMIO_CB_HEAD / 8) !=
|
||||
*((uint64_t *)args_ptr->iommu_mmio_va + IOMMU_MMIO_CB_TAIL / 8))
|
||||
;
|
||||
}
|
||||
|
||||
// Write 8 bytes to a physical address using IOMMU completion wait store
|
||||
__attribute__((noinline, optimize("O0"))) void
|
||||
iommu_write8_pa(volatile shellcode_kernel_args *args_ptr, uint64_t pa, uint64_t val) {
|
||||
uint32_t cmd[4] = {0};
|
||||
@@ -230,26 +205,22 @@ __attribute__((noinline, optimize("O0"))) void
|
||||
patch_vmcb(volatile shellcode_kernel_args *args_ptr) {
|
||||
for (int i = 0; i < 16; i++) {
|
||||
uint64_t pa = args_ptr->vmcb[i];
|
||||
// args_ptr->fun_printf("Patching core: %02d VMCB_PA: 0x%016lx\n", i,
|
||||
// args_ptr->vmcb[i]);
|
||||
|
||||
iommu_write8_pa(args_ptr, pa + 0x00,
|
||||
0x0000000000000000ULL); // Clear all intercepts (R/W) to
|
||||
// CR0-CR15 and DR0-DR15
|
||||
0x0000000000000000ULL);
|
||||
iommu_write8_pa(args_ptr, pa + 0x08,
|
||||
0x0004000000000000ULL); // Clear all intercepts of except.
|
||||
// vectors but CPUID
|
||||
0x0004000000000000ULL);
|
||||
iommu_write8_pa(args_ptr, pa + 0x10,
|
||||
0x000000000000000FULL); // Clear all except VMMCALL, VMLOAD,
|
||||
// VMSAVE, VMRUN
|
||||
0x000000000000000FULL);
|
||||
iommu_write8_pa(args_ptr, pa + 0x58,
|
||||
0x0000000000000001ULL); // Guest ASID ... 1 ?
|
||||
0x0000000000000001ULL);
|
||||
iommu_write8_pa(args_ptr, pa + 0x90,
|
||||
0x0000000000000000ULL); // Disable NP_ENABLE
|
||||
0x0000000000000000ULL);
|
||||
}
|
||||
}
|
||||
|
||||
__attribute__((noinline, optimize("O0"))) uint32_t tmr_read(uint64_t dmap,
|
||||
uint32_t addr) {
|
||||
__attribute__((noinline, optimize("O0")))
|
||||
uint32_t tmr_read(uint64_t dmap, uint32_t addr) {
|
||||
*(uint32_t *)(dmap + ECAM_B0D18F2 + TMR_INDEX_OFF) = addr;
|
||||
return *(uint32_t *)(dmap + ECAM_B0D18F2 + TMR_DATA_OFF);
|
||||
}
|
||||
@@ -260,8 +231,6 @@ tmr_write(uint64_t dmap, uint32_t addr, uint32_t val) {
|
||||
*(uint32_t *)(dmap + ECAM_B0D18F2 + TMR_DATA_OFF) = val;
|
||||
}
|
||||
|
||||
// On 1.xx and 2.xx the HV is embedded in kernel area on TMR 16
|
||||
// On 3.xx and 4.xx there are multiple TMR protecting HV and Kernel
|
||||
__attribute__((noinline, optimize("O0"))) int tmr_disable(uint64_t dmap) {
|
||||
for (int i = 0; i < 24; i++) {
|
||||
if (tmr_read(dmap, TMR_CONFIG(i)) != 0) {
|
||||
@@ -282,7 +251,6 @@ void init_global_pointers(volatile shellcode_kernel_args *args_ptr) {
|
||||
smp_rendezvous = (void (*)(void (*)(void), void (*)(void),
|
||||
void (*)(void), void *)) args.fun_smp_rendezvous;
|
||||
smp_no_rendevous_barrier = (void (*)(void)) args.fun_smp_no_rendevous_barrier;
|
||||
|
||||
transmitter_control = (int (*) (int, void*)) args.fun_transmitter_control;
|
||||
mp3_initialize = (int (*) (int)) args.fun_mp3_initialize;
|
||||
mp3_invoke = (int (*) (int, void*, void*)) args.fun_mp3_invoke;
|
||||
|
||||
@@ -16,9 +16,9 @@ void memcpy(void *dest, void *src, uint64_t len) {
|
||||
uint64_t read_cr3(void) {
|
||||
uint64_t cr3;
|
||||
__asm__ volatile("mov %%cr3, %0"
|
||||
: "=r"(cr3) // Output: move CR3 into the variable 'cr3'
|
||||
: // No inputs
|
||||
: // No clobbered registers
|
||||
: "=r"(cr3)
|
||||
:
|
||||
:
|
||||
);
|
||||
return cr3;
|
||||
}
|
||||
|
||||
145
source/firmware.c
Normal file
145
source/firmware.c
Normal file
@@ -0,0 +1,145 @@
|
||||
#include "firmware.h"
|
||||
#include "utils.h"
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define PS5_WIFI_FW_BOOT_PATH "lib/nxp/pcieuartiw620_combo_v1.bin"
|
||||
|
||||
static size_t ps5_wifi_firmware_size(void) {
|
||||
return (size_t)env_offset.PS5_WIFI_FW_SIZE;
|
||||
}
|
||||
|
||||
static uint64_t ps5_wifi_firmware_va(void) {
|
||||
return get_offset_va(env_offset.PS5_WIFI_FW_OFFSET);
|
||||
}
|
||||
|
||||
static int write_all(int fd, const void *buf, size_t len) {
|
||||
size_t written = 0;
|
||||
|
||||
while (written < len) {
|
||||
ssize_t ret = write(fd, (const uint8_t *)buf + written, len - written);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
if (ret == 0)
|
||||
return -1;
|
||||
written += (size_t)ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mkdir_if_needed(const char *path) {
|
||||
struct stat st;
|
||||
|
||||
if (mkdir(path, 0777) == 0)
|
||||
return 0;
|
||||
|
||||
if (errno != EEXIST)
|
||||
return -1;
|
||||
|
||||
if (stat(path, &st) < 0)
|
||||
return -1;
|
||||
|
||||
return S_ISDIR(st.st_mode) ? 0 : -1;
|
||||
}
|
||||
|
||||
static int build_firmware_path(const char *boot_file_path, char *boot_dir,
|
||||
size_t boot_dir_size, char *fw_path,
|
||||
size_t fw_path_size) {
|
||||
const char *slash = strrchr(boot_file_path, '/');
|
||||
int ret;
|
||||
|
||||
if (slash == NULL)
|
||||
return -1;
|
||||
|
||||
ret = snprintf(boot_dir, boot_dir_size, "%.*s",
|
||||
(int)(slash - boot_file_path), boot_file_path);
|
||||
if (ret < 0 || (size_t)ret >= boot_dir_size)
|
||||
return -1;
|
||||
|
||||
ret = snprintf(fw_path, fw_path_size, "%s/%s", boot_dir,
|
||||
PS5_WIFI_FW_BOOT_PATH);
|
||||
if (ret < 0 || (size_t)ret >= fw_path_size)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int create_firmware_dirs(const char *boot_dir) {
|
||||
char path[512];
|
||||
int ret;
|
||||
|
||||
ret = snprintf(path, sizeof(path), "%s/lib", boot_dir);
|
||||
if (ret < 0 || (size_t)ret >= sizeof(path))
|
||||
return -1;
|
||||
if (mkdir_if_needed(path) < 0)
|
||||
return -1;
|
||||
|
||||
ret = snprintf(path, sizeof(path), "%s/lib/nxp", boot_dir);
|
||||
if (ret < 0 || (size_t)ret >= sizeof(path))
|
||||
return -1;
|
||||
if (mkdir_if_needed(path) < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dump_ps5_wifi_firmware(const char *boot_file_path) {
|
||||
char boot_dir[512];
|
||||
char fw_path[512];
|
||||
uint8_t buf[0x4000];
|
||||
uint64_t fw_va;
|
||||
size_t fw_size;
|
||||
int fd;
|
||||
|
||||
if (env_offset.PS5_WIFI_FW_OFFSET == 0 || env_offset.PS5_WIFI_FW_SIZE == 0) {
|
||||
notify("PS5 WiFi firmware offset missing for firmware %04x\n", fw);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (build_firmware_path(boot_file_path, boot_dir, sizeof(boot_dir), fw_path,
|
||||
sizeof(fw_path)) < 0) {
|
||||
notify("PS5 WiFi firmware dump path is too long\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (create_firmware_dirs(boot_dir) < 0) {
|
||||
notify("Could not create PS5 WiFi firmware directory under %s\n", boot_dir);
|
||||
return -1;
|
||||
}
|
||||
|
||||
fd = open(fw_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
||||
if (fd < 0) {
|
||||
notify("Could not create PS5 WiFi firmware file %s\n", fw_path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
fw_va = ps5_wifi_firmware_va();
|
||||
fw_size = ps5_wifi_firmware_size();
|
||||
for (size_t copied = 0; copied < fw_size; copied += sizeof(buf)) {
|
||||
size_t chunk = fw_size - copied;
|
||||
if (chunk > sizeof(buf))
|
||||
chunk = sizeof(buf);
|
||||
|
||||
kread(fw_va + copied, buf, chunk);
|
||||
if (write_all(fd, buf, chunk) < 0) {
|
||||
close(fd);
|
||||
notify("Could not write PS5 WiFi firmware file %s\n", fw_path);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
close(fd);
|
||||
notify("Dumped PS5 WiFi firmware to %s (%llu bytes)\n", fw_path,
|
||||
(unsigned long long)fw_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dump_device_firmwares(const char *boot_file_path) {
|
||||
return dump_ps5_wifi_firmware(boot_file_path);
|
||||
}
|
||||
@@ -217,8 +217,7 @@ int stage4_force_vmcb_reload(void) {
|
||||
int stage5_remove_xotext(void) {
|
||||
DEBUG_PRINT("\nHV-Defeat [stage5] xotext removal\n");
|
||||
|
||||
uint64_t start =
|
||||
ktext - 0xF0000; // Include first pages where fun stuff is located
|
||||
uint64_t start = ktext;
|
||||
uint64_t end = kdata;
|
||||
int n __attribute__((unused)) = 0;
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "loader.h"
|
||||
#include "config.h"
|
||||
#include "firmware.h"
|
||||
#include "utils.h"
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
@@ -79,11 +80,52 @@ const char *file_paths[] = {
|
||||
"/mnt/usb2/PS5/Linux/", "/mnt/usb3/PS5/Linux/",
|
||||
};
|
||||
|
||||
long find_and_get_size_of_file(const char *filename, char *found_path);
|
||||
int find_and_read_file(const char *filename, void *buf, size_t bufsize);
|
||||
|
||||
static const char *get_overridden_filename(const char *filename) {
|
||||
static int state = 0;
|
||||
static char *overrides_start = nullptr;
|
||||
static char *overrides_end = nullptr;
|
||||
|
||||
if (state == 0) {
|
||||
state = 1;
|
||||
char found_path[256];
|
||||
ssize_t size = find_and_get_size_of_file("path-override.txt", found_path);
|
||||
if (size > 0) {
|
||||
overrides_start = malloc(size + 1);
|
||||
overrides_end = overrides_start + size + 1;
|
||||
if (read_file(found_path, overrides_start, size) == size) {
|
||||
state = 2;
|
||||
for (char *p = overrides_start; p < overrides_end; p++)
|
||||
if (*p == '\n')
|
||||
*p = 0;
|
||||
overrides_start[size] = 0; // make sure the last string is null-terminated
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (state == 1) // overrides not found, or unreadable, or currently looking for it
|
||||
return filename;
|
||||
|
||||
size_t needle_len = strlen(filename);
|
||||
for (const char *p = overrides_start; p < overrides_end;) {
|
||||
size_t haystack_len = strlen(p);
|
||||
if (haystack_len > needle_len && !strncmp(p, filename, needle_len) && p[needle_len] == '=')
|
||||
return p + needle_len + 1;
|
||||
p += haystack_len + 1;
|
||||
}
|
||||
|
||||
// haven't found an override, return original filename
|
||||
return filename;
|
||||
}
|
||||
|
||||
long find_and_get_size_of_file(const char *filename, char *found_path) {
|
||||
|
||||
char full_path[256];
|
||||
struct stat st;
|
||||
|
||||
filename = get_overridden_filename(filename);
|
||||
int num_paths = sizeof(file_paths) / sizeof(file_paths[0]);
|
||||
|
||||
for (int i = 0; i < num_paths; i++) {
|
||||
@@ -186,6 +228,10 @@ int fetch_linux(struct linux_info *info) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (dump_device_firmwares(initrd_path) < 0) {
|
||||
notify("Something went wrong while dumping device firmwares - Continuing\n");
|
||||
}
|
||||
|
||||
size_t vram_size;
|
||||
char buf_vram[16] = {};
|
||||
int ret = find_and_read_file("vram.txt", buf_vram, sizeof(buf_vram) - 1);
|
||||
@@ -220,6 +266,7 @@ int fetch_linux(struct linux_info *info) {
|
||||
info->initrd_size = initrd_size;
|
||||
info->vram_size = vram_size;
|
||||
strcpy(info->cmdline, cmdline);
|
||||
info->kit_type = (int) get_kit_type();
|
||||
|
||||
uint64_t page = alloc_page();
|
||||
kwrite(pa_to_dmap(page), info, sizeof(struct linux_info));
|
||||
|
||||
147
source/main.c
147
source/main.c
@@ -1,11 +1,8 @@
|
||||
#include "main.h"
|
||||
#include "../shellcode_kernel/shellcode_kernel.h"
|
||||
#include "hv_defeat.h"
|
||||
#include "loader.h"
|
||||
#include "offsets.h"
|
||||
#include "utils.h"
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include "utils.h"
|
||||
#include "hv_defeat.h"
|
||||
#include "prepare_resume.h"
|
||||
#include "loader.h"
|
||||
|
||||
int main(void) {
|
||||
|
||||
@@ -36,143 +33,9 @@ int main(void) {
|
||||
sleep(5);
|
||||
enter_rest_mode();
|
||||
|
||||
while (1) {
|
||||
while (1) {
|
||||
sleep(30);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int setup_env(void) {
|
||||
notify("Welcome to ps5-linux-loader. We'll defeat HV and prepare the system "
|
||||
"to boot Linux on sleep resume.\n");
|
||||
if (set_offsets())
|
||||
return -1;
|
||||
if (init_global_vars())
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int prepare_resume(void) {
|
||||
|
||||
if (env_offset.KERNEL_CODE_CAVE == 0) {
|
||||
printf("Error: missing code cave offset\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (env_offset.KERNEL_DATA_CAVE == 0) {
|
||||
printf("Error: missing data cave offset\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("\nWriting Shell Code for WakeUp path and patching "
|
||||
"AcpiSetFirmwareWakingVector in acpi_wakeup_machdep\n");
|
||||
|
||||
uint64_t dest_text = ktext + env_offset.KERNEL_CODE_CAVE;
|
||||
uint64_t dest_data =
|
||||
ktext + env_offset.KERNEL_DATA_CAVE; // For arguments only, rest of .data
|
||||
// variables are in shellcode
|
||||
|
||||
uint64_t sz = shellcode_kernel_text_len;
|
||||
|
||||
uint32_t CHUNK = 0x1000;
|
||||
uint64_t written = 0;
|
||||
while (written < sz) {
|
||||
uint32_t n = (sz - written > CHUNK) ? CHUNK : (uint32_t)(sz - written);
|
||||
kernel_copyin(&shellcode_kernel_text[written], dest_text + written, n);
|
||||
written += n;
|
||||
}
|
||||
DEBUG_PRINT(" copied %d bytes to text cave\n", sz);
|
||||
|
||||
DEBUG_PRINT("\n\nI wrote this shellcode text on %016lx (ktext+%08lx):\n",
|
||||
dest_text, env_offset.KERNEL_CODE_CAVE);
|
||||
for (uint64_t i = 0; i < sz; i++) {
|
||||
DEBUG_PRINT("%02x", kread8(dest_text + i));
|
||||
}
|
||||
DEBUG_PRINT("\n\n");
|
||||
|
||||
shellcode_kernel_args args;
|
||||
|
||||
// Fill structure of ShellCode Arguments
|
||||
args.fw_version = kernel_get_fw_version() & 0xFFFF0000;
|
||||
args.ktext = ktext;
|
||||
args.kdata = kdata;
|
||||
args.dmap_base = dmap;
|
||||
|
||||
args.fun_printf = ktext + env_offset.FUN_PRINTF;
|
||||
args.fun_va_to_pa = ktext + env_offset.FUN_VA_TO_PA;
|
||||
args.fun_hv_iommu_set_buffers = ktext + env_offset.FUN_HV_IOMMU_SET_BUFFERS;
|
||||
args.fun_hv_iommu_wait_completion =
|
||||
ktext + env_offset.FUN_HV_IOMM_WAIT_COMPLETION;
|
||||
args.fun_smp_rendezvous = ktext + env_offset.FUN_SMP_RENDEZVOUS;
|
||||
args.fun_smp_no_rendevous_barrier =
|
||||
ktext + env_offset.FUN_SMP_NO_RENDEVOUS_BARRIER;
|
||||
args.g_vbios = ktext + env_offset.G_VBIOS;
|
||||
|
||||
args.fun_transmitter_control = ktext + env_offset.FUN_TRANSMITTER_CONTROL;
|
||||
args.fun_mp3_initialize = ktext + env_offset.FUN_MP3_INITIALIZE;
|
||||
args.fun_mp3_invoke = ktext + env_offset.FUN_MP3_INVOKE;
|
||||
|
||||
args.iommu_mmio_va = iommu->mmio_va;
|
||||
args.iommu_cb2_va = iommu->cb2_base;
|
||||
args.iommu_cb3_va = iommu->cb3_base;
|
||||
args.iommu_eb_va = iommu->eb_base;
|
||||
memcpy(&args.vmcb[0], &vmcb_pa[0], sizeof(args.vmcb[0]) * 16);
|
||||
|
||||
args.kernel_uart_override = ktext + env_offset.KERNEL_UART_OVERRIDE;
|
||||
args.hv_handle_vmexit_pa = env_offset.HV_HANDLE_VMEXIT_PA;
|
||||
args.hv_code_cave_pa = env_offset.HV_CODE_CAVE_PA;
|
||||
args.hv_uart_override_pa = env_offset.HV_UART_OVERRIDE_PA;
|
||||
|
||||
args.linux_info_va = linux_i.linux_info; // To relocate by kernel shellcode
|
||||
// bzimage_va and initrd_va are passed in the linux_info structure
|
||||
|
||||
// Copy arguments to small .data cave
|
||||
kernel_copyin(&args, dest_data, sizeof(args));
|
||||
|
||||
DEBUG_PRINT("\n\nI wrote this arguments data on %016lx (ktext+%08lx):\n",
|
||||
dest_data, env_offset.KERNEL_DATA_CAVE);
|
||||
for (uint64_t i = 0; i < sz; i++) {
|
||||
DEBUG_PRINT("%02x", kread8(dest_data + i));
|
||||
}
|
||||
DEBUG_PRINT("\n\n");
|
||||
|
||||
// Now find the address 0x11AA11AA11AA11AA used as marker for args_ptr and
|
||||
// overwrite it with proper VA in .data for arguments
|
||||
int offset = -1;
|
||||
for (int i = 0; i < 0x40; i++) {
|
||||
if (*(uint64_t *)((uint64_t)shellcode_kernel_text + i) ==
|
||||
0x11AA11AA11AA11AA) {
|
||||
offset = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (offset == -1) {
|
||||
notify("Could not find offset of args_ptr address - Aborting\n");
|
||||
}
|
||||
kwrite64(dest_text + offset, dest_data);
|
||||
|
||||
DEBUG_PRINT("\n\nI wrote this ptr %016lx on %016lx (offset %08lx)\n",
|
||||
dest_data, dest_text + offset, offset);
|
||||
|
||||
uint64_t instr_to_patch =
|
||||
ktext + env_offset.HOOK_ACPI_WAKEUP_MACHDEP; // AcpiSetFirmwareWakingVector
|
||||
// in acpi_wakeup_machdep
|
||||
int64_t diff_call = dest_text - instr_to_patch;
|
||||
uint8_t new_instr[5];
|
||||
new_instr[0] = 0xE8; // Call Near
|
||||
*((uint32_t *)&new_instr[1]) =
|
||||
(int32_t)(diff_call - 5); // Call Offset is relative to the next
|
||||
// instruction and Call uses 5 bytes
|
||||
|
||||
// Patch instruction
|
||||
kernel_copyin(new_instr, instr_to_patch, 5);
|
||||
DEBUG_PRINT("Instruction patched\n");
|
||||
|
||||
// Patch debug exception
|
||||
kwrite8(ktext + env_offset.KERNEL_DEBUG_PATCH, 0xC3);
|
||||
// Patch cfi_check
|
||||
kwrite8(ktext + env_offset.KERNEL_CFI_CHECK, 0xC3);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -5,8 +5,8 @@ offset_list off_0300 = {
|
||||
.HV_VCPU_ARRAY_OFF = 0x5D0,
|
||||
.HV_VCPU_STRIDE = 0x320,
|
||||
.HV_VCPU_VMCB_PTR = 0x08,
|
||||
.KERNEL_CODE_CAVE = 0x0043000,
|
||||
.KERNEL_DATA_CAVE = 0x0043000 + 0xBBE300,
|
||||
.KERNEL_CODE_CAVE = 0x500,
|
||||
.KERNEL_DATA_CAVE = 0xC01300,
|
||||
.IOMMU_SOFTC = 0x33175E0,
|
||||
.VMSPACE_VM_VMID = 0x1E4,
|
||||
.VMSPACE_VM_PMAP = 0x1D0,
|
||||
@@ -30,6 +30,8 @@ offset_list off_0300 = {
|
||||
.KERNEL_UART_OVERRIDE = 0x1EB0258,
|
||||
.KERNEL_DEBUG_PATCH = 0x0752460,
|
||||
.KERNEL_CFI_CHECK = 0x0441DD0,
|
||||
.PS5_WIFI_FW_OFFSET = 0x1274460,
|
||||
.PS5_WIFI_FW_SIZE = 492304,
|
||||
};
|
||||
|
||||
offset_list off_0310 = {
|
||||
@@ -37,8 +39,8 @@ offset_list off_0310 = {
|
||||
.HV_VCPU_ARRAY_OFF = 0x5D0,
|
||||
.HV_VCPU_STRIDE = 0x320,
|
||||
.HV_VCPU_VMCB_PTR = 0x08,
|
||||
.KERNEL_CODE_CAVE = 0x0043000,
|
||||
.KERNEL_DATA_CAVE = 0x0043000 + 0xBBE300,
|
||||
.KERNEL_CODE_CAVE = 0x500,
|
||||
.KERNEL_DATA_CAVE = 0xC01300,
|
||||
.IOMMU_SOFTC = 0x33175E0,
|
||||
.VMSPACE_VM_VMID = 0x1E4,
|
||||
.VMSPACE_VM_PMAP = 0x1D0,
|
||||
@@ -62,6 +64,8 @@ offset_list off_0310 = {
|
||||
.KERNEL_UART_OVERRIDE = 0x1EB0258,
|
||||
.KERNEL_DEBUG_PATCH = 0x07524A0,
|
||||
.KERNEL_CFI_CHECK = 0x0441E10,
|
||||
.PS5_WIFI_FW_OFFSET = 0x1274490,
|
||||
.PS5_WIFI_FW_SIZE = 492304,
|
||||
};
|
||||
|
||||
offset_list off_0320 = {
|
||||
@@ -69,8 +73,8 @@ offset_list off_0320 = {
|
||||
.HV_VCPU_ARRAY_OFF = 0x5D0,
|
||||
.HV_VCPU_STRIDE = 0x320,
|
||||
.HV_VCPU_VMCB_PTR = 0x08,
|
||||
.KERNEL_CODE_CAVE = 0x0043000,
|
||||
.KERNEL_DATA_CAVE = 0x0043000 + 0xBBE300,
|
||||
.KERNEL_CODE_CAVE = 0x500,
|
||||
.KERNEL_DATA_CAVE = 0xC01300,
|
||||
.IOMMU_SOFTC = 0x33175E0,
|
||||
.VMSPACE_VM_VMID = 0x1E4,
|
||||
.VMSPACE_VM_PMAP = 0x1D0,
|
||||
@@ -94,6 +98,8 @@ offset_list off_0320 = {
|
||||
.KERNEL_UART_OVERRIDE = 0x1EB0258,
|
||||
.KERNEL_DEBUG_PATCH = 0x7527F0,
|
||||
.KERNEL_CFI_CHECK = 0x442160,
|
||||
.PS5_WIFI_FW_OFFSET = 0x1274550,
|
||||
.PS5_WIFI_FW_SIZE = 492304,
|
||||
};
|
||||
|
||||
offset_list off_0321 = {
|
||||
@@ -101,8 +107,8 @@ offset_list off_0321 = {
|
||||
.HV_VCPU_ARRAY_OFF = 0x5D0,
|
||||
.HV_VCPU_STRIDE = 0x320,
|
||||
.HV_VCPU_VMCB_PTR = 0x08,
|
||||
.KERNEL_CODE_CAVE = 0x0043000,
|
||||
.KERNEL_DATA_CAVE = 0x0043000 + 0xBBE300,
|
||||
.KERNEL_CODE_CAVE = 0x500,
|
||||
.KERNEL_DATA_CAVE = 0xC01300,
|
||||
.IOMMU_SOFTC = 0x33175E0,
|
||||
.VMSPACE_VM_VMID = 0x1E4,
|
||||
.VMSPACE_VM_PMAP = 0x1D0,
|
||||
@@ -126,6 +132,8 @@ offset_list off_0321 = {
|
||||
.KERNEL_UART_OVERRIDE = 0x1EB0258,
|
||||
.KERNEL_DEBUG_PATCH = 0x7527F0,
|
||||
.KERNEL_CFI_CHECK = 0x442160,
|
||||
.PS5_WIFI_FW_OFFSET = 0x1274550,
|
||||
.PS5_WIFI_FW_SIZE = 492304,
|
||||
};
|
||||
|
||||
offset_list off_0400 = {
|
||||
@@ -133,8 +141,8 @@ offset_list off_0400 = {
|
||||
.HV_VCPU_ARRAY_OFF = 0x5D0,
|
||||
.HV_VCPU_STRIDE = 0x320,
|
||||
.HV_VCPU_VMCB_PTR = 0x08,
|
||||
.KERNEL_CODE_CAVE = 0x0043000,
|
||||
.KERNEL_DATA_CAVE = 0x0043000 + 0xBBE300,
|
||||
.KERNEL_CODE_CAVE = 0x500,
|
||||
.KERNEL_DATA_CAVE = 0xC01300,
|
||||
.IOMMU_SOFTC = 0x33C7680,
|
||||
.VMSPACE_VM_VMID = 0x1E4,
|
||||
.VMSPACE_VM_PMAP = 0x1D0,
|
||||
@@ -158,6 +166,8 @@ offset_list off_0400 = {
|
||||
.KERNEL_UART_OVERRIDE = 0x1F522A8,
|
||||
.KERNEL_DEBUG_PATCH = 0x77DA70,
|
||||
.KERNEL_CFI_CHECK = 0x45A170,
|
||||
.PS5_WIFI_FW_OFFSET = 0x1392FB0,
|
||||
.PS5_WIFI_FW_SIZE = 493000,
|
||||
};
|
||||
|
||||
offset_list off_0402 = {
|
||||
@@ -165,8 +175,8 @@ offset_list off_0402 = {
|
||||
.HV_VCPU_ARRAY_OFF = 0x5D0,
|
||||
.HV_VCPU_STRIDE = 0x320,
|
||||
.HV_VCPU_VMCB_PTR = 0x08,
|
||||
.KERNEL_CODE_CAVE = 0x0043000,
|
||||
.KERNEL_DATA_CAVE = 0x0043000 + 0xBBE300,
|
||||
.KERNEL_CODE_CAVE = 0x500,
|
||||
.KERNEL_DATA_CAVE = 0xC01300,
|
||||
.IOMMU_SOFTC = 0x33C7680,
|
||||
.VMSPACE_VM_VMID = 0x1E4,
|
||||
.VMSPACE_VM_PMAP = 0x1D0,
|
||||
@@ -190,6 +200,8 @@ offset_list off_0402 = {
|
||||
.KERNEL_UART_OVERRIDE = 0x1F522A8,
|
||||
.KERNEL_DEBUG_PATCH = 0x77DAC0,
|
||||
.KERNEL_CFI_CHECK = 0x45A170,
|
||||
.PS5_WIFI_FW_OFFSET = 0x1392FB0,
|
||||
.PS5_WIFI_FW_SIZE = 493000,
|
||||
};
|
||||
|
||||
offset_list off_0403 = {
|
||||
@@ -198,7 +210,7 @@ offset_list off_0403 = {
|
||||
.HV_VCPU_STRIDE = 0x320,
|
||||
.HV_VCPU_VMCB_PTR = 0x08,
|
||||
.KERNEL_CODE_CAVE = 0x500,
|
||||
.KERNEL_DATA_CAVE = 0x0043000 + 0xBBE300,
|
||||
.KERNEL_DATA_CAVE = 0xC01300,
|
||||
.IOMMU_SOFTC = 0x33C7680,
|
||||
.VMSPACE_VM_VMID = 0x1E4,
|
||||
.VMSPACE_VM_PMAP = 0x1D0,
|
||||
@@ -222,6 +234,8 @@ offset_list off_0403 = {
|
||||
.KERNEL_UART_OVERRIDE = 0x1F522A8,
|
||||
.KERNEL_DEBUG_PATCH = 0x77DB50,
|
||||
.KERNEL_CFI_CHECK = 0x45A170,
|
||||
.PS5_WIFI_FW_OFFSET = 0x1392FB0,
|
||||
.PS5_WIFI_FW_SIZE = 493000,
|
||||
};
|
||||
|
||||
offset_list off_0450 = {
|
||||
@@ -229,8 +243,8 @@ offset_list off_0450 = {
|
||||
.HV_VCPU_ARRAY_OFF = 0x5D0,
|
||||
.HV_VCPU_STRIDE = 0x320,
|
||||
.HV_VCPU_VMCB_PTR = 0x08,
|
||||
.KERNEL_CODE_CAVE = 0x0043000,
|
||||
.KERNEL_DATA_CAVE = 0x0043000 + 0xBBE300,
|
||||
.KERNEL_CODE_CAVE = 0x500,
|
||||
.KERNEL_DATA_CAVE = 0xC01300,
|
||||
.IOMMU_SOFTC = 0x33C7680,
|
||||
.VMSPACE_VM_VMID = 0x1E4,
|
||||
.VMSPACE_VM_PMAP = 0x1D0,
|
||||
@@ -254,6 +268,8 @@ offset_list off_0450 = {
|
||||
.KERNEL_UART_OVERRIDE = 0x1F522A8,
|
||||
.KERNEL_DEBUG_PATCH = 0x77DC80,
|
||||
.KERNEL_CFI_CHECK = 0x45A1A0,
|
||||
.PS5_WIFI_FW_OFFSET = 0x1392FC0,
|
||||
.PS5_WIFI_FW_SIZE = 493000,
|
||||
};
|
||||
|
||||
offset_list off_0451 = {
|
||||
@@ -261,8 +277,8 @@ offset_list off_0451 = {
|
||||
.HV_VCPU_ARRAY_OFF = 0x5D0,
|
||||
.HV_VCPU_STRIDE = 0x320,
|
||||
.HV_VCPU_VMCB_PTR = 0x08,
|
||||
.KERNEL_CODE_CAVE = 0x0043000,
|
||||
.KERNEL_DATA_CAVE = 0x0043000 + 0xBBE300,
|
||||
.KERNEL_CODE_CAVE = 0x500,
|
||||
.KERNEL_DATA_CAVE = 0xC01300,
|
||||
.IOMMU_SOFTC = 0x33C7680,
|
||||
.VMSPACE_VM_VMID = 0x1E4,
|
||||
.VMSPACE_VM_PMAP = 0x1D0,
|
||||
@@ -286,4 +302,6 @@ offset_list off_0451 = {
|
||||
.KERNEL_UART_OVERRIDE = 0x1F522A8,
|
||||
.KERNEL_DEBUG_PATCH = 0x77DC90,
|
||||
.KERNEL_CFI_CHECK = 0x45A1A0,
|
||||
.PS5_WIFI_FW_OFFSET = 0x1393000,
|
||||
.PS5_WIFI_FW_SIZE = 493000,
|
||||
};
|
||||
|
||||
101
source/prepare_resume.c
Normal file
101
source/prepare_resume.c
Normal file
@@ -0,0 +1,101 @@
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include "prepare_resume.h"
|
||||
#include "iommu.h"
|
||||
#include "../shellcode_kernel/shellcode_kernel.h"
|
||||
#include "offsets.h"
|
||||
#include "utils.h"
|
||||
|
||||
int prepare_resume(void) {
|
||||
|
||||
if (env_offset.KERNEL_CODE_CAVE == 0) {
|
||||
printf("Error: missing code cave offset\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (env_offset.KERNEL_DATA_CAVE == 0) {
|
||||
printf("Error: missing data cave offset\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("\nWriting Shell Code for WakeUp path and patching "
|
||||
"AcpiSetFirmwareWakingVector in acpi_wakeup_machdep\n");
|
||||
|
||||
uint64_t dest_text = ktext + env_offset.KERNEL_CODE_CAVE;
|
||||
uint64_t dest_data = ktext + env_offset.KERNEL_DATA_CAVE;
|
||||
|
||||
kwrite_large(dest_text, shellcode_kernel_text, shellcode_kernel_text_len);
|
||||
prepare_sck_args(dest_data);
|
||||
|
||||
if(update_sck_data_ptr(shellcode_kernel_text, dest_text, dest_data))
|
||||
return -1;
|
||||
|
||||
hook_call_near(ktext + env_offset.HOOK_ACPI_WAKEUP_MACHDEP, dest_text);
|
||||
|
||||
kwrite8(ktext + env_offset.KERNEL_DEBUG_PATCH, 0xC3);
|
||||
kwrite8(ktext + env_offset.KERNEL_CFI_CHECK, 0xC3);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int update_sck_data_ptr (void* sc, uint64_t dest_text, uint64_t dest_data) {
|
||||
// Find the address 0x11AA11AA11AA11AA used as marker
|
||||
int offset = -1;
|
||||
for (int i = 0; i < 0x40; i++) {
|
||||
if (*(uint64_t *)((uint64_t)sc + i) == 0x11AA11AA11AA11AA) {
|
||||
offset = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (offset == -1) {
|
||||
notify("Could not find offset of args_ptr address - Aborting\n");
|
||||
return -1;
|
||||
}
|
||||
kwrite64(dest_text + offset, dest_data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void hook_call_near(uint64_t hook, uint64_t dst) {
|
||||
int64_t diff_call = dst - hook;
|
||||
uint8_t new_instr[5]; new_instr[0] = 0xE8;
|
||||
*((uint32_t *)&new_instr[1]) = (int32_t)(diff_call - 5);
|
||||
kernel_copyin(new_instr, hook, 5);
|
||||
DEBUG_PRINT("Instruction patched\n");
|
||||
}
|
||||
|
||||
void prepare_sck_args(uint64_t dest_data) {
|
||||
shellcode_kernel_args args;
|
||||
args.fw_version = kernel_get_fw_version() & 0xFFFF0000;
|
||||
args.ktext = ktext;
|
||||
args.kdata = kdata;
|
||||
args.dmap_base = dmap;
|
||||
|
||||
args.fun_printf = ktext + env_offset.FUN_PRINTF;
|
||||
args.fun_va_to_pa = ktext + env_offset.FUN_VA_TO_PA;
|
||||
args.fun_hv_iommu_set_buffers = ktext + env_offset.FUN_HV_IOMMU_SET_BUFFERS;
|
||||
args.fun_hv_iommu_wait_completion =
|
||||
ktext + env_offset.FUN_HV_IOMM_WAIT_COMPLETION;
|
||||
args.fun_smp_rendezvous = ktext + env_offset.FUN_SMP_RENDEZVOUS;
|
||||
args.fun_smp_no_rendevous_barrier =
|
||||
ktext + env_offset.FUN_SMP_NO_RENDEVOUS_BARRIER;
|
||||
args.g_vbios = ktext + env_offset.G_VBIOS;
|
||||
|
||||
args.fun_transmitter_control = ktext + env_offset.FUN_TRANSMITTER_CONTROL;
|
||||
args.fun_mp3_initialize = ktext + env_offset.FUN_MP3_INITIALIZE;
|
||||
args.fun_mp3_invoke = ktext + env_offset.FUN_MP3_INVOKE;
|
||||
|
||||
args.iommu_mmio_va = iommu->mmio_va;
|
||||
args.iommu_cb2_va = iommu->cb2_base;
|
||||
args.iommu_cb3_va = iommu->cb3_base;
|
||||
args.iommu_eb_va = iommu->eb_base;
|
||||
memcpy(&args.vmcb[0], &vmcb_pa[0], sizeof(args.vmcb[0]) * 16);
|
||||
|
||||
args.kernel_uart_override = ktext + env_offset.KERNEL_UART_OVERRIDE;
|
||||
args.hv_handle_vmexit_pa = env_offset.HV_HANDLE_VMEXIT_PA;
|
||||
args.hv_code_cave_pa = env_offset.HV_CODE_CAVE_PA;
|
||||
args.hv_uart_override_pa = env_offset.HV_UART_OVERRIDE_PA;
|
||||
|
||||
args.linux_info_va = linux_i.linux_info;
|
||||
|
||||
kernel_copyin(&args, dest_data, sizeof(args));
|
||||
}
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <sys/param.h>
|
||||
#include <sys/proc.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
/* Global Variables */
|
||||
offset_list env_offset;
|
||||
@@ -16,6 +17,16 @@ uint64_t cr3;
|
||||
uint32_t fw;
|
||||
struct linux_info linux_i;
|
||||
|
||||
int setup_env(void) {
|
||||
notify("Welcome to ps5-linux-loader. We'll defeat HV and prepare the system "
|
||||
"to boot Linux on sleep resume.\n");
|
||||
if (set_offsets())
|
||||
return -1;
|
||||
if (init_global_vars())
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int set_offsets(void) {
|
||||
fw = kernel_get_fw_version() >> 16;
|
||||
if (fw == 0)
|
||||
@@ -247,4 +258,32 @@ void enter_rest_mode(void) {
|
||||
sceKernelNotifySystemSuspendStart();
|
||||
sceKernelSetEventFlag(event, 0x400);
|
||||
sceKernelCloseEventFlag(&event);
|
||||
}
|
||||
|
||||
|
||||
// Kit type by EchoStretch
|
||||
bool if_exists(const char* path) {
|
||||
struct stat st;
|
||||
return stat(path, &st) == 0;
|
||||
}
|
||||
|
||||
bool sceKernelIsTestKit(void) {
|
||||
return if_exists("/system/priv/lib/libSceDeci5Ttyp.sprx");
|
||||
}
|
||||
|
||||
bool sceKernelIsDevKit(void) {
|
||||
return if_exists("/system/priv/lib/libSceDeci5Dtracep.sprx");
|
||||
}
|
||||
|
||||
enum kit_type get_kit_type(void) {
|
||||
if (sceKernelIsDevKit()) {
|
||||
notify("DevKit detected\n");
|
||||
return KIT_DEVKIT;
|
||||
}
|
||||
if (sceKernelIsTestKit()) {
|
||||
notify("TestKit detected\n");
|
||||
return KIT_TESTKIT;
|
||||
}
|
||||
notify("Retail console detected\n");
|
||||
return KIT_RETAIL;
|
||||
}
|
||||
Reference in New Issue
Block a user