mirror of
https://github.com/ps5-linux/ps5-linux-loader.git
synced 2026-05-13 18:22:00 +00:00
Compare commits
12 Commits
dev-wifi-f
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a5f27e2205 | ||
|
|
9d58e22a77 | ||
|
|
e439d8d36a | ||
|
|
854c44ef56 | ||
|
|
d024563d48 | ||
|
|
6a95a5ee82 | ||
|
|
81e2b00059 | ||
|
|
50b28fb8c1 | ||
|
|
238f89d954 | ||
|
|
d66ed49866 | ||
|
|
f87828b554 | ||
|
|
4b5fc13e80 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,6 +1,6 @@
|
|||||||
bin/
|
bin/
|
||||||
shellcode_kernel/shellcode_kernel.h
|
shellcode_kernel/shellcode_kernel.h
|
||||||
shellcode_hypervisor/shellcode_hypervisor.h
|
shellcode_hv/shellcode_hv.h
|
||||||
*.elf
|
*.elf
|
||||||
*.bin
|
*.bin
|
||||||
*.o
|
*.o
|
||||||
|
|||||||
8
Makefile
8
Makefile
@@ -10,16 +10,16 @@ BIN := bin/ps5-linux-loader.elf
|
|||||||
SRC := $(wildcard source/*.c)
|
SRC := $(wildcard source/*.c)
|
||||||
OBJS := $(SRC:.c=.o)
|
OBJS := $(SRC:.c=.o)
|
||||||
|
|
||||||
CFLAGS := -std=c23 -Wall -Iinclude -Ishellcode_hypervisor -Ishellcode_kernel
|
CFLAGS := -std=c23 -Wall -Iinclude -Ishellcode_hv -Ishellcode_kernel
|
||||||
LDFLAGS :=
|
LDFLAGS :=
|
||||||
|
|
||||||
SC_HV_H := shellcode_hypervisor/shellcode_hypervisor.h
|
SC_HV_H := shellcode_hv/shellcode_hv.h
|
||||||
SC_K_H := shellcode_kernel/shellcode_kernel.h
|
SC_K_H := shellcode_kernel/shellcode_kernel.h
|
||||||
|
|
||||||
all: $(SC_HV_H) $(SC_K_H) $(BIN)
|
all: $(SC_HV_H) $(SC_K_H) $(BIN)
|
||||||
|
|
||||||
$(SC_HV_H):
|
$(SC_HV_H):
|
||||||
$(MAKE) -C shellcode_hypervisor
|
$(MAKE) -C shellcode_hv
|
||||||
|
|
||||||
$(SC_K_H):
|
$(SC_K_H):
|
||||||
$(MAKE) -C shellcode_kernel
|
$(MAKE) -C shellcode_kernel
|
||||||
@@ -33,5 +33,5 @@ $(BIN): $(OBJS)
|
|||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f $(BIN) $(OBJS)
|
rm -f $(BIN) $(OBJS)
|
||||||
$(MAKE) -C shellcode_hypervisor clean
|
$(MAKE) -C shellcode_hv clean
|
||||||
$(MAKE) -C shellcode_kernel clean
|
$(MAKE) -C shellcode_kernel clean
|
||||||
|
|||||||
28
README.md
28
README.md
@@ -124,14 +124,20 @@ The front top Type-A port is USB 2.0 which is slower and thus not recommended.
|
|||||||
|
|
||||||
### 4. Run the jailbreak exploit
|
### 4. Run the jailbreak exploit
|
||||||
|
|
||||||
1. Clone https://github.com/idlesauce/umtx2
|
1. Clone via: `git clone https://github.com/idlesauce/umtx2`
|
||||||
2. Configure fakedns via `dns.conf` to point `manuals.playstation.net` to your PCs IP address
|
2. Configure fakedns via `dns.conf` to point `manuals.playstation.net` to your PCs IP address
|
||||||
3. Run fake dns: `python fakedns.py -c dns.conf`
|
3. Run fake dns: `sudo python fakedns.py -c dns.conf`
|
||||||
4. Run HTTPS server: `python host.py`
|
4. In a different terminal, run HTTPS server: `sudo python host.py`
|
||||||
5. Go into PS5 advanced network settings and set primary DNS to your PCs IP address and leave secondary at `0.0.0.0`
|
5. Go into PS5 advanced network settings and set primary DNS to your PCs IP address and leave secondary at `0.0.0.0`
|
||||||
6. Go to user manual in settings and accept untrusted certificate prompt, run.
|
6. Go to user manual in settings and accept untrusted certificate prompt, run.
|
||||||
|
|
||||||
#### 5. Send the payload
|
#### 5. Send the payload
|
||||||
|
If you're on ARM64 Linux, first install the x86-64 cross-compilation tools before:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo apt install gcc-x86-64-linux-gnu binutils-x86-64-linux-gnu
|
||||||
|
```
|
||||||
|
|
||||||
Either download [ps5-linux-loader.elf](https://github.com/ps5-linux/ps5-linux-loader/releases/), or install [ps5-payload-sdk](https://github.com/ps5-payload-dev/sdk) and compile it yourself:
|
Either download [ps5-linux-loader.elf](https://github.com/ps5-linux/ps5-linux-loader/releases/), or install [ps5-payload-sdk](https://github.com/ps5-payload-dev/sdk) and compile it yourself:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -140,16 +146,10 @@ cd ps5-linux-loader
|
|||||||
make
|
make
|
||||||
```
|
```
|
||||||
|
|
||||||
If you're on ARM64 Linux, then additionall install the x86-64 cross-compilation tools before:
|
Send the payload with your `$PS5IP` (shown on the page):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo apt install gcc-x86-64-linux-gnu binutils-x86-64-linux-gnu
|
socat -t 99999999 - TCP:$PS5IP:9021 < ps5-linux-loader.elf
|
||||||
```
|
|
||||||
|
|
||||||
Find your PS5 IP at `Settings → Network → View Connection Status`.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
socat -t 99999999 - TCP:192.168.178.127:9021 < ps5-linux-loader.elf
|
|
||||||
```
|
```
|
||||||
|
|
||||||
If all is successful, the payload will automatically go into rest mode. Wait until the orange LED stops blinking and becomes static. Only then, press the power button again to boot your PS5 into Linux. If the boot is successful, **the LED should turn white**. If it boots back into PS5 OS, then it's because you pressed the power button too early. Or, you did not enable rest mode features as described above.
|
If all is successful, the payload will automatically go into rest mode. Wait until the orange LED stops blinking and becomes static. Only then, press the power button again to boot your PS5 into Linux. If the boot is successful, **the LED should turn white**. If it boots back into PS5 OS, then it's because you pressed the power button too early. Or, you did not enable rest mode features as described above.
|
||||||
@@ -251,6 +251,10 @@ Always turn on fan when your turn on boost, as this is what the official PS5 OS
|
|||||||
|
|
||||||
## FAQ
|
## FAQ
|
||||||
|
|
||||||
|
- Q: Will higher >=6.50 firmwares be supported?
|
||||||
|
- A: No.
|
||||||
|
- Q: Why can I not use M.2 on 3.xx?
|
||||||
|
- A: Because the PS5 fails to boot with it attached.
|
||||||
- Q: Can I dual-boot Linux and PS5 OS?
|
- Q: Can I dual-boot Linux and PS5 OS?
|
||||||
- A: No, this is a soft-mod. You need to re-run the exploit in order to boot into Linux.
|
- 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?
|
- Q: Can I put Linux into standby and resume?
|
||||||
@@ -259,8 +263,6 @@ Always turn on fan when your turn on boost, as this is what the official PS5 OS
|
|||||||
- A: Yes, the internal SSD is not modified
|
- A: Yes, the internal SSD is not modified
|
||||||
- Q: Can I use the PS5's NIC/WLAN module in Linux?
|
- 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.
|
- A: In theory yes, but someone needs to write or adapt drivers to use them.
|
||||||
- Q: Will higher >=6.50 firmwares be supported?
|
|
||||||
- A: No.
|
|
||||||
- Q: Does the DualSense controller work?
|
- Q: Does the DualSense controller work?
|
||||||
- A: Via a Bluetooth dongle. Built-in Bluetooth is not yet supported.
|
- A: Via a Bluetooth dongle. Built-in Bluetooth is not yet supported.
|
||||||
- Q: What resolutions and refresh rates are supported?
|
- Q: What resolutions and refresh rates are supported?
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#define __LINUX_H__
|
#define __LINUX_H__
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#define X86_SUBARCH_PS5 5
|
#define X86_SUBARCH_PS5 5
|
||||||
|
|
||||||
@@ -104,4 +105,15 @@ struct boot_params {
|
|||||||
uint8_t _pad9[276]; // 0xeec
|
uint8_t _pad9[276]; // 0xeec
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
struct linux_info {
|
||||||
|
uintptr_t linux_info; // PA of linux_info
|
||||||
|
uintptr_t bzimage;
|
||||||
|
size_t bzimage_size;
|
||||||
|
uintptr_t initrd;
|
||||||
|
size_t initrd_size;
|
||||||
|
size_t vram_size;
|
||||||
|
int kit_type;
|
||||||
|
char cmdline[2048];
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -1,12 +1,10 @@
|
|||||||
#ifndef LOADER_H
|
#ifndef LOADER_H
|
||||||
#define LOADER_H
|
#define LOADER_H
|
||||||
|
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
uint64_t alloc_page(void);
|
uint64_t alloc_page(void);
|
||||||
void install_page(uintptr_t pml4, vm_offset_t va, vm_paddr_t pa,
|
void install_page(uintptr_t pml4, vm_offset_t va, vm_paddr_t pa, int bits);
|
||||||
int bits);
|
|
||||||
void pte_store(uintptr_t ptep, uint64_t pte);
|
void pte_store(uintptr_t ptep, uint64_t pte);
|
||||||
int read_file(const char *path, void *buf, size_t bufsize);
|
int read_file(const char *path, void *buf, size_t bufsize);
|
||||||
void trim_newline(char *s);
|
void trim_newline(char *s);
|
||||||
|
|||||||
8
include/main.h
Normal file
8
include/main.h
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#ifndef MAIN_H
|
||||||
|
#define MAIN_H
|
||||||
|
|
||||||
|
int main(void);
|
||||||
|
int setup_env(void);
|
||||||
|
int prepare_resume(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -4,37 +4,33 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
typedef struct _offset_list {
|
typedef struct _offset_list {
|
||||||
uint64_t PMAP_STORE;
|
/* Loader utils */
|
||||||
uint64_t HV_VCPU; // Needed for 1.xx and 2.xx
|
|
||||||
uint64_t HV_VCPU_CPUID; // Needed for 1.xx and 2.xx
|
|
||||||
uint64_t HV_VCPU_ARRAY_OFF; // Needed for 1.xx and 2.xx
|
|
||||||
uint64_t HV_VCPU_STRIDE; // Needed for 1.xx and 2.xx
|
|
||||||
uint64_t HV_VCPU_VMCB_PTR; // Needed for 1.xx and 2.xx
|
|
||||||
uint64_t KERNEL_CODE_CAVE;
|
|
||||||
uint64_t KERNEL_DATA_CAVE;
|
|
||||||
uint64_t IOMMU_SOFTC;
|
uint64_t IOMMU_SOFTC;
|
||||||
uint64_t VMSPACE_VM_VMID;
|
uint64_t VMSPACE_VM_VMID;
|
||||||
uint64_t VMSPACE_VM_PMAP;
|
uint64_t VMSPACE_VM_PMAP;
|
||||||
uint64_t PMAP_PM_PML4;
|
|
||||||
uint64_t PMAP_PM_CR3;
|
|
||||||
uint64_t DATA_BASE_GVMSPACE;
|
uint64_t DATA_BASE_GVMSPACE;
|
||||||
|
/* Shellcode Kernel */
|
||||||
uint64_t HOOK_ACPI_WAKEUP_MACHDEP;
|
uint64_t HOOK_ACPI_WAKEUP_MACHDEP;
|
||||||
|
uint64_t KERNEL_CODE_CAVE;
|
||||||
|
uint64_t KERNEL_DATA_CAVE;
|
||||||
uint64_t FUN_PRINTF;
|
uint64_t FUN_PRINTF;
|
||||||
uint64_t FUN_VA_TO_PA;
|
|
||||||
uint64_t FUN_HV_IOMMU_SET_BUFFERS;
|
uint64_t FUN_HV_IOMMU_SET_BUFFERS;
|
||||||
uint64_t FUN_HV_IOMM_WAIT_COMPLETION;
|
uint64_t FUN_HV_IOMM_WAIT_COMPLETION;
|
||||||
uint64_t FUN_SMP_RENDEZVOUS;
|
uint64_t FUN_SMP_RENDEZVOUS;
|
||||||
uint64_t FUN_SMP_NO_RENDEVOUS_BARRIER;
|
uint64_t FUN_SMP_NO_RENDEVOUS_BARRIER;
|
||||||
uint64_t HV_HANDLE_VMEXIT_PA;
|
/* Shellcode HV */
|
||||||
uint64_t HV_CODE_CAVE_PA;
|
uint64_t HV_CODE_CAVE_PA;
|
||||||
uint64_t HV_UART_OVERRIDE_PA;
|
uint64_t HV_HANDLE_VMEXIT_PA;
|
||||||
|
/* Patches on Kernel */
|
||||||
|
uint64_t KERNEL_UART_OVERRIDE;
|
||||||
|
uint64_t KERNEL_DEBUG_PATCH;
|
||||||
|
uint64_t KERNEL_CFI_CHECK;
|
||||||
|
/* Internal functions to prepare boot */
|
||||||
uint64_t G_VBIOS;
|
uint64_t G_VBIOS;
|
||||||
uint64_t FUN_TRANSMITTER_CONTROL;
|
uint64_t FUN_TRANSMITTER_CONTROL;
|
||||||
uint64_t FUN_MP3_INITIALIZE;
|
uint64_t FUN_MP3_INITIALIZE;
|
||||||
uint64_t FUN_MP3_INVOKE;
|
uint64_t FUN_MP3_INVOKE;
|
||||||
uint64_t KERNEL_UART_OVERRIDE;
|
/* Wifi FW */
|
||||||
uint64_t KERNEL_DEBUG_PATCH;
|
|
||||||
uint64_t KERNEL_CFI_CHECK;
|
|
||||||
uint64_t PS5_WIFI_FW_OFFSET;
|
uint64_t PS5_WIFI_FW_OFFSET;
|
||||||
uint64_t PS5_WIFI_FW_SIZE;
|
uint64_t PS5_WIFI_FW_SIZE;
|
||||||
} offset_list;
|
} offset_list;
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
extern struct linux_info linux_i;
|
extern struct linux_info linux_i;
|
||||||
|
|
||||||
int prepare_resume(void);
|
int prepare_resume(void);
|
||||||
int update_sck_data_ptr (void* sc, uint64_t dest_text, uint64_t dest_data);
|
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 hook_call_near(uint64_t hook, uint64_t dst);
|
||||||
void prepare_sck_args(uint64_t dest_data);
|
void prepare_sck_args(uint64_t dest_data);
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#ifndef UTILS_H
|
#ifndef UTILS_H
|
||||||
#define UTILS_H
|
#define UTILS_H
|
||||||
|
|
||||||
|
#include "linux.h"
|
||||||
#include "offsets.h"
|
#include "offsets.h"
|
||||||
#include <ps5/kernel.h>
|
#include <ps5/kernel.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
@@ -9,10 +10,10 @@
|
|||||||
|
|
||||||
int sceKernelGetCurrentCpu();
|
int sceKernelGetCurrentCpu();
|
||||||
int sceKernelSendNotificationRequest(int, void *, size_t, int);
|
int sceKernelSendNotificationRequest(int, void *, size_t, int);
|
||||||
int sceKernelOpenEventFlag(void*, const char *);
|
int sceKernelOpenEventFlag(void *, const char *);
|
||||||
int sceKernelNotifySystemSuspendStart(void);
|
int sceKernelNotifySystemSuspendStart(void);
|
||||||
int sceKernelSetEventFlag(void *, int);
|
int sceKernelSetEventFlag(void *, int);
|
||||||
int sceKernelCloseEventFlag(void*);
|
int sceKernelCloseEventFlag(void *);
|
||||||
|
|
||||||
typedef struct _sysent {
|
typedef struct _sysent {
|
||||||
uint32_t n_arg;
|
uint32_t n_arg;
|
||||||
@@ -35,17 +36,6 @@ typedef struct __flat_pmap {
|
|||||||
uint64_t pm_cr3;
|
uint64_t pm_cr3;
|
||||||
} flat_pmap;
|
} flat_pmap;
|
||||||
|
|
||||||
struct linux_info {
|
|
||||||
uintptr_t bzimage;
|
|
||||||
size_t bzimage_size;
|
|
||||||
uintptr_t initrd;
|
|
||||||
size_t initrd_size;
|
|
||||||
size_t vram_size;
|
|
||||||
char cmdline[2048];
|
|
||||||
int kit_type;
|
|
||||||
uintptr_t linux_info; // PA of linux_info
|
|
||||||
};
|
|
||||||
|
|
||||||
/** These vars are global for the payload to simplify things */
|
/** These vars are global for the payload to simplify things */
|
||||||
extern offset_list env_offset; // Defined on utils.c
|
extern offset_list env_offset; // Defined on utils.c
|
||||||
extern uint64_t ktext; // Defined on utils.c
|
extern uint64_t ktext; // Defined on utils.c
|
||||||
@@ -58,12 +48,12 @@ extern struct linux_info linux_i; // Declared on main.c
|
|||||||
|
|
||||||
int setup_env(void);
|
int setup_env(void);
|
||||||
|
|
||||||
static inline void kwrite_large(uint64_t ka, void* src, uint64_t len) {
|
static inline void kwrite_large(uint64_t ka, void *src, uint64_t len) {
|
||||||
uint32_t CHUNK = 0x1000;
|
uint32_t CHUNK = 0x1000;
|
||||||
uint64_t written = 0;
|
uint64_t written = 0;
|
||||||
while (written < len) {
|
while (written < len) {
|
||||||
uint32_t n = (len - written > CHUNK) ? CHUNK : (uint32_t)(len - written);
|
uint32_t n = (len - written > CHUNK) ? CHUNK : (uint32_t)(len - written);
|
||||||
kernel_copyin(src + written, ka + written, n);
|
kernel_copyin(src + written, ka + written, n);
|
||||||
written += n;
|
written += n;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -146,9 +136,9 @@ enum page_bits {
|
|||||||
#define pmap_pde_index(va) ((va >> 21) & 0x1FF)
|
#define pmap_pde_index(va) ((va >> 21) & 0x1FF)
|
||||||
#define pmap_pte_index(va) ((va >> 12) & 0x1FF)
|
#define pmap_pte_index(va) ((va >> 12) & 0x1FF)
|
||||||
|
|
||||||
uint64_t va_to_pa_user(uint64_t va);
|
uint64_t vtophys_user(uint64_t va);
|
||||||
uint64_t va_to_pa_kernel(uint64_t va);
|
uint64_t vtophys(uint64_t va);
|
||||||
uint64_t va_to_pa_custom(uint64_t va, uint64_t cr3_custom);
|
uint64_t vtophys_custom(uint64_t va, uint64_t cr3_custom);
|
||||||
uint64_t pa_to_dmap(uint64_t pa);
|
uint64_t pa_to_dmap(uint64_t pa);
|
||||||
void page_chain_set_rw(uint64_t va);
|
void page_chain_set_rw(uint64_t va);
|
||||||
uint64_t page_remove_global(uint64_t va);
|
uint64_t page_remove_global(uint64_t va);
|
||||||
@@ -169,16 +159,11 @@ void enter_rest_mode(void);
|
|||||||
#define DEBUG_PRINT(fmt, ...)
|
#define DEBUG_PRINT(fmt, ...)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
bool if_exists(const char *path);
|
||||||
bool if_exists(const char* path);
|
|
||||||
bool sceKernelIsTestKit(void);
|
bool sceKernelIsTestKit(void);
|
||||||
bool sceKernelIsDevKit(void);
|
bool sceKernelIsDevKit(void);
|
||||||
|
|
||||||
enum kit_type {
|
enum kit_type { KIT_RETAIL, KIT_TESTKIT, KIT_DEVKIT };
|
||||||
KIT_RETAIL,
|
|
||||||
KIT_TESTKIT,
|
|
||||||
KIT_DEVKIT
|
|
||||||
};
|
|
||||||
|
|
||||||
enum kit_type get_kit_type(void);
|
enum kit_type get_kit_type(void);
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,3 @@
|
|||||||
ifndef PS5_PAYLOAD_SDK
|
|
||||||
PS5_PAYLOAD_SDK = /opt/ps5-payload-sdk/
|
|
||||||
endif
|
|
||||||
|
|
||||||
# 1. Variables
|
|
||||||
ifeq ($(shell uname -m),aarch64)
|
ifeq ($(shell uname -m),aarch64)
|
||||||
CC = x86_64-linux-gnu-gcc
|
CC = x86_64-linux-gnu-gcc
|
||||||
LD = x86_64-linux-gnu-ld
|
LD = x86_64-linux-gnu-ld
|
||||||
@@ -12,11 +7,11 @@ CC = gcc
|
|||||||
LD = ld
|
LD = ld
|
||||||
OBJCOPY = objcopy
|
OBJCOPY = objcopy
|
||||||
endif
|
endif
|
||||||
CFLAGS = -O2 -fno-stack-protector -ffreestanding -nostdlib -fcf-protection=none -m64 -I$(PS5_PAYLOAD_SDK)/target/include
|
CFLAGS = -O2 -fno-stack-protector -ffreestanding -nostdlib -fcf-protection=none -m64
|
||||||
LDFLAGS = -T linker.ld
|
LDFLAGS = -T linker.ld -Wl,--no-warn-rwx-segments
|
||||||
TARGET = shellcode_hypervisor.elf
|
TARGET = shellcode_hv.elf
|
||||||
TEXT_BIN = shellcode_hypervisor.bin
|
TEXT_BIN = shellcode_hv.bin
|
||||||
dump = shellcode_hypervisor.h
|
dump = shellcode_hv.h
|
||||||
|
|
||||||
SRC = main.c utils.c boot_linux.c
|
SRC = main.c utils.c boot_linux.c
|
||||||
OBJ = $(SRC:.c=.o)
|
OBJ = $(SRC:.c=.o)
|
||||||
@@ -36,4 +31,4 @@ clean:
|
|||||||
rm -f $(OBJ) $(TARGET) $(TEXT_BIN) $(dump)
|
rm -f $(OBJ) $(TARGET) $(TEXT_BIN) $(dump)
|
||||||
|
|
||||||
$(dump): $(TEXT_BIN)
|
$(dump): $(TEXT_BIN)
|
||||||
python3 bin_to_c_hypervisor.py $(TEXT_BIN)
|
xxd -i $(TEXT_BIN) > $(dump)
|
||||||
@@ -1,20 +1,10 @@
|
|||||||
#include "boot_linux.h"
|
#include "boot_linux.h"
|
||||||
#include "../include/config.h"
|
#include "../include/config.h"
|
||||||
#include "linux.h"
|
#include "../include/linux.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
struct linux_info {
|
|
||||||
uintptr_t bzimage;
|
|
||||||
size_t bzimage_size;
|
|
||||||
uintptr_t initrd;
|
|
||||||
size_t initrd_size;
|
|
||||||
size_t vram_size;
|
|
||||||
char cmdline[2048];
|
|
||||||
int kit_type;
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct linux_info info;
|
static struct linux_info info;
|
||||||
|
|
||||||
static volatile int exited_cpus = 0;
|
static volatile int exited_cpus = 0;
|
||||||
@@ -94,8 +84,7 @@ static void e820_memory_setup(struct boot_params *bp) {
|
|||||||
if (info.kit_type != KIT_DEVKIT) {
|
if (info.kit_type != KIT_DEVKIT) {
|
||||||
append_e820_table(bp, 0x470000000, 0x47f300000, E820_TYPE_RAM);
|
append_e820_table(bp, 0x470000000, 0x47f300000, E820_TYPE_RAM);
|
||||||
append_e820_table(bp, 0x47f300000, 0x480000000, E820_TYPE_RESERVED);
|
append_e820_table(bp, 0x47f300000, 0x480000000, E820_TYPE_RESERVED);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
append_e820_table(bp, 0x470000000, 0x87f300000, E820_TYPE_RAM);
|
append_e820_table(bp, 0x470000000, 0x87f300000, E820_TYPE_RAM);
|
||||||
append_e820_table(bp, 0x87f300000, 0x880000000, E820_TYPE_RESERVED);
|
append_e820_table(bp, 0x87f300000, 0x880000000, E820_TYPE_RESERVED);
|
||||||
}
|
}
|
||||||
@@ -133,7 +122,6 @@ void boot_linux(void) {
|
|||||||
|
|
||||||
memcpy((void *)kernel_pa, (void *)(info.bzimage + setup_size), kernel_size);
|
memcpy((void *)kernel_pa, (void *)(info.bzimage + setup_size), kernel_size);
|
||||||
|
|
||||||
|
|
||||||
void (*startup_64)(uint64_t physaddr, struct boot_params *bp) =
|
void (*startup_64)(uint64_t physaddr, struct boot_params *bp) =
|
||||||
(void *)(kernel_pa + 0x200);
|
(void *)(kernel_pa + 0x200);
|
||||||
startup_64(kernel_pa, bp);
|
startup_64(kernel_pa, bp);
|
||||||
@@ -45,8 +45,4 @@
|
|||||||
void entry(void);
|
void entry(void);
|
||||||
void boot_linux(void);
|
void boot_linux(void);
|
||||||
|
|
||||||
enum kit_type {
|
enum kit_type { KIT_RETAIL, KIT_TESTKIT, KIT_DEVKIT };
|
||||||
KIT_RETAIL,
|
|
||||||
KIT_TESTKIT,
|
|
||||||
KIT_DEVKIT
|
|
||||||
};
|
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
#include <stdint.h>
|
|
||||||
#include "main.h"
|
|
||||||
#include "../include/config.h"
|
#include "../include/config.h"
|
||||||
#include "boot_linux.h"
|
#include "boot_linux.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
__attribute__((section(".entry_point"), naked)) uint32_t main(void) {
|
__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 ebax, ebx, ecx, edx;
|
||||||
uint32_t cpu_id;
|
uint32_t cpu_id;
|
||||||
|
|
||||||
@@ -15,10 +15,12 @@ __attribute__((section(".entry_point"), naked)) uint32_t main(void) {
|
|||||||
|
|
||||||
cpu_id = (ebx >> 24) & 0xFF;
|
cpu_id = (ebx >> 24) & 0xFF;
|
||||||
|
|
||||||
// Each CPU should have a different stack
|
// We point to a location after the main linux boot code
|
||||||
|
// Each CPU should have a different location
|
||||||
uintptr_t new_rsp =
|
uintptr_t new_rsp =
|
||||||
(uintptr_t)hv_base_rsp + ((uint64_t)(cpu_id)*hv_stack_size);
|
(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"
|
__asm__ volatile("movq %0, %%rsp \n\t"
|
||||||
"movq %%rsp, %%rbp \n\t"
|
"movq %%rsp, %%rbp \n\t"
|
||||||
:
|
:
|
||||||
3
shellcode_hv/main.h
Normal file
3
shellcode_hv/main.h
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
#include "shellcode_hv_args.h"
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdint.h>
|
||||||
9
shellcode_hv/shellcode_hv_args.h
Normal file
9
shellcode_hv/shellcode_hv_args.h
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
// 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
|
||||||
|
} shellcode_hv_args;
|
||||||
@@ -1,12 +1,9 @@
|
|||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "shellcode_hypervisor_args.h"
|
|
||||||
#include <cpuid.h>
|
#include <cpuid.h>
|
||||||
|
|
||||||
extern shellcode_hypervisor_args args;
|
|
||||||
|
|
||||||
__attribute__((noinline, optimize("O0"))) uint32_t putc_uart(uint8_t tx_byte) {
|
__attribute__((noinline, optimize("O0"))) uint32_t putc_uart(uint8_t tx_byte) {
|
||||||
volatile uint32_t *uart_tx = (volatile uint32_t *) 0xc1010104ULL;
|
volatile uint32_t *uart_tx = (volatile uint32_t *)0xc1010104ULL;
|
||||||
volatile uint32_t *uart_busy = (volatile uint32_t *) 0xc101010cULL;
|
volatile uint32_t *uart_busy = (volatile uint32_t *)0xc101010cULL;
|
||||||
uint64_t timeout = 0xFFFFFFFF;
|
uint64_t timeout = 0xFFFFFFFF;
|
||||||
do {
|
do {
|
||||||
timeout--;
|
timeout--;
|
||||||
@@ -26,7 +23,6 @@ uint8_t hex_val[17];
|
|||||||
|
|
||||||
__attribute__((noinline, optimize("O0"))) uint8_t *
|
__attribute__((noinline, optimize("O0"))) uint8_t *
|
||||||
u64_to_hex_custom(uint64_t val, uint8_t *dest) {
|
u64_to_hex_custom(uint64_t val, uint8_t *dest) {
|
||||||
|
|
||||||
const uint8_t hex_chars[] = "0123456789abcdef";
|
const uint8_t hex_chars[] = "0123456789abcdef";
|
||||||
dest[16] = '\0';
|
dest[16] = '\0';
|
||||||
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
import sys
|
|
||||||
import os
|
|
||||||
|
|
||||||
def create_shellcode_header(input_file):
|
|
||||||
if not os.path.exists(input_file):
|
|
||||||
print(f"Error: {input_file} not found.")
|
|
||||||
return
|
|
||||||
|
|
||||||
# Read binary data_text
|
|
||||||
with open(input_file, "rb") as f:
|
|
||||||
data_text = f.read()
|
|
||||||
|
|
||||||
# Hardcoded output name
|
|
||||||
output_name = "shellcode_hypervisor.h"
|
|
||||||
array_name = "shellcode_hypervisor"
|
|
||||||
|
|
||||||
with open(output_name, "w") as f:
|
|
||||||
f.write(f"// Generated from {input_file}\n")
|
|
||||||
f.write(f"#ifndef SHELLCODE_HV_H\n")
|
|
||||||
f.write(f"#define SHELLCODE_HV_H\n\n")
|
|
||||||
f.write(f"#include <unistd.h>\n\n")
|
|
||||||
|
|
||||||
f.write(f"uint8_t {array_name}[] = {{\n ")
|
|
||||||
|
|
||||||
for i, byte in enumerate(data_text):
|
|
||||||
f.write(f"0x{byte:02X}")
|
|
||||||
|
|
||||||
if i < len(data_text) - 1:
|
|
||||||
f.write(", ")
|
|
||||||
|
|
||||||
# New line every 12 bytes
|
|
||||||
if (i + 1) % 12 == 0:
|
|
||||||
f.write("\n ")
|
|
||||||
|
|
||||||
f.write(f"\n}};\n\n")
|
|
||||||
f.write(f"uint64_t {array_name}_len = {len(data_text)};\n\n")
|
|
||||||
|
|
||||||
f.write(f"#endif // SHELLCODE_HV_H\n")
|
|
||||||
|
|
||||||
print(f"Done! Created {output_name} ({len(data_text)} bytes)")
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
if len(sys.argv) < 2:
|
|
||||||
print("Usage: python bin_to_c_hypervisor.py <shellcode.bin>")
|
|
||||||
else:
|
|
||||||
create_shellcode_header(sys.argv[1])
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
#include "shellcode_hypervisor_args.h"
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint64_t bzimage_pa;
|
|
||||||
uint64_t initrd_pa;
|
|
||||||
uint64_t linux_info_pa;
|
|
||||||
} shellcode_hypervisor_args;
|
|
||||||
@@ -1,8 +1,3 @@
|
|||||||
ifndef PS5_PAYLOAD_SDK
|
|
||||||
PS5_PAYLOAD_SDK = /opt/ps5-payload-sdk/
|
|
||||||
endif
|
|
||||||
|
|
||||||
|
|
||||||
ifeq ($(shell uname -m),aarch64)
|
ifeq ($(shell uname -m),aarch64)
|
||||||
CC = x86_64-linux-gnu-gcc
|
CC = x86_64-linux-gnu-gcc
|
||||||
LD = x86_64-linux-gnu-ld
|
LD = x86_64-linux-gnu-ld
|
||||||
@@ -12,16 +7,15 @@ CC = gcc
|
|||||||
LD = ld
|
LD = ld
|
||||||
OBJCOPY = objcopy
|
OBJCOPY = objcopy
|
||||||
endif
|
endif
|
||||||
CFLAGS = -O2 -fno-stack-protector -ffreestanding -nostdlib -m64 -I$(PS5_PAYLOAD_SDK)/target/include
|
CFLAGS = -O2 -fno-stack-protector -ffreestanding -nostdlib -fcf-protection=none -m64
|
||||||
LDFLAGS = -T linker.ld
|
LDFLAGS = -T linker.ld -Wl,--no-warn-rwx-segments
|
||||||
TARGET = shellcode_kernel.elf
|
TARGET = shellcode_kernel.elf
|
||||||
TEXT_BIN = shellcode_text.bin
|
TEXT_BIN = shellcode_kernel.bin
|
||||||
|
|
||||||
SRC = main.c utils.c kernel_code.c
|
|
||||||
OBJ = $(SRC:.c=.o)
|
|
||||||
|
|
||||||
dump = shellcode_kernel.h
|
dump = shellcode_kernel.h
|
||||||
|
|
||||||
|
SRC = $(wildcard *.c)
|
||||||
|
OBJ = $(SRC:.c=.o)
|
||||||
|
|
||||||
all: $(dump)
|
all: $(dump)
|
||||||
|
|
||||||
$(TARGET): $(OBJ)
|
$(TARGET): $(OBJ)
|
||||||
@@ -31,10 +25,10 @@ $(TARGET): $(OBJ)
|
|||||||
$(CC) $(CFLAGS) -c $< -o $@
|
$(CC) $(CFLAGS) -c $< -o $@
|
||||||
|
|
||||||
$(TEXT_BIN): $(TARGET)
|
$(TEXT_BIN): $(TARGET)
|
||||||
$(OBJCOPY) -O binary -j .text $(TARGET) $(TEXT_BIN)
|
$(OBJCOPY) -O binary -j .shell_code $(TARGET) $(TEXT_BIN)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f $(OBJ) $(TARGET) $(TEXT_BIN) $(dump)
|
rm -f $(OBJ) $(TARGET) $(TEXT_BIN) $(dump)
|
||||||
|
|
||||||
$(dump): $(TEXT_BIN)
|
$(dump): $(TEXT_BIN)
|
||||||
python3 bin_to_c_kernel.py $(TEXT_BIN)
|
xxd -i $(TEXT_BIN) > $(dump)
|
||||||
|
|||||||
@@ -1,48 +0,0 @@
|
|||||||
import sys
|
|
||||||
import os
|
|
||||||
|
|
||||||
def create_shellcode_header(input_file_text):
|
|
||||||
if not os.path.exists(input_file_text):
|
|
||||||
print(f"Error: {input_file_text} not found.")
|
|
||||||
return
|
|
||||||
|
|
||||||
# Read binary data_text
|
|
||||||
with open(input_file_text, "rb") as f:
|
|
||||||
data_text = f.read()
|
|
||||||
|
|
||||||
# Hardcoded output name
|
|
||||||
output_name = "shellcode_kernel.h"
|
|
||||||
array_name_text = "shellcode_kernel_text"
|
|
||||||
|
|
||||||
with open(output_name, "w") as f:
|
|
||||||
f.write(f"// Generated from {input_file_text}\n")
|
|
||||||
f.write(f"#ifndef SHELLCODE_KERNEL_H\n")
|
|
||||||
f.write(f"#define SHELLCODE_KERNEL_H\n\n")
|
|
||||||
f.write(f"#include <unistd.h>\n\n")
|
|
||||||
|
|
||||||
f.write(f"#include \"shellcode_kernel_args.h\"\n\n")
|
|
||||||
|
|
||||||
f.write(f"uint8_t {array_name_text}[] = {{\n ")
|
|
||||||
|
|
||||||
for i, byte in enumerate(data_text):
|
|
||||||
f.write(f"0x{byte:02X}")
|
|
||||||
|
|
||||||
if i < len(data_text) - 1:
|
|
||||||
f.write(", ")
|
|
||||||
|
|
||||||
# New line every 12 bytes
|
|
||||||
if (i + 1) % 12 == 0:
|
|
||||||
f.write("\n ")
|
|
||||||
|
|
||||||
f.write(f"\n}};\n\n")
|
|
||||||
f.write(f"uint64_t {array_name_text}_len = {len(data_text)};\n\n")
|
|
||||||
|
|
||||||
f.write(f"#endif // SHELLCODE_KERNEL_H\n")
|
|
||||||
|
|
||||||
print(f"Done! Created {output_name} ({len(data_text)} bytes)")
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
if len(sys.argv) < 2:
|
|
||||||
print("Usage: python bin_to_c_kernel.py <text.bin>")
|
|
||||||
else:
|
|
||||||
create_shellcode_header(sys.argv[1])
|
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
#include "kernel_code.h"
|
#include "boot_linux.h"
|
||||||
#include "../include/config.h"
|
#include "../include/config.h"
|
||||||
#include "../shellcode_hypervisor/shellcode_hypervisor.h"
|
#include "../include/linux.h"
|
||||||
#include "shellcode_kernel_args.h"
|
#include "../shellcode_hv/shellcode_hv.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#define DIG1TRANSMITTERCONTROL 0x4c
|
#define DIG1TRANSMITTERCONTROL 0x4c
|
||||||
|
|
||||||
@@ -39,16 +40,6 @@ struct dig_transmitter_control_parameters_v1_6 {
|
|||||||
uint32_t reserved1;
|
uint32_t reserved1;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct linux_info {
|
|
||||||
uintptr_t bzimage;
|
|
||||||
size_t bzimage_size;
|
|
||||||
uintptr_t initrd;
|
|
||||||
size_t initrd_size;
|
|
||||||
size_t vram_size;
|
|
||||||
char cmdline[2048];
|
|
||||||
int kit_type;
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct linux_info info;
|
static struct linux_info info;
|
||||||
|
|
||||||
static int mp3_req[1281], mp3_rsp[1282];
|
static int mp3_req[1281], mp3_rsp[1282];
|
||||||
@@ -93,58 +84,35 @@ static int mp3_enable_output(int be, int mode) {
|
|||||||
return mp3_invoke(22, mp3_req, mp3_rsp);
|
return mp3_invoke(22, mp3_req, mp3_rsp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void patch_hv(void) {
|
static void install_hv_code(void) {
|
||||||
|
// Install identity map for HV
|
||||||
uint64_t identity_cr3 = cave_hv_paging;
|
uint64_t identity_cr3 = cave_hv_paging;
|
||||||
uint64_t identity_pml4_0 = identity_cr3 + 0x1003ULL;
|
uint64_t identity_pml4_0 = identity_cr3 + 0x1003ULL;
|
||||||
uint64_t l40_l3_addr = PAGE_PA(identity_pml4_0);
|
uint64_t l40_l3_addr = PAGE_PA(identity_pml4_0); // addr PML4[0]
|
||||||
uint64_t identity_pml40_l3[] = {
|
uint64_t identity_pml40_l3[] = {
|
||||||
0x0000000000000083,
|
0x0000000000000083, // P, RW, US=0 - 0 GB to 1 GB
|
||||||
0x0000000040000083,
|
0x0000000040000083, // P, RW, US=0 - 1 GB to 2 GB
|
||||||
0x0000000080000083,
|
0x0000000080000083, // P, RW, US=0 - 3 GB to 3 GB
|
||||||
0x00000000C0000083,
|
0x00000000C0000083, // P, RW, US=0 - 4 GB to 4 GB
|
||||||
0x0000000100000083
|
0x0000000100000083 // P, RW, US=0 - 5 GB to 6 GB --> Our paging structure
|
||||||
};
|
};
|
||||||
uint64_t l3_size = sizeof(identity_pml40_l3) / sizeof(identity_pml40_l3[0]);
|
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;
|
*(uint64_t *)PHYS_TO_DMAP(identity_cr3) = identity_pml4_0;
|
||||||
for (uint64_t i = 0; i < l3_size; i++) {
|
for (uint64_t i = 0; i < l3_size; i++) {
|
||||||
*(uint64_t *)PHYS_TO_DMAP(l40_l3_addr + i * 8) = identity_pml40_l3[i];
|
*(uint64_t *)PHYS_TO_DMAP(l40_l3_addr + i * 8) = identity_pml40_l3[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy((void *)PHYS_TO_DMAP(cave_hv_code), shellcode_hypervisor,
|
// Install shellcode_hv
|
||||||
shellcode_hypervisor_len);
|
memcpy((void *)PHYS_TO_DMAP(cave_hv_code), shellcode_hv_bin,
|
||||||
|
shellcode_hv_bin_len);
|
||||||
uint8_t shellcode_jmp[] = {
|
|
||||||
0x48, 0xC7, 0xC0, 0x00, 0x6F, 0x80, 0x62,
|
|
||||||
0xFF, 0xE0, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3,
|
|
||||||
0xC3, 0xC3};
|
|
||||||
|
|
||||||
*(uint32_t *)(&shellcode_jmp[3]) = (uint32_t)args.hv_code_cave_pa;
|
|
||||||
|
|
||||||
// Just patch the VMEXIT handler directly, avoiding all checks
|
|
||||||
memcpy((void *)PHYS_TO_DMAP(args.hv_handle_vmexit_pa), shellcode_jmp,
|
|
||||||
sizeof(shellcode_jmp));
|
|
||||||
|
|
||||||
uint8_t shellcode_identity_and_jmp[] = {
|
|
||||||
0x48, 0xB8, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x01, 0x00, 0x00, 0x00, // movabs rax, 0x100000000
|
|
||||||
0x0F, 0x22, 0xD8, // mov cr3, rax
|
|
||||||
0x48, 0xB8, 0x00, 0x30, 0x00,
|
|
||||||
0x00, 0x01, 0x00, 0x00, 0x00, // movabs rax, 0x100003000
|
|
||||||
0xFF, 0xE0 // jmp rax
|
|
||||||
};
|
|
||||||
|
|
||||||
*(uint64_t *)(&shellcode_identity_and_jmp[2]) = cave_hv_paging;
|
|
||||||
*(uint64_t *)(&shellcode_identity_and_jmp[15]) = cave_hv_code;
|
|
||||||
|
|
||||||
memcpy((void *)PHYS_TO_DMAP(args.hv_code_cave_pa), shellcode_identity_and_jmp,
|
|
||||||
sizeof(shellcode_identity_and_jmp));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void boot_linux(void) {
|
void boot_linux(void) {
|
||||||
|
|
||||||
patch_hv();
|
// Common bootloader code
|
||||||
|
install_hv_code();
|
||||||
|
|
||||||
memcpy((void *)PHYS_TO_DMAP(0xC0000), (void *)g_vbios, 0x10000);
|
memcpy((void *)PHYS_TO_DMAP(0xC0000), (void *)g_vbios, 0x10000);
|
||||||
|
|
||||||
@@ -159,8 +127,8 @@ void boot_linux(void) {
|
|||||||
// Copy bzImage and initrd into contiguous memory.
|
// Copy bzImage and initrd into contiguous memory.
|
||||||
memcpy(&info, (void *)args.linux_info_va, sizeof(struct linux_info));
|
memcpy(&info, (void *)args.linux_info_va, sizeof(struct linux_info));
|
||||||
|
|
||||||
uintptr_t bzimage = info.bzimage; // Kernel wrote the VA here
|
uintptr_t bzimage = info.bzimage;
|
||||||
uintptr_t initrd = info.initrd; // Kernel wrote the VA here
|
uintptr_t initrd = info.initrd;
|
||||||
|
|
||||||
info.bzimage = cave_bzImage;
|
info.bzimage = cave_bzImage;
|
||||||
info.initrd = cave_bzImage + ALIGN_UP(info.bzimage_size, PAGE_SIZE);
|
info.initrd = cave_bzImage + ALIGN_UP(info.bzimage_size, PAGE_SIZE);
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
#ifndef KERNEL_CODE_H
|
#ifndef BOOT_LINUX_H
|
||||||
#define KERNEL_CODE_H
|
#define BOOT_LINUX_H
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#define ALIGN_UP(size, align) (((size) + (align) - 1) & ~((align) - 1))
|
#define ALIGN_UP(size, align) (((size) + (align) - 1) & ~((align) - 1))
|
||||||
|
|
||||||
static int dp_enable_link_phy(int lanenum, int linkrate);
|
static int dp_enable_link_phy(int lanenum, int linkrate);
|
||||||
static void patch_hv(void);
|
static void install_hv_code(void);
|
||||||
void boot_linux(void);
|
void boot_linux(void);
|
||||||
|
|
||||||
extern int (*transmitter_control)(int cmd, void *control);
|
extern int (*transmitter_control)(int cmd, void *control);
|
||||||
154
shellcode_kernel/exploit_0304.c
Normal file
154
shellcode_kernel/exploit_0304.c
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
#include "exploit_0304.h"
|
||||||
|
#include "../include/config.h"
|
||||||
|
#include "shellcode_kernel_args.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
uint32_t (*hv_iommu_set_buffers)(uint64_t cb2_pa, uint64_t cb3_pa,
|
||||||
|
uint64_t eb_pa, uint64_t unk, int *n_devices);
|
||||||
|
uint32_t (*hv_iommu_wait_completion)(void);
|
||||||
|
|
||||||
|
int disable_npts_0304(volatile shellcode_kernel_args *args_ptr) {
|
||||||
|
uint64_t iommu_cb2_pa = vtophys(args_ptr->dmap_base, args_ptr->iommu_cb2_va);
|
||||||
|
uint64_t iommu_cb3_pa = vtophys(args_ptr->dmap_base, args_ptr->iommu_cb3_va);
|
||||||
|
uint64_t iommu_eb_pa = vtophys(args_ptr->dmap_base, args_ptr->iommu_eb_va);
|
||||||
|
|
||||||
|
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);
|
||||||
|
if (ret != 0) {
|
||||||
|
puts_uart(args_ptr->dmap_base, (char[]){"IOMMU sb X\n"});
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = ((uint64_t(*)(void))args_ptr->fun_hv_iommu_wait_completion)();
|
||||||
|
if (ret) {
|
||||||
|
puts_uart(args_ptr->dmap_base, (char[]){"IOMMU sb NO OK\n"});
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
puts_uart(args_ptr->dmap_base, (char[]){"IOMMU sb OK\n"});
|
||||||
|
|
||||||
|
if (tmr_disable(args_ptr->dmap_base)) {
|
||||||
|
puts_uart(args_ptr->dmap_base, (char[]){"TMR NO OK\n"});
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
puts_uart(args_ptr->dmap_base, (char[]){"TMR OK\n"});
|
||||||
|
|
||||||
|
patch_vmcb(args_ptr);
|
||||||
|
puts_uart(args_ptr->dmap_base, (char[]){"VMCB OK\n"});
|
||||||
|
|
||||||
|
// Re-do this to force a VMEXIT without HV injecting faults
|
||||||
|
((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);
|
||||||
|
((uint64_t(*)(void))args_ptr->fun_hv_iommu_wait_completion)();
|
||||||
|
puts_uart(args_ptr->dmap_base, (char[]){"Back from HV\n"});
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void patch_hv_0304(void) {
|
||||||
|
// 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
|
||||||
|
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
|
||||||
|
memcpy((void *)PHYS_TO_DMAP(args.hv_handle_vmexit_pa), shellcode_jmp,
|
||||||
|
sizeof(shellcode_jmp));
|
||||||
|
|
||||||
|
uint8_t shellcode_identity_and_jmp[] = {
|
||||||
|
0x48, 0xB8, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x01, 0x00, 0x00, 0x00, // movabs rax, 0x100000000
|
||||||
|
0x0F, 0x22, 0xD8, // mov cr3, rax
|
||||||
|
0x48, 0xB8, 0x00, 0x30, 0x00,
|
||||||
|
0x00, 0x01, 0x00, 0x00, 0x00, // movabs rax, 0x100003000
|
||||||
|
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 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));
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((noinline, optimize("O0"))) void
|
||||||
|
iommu_submit_cmd(volatile shellcode_kernel_args *args_ptr, uint64_t *cmd) {
|
||||||
|
uint64_t curr_tail =
|
||||||
|
*((uint64_t *)args_ptr->iommu_mmio_va + IOMMU_MMIO_CB_TAIL / 8);
|
||||||
|
uint64_t next_tail = (curr_tail + IOMMU_CMD_ENTRY_SIZE) & IOMMU_CB_MASK;
|
||||||
|
|
||||||
|
uint64_t *cmd_buffer = (uint64_t *)args_ptr->iommu_cb2_va + curr_tail / 8;
|
||||||
|
|
||||||
|
cmd_buffer[0] = cmd[0];
|
||||||
|
cmd_buffer[1] = cmd[1];
|
||||||
|
|
||||||
|
__asm__ volatile("" : : : "memory");
|
||||||
|
|
||||||
|
*((uint64_t *)args_ptr->iommu_mmio_va + IOMMU_MMIO_CB_TAIL / 8) = next_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))
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
__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};
|
||||||
|
cmd[0] = (uint32_t)(pa & 0xFFFFFFF8) | 0x05;
|
||||||
|
cmd[1] = ((uint32_t)(pa >> 32) & 0xFFFFF) | 0x10000000;
|
||||||
|
cmd[2] = (uint32_t)(val);
|
||||||
|
cmd[3] = (uint32_t)(val >> 32);
|
||||||
|
iommu_submit_cmd(args_ptr, (uint64_t *)cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
__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];
|
||||||
|
|
||||||
|
iommu_write8_pa(args_ptr, pa + 0x00, 0x0000000000000000ULL);
|
||||||
|
iommu_write8_pa(args_ptr, pa + 0x08, 0x0004000000000000ULL);
|
||||||
|
iommu_write8_pa(args_ptr, pa + 0x10, 0x000000000000000FULL);
|
||||||
|
iommu_write8_pa(args_ptr, pa + 0x58, 0x0000000000000001ULL);
|
||||||
|
iommu_write8_pa(args_ptr, pa + 0x90, 0x0000000000000000ULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
__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);
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((noinline, optimize("O0"))) void
|
||||||
|
tmr_write(uint64_t dmap, uint32_t addr, uint32_t val) {
|
||||||
|
*(uint32_t *)(dmap + ECAM_B0D18F2 + TMR_INDEX_OFF) = addr;
|
||||||
|
*(uint32_t *)(dmap + ECAM_B0D18F2 + TMR_DATA_OFF) = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
__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) {
|
||||||
|
tmr_write(dmap, TMR_CONFIG(i), 0);
|
||||||
|
if (tmr_read(dmap, TMR_CONFIG(i)) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
49
shellcode_kernel/exploit_0304.h
Normal file
49
shellcode_kernel/exploit_0304.h
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
#ifndef EXPLOIT_0304_H
|
||||||
|
#define EXPLOIT_0304_H
|
||||||
|
#include "shellcode_kernel_args.h"
|
||||||
|
|
||||||
|
extern uint32_t (*hv_iommu_set_buffers)(uint64_t cb2_pa, uint64_t cb3_pa,
|
||||||
|
uint64_t eb_pa, uint64_t unk,
|
||||||
|
int *n_devices);
|
||||||
|
extern uint32_t (*hv_iommu_wait_completion)(void);
|
||||||
|
|
||||||
|
int disable_npts_0304(volatile shellcode_kernel_args *args_ptr);
|
||||||
|
void patch_hv_0304(void);
|
||||||
|
|
||||||
|
// tmr via ecam b0d18f2
|
||||||
|
#ifndef ECAM_B0D18F2
|
||||||
|
#define ECAM_B0D18F2 (0xF0000000ULL + 0x18ULL * 0x8000 + 2 * 0x1000)
|
||||||
|
#define TMR_INDEX_OFF 0x80
|
||||||
|
#define TMR_DATA_OFF 0x84
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// tmr layout (hardware)
|
||||||
|
#define TMR_BASE(n) ((n) * 0x10 + 0x00)
|
||||||
|
#define TMR_LIMIT(n) ((n) * 0x10 + 0x04)
|
||||||
|
#define TMR_CONFIG(n) ((n) * 0x10 + 0x08)
|
||||||
|
#define TMR_REQUESTORS(n) ((n) * 0x10 + 0x0C)
|
||||||
|
#define TMR_CFG_PERMISSIVE 0x3F07
|
||||||
|
#define MAX_TMR 22
|
||||||
|
#define MAX_SAVED_TMRS 8
|
||||||
|
|
||||||
|
uint32_t tmr_read(uint64_t dmap, uint32_t addr);
|
||||||
|
void tmr_write(uint64_t dmap, uint32_t addr, uint32_t val);
|
||||||
|
int tmr_disable(uint64_t dmap);
|
||||||
|
|
||||||
|
// Command buffer MMIO offsets
|
||||||
|
#define IOMMU_MMIO_CB_HEAD 0xa000
|
||||||
|
#define IOMMU_MMIO_CB_TAIL 0xa008
|
||||||
|
|
||||||
|
// Queue constants
|
||||||
|
#define IOMMU_CB_SIZE 0x2000
|
||||||
|
#define IOMMU_CB_MASK (IOMMU_CB_SIZE - 1)
|
||||||
|
#define IOMMU_CMD_ENTRY_SIZE 0x10
|
||||||
|
|
||||||
|
// Submit a single 16-byte command and wait for completion
|
||||||
|
void iommu_submit_cmd(volatile shellcode_kernel_args *args_ptr, uint64_t *cmd);
|
||||||
|
// Write 8 bytes to a physical address using IOMMU completion wait store
|
||||||
|
void iommu_write8_pa(volatile shellcode_kernel_args *args_ptr, uint64_t pa,
|
||||||
|
uint64_t val);
|
||||||
|
|
||||||
|
void patch_vmcb(volatile shellcode_kernel_args *args_ptr);
|
||||||
|
#endif
|
||||||
@@ -4,13 +4,13 @@ ENTRY(main)
|
|||||||
SECTIONS
|
SECTIONS
|
||||||
{
|
{
|
||||||
. = 0x1000; /* 0x1000 to avoid warnings from linker */
|
. = 0x1000; /* 0x1000 to avoid warnings from linker */
|
||||||
.text :
|
/* Place our custom header first */
|
||||||
|
.shell_code :
|
||||||
{
|
{
|
||||||
*(.entry_point)
|
*(.entry_point)
|
||||||
*(.text)
|
*(.text)
|
||||||
*(.text.*)
|
*(.text.*)
|
||||||
*(.data)
|
*(.data*)
|
||||||
*(.data.*)
|
|
||||||
*(.rodata*)
|
*(.rodata*)
|
||||||
*(.bss)
|
*(.bss)
|
||||||
*(.bss.*)
|
*(.bss.*)
|
||||||
|
|||||||
@@ -1,258 +1,52 @@
|
|||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "kernel_code.h"
|
#include "boot_linux.h"
|
||||||
|
#include "exploit_0304.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
shellcode_kernel_args args = {0};
|
shellcode_kernel_args args = {0};
|
||||||
|
|
||||||
|
// We are being called instead of AcpiSetFirmwareWakingVector
|
||||||
__attribute__((section(".entry_point"))) uint32_t main(uint64_t add1,
|
__attribute__((section(".entry_point"))) uint32_t main(uint64_t add1,
|
||||||
uint64_t add2) {
|
uint64_t add2) {
|
||||||
|
// We will do main checks on .text only with a reference to .data
|
||||||
volatile shellcode_kernel_args *args_ptr =
|
volatile shellcode_kernel_args *args_ptr =
|
||||||
(volatile shellcode_kernel_args
|
(volatile shellcode_kernel_args
|
||||||
*)0x11AA11AA11AA11AA; // To be replaced with proper address in .kdata
|
*)0x11AA11AA11AA11AA; // To be replaced with proper address in .kdata
|
||||||
// by loader
|
|
||||||
|
|
||||||
// "Hide" the pointer from the optimizer
|
// "Hide" the pointer from the optimizer
|
||||||
__asm__ volatile("" : "+r"(args_ptr));
|
__asm__ volatile("" : "+r"(args_ptr));
|
||||||
|
|
||||||
|
// We don't have required information - Abort
|
||||||
if ((args_ptr->fun_printf & 0xFFFF) == 0) {
|
if ((args_ptr->fun_printf & 0xFFFF) == 0) {
|
||||||
goto out;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t *uart_va = (uint32_t *)(args_ptr->dmap_base + 0xC0115110ULL);
|
activate_uart(args_ptr);
|
||||||
*uart_va &= ~0x200;
|
|
||||||
uint32_t *override_char_va = (uint32_t *)args_ptr->kernel_uart_override;
|
|
||||||
*override_char_va = 0x0;
|
|
||||||
|
|
||||||
uint64_t iommu_cb2_pa =
|
if ((0x0300 <= args_ptr->fw_version) && (args_ptr->fw_version < 0x0500)) {
|
||||||
((uint64_t(*)(uint64_t))args_ptr->fun_va_to_pa)(args_ptr->iommu_cb2_va);
|
if (disable_npts_0304(args_ptr))
|
||||||
uint64_t iommu_cb3_pa =
|
return -1;
|
||||||
((uint64_t(*)(uint64_t))args_ptr->fun_va_to_pa)(args_ptr->iommu_cb3_va);
|
// Now we can R/W on .text
|
||||||
uint64_t iommu_eb_pa =
|
|
||||||
((uint64_t(*)(uint64_t))args_ptr->fun_va_to_pa)(args_ptr->iommu_eb_va);
|
|
||||||
|
|
||||||
uint64_t unk;
|
|
||||||
int n_devices;
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
if (ret != 0) {
|
|
||||||
putc_uart(args_ptr->dmap_base, 'I');
|
|
||||||
putc_uart(args_ptr->dmap_base, 'O');
|
|
||||||
putc_uart(args_ptr->dmap_base, 'M');
|
|
||||||
putc_uart(args_ptr->dmap_base, 'M');
|
|
||||||
putc_uart(args_ptr->dmap_base, 'U');
|
|
||||||
putc_uart(args_ptr->dmap_base, ' ');
|
|
||||||
putc_uart(args_ptr->dmap_base, 's');
|
|
||||||
putc_uart(args_ptr->dmap_base, 'b');
|
|
||||||
putc_uart(args_ptr->dmap_base, ' ');
|
|
||||||
putc_uart(args_ptr->dmap_base, 'X');
|
|
||||||
putc_uart(args_ptr->dmap_base, '\n');
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = ((uint64_t(*)(void))args_ptr->fun_hv_iommu_wait_completion)();
|
|
||||||
|
|
||||||
if (ret == 0) {
|
|
||||||
|
|
||||||
putc_uart(args_ptr->dmap_base, 'I');
|
|
||||||
putc_uart(args_ptr->dmap_base, 'O');
|
|
||||||
putc_uart(args_ptr->dmap_base, 'M');
|
|
||||||
putc_uart(args_ptr->dmap_base, 'M');
|
|
||||||
putc_uart(args_ptr->dmap_base, 'U');
|
|
||||||
putc_uart(args_ptr->dmap_base, ' ');
|
|
||||||
putc_uart(args_ptr->dmap_base, 's');
|
|
||||||
putc_uart(args_ptr->dmap_base, 'b');
|
|
||||||
putc_uart(args_ptr->dmap_base, ' ');
|
|
||||||
putc_uart(args_ptr->dmap_base, 'O');
|
|
||||||
putc_uart(args_ptr->dmap_base, 'K');
|
|
||||||
putc_uart(args_ptr->dmap_base, '\n');
|
|
||||||
|
|
||||||
if (tmr_disable(args_ptr->dmap_base)) {
|
|
||||||
|
|
||||||
putc_uart(args_ptr->dmap_base, 'T');
|
|
||||||
putc_uart(args_ptr->dmap_base, 'M');
|
|
||||||
putc_uart(args_ptr->dmap_base, 'R');
|
|
||||||
putc_uart(args_ptr->dmap_base, ' ');
|
|
||||||
putc_uart(args_ptr->dmap_base, 'X');
|
|
||||||
putc_uart(args_ptr->dmap_base, '\n');
|
|
||||||
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
putc_uart(args_ptr->dmap_base, 'T');
|
|
||||||
putc_uart(args_ptr->dmap_base, 'M');
|
|
||||||
putc_uart(args_ptr->dmap_base, 'R');
|
|
||||||
putc_uart(args_ptr->dmap_base, ' ');
|
|
||||||
putc_uart(args_ptr->dmap_base, 'O');
|
|
||||||
putc_uart(args_ptr->dmap_base, 'K');
|
|
||||||
putc_uart(args_ptr->dmap_base, '\n');
|
|
||||||
|
|
||||||
patch_vmcb(args_ptr);
|
|
||||||
|
|
||||||
putc_uart(args_ptr->dmap_base, 'V');
|
|
||||||
putc_uart(args_ptr->dmap_base, 'M');
|
|
||||||
putc_uart(args_ptr->dmap_base, 'C');
|
|
||||||
putc_uart(args_ptr->dmap_base, 'B');
|
|
||||||
putc_uart(args_ptr->dmap_base, ' ');
|
|
||||||
putc_uart(args_ptr->dmap_base, 'O');
|
|
||||||
putc_uart(args_ptr->dmap_base, 'K');
|
|
||||||
putc_uart(args_ptr->dmap_base, '\n');
|
|
||||||
|
|
||||||
// Re-do this to force a VMEXIT without HV injecting faults
|
|
||||||
((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);
|
|
||||||
((uint64_t(*)(void))args_ptr->fun_hv_iommu_wait_completion)();
|
|
||||||
|
|
||||||
putc_uart(args_ptr->dmap_base, 'B');
|
|
||||||
putc_uart(args_ptr->dmap_base, 'a');
|
|
||||||
putc_uart(args_ptr->dmap_base, 'c');
|
|
||||||
putc_uart(args_ptr->dmap_base, 'k');
|
|
||||||
putc_uart(args_ptr->dmap_base, ' ');
|
|
||||||
putc_uart(args_ptr->dmap_base, 'f');
|
|
||||||
putc_uart(args_ptr->dmap_base, 'r');
|
|
||||||
putc_uart(args_ptr->dmap_base, 'o');
|
|
||||||
putc_uart(args_ptr->dmap_base, 'm');
|
|
||||||
putc_uart(args_ptr->dmap_base, ' ');
|
|
||||||
putc_uart(args_ptr->dmap_base, 'H');
|
|
||||||
putc_uart(args_ptr->dmap_base, 'V');
|
|
||||||
putc_uart(args_ptr->dmap_base, '\n');
|
|
||||||
|
|
||||||
// We can now initiate the global args variable and use it, as NPTs are
|
|
||||||
// disabled
|
|
||||||
init_global_pointers(args_ptr);
|
init_global_pointers(args_ptr);
|
||||||
|
patch_hv_0304();
|
||||||
printf("HV_Defeat: we should be ready for Linux part\n");
|
} else if ((0x0500 <= args_ptr->fw_version) &&
|
||||||
|
(args_ptr->fw_version < 0x0650)) {
|
||||||
boot_linux();
|
// escape_hv_0506();
|
||||||
printf("Linux prepared OK\n");
|
// Now we can R/W on .text
|
||||||
|
// init_global_pointers(args_ptr);
|
||||||
printf("Calling smp_rendezvous to exit all cores to HV with ptr: %016lx\n",
|
|
||||||
(uint64_t)vmmcall_dummy);
|
|
||||||
printf("Good Bye VM :)\n");
|
|
||||||
|
|
||||||
smp_rendezvous(smp_no_rendevous_barrier, vmmcall_dummy,
|
|
||||||
smp_no_rendevous_barrier, NULL);
|
|
||||||
|
|
||||||
printf("We shouldn't be here :(\n");
|
|
||||||
} else {
|
} else {
|
||||||
putc_uart(args_ptr->dmap_base, 'I');
|
return 0;
|
||||||
putc_uart(args_ptr->dmap_base, 'O');
|
|
||||||
putc_uart(args_ptr->dmap_base, 'M');
|
|
||||||
putc_uart(args_ptr->dmap_base, 'M');
|
|
||||||
putc_uart(args_ptr->dmap_base, 'U');
|
|
||||||
putc_uart(args_ptr->dmap_base, ' ');
|
|
||||||
putc_uart(args_ptr->dmap_base, 's');
|
|
||||||
putc_uart(args_ptr->dmap_base, 'b');
|
|
||||||
putc_uart(args_ptr->dmap_base, ' ');
|
|
||||||
putc_uart(args_ptr->dmap_base, 'N');
|
|
||||||
putc_uart(args_ptr->dmap_base, 'O');
|
|
||||||
putc_uart(args_ptr->dmap_base, ' ');
|
|
||||||
putc_uart(args_ptr->dmap_base, 'O');
|
|
||||||
putc_uart(args_ptr->dmap_base, 'K');
|
|
||||||
putc_uart(args_ptr->dmap_base, '\n');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
boot_linux();
|
||||||
|
printf("Linux prepared OK\n");
|
||||||
|
|
||||||
|
printf("Good Bye VM :)\n");
|
||||||
|
smp_rendezvous(smp_no_rendevous_barrier, vmmcall_dummy,
|
||||||
|
smp_no_rendevous_barrier, NULL);
|
||||||
|
|
||||||
|
printf("We shouldn't be here :(\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute__((noinline, optimize("O0"), naked)) void vmmcall_dummy(void) {
|
|
||||||
__asm__ volatile("mov $0x1, %rax \n"
|
|
||||||
"vmmcall \n"
|
|
||||||
"ret \n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void halt(void) { __asm__ __volatile__("hlt"); }
|
|
||||||
|
|
||||||
__attribute__((noinline, optimize("O0"))) void
|
|
||||||
iommu_submit_cmd(volatile shellcode_kernel_args *args_ptr, uint64_t *cmd) {
|
|
||||||
|
|
||||||
uint64_t curr_tail = *(
|
|
||||||
(uint64_t *)args_ptr->iommu_mmio_va +
|
|
||||||
IOMMU_MMIO_CB_TAIL / 8);
|
|
||||||
uint64_t next_tail = (curr_tail + IOMMU_CMD_ENTRY_SIZE) & IOMMU_CB_MASK;
|
|
||||||
|
|
||||||
uint64_t *cmd_buffer =
|
|
||||||
(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;
|
|
||||||
|
|
||||||
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))
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
__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};
|
|
||||||
cmd[0] = (uint32_t)(pa & 0xFFFFFFF8) | 0x05;
|
|
||||||
cmd[1] = ((uint32_t)(pa >> 32) & 0xFFFFF) | 0x10000000;
|
|
||||||
cmd[2] = (uint32_t)(val);
|
|
||||||
cmd[3] = (uint32_t)(val >> 32);
|
|
||||||
iommu_submit_cmd(args_ptr, (uint64_t *)cmd);
|
|
||||||
}
|
|
||||||
|
|
||||||
__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];
|
|
||||||
|
|
||||||
iommu_write8_pa(args_ptr, pa + 0x00,
|
|
||||||
0x0000000000000000ULL);
|
|
||||||
iommu_write8_pa(args_ptr, pa + 0x08,
|
|
||||||
0x0004000000000000ULL);
|
|
||||||
iommu_write8_pa(args_ptr, pa + 0x10,
|
|
||||||
0x000000000000000FULL);
|
|
||||||
iommu_write8_pa(args_ptr, pa + 0x58,
|
|
||||||
0x0000000000000001ULL);
|
|
||||||
iommu_write8_pa(args_ptr, pa + 0x90,
|
|
||||||
0x0000000000000000ULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
__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);
|
|
||||||
}
|
|
||||||
|
|
||||||
__attribute__((noinline, optimize("O0"))) void
|
|
||||||
tmr_write(uint64_t dmap, uint32_t addr, uint32_t val) {
|
|
||||||
*(uint32_t *)(dmap + ECAM_B0D18F2 + TMR_INDEX_OFF) = addr;
|
|
||||||
*(uint32_t *)(dmap + ECAM_B0D18F2 + TMR_DATA_OFF) = val;
|
|
||||||
}
|
|
||||||
|
|
||||||
__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) {
|
|
||||||
tmr_write(dmap, TMR_CONFIG(i), 0);
|
|
||||||
if (tmr_read(dmap, TMR_CONFIG(i)) != 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void init_global_pointers(volatile shellcode_kernel_args *args_ptr) {
|
|
||||||
|
|
||||||
memcpy(&args, (void *)args_ptr, sizeof(args));
|
|
||||||
|
|
||||||
printf = (void (*)(const char *, ...)) args.fun_printf;
|
|
||||||
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;
|
|
||||||
g_vbios = args.g_vbios;
|
|
||||||
}
|
|
||||||
@@ -4,62 +4,10 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
void (*printf)(const char *format, ...);
|
void (*printf)(const char *format, ...);
|
||||||
uint32_t (*AcpiSetFirmwareWakingVector)(uint64_t PhysicalAddress,
|
|
||||||
uint64_t PhysicalAddress64);
|
|
||||||
uint64_t (*kernel_va_to_pa)(uint64_t va);
|
|
||||||
uint32_t (*hv_iommu_set_buffers)(uint64_t cb2_pa, uint64_t cb3_pa,
|
|
||||||
uint64_t eb_pa, uint64_t unk, int *n_devices);
|
|
||||||
uint32_t (*hv_iommu_wait_completion)(void);
|
|
||||||
void (*smp_rendezvous)(void (*setup_func)(void), void (*action_func)(void),
|
void (*smp_rendezvous)(void (*setup_func)(void), void (*action_func)(void),
|
||||||
void (*teardown_func)(void), void *arg);
|
void (*teardown_func)(void), void *arg);
|
||||||
void (*smp_no_rendevous_barrier)(void);
|
void (*smp_no_rendevous_barrier)(void);
|
||||||
|
|
||||||
// We are being called instead of AcpiSetFirmwareWakingVector from
|
|
||||||
// acpi_wakeup_machdep
|
|
||||||
uint32_t main(uint64_t add1, uint64_t add2);
|
uint32_t main(uint64_t add1, uint64_t add2);
|
||||||
|
|
||||||
uint64_t rdmsr(uint32_t msr);
|
|
||||||
|
|
||||||
// tmr via ecam b0d18f2
|
|
||||||
#ifndef ECAM_B0D18F2
|
|
||||||
#define ECAM_B0D18F2 (0xF0000000ULL + 0x18ULL * 0x8000 + 2 * 0x1000)
|
|
||||||
#define TMR_INDEX_OFF 0x80
|
|
||||||
#define TMR_DATA_OFF 0x84
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// tmr layout (hardware)
|
|
||||||
#define TMR_BASE(n) ((n) * 0x10 + 0x00)
|
|
||||||
#define TMR_LIMIT(n) ((n) * 0x10 + 0x04)
|
|
||||||
#define TMR_CONFIG(n) ((n) * 0x10 + 0x08)
|
|
||||||
#define TMR_REQUESTORS(n) ((n) * 0x10 + 0x0C)
|
|
||||||
#define TMR_CFG_PERMISSIVE 0x3F07
|
|
||||||
#define MAX_TMR 22
|
|
||||||
#define MAX_SAVED_TMRS 8
|
|
||||||
|
|
||||||
uint32_t tmr_read(uint64_t dmap, uint32_t addr);
|
|
||||||
void tmr_write(uint64_t dmap, uint32_t addr, uint32_t val);
|
|
||||||
int tmr_disable(uint64_t dmap);
|
|
||||||
|
|
||||||
// Command buffer MMIO offsets
|
|
||||||
#define IOMMU_MMIO_CB_HEAD 0xa000
|
|
||||||
#define IOMMU_MMIO_CB_TAIL 0xa008
|
|
||||||
|
|
||||||
// Queue constants
|
|
||||||
#define IOMMU_CB_SIZE 0x2000
|
|
||||||
#define IOMMU_CB_MASK (IOMMU_CB_SIZE - 1)
|
|
||||||
#define IOMMU_CMD_ENTRY_SIZE 0x10
|
|
||||||
|
|
||||||
// Submit a single 16-byte command and wait for completion
|
|
||||||
void iommu_submit_cmd(volatile shellcode_kernel_args *args_ptr, uint64_t *cmd);
|
|
||||||
// Write 8 bytes to a physical address using IOMMU completion wait store
|
|
||||||
void iommu_write8_pa(volatile shellcode_kernel_args *args_ptr, uint64_t pa,
|
|
||||||
uint64_t val);
|
|
||||||
|
|
||||||
void patch_vmcb(volatile shellcode_kernel_args *args_ptr);
|
|
||||||
|
|
||||||
#define NULL (void *)0
|
|
||||||
void vmmcall_dummy(void);
|
|
||||||
void halt(void);
|
|
||||||
void init_global_pointers(volatile shellcode_kernel_args *args_ptr);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -5,12 +5,12 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint32_t fw_version;
|
uint16_t fw_version;
|
||||||
uint64_t ktext;
|
uint64_t ktext;
|
||||||
uint64_t kdata;
|
uint64_t kdata;
|
||||||
uint64_t dmap_base;
|
uint64_t dmap_base;
|
||||||
uint64_t fun_printf;
|
uint64_t fun_printf;
|
||||||
uint64_t fun_va_to_pa;
|
uint64_t fun_vtophys;
|
||||||
uint64_t fun_hv_iommu_set_buffers;
|
uint64_t fun_hv_iommu_set_buffers;
|
||||||
uint64_t fun_hv_iommu_wait_completion;
|
uint64_t fun_hv_iommu_wait_completion;
|
||||||
uint64_t fun_acpi_set_fw_waking_vector;
|
uint64_t fun_acpi_set_fw_waking_vector;
|
||||||
@@ -28,7 +28,6 @@ typedef struct {
|
|||||||
uint64_t kernel_uart_override;
|
uint64_t kernel_uart_override;
|
||||||
uint64_t hv_handle_vmexit_pa;
|
uint64_t hv_handle_vmexit_pa;
|
||||||
uint64_t hv_code_cave_pa;
|
uint64_t hv_code_cave_pa;
|
||||||
uint64_t hv_uart_override_pa;
|
|
||||||
uint64_t linux_info_va; // To relocate by kernel shellcode
|
uint64_t linux_info_va; // To relocate by kernel shellcode
|
||||||
} shellcode_kernel_args;
|
} shellcode_kernel_args;
|
||||||
|
|
||||||
|
|||||||
@@ -15,30 +15,23 @@ void memcpy(void *dest, void *src, uint64_t len) {
|
|||||||
|
|
||||||
uint64_t read_cr3(void) {
|
uint64_t read_cr3(void) {
|
||||||
uint64_t cr3;
|
uint64_t cr3;
|
||||||
__asm__ volatile("mov %%cr3, %0"
|
__asm__ volatile("mov %%cr3, %0" : "=r"(cr3) : :);
|
||||||
: "=r"(cr3)
|
|
||||||
:
|
|
||||||
:
|
|
||||||
);
|
|
||||||
return cr3;
|
return cr3;
|
||||||
}
|
}
|
||||||
|
|
||||||
// for ring0
|
uint64_t vtophys(uint64_t dmap, uint64_t va) {
|
||||||
uint64_t va_to_pa_kernel(uint64_t va) {
|
|
||||||
uint64_t cr3 = read_cr3();
|
uint64_t cr3 = read_cr3();
|
||||||
return va_to_pa_custom(va, cr3);
|
return vtophys_custom(dmap, va, cr3);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Source: PS5_kldload
|
uint64_t vtophys_custom(uint64_t dmap, uint64_t va, uint64_t cr3_custom) {
|
||||||
uint64_t va_to_pa_custom(uint64_t va, uint64_t cr3_custom) {
|
|
||||||
|
|
||||||
uint64_t table_phys = cr3_custom & 0xFFFFFFFF;
|
uint64_t table_phys = cr3_custom & 0xFFFFFFFF;
|
||||||
|
|
||||||
for (int level = 0; level < 4; level++) {
|
for (int level = 0; level < 4; level++) {
|
||||||
int shift = 39 - (level * 9);
|
int shift = 39 - (level * 9);
|
||||||
uint64_t idx = (va >> shift) & 0x1FF;
|
uint64_t idx = (va >> shift) & 0x1FF;
|
||||||
uint64_t entry;
|
uint64_t entry;
|
||||||
uint64_t entry_va = PHYS_TO_DMAP(PAGE_PA(table_phys) + idx * 8);
|
uint64_t entry_va = dmap + PAGE_PA(table_phys) + idx * 8;
|
||||||
|
|
||||||
entry = *(uint64_t *)entry_va;
|
entry = *(uint64_t *)entry_va;
|
||||||
|
|
||||||
@@ -58,10 +51,9 @@ uint64_t va_to_pa_custom(uint64_t va, uint64_t cr3_custom) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute__((noinline, optimize("O0"))) uint32_t putc_uart(uint64_t dmap,
|
uint32_t putc_uart(uint64_t dmap, uint8_t tx_byte) {
|
||||||
uint8_t tx_byte) {
|
volatile uint32_t *uart_tx = (uint32_t *)(dmap + 0xc1010104ULL);
|
||||||
volatile uint32_t *uart_tx = (uint32_t *) (dmap + 0xc1010104ULL);
|
volatile uint32_t *uart_busy = (uint32_t *)(dmap + 0xc101010cULL);
|
||||||
volatile uint32_t *uart_busy = (uint32_t *) (dmap + 0xc101010cULL);
|
|
||||||
uint64_t timeout = 0xFFFFFFFF;
|
uint64_t timeout = 0xFFFFFFFF;
|
||||||
do {
|
do {
|
||||||
timeout--;
|
timeout--;
|
||||||
@@ -75,3 +67,49 @@ __attribute__((noinline, optimize("O0"))) uint32_t putc_uart(uint64_t dmap,
|
|||||||
*uart_tx = (uint32_t)tx_byte & 0xFF;
|
*uart_tx = (uint32_t)tx_byte & 0xFF;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int puts_uart(uint64_t dmap, const uint8_t *msg) {
|
||||||
|
uint32_t max = 255;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < 255; i++) {
|
||||||
|
if (msg[i] == '\0') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (msg[i] == '\n') {
|
||||||
|
putc_uart(dmap, '\r');
|
||||||
|
}
|
||||||
|
ret = putc_uart(dmap, msg[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void activate_uart(volatile shellcode_kernel_args *args_ptr) {
|
||||||
|
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;
|
||||||
|
*override_char_va = 0x0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void halt(void) { __asm__ __volatile__("hlt"); }
|
||||||
|
|
||||||
|
void init_global_pointers(volatile shellcode_kernel_args *args_ptr) {
|
||||||
|
memcpy(&args, (void *)args_ptr, sizeof(args));
|
||||||
|
|
||||||
|
printf = (void (*)(const char *, ...))args.fun_printf;
|
||||||
|
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;
|
||||||
|
g_vbios = args.g_vbios;
|
||||||
|
}
|
||||||
|
|
||||||
|
void vmmcall_dummy(void) {
|
||||||
|
__asm__ volatile("mov $0x1, %rax \n"
|
||||||
|
"vmmcall \n"
|
||||||
|
"ret \n");
|
||||||
|
}
|
||||||
@@ -1,11 +1,18 @@
|
|||||||
#ifndef UTILS_H
|
#ifndef UTILS_H
|
||||||
#define UTILS_H
|
#define UTILS_H
|
||||||
|
#include "boot_linux.h"
|
||||||
#include "shellcode_kernel_args.h"
|
#include "shellcode_kernel_args.h"
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
extern void (*printf)(const char *format, ...);
|
extern void (*printf)(const char *format, ...);
|
||||||
uint64_t PHYS_TO_DMAP(uint64_t pa);
|
extern void (*smp_rendezvous)(void (*setup_func)(void),
|
||||||
void memcpy(void *dest, void *src, uint64_t len);
|
void (*action_func)(void),
|
||||||
|
void (*teardown_func)(void), void *arg);
|
||||||
|
extern void (*smp_no_rendevous_barrier)(void);
|
||||||
|
extern int (*transmitter_control)(int cmd, void *control);
|
||||||
|
extern int (*mp3_initialize)(int vmid);
|
||||||
|
extern int (*mp3_invoke)(int cmd_id, void *req, void *rsp);
|
||||||
|
extern uint64_t g_vbios;
|
||||||
|
|
||||||
// Defines for Page management
|
// Defines for Page management
|
||||||
enum page_bits {
|
enum page_bits {
|
||||||
@@ -36,8 +43,14 @@ enum page_bits {
|
|||||||
#define P_SIZE(l) ((l == 1) ? (1ULL << 30) : (1ULL << 21))
|
#define P_SIZE(l) ((l == 1) ? (1ULL << 30) : (1ULL << 21))
|
||||||
|
|
||||||
uint64_t read_cr3(void);
|
uint64_t read_cr3(void);
|
||||||
uint64_t va_to_pa_kernel(uint64_t va);
|
uint64_t vtophys(uint64_t dmap, uint64_t va);
|
||||||
uint64_t va_to_pa_custom(uint64_t va, uint64_t cr3_custom);
|
uint64_t vtophys_custom(uint64_t dmap, uint64_t va, uint64_t cr3_custom);
|
||||||
|
uint64_t PHYS_TO_DMAP(uint64_t pa);
|
||||||
|
void memcpy(void *dest, void *src, uint64_t len);
|
||||||
uint32_t putc_uart(uint64_t dmap, uint8_t tx_byte);
|
uint32_t putc_uart(uint64_t dmap, uint8_t tx_byte);
|
||||||
|
int puts_uart(uint64_t dmap, const uint8_t *msg);
|
||||||
|
void activate_uart(volatile shellcode_kernel_args *args_ptr);
|
||||||
|
void halt(void);
|
||||||
|
void init_global_pointers(volatile shellcode_kernel_args *args_ptr);
|
||||||
|
void vmmcall_dummy(void);
|
||||||
#endif
|
#endif
|
||||||
@@ -57,13 +57,13 @@ static int build_firmware_path(const char *boot_file_path, char *boot_dir,
|
|||||||
if (slash == NULL)
|
if (slash == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
ret = snprintf(boot_dir, boot_dir_size, "%.*s",
|
ret = snprintf(boot_dir, boot_dir_size, "%.*s", (int)(slash - boot_file_path),
|
||||||
(int)(slash - boot_file_path), boot_file_path);
|
boot_file_path);
|
||||||
if (ret < 0 || (size_t)ret >= boot_dir_size)
|
if (ret < 0 || (size_t)ret >= boot_dir_size)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
ret = snprintf(fw_path, fw_path_size, "%s/%s", boot_dir,
|
ret =
|
||||||
PS5_WIFI_FW_BOOT_PATH);
|
snprintf(fw_path, fw_path_size, "%s/%s", boot_dir, PS5_WIFI_FW_BOOT_PATH);
|
||||||
if (ret < 0 || (size_t)ret >= fw_path_size)
|
if (ret < 0 || (size_t)ret >= fw_path_size)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
|||||||
@@ -352,7 +352,7 @@ int gpu_init_internal(void) {
|
|||||||
DEBUG_PRINT("[gpu] cmd_va = 0x%lx\n", s_gpu.cmd_va);
|
DEBUG_PRINT("[gpu] cmd_va = 0x%lx\n", s_gpu.cmd_va);
|
||||||
|
|
||||||
// Step 3: Get the physical address of the victim buffer
|
// Step 3: Get the physical address of the victim buffer
|
||||||
s_gpu.victim_real_pa = va_to_pa_user(s_gpu.victim_va);
|
s_gpu.victim_real_pa = vtophys_user(s_gpu.victim_va);
|
||||||
DEBUG_PRINT("[gpu] victim_real_pa = 0x%lx\n", s_gpu.victim_real_pa);
|
DEBUG_PRINT("[gpu] victim_real_pa = 0x%lx\n", s_gpu.victim_real_pa);
|
||||||
|
|
||||||
// Step 4: Walk GPU page tables to find the PTE for the victim buffer
|
// Step 4: Walk GPU page tables to find the PTE for the victim buffer
|
||||||
@@ -413,7 +413,7 @@ int gpu_test(void) {
|
|||||||
|
|
||||||
// Test 1: Read a known kernel .data value via GPU DMA and compare
|
// Test 1: Read a known kernel .data value via GPU DMA and compare
|
||||||
uint64_t test_va = (uint64_t)KERNEL_ADDRESS_DATA_BASE;
|
uint64_t test_va = (uint64_t)KERNEL_ADDRESS_DATA_BASE;
|
||||||
uint64_t test_pa = va_to_pa_kernel(test_va);
|
uint64_t test_pa = vtophys(test_va);
|
||||||
DEBUG_PRINT("[gpu] Test target: VA=0x%lx PA=0x%lx\n", test_va, test_pa);
|
DEBUG_PRINT("[gpu] Test target: VA=0x%lx PA=0x%lx\n", test_va, test_pa);
|
||||||
|
|
||||||
uint64_t kernel_val = kernel_getlong(test_va);
|
uint64_t kernel_val = kernel_getlong(test_va);
|
||||||
@@ -430,7 +430,7 @@ int gpu_test(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Test 2: Write and read-back test
|
// Test 2: Write and read-back test
|
||||||
uint64_t test_write_pa = va_to_pa_user(s_gpu.transfer_va + 0x100000);
|
uint64_t test_write_pa = vtophys_user(s_gpu.transfer_va + 0x100000);
|
||||||
uint64_t magic = 0xDEADBEEFCAFEBABEULL;
|
uint64_t magic = 0xDEADBEEFCAFEBABEULL;
|
||||||
|
|
||||||
DEBUG_PRINT("[gpu] Write test: PA=0x%lx val=0x%lx\n", test_write_pa, magic);
|
DEBUG_PRINT("[gpu] Write test: PA=0x%lx val=0x%lx\n", test_write_pa, magic);
|
||||||
|
|||||||
@@ -80,14 +80,6 @@ no_ok:
|
|||||||
int stage2_find_vmcbs(void) {
|
int stage2_find_vmcbs(void) {
|
||||||
DEBUG_PRINT("\nHV-defeat [stage2] vmcb discovery\n");
|
DEBUG_PRINT("\nHV-defeat [stage2] vmcb discovery\n");
|
||||||
|
|
||||||
uint64_t vcpu_off = env_offset.HV_VCPU;
|
|
||||||
uint64_t stride = env_offset.HV_VCPU_CPUID;
|
|
||||||
// Testing direct VMCB on 04.03
|
|
||||||
if ((!vcpu_off || !stride) && fw < 0x0300) {
|
|
||||||
DEBUG_PRINT(" missing HV_VCPU offsets for fw 0x%04x\n", fw);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int c = 0; c < 16; c++) {
|
for (int c = 0; c < 16; c++) {
|
||||||
vmcb_pa[c] = get_vmcb(c);
|
vmcb_pa[c] = get_vmcb(c);
|
||||||
DEBUG_PRINT(" core %02d: pa=0x%016lx\n", c, vmcb_pa[c]);
|
DEBUG_PRINT(" core %02d: pa=0x%016lx\n", c, vmcb_pa[c]);
|
||||||
@@ -96,9 +88,6 @@ int stage2_find_vmcbs(void) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only valid for 3.xx and 4.xx
|
|
||||||
// 1.xx and 2.xx have dynamic page alloc for VMCB
|
|
||||||
// TODO: add 1.xx and 2.xx logic
|
|
||||||
uint64_t get_vmcb(int core) {
|
uint64_t get_vmcb(int core) {
|
||||||
switch (fw) {
|
switch (fw) {
|
||||||
case 0x0300:
|
case 0x0300:
|
||||||
@@ -123,7 +112,7 @@ int iommu_selftest(void) {
|
|||||||
DEBUG_PRINT("\n[iommu] self-test\n");
|
DEBUG_PRINT("\n[iommu] self-test\n");
|
||||||
|
|
||||||
uint64_t scratch = 0xAAAAAAAABBBBBBBBULL;
|
uint64_t scratch = 0xAAAAAAAABBBBBBBBULL;
|
||||||
uint64_t scratch_pa = va_to_pa_user((uint64_t)&scratch);
|
uint64_t scratch_pa = vtophys_user((uint64_t)&scratch);
|
||||||
|
|
||||||
if (!scratch_pa || scratch_pa >= 0x100000000ULL) {
|
if (!scratch_pa || scratch_pa >= 0x100000000ULL) {
|
||||||
DEBUG_PRINT(" bad scratch PA 0x%016lx\n", scratch_pa);
|
DEBUG_PRINT(" bad scratch PA 0x%016lx\n", scratch_pa);
|
||||||
@@ -159,16 +148,6 @@ int stage3_patch_vmcbs(void) {
|
|||||||
|
|
||||||
DEBUG_PRINT(" vmcb[%2d] patched (pa=0x%016lx)\n", i, pa);
|
DEBUG_PRINT(" vmcb[%2d] patched (pa=0x%016lx)\n", i, pa);
|
||||||
|
|
||||||
// uint64_t vmcb_00 = gpu_read_phys8(pa + 0x00);
|
|
||||||
// uint64_t vmcb_08 = gpu_read_phys8(pa + 0x08);
|
|
||||||
// uint64_t vmcb_10 = gpu_read_phys8(pa + 0x10);
|
|
||||||
// uint64_t vmcb_58 = gpu_read_phys8(pa + 0x58);
|
|
||||||
// uint64_t vmcb_90 = gpu_read_phys8(pa + 0x90);
|
|
||||||
|
|
||||||
// printf("Values read from VMCB: %016lx %016lx %016lx %016lx %016lx\n",
|
|
||||||
// vmcb_00, vmcb_08, vmcb_10, vmcb_58, vmcb_90
|
|
||||||
// );
|
|
||||||
|
|
||||||
usleep(1000);
|
usleep(1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,7 +166,6 @@ void handle_sigill(int sig) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int stage4_force_vmcb_reload(void) {
|
int stage4_force_vmcb_reload(void) {
|
||||||
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
auto old_handler = signal(SIGILL, handle_sigill);
|
auto old_handler = signal(SIGILL, handle_sigill);
|
||||||
@@ -239,27 +217,22 @@ int stage5_remove_xotext(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int stage6_kernel_pmap_invalidate_all(void) {
|
int stage6_kernel_pmap_invalidate_all(void) {
|
||||||
|
|
||||||
DEBUG_PRINT("HV-Defeat [stage6] invalidate paging entries\n");
|
DEBUG_PRINT("HV-Defeat [stage6] invalidate paging entries\n");
|
||||||
|
|
||||||
static uint64_t two_zero_pages[PAGE_SIZE * 2] = {0};
|
static uint64_t two_zero_pages[PAGE_SIZE * 2] = {0};
|
||||||
|
|
||||||
int pipe_fds[2];
|
int pipe_fds[2];
|
||||||
// set O_NONBLOCK to avoid PIPE_DIRECTW
|
|
||||||
if (pipe2(pipe_fds, O_NONBLOCK)) {
|
if (pipe2(pipe_fds, O_NONBLOCK)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// the pipe starts off as 1 page large - we need to write into the pipe so it
|
|
||||||
// will grow to BIG_PIPE_SIZE we need to make sure pmap_invalidate_all doesnt
|
|
||||||
// use the one page fast path
|
|
||||||
if (write(pipe_fds[1], two_zero_pages, PAGE_SIZE * 2) < 0) {
|
if (write(pipe_fds[1], two_zero_pages, PAGE_SIZE * 2) < 0) {
|
||||||
close(pipe_fds[0]);
|
close(pipe_fds[0]);
|
||||||
close(pipe_fds[1]);
|
close(pipe_fds[1]);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// dont need this anymore
|
|
||||||
close(pipe_fds[1]);
|
close(pipe_fds[1]);
|
||||||
|
|
||||||
uint64_t read_fd_file_data = kernel_get_proc_file(-1, pipe_fds[0]);
|
uint64_t read_fd_file_data = kernel_get_proc_file(-1, pipe_fds[0]);
|
||||||
@@ -278,17 +251,11 @@ int stage6_kernel_pmap_invalidate_all(void) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// inside pmap_remove anyvalid has to be 1 for pmap_invalidate_all to be
|
|
||||||
// called anyvalid is only set if there is at least 1 non global entry being
|
|
||||||
// removed set the first entry as non global, its being removed anyway so its
|
|
||||||
// fine (?)
|
|
||||||
if (!page_remove_global(read_fd_buffer)) {
|
if (!page_remove_global(read_fd_buffer)) {
|
||||||
close(pipe_fds[0]);
|
close(pipe_fds[0]);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// fd 0 is read end, it holds the buffer, this close is what does the
|
|
||||||
// pmap_invalidate_all because pmap == kernel_pmap, it will do invltlb_glob
|
|
||||||
close(pipe_fds[0]);
|
close(pipe_fds[0]);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -37,7 +37,6 @@ int iommu_init(void) {
|
|||||||
|
|
||||||
// Submit a single 16-byte command and wait for completion
|
// Submit a single 16-byte command and wait for completion
|
||||||
void iommu_submit_cmd(const void *cmd) {
|
void iommu_submit_cmd(const void *cmd) {
|
||||||
|
|
||||||
if (iommu->mmio_va == 0)
|
if (iommu->mmio_va == 0)
|
||||||
iommu_init();
|
iommu_init();
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include "loader.h"
|
#include "loader.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "firmware.h"
|
#include "firmware.h"
|
||||||
|
#include "linux.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
@@ -21,18 +22,16 @@
|
|||||||
#define MINI_SYSCORE_PID 1
|
#define MINI_SYSCORE_PID 1
|
||||||
|
|
||||||
uint64_t alloc_page(void) {
|
uint64_t alloc_page(void) {
|
||||||
|
|
||||||
void *page = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE,
|
void *page = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE,
|
||||||
MAP_SHARED | MAP_ANONYMOUS, -1, 0);
|
MAP_SHARED | MAP_ANONYMOUS, -1, 0);
|
||||||
|
|
||||||
// Fault it to force physical allocation
|
// Fault it to force physical allocation
|
||||||
*(uint8_t *)page = 0;
|
*(uint8_t *)page = 0;
|
||||||
|
|
||||||
return va_to_pa_user((uintptr_t)page);
|
return vtophys_user((uintptr_t)page);
|
||||||
}
|
}
|
||||||
|
|
||||||
void install_page(uintptr_t pml4, vm_offset_t va, vm_paddr_t pa,
|
void install_page(uintptr_t pml4, vm_offset_t va, vm_paddr_t pa, int bits) {
|
||||||
int bits) {
|
|
||||||
uint64_t entry;
|
uint64_t entry;
|
||||||
|
|
||||||
uintptr_t pml4e = pml4 + pmap_pml4e_index(va) * 8;
|
uintptr_t pml4e = pml4 + pmap_pml4e_index(va) * 8;
|
||||||
@@ -65,7 +64,6 @@ void install_page(uintptr_t pml4, vm_offset_t va, vm_paddr_t pa,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void pte_store(uintptr_t ptep, uint64_t pte) {
|
void pte_store(uintptr_t ptep, uint64_t pte) {
|
||||||
|
|
||||||
static_assert((PAGE_SIZE % 0x1000) == 0,
|
static_assert((PAGE_SIZE % 0x1000) == 0,
|
||||||
"PAGE_SIZE should be a multiple of 0x1000");
|
"PAGE_SIZE should be a multiple of 0x1000");
|
||||||
|
|
||||||
@@ -100,18 +98,21 @@ static const char *get_overridden_filename(const char *filename) {
|
|||||||
for (char *p = overrides_start; p < overrides_end; p++)
|
for (char *p = overrides_start; p < overrides_end; p++)
|
||||||
if (*p == '\n')
|
if (*p == '\n')
|
||||||
*p = 0;
|
*p = 0;
|
||||||
overrides_start[size] = 0; // make sure the last string is null-terminated
|
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
|
if (state ==
|
||||||
|
1) // overrides not found, or unreadable, or currently looking for it
|
||||||
return filename;
|
return filename;
|
||||||
|
|
||||||
size_t needle_len = strlen(filename);
|
size_t needle_len = strlen(filename);
|
||||||
for (const char *p = overrides_start; p < overrides_end;) {
|
for (const char *p = overrides_start; p < overrides_end;) {
|
||||||
size_t haystack_len = strlen(p);
|
size_t haystack_len = strlen(p);
|
||||||
if (haystack_len > needle_len && !strncmp(p, filename, needle_len) && p[needle_len] == '=')
|
if (haystack_len > needle_len && !strncmp(p, filename, needle_len) &&
|
||||||
|
p[needle_len] == '=')
|
||||||
return p + needle_len + 1;
|
return p + needle_len + 1;
|
||||||
p += haystack_len + 1;
|
p += haystack_len + 1;
|
||||||
}
|
}
|
||||||
@@ -121,7 +122,6 @@ static const char *get_overridden_filename(const char *filename) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
long find_and_get_size_of_file(const char *filename, char *found_path) {
|
long find_and_get_size_of_file(const char *filename, char *found_path) {
|
||||||
|
|
||||||
char full_path[256];
|
char full_path[256];
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
||||||
@@ -129,7 +129,6 @@ long find_and_get_size_of_file(const char *filename, char *found_path) {
|
|||||||
int num_paths = sizeof(file_paths) / sizeof(file_paths[0]);
|
int num_paths = sizeof(file_paths) / sizeof(file_paths[0]);
|
||||||
|
|
||||||
for (int i = 0; i < num_paths; i++) {
|
for (int i = 0; i < num_paths; i++) {
|
||||||
|
|
||||||
snprintf(full_path, sizeof(full_path), "%s%s", file_paths[i], filename);
|
snprintf(full_path, sizeof(full_path), "%s%s", file_paths[i], filename);
|
||||||
|
|
||||||
if (stat(full_path, &st) == 0) {
|
if (stat(full_path, &st) == 0) {
|
||||||
@@ -149,7 +148,6 @@ int find_and_read_file(const char *filename, void *buf, size_t bufsize) {
|
|||||||
int num_paths = sizeof(file_paths) / sizeof(file_paths[0]);
|
int num_paths = sizeof(file_paths) / sizeof(file_paths[0]);
|
||||||
|
|
||||||
for (int i = 0; i < num_paths; i++) {
|
for (int i = 0; i < num_paths; i++) {
|
||||||
|
|
||||||
snprintf(full_path, sizeof(full_path), "%s%s", file_paths[i], filename);
|
snprintf(full_path, sizeof(full_path), "%s%s", file_paths[i], filename);
|
||||||
|
|
||||||
if (stat(full_path, &st) == 0) {
|
if (stat(full_path, &st) == 0) {
|
||||||
@@ -229,7 +227,8 @@ int fetch_linux(struct linux_info *info) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (dump_device_firmwares(initrd_path) < 0) {
|
if (dump_device_firmwares(initrd_path) < 0) {
|
||||||
notify("Something went wrong while dumping device firmwares - Continuing\n");
|
notify(
|
||||||
|
"Something went wrong while dumping device firmwares - Continuing\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t vram_size;
|
size_t vram_size;
|
||||||
@@ -266,7 +265,7 @@ int fetch_linux(struct linux_info *info) {
|
|||||||
info->initrd_size = initrd_size;
|
info->initrd_size = initrd_size;
|
||||||
info->vram_size = vram_size;
|
info->vram_size = vram_size;
|
||||||
strcpy(info->cmdline, cmdline);
|
strcpy(info->cmdline, cmdline);
|
||||||
info->kit_type = (int) get_kit_type();
|
info->kit_type = (int)get_kit_type();
|
||||||
|
|
||||||
uint64_t page = alloc_page();
|
uint64_t page = alloc_page();
|
||||||
kwrite(pa_to_dmap(page), info, sizeof(struct linux_info));
|
kwrite(pa_to_dmap(page), info, sizeof(struct linux_info));
|
||||||
@@ -274,12 +273,12 @@ int fetch_linux(struct linux_info *info) {
|
|||||||
|
|
||||||
for (int i = 0; i < bzimage_size; i += PAGE_SIZE) {
|
for (int i = 0; i < bzimage_size; i += PAGE_SIZE) {
|
||||||
install_page(syscore_pml4, info->bzimage + i,
|
install_page(syscore_pml4, info->bzimage + i,
|
||||||
va_to_pa_user((uintptr_t)bzimage + i), 0);
|
vtophys_user((uintptr_t)bzimage + i), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < initrd_size; i += PAGE_SIZE) {
|
for (int i = 0; i < initrd_size; i += PAGE_SIZE) {
|
||||||
install_page(syscore_pml4, info->initrd + i,
|
install_page(syscore_pml4, info->initrd + i,
|
||||||
va_to_pa_user((uintptr_t)initrd + i), 0);
|
vtophys_user((uintptr_t)initrd + i), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
#include <unistd.h>
|
|
||||||
#include "utils.h"
|
|
||||||
#include "hv_defeat.h"
|
#include "hv_defeat.h"
|
||||||
#include "prepare_resume.h"
|
|
||||||
#include "loader.h"
|
#include "loader.h"
|
||||||
|
#include "prepare_resume.h"
|
||||||
|
#include "utils.h"
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
|
|
||||||
if (setup_env()) {
|
if (setup_env()) {
|
||||||
notify("Something went wrong while initiating.\nPlease make sure your fw "
|
notify("Something went wrong while initiating.\nPlease make sure your fw "
|
||||||
"is supported.");
|
"is supported.");
|
||||||
@@ -27,7 +26,8 @@ int main(void) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
notify("Finished preparation. Going to rest mode in 5 seconds.\nPlease wait for the orange light to stop "
|
notify("Finished preparation. Going to rest mode in 5 seconds.\nPlease wait "
|
||||||
|
"for the orange light to stop "
|
||||||
"blinking and then wakeup to Linux :)\n");
|
"blinking and then wakeup to Linux :)\n");
|
||||||
|
|
||||||
sleep(5);
|
sleep(5);
|
||||||
|
|||||||
180
source/offsets.c
180
source/offsets.c
@@ -1,307 +1,235 @@
|
|||||||
#include "offsets.h"
|
#include "offsets.h"
|
||||||
|
|
||||||
offset_list off_0300 = {
|
offset_list off_0300 = {
|
||||||
.PMAP_STORE = 0x3D8E218,
|
|
||||||
.HV_VCPU_ARRAY_OFF = 0x5D0,
|
|
||||||
.HV_VCPU_STRIDE = 0x320,
|
|
||||||
.HV_VCPU_VMCB_PTR = 0x08,
|
|
||||||
.KERNEL_CODE_CAVE = 0x500,
|
|
||||||
.KERNEL_DATA_CAVE = 0xC01300,
|
|
||||||
.IOMMU_SOFTC = 0x33175E0,
|
.IOMMU_SOFTC = 0x33175E0,
|
||||||
.VMSPACE_VM_VMID = 0x1E4,
|
.VMSPACE_VM_VMID = 0x1E4,
|
||||||
.VMSPACE_VM_PMAP = 0x1D0,
|
.VMSPACE_VM_PMAP = 0x1D0,
|
||||||
.PMAP_PM_PML4 = 0x020,
|
|
||||||
.PMAP_PM_CR3 = 0x028,
|
|
||||||
.DATA_BASE_GVMSPACE = 0x06423F80,
|
.DATA_BASE_GVMSPACE = 0x06423F80,
|
||||||
.HOOK_ACPI_WAKEUP_MACHDEP = 0x0390E73,
|
.HOOK_ACPI_WAKEUP_MACHDEP = 0x0390E73,
|
||||||
|
.KERNEL_CODE_CAVE = 0x500,
|
||||||
|
.KERNEL_DATA_CAVE = 0xC01300,
|
||||||
.FUN_PRINTF = 0x048B9A0,
|
.FUN_PRINTF = 0x048B9A0,
|
||||||
.FUN_VA_TO_PA = 0x0831410,
|
|
||||||
.FUN_HV_IOMMU_SET_BUFFERS = 0x0B33E20,
|
.FUN_HV_IOMMU_SET_BUFFERS = 0x0B33E20,
|
||||||
.FUN_HV_IOMM_WAIT_COMPLETION = 0x0B33D50,
|
.FUN_HV_IOMM_WAIT_COMPLETION = 0x0B33D50,
|
||||||
.FUN_SMP_RENDEZVOUS = 0x0A3E850,
|
.FUN_SMP_RENDEZVOUS = 0x0A3E850,
|
||||||
.FUN_SMP_NO_RENDEVOUS_BARRIER = 0x0287E50,
|
.FUN_SMP_NO_RENDEVOUS_BARRIER = 0x0287E50,
|
||||||
.HV_HANDLE_VMEXIT_PA = 0x6282CBCB,
|
|
||||||
.HV_CODE_CAVE_PA = 0x62806F00,
|
.HV_CODE_CAVE_PA = 0x62806F00,
|
||||||
.HV_UART_OVERRIDE_PA = 0x62800008,
|
.HV_HANDLE_VMEXIT_PA = 0x6282CBCB,
|
||||||
|
.KERNEL_UART_OVERRIDE = 0x1EB0258,
|
||||||
|
.KERNEL_DEBUG_PATCH = 0x0752460,
|
||||||
|
.KERNEL_CFI_CHECK = 0x0441DD0,
|
||||||
.G_VBIOS = 0x0734B5D0,
|
.G_VBIOS = 0x0734B5D0,
|
||||||
.FUN_TRANSMITTER_CONTROL = 0x0B2A560,
|
.FUN_TRANSMITTER_CONTROL = 0x0B2A560,
|
||||||
.FUN_MP3_INITIALIZE = 0x0953890,
|
.FUN_MP3_INITIALIZE = 0x0953890,
|
||||||
.FUN_MP3_INVOKE = 0x0952670,
|
.FUN_MP3_INVOKE = 0x0952670,
|
||||||
.KERNEL_UART_OVERRIDE = 0x1EB0258,
|
|
||||||
.KERNEL_DEBUG_PATCH = 0x0752460,
|
|
||||||
.KERNEL_CFI_CHECK = 0x0441DD0,
|
|
||||||
.PS5_WIFI_FW_OFFSET = 0x1274460,
|
.PS5_WIFI_FW_OFFSET = 0x1274460,
|
||||||
.PS5_WIFI_FW_SIZE = 492304,
|
.PS5_WIFI_FW_SIZE = 492304,
|
||||||
};
|
};
|
||||||
|
|
||||||
offset_list off_0310 = {
|
offset_list off_0310 = {
|
||||||
.PMAP_STORE = 0x3D8E218,
|
|
||||||
.HV_VCPU_ARRAY_OFF = 0x5D0,
|
|
||||||
.HV_VCPU_STRIDE = 0x320,
|
|
||||||
.HV_VCPU_VMCB_PTR = 0x08,
|
|
||||||
.KERNEL_CODE_CAVE = 0x500,
|
|
||||||
.KERNEL_DATA_CAVE = 0xC01300,
|
|
||||||
.IOMMU_SOFTC = 0x33175E0,
|
.IOMMU_SOFTC = 0x33175E0,
|
||||||
.VMSPACE_VM_VMID = 0x1E4,
|
.VMSPACE_VM_VMID = 0x1E4,
|
||||||
.VMSPACE_VM_PMAP = 0x1D0,
|
.VMSPACE_VM_PMAP = 0x1D0,
|
||||||
.PMAP_PM_PML4 = 0x020,
|
|
||||||
.PMAP_PM_CR3 = 0x028,
|
|
||||||
.DATA_BASE_GVMSPACE = 0x06423F80,
|
.DATA_BASE_GVMSPACE = 0x06423F80,
|
||||||
.HOOK_ACPI_WAKEUP_MACHDEP = 0x0390EB3,
|
.HOOK_ACPI_WAKEUP_MACHDEP = 0x0390EB3,
|
||||||
|
.KERNEL_CODE_CAVE = 0x500,
|
||||||
|
.KERNEL_DATA_CAVE = 0xC01300,
|
||||||
.FUN_PRINTF = 0x048B9E0,
|
.FUN_PRINTF = 0x048B9E0,
|
||||||
.FUN_VA_TO_PA = 0x0831450,
|
|
||||||
.FUN_HV_IOMMU_SET_BUFFERS = 0x0B33E60,
|
.FUN_HV_IOMMU_SET_BUFFERS = 0x0B33E60,
|
||||||
.FUN_HV_IOMM_WAIT_COMPLETION = 0x0B33D90,
|
.FUN_HV_IOMM_WAIT_COMPLETION = 0x0B33D90,
|
||||||
.FUN_SMP_RENDEZVOUS = 0x0A3E890,
|
.FUN_SMP_RENDEZVOUS = 0x0A3E890,
|
||||||
.FUN_SMP_NO_RENDEVOUS_BARRIER = 0x0287EA8,
|
.FUN_SMP_NO_RENDEVOUS_BARRIER = 0x0287EA8,
|
||||||
.HV_HANDLE_VMEXIT_PA = 0x6282CBCB,
|
|
||||||
.HV_CODE_CAVE_PA = 0x62806F00,
|
.HV_CODE_CAVE_PA = 0x62806F00,
|
||||||
.HV_UART_OVERRIDE_PA = 0x62800008,
|
.HV_HANDLE_VMEXIT_PA = 0x6282CBCB,
|
||||||
|
.KERNEL_UART_OVERRIDE = 0x1EB0258,
|
||||||
|
.KERNEL_DEBUG_PATCH = 0x07524A0,
|
||||||
|
.KERNEL_CFI_CHECK = 0x0441E10,
|
||||||
.G_VBIOS = 0x0734B5D0,
|
.G_VBIOS = 0x0734B5D0,
|
||||||
.FUN_TRANSMITTER_CONTROL = 0x0B2A5A0,
|
.FUN_TRANSMITTER_CONTROL = 0x0B2A5A0,
|
||||||
.FUN_MP3_INITIALIZE = 0x09538D0,
|
.FUN_MP3_INITIALIZE = 0x09538D0,
|
||||||
.FUN_MP3_INVOKE = 0x09526B0,
|
.FUN_MP3_INVOKE = 0x09526B0,
|
||||||
.KERNEL_UART_OVERRIDE = 0x1EB0258,
|
|
||||||
.KERNEL_DEBUG_PATCH = 0x07524A0,
|
|
||||||
.KERNEL_CFI_CHECK = 0x0441E10,
|
|
||||||
.PS5_WIFI_FW_OFFSET = 0x1274490,
|
.PS5_WIFI_FW_OFFSET = 0x1274490,
|
||||||
.PS5_WIFI_FW_SIZE = 492304,
|
.PS5_WIFI_FW_SIZE = 492304,
|
||||||
};
|
};
|
||||||
|
|
||||||
offset_list off_0320 = {
|
offset_list off_0320 = {
|
||||||
.PMAP_STORE = 0x3D8E218,
|
|
||||||
.HV_VCPU_ARRAY_OFF = 0x5D0,
|
|
||||||
.HV_VCPU_STRIDE = 0x320,
|
|
||||||
.HV_VCPU_VMCB_PTR = 0x08,
|
|
||||||
.KERNEL_CODE_CAVE = 0x500,
|
|
||||||
.KERNEL_DATA_CAVE = 0xC01300,
|
|
||||||
.IOMMU_SOFTC = 0x33175E0,
|
.IOMMU_SOFTC = 0x33175E0,
|
||||||
.VMSPACE_VM_VMID = 0x1E4,
|
.VMSPACE_VM_VMID = 0x1E4,
|
||||||
.VMSPACE_VM_PMAP = 0x1D0,
|
.VMSPACE_VM_PMAP = 0x1D0,
|
||||||
.PMAP_PM_PML4 = 0x020,
|
|
||||||
.PMAP_PM_CR3 = 0x028,
|
|
||||||
.DATA_BASE_GVMSPACE = 0x06423F80,
|
.DATA_BASE_GVMSPACE = 0x06423F80,
|
||||||
.HOOK_ACPI_WAKEUP_MACHDEP = 0x391203,
|
.HOOK_ACPI_WAKEUP_MACHDEP = 0x391203,
|
||||||
|
.KERNEL_CODE_CAVE = 0x500,
|
||||||
|
.KERNEL_DATA_CAVE = 0xC01300,
|
||||||
.FUN_PRINTF = 0x48BD30,
|
.FUN_PRINTF = 0x48BD30,
|
||||||
.FUN_VA_TO_PA = 0x8317A0,
|
|
||||||
.FUN_HV_IOMMU_SET_BUFFERS = 0xB34320,
|
.FUN_HV_IOMMU_SET_BUFFERS = 0xB34320,
|
||||||
.FUN_HV_IOMM_WAIT_COMPLETION = 0xB34250,
|
.FUN_HV_IOMM_WAIT_COMPLETION = 0xB34250,
|
||||||
.FUN_SMP_RENDEZVOUS = 0xA3ED50,
|
.FUN_SMP_RENDEZVOUS = 0xA3ED50,
|
||||||
.FUN_SMP_NO_RENDEVOUS_BARRIER = 0x288230,
|
.FUN_SMP_NO_RENDEVOUS_BARRIER = 0x288230,
|
||||||
.HV_HANDLE_VMEXIT_PA = 0x6282CBCB,
|
|
||||||
.HV_CODE_CAVE_PA = 0x62806F00,
|
.HV_CODE_CAVE_PA = 0x62806F00,
|
||||||
.HV_UART_OVERRIDE_PA = 0x62800008,
|
.HV_HANDLE_VMEXIT_PA = 0x6282CBCB,
|
||||||
|
.KERNEL_UART_OVERRIDE = 0x1EB0258,
|
||||||
|
.KERNEL_DEBUG_PATCH = 0x7527F0,
|
||||||
|
.KERNEL_CFI_CHECK = 0x442160,
|
||||||
.G_VBIOS = 0x734B5D0,
|
.G_VBIOS = 0x734B5D0,
|
||||||
.FUN_TRANSMITTER_CONTROL = 0xB2AA60,
|
.FUN_TRANSMITTER_CONTROL = 0xB2AA60,
|
||||||
.FUN_MP3_INITIALIZE = 0x953D30,
|
.FUN_MP3_INITIALIZE = 0x953D30,
|
||||||
.FUN_MP3_INVOKE = 0x952B10,
|
.FUN_MP3_INVOKE = 0x952B10,
|
||||||
.KERNEL_UART_OVERRIDE = 0x1EB0258,
|
|
||||||
.KERNEL_DEBUG_PATCH = 0x7527F0,
|
|
||||||
.KERNEL_CFI_CHECK = 0x442160,
|
|
||||||
.PS5_WIFI_FW_OFFSET = 0x1274550,
|
.PS5_WIFI_FW_OFFSET = 0x1274550,
|
||||||
.PS5_WIFI_FW_SIZE = 492304,
|
.PS5_WIFI_FW_SIZE = 492304,
|
||||||
};
|
};
|
||||||
|
|
||||||
offset_list off_0321 = {
|
offset_list off_0321 = {
|
||||||
.PMAP_STORE = 0x3D8E218,
|
|
||||||
.HV_VCPU_ARRAY_OFF = 0x5D0,
|
|
||||||
.HV_VCPU_STRIDE = 0x320,
|
|
||||||
.HV_VCPU_VMCB_PTR = 0x08,
|
|
||||||
.KERNEL_CODE_CAVE = 0x500,
|
|
||||||
.KERNEL_DATA_CAVE = 0xC01300,
|
|
||||||
.IOMMU_SOFTC = 0x33175E0,
|
.IOMMU_SOFTC = 0x33175E0,
|
||||||
.VMSPACE_VM_VMID = 0x1E4,
|
.VMSPACE_VM_VMID = 0x1E4,
|
||||||
.VMSPACE_VM_PMAP = 0x1D0,
|
.VMSPACE_VM_PMAP = 0x1D0,
|
||||||
.PMAP_PM_PML4 = 0x020,
|
|
||||||
.PMAP_PM_CR3 = 0x028,
|
|
||||||
.DATA_BASE_GVMSPACE = 0x06423F80,
|
.DATA_BASE_GVMSPACE = 0x06423F80,
|
||||||
.HOOK_ACPI_WAKEUP_MACHDEP = 0x391203,
|
.HOOK_ACPI_WAKEUP_MACHDEP = 0x391203,
|
||||||
|
.KERNEL_CODE_CAVE = 0x500,
|
||||||
|
.KERNEL_DATA_CAVE = 0xC01300,
|
||||||
.FUN_PRINTF = 0x48BD30,
|
.FUN_PRINTF = 0x48BD30,
|
||||||
.FUN_VA_TO_PA = 0x8317A0,
|
|
||||||
.FUN_HV_IOMMU_SET_BUFFERS = 0xB34320,
|
.FUN_HV_IOMMU_SET_BUFFERS = 0xB34320,
|
||||||
.FUN_HV_IOMM_WAIT_COMPLETION = 0xB34250,
|
.FUN_HV_IOMM_WAIT_COMPLETION = 0xB34250,
|
||||||
.FUN_SMP_RENDEZVOUS = 0xA3ED50,
|
.FUN_SMP_RENDEZVOUS = 0xA3ED50,
|
||||||
.FUN_SMP_NO_RENDEVOUS_BARRIER = 0x288250,
|
.FUN_SMP_NO_RENDEVOUS_BARRIER = 0x288250,
|
||||||
.HV_HANDLE_VMEXIT_PA = 0x6282CBCB,
|
|
||||||
.HV_CODE_CAVE_PA = 0x62806F00,
|
.HV_CODE_CAVE_PA = 0x62806F00,
|
||||||
.HV_UART_OVERRIDE_PA = 0x62800008,
|
.HV_HANDLE_VMEXIT_PA = 0x6282CBCB,
|
||||||
|
.KERNEL_UART_OVERRIDE = 0x1EB0258,
|
||||||
|
.KERNEL_DEBUG_PATCH = 0x7527F0,
|
||||||
|
.KERNEL_CFI_CHECK = 0x442160,
|
||||||
.G_VBIOS = 0x734B5D0,
|
.G_VBIOS = 0x734B5D0,
|
||||||
.FUN_TRANSMITTER_CONTROL = 0xB2AA60,
|
.FUN_TRANSMITTER_CONTROL = 0xB2AA60,
|
||||||
.FUN_MP3_INITIALIZE = 0x953D30,
|
.FUN_MP3_INITIALIZE = 0x953D30,
|
||||||
.FUN_MP3_INVOKE = 0x952B10,
|
.FUN_MP3_INVOKE = 0x952B10,
|
||||||
.KERNEL_UART_OVERRIDE = 0x1EB0258,
|
|
||||||
.KERNEL_DEBUG_PATCH = 0x7527F0,
|
|
||||||
.KERNEL_CFI_CHECK = 0x442160,
|
|
||||||
.PS5_WIFI_FW_OFFSET = 0x1274550,
|
.PS5_WIFI_FW_OFFSET = 0x1274550,
|
||||||
.PS5_WIFI_FW_SIZE = 492304,
|
.PS5_WIFI_FW_SIZE = 492304,
|
||||||
};
|
};
|
||||||
|
|
||||||
offset_list off_0400 = {
|
offset_list off_0400 = {
|
||||||
.PMAP_STORE = 0x3E57A78,
|
|
||||||
.HV_VCPU_ARRAY_OFF = 0x5D0,
|
|
||||||
.HV_VCPU_STRIDE = 0x320,
|
|
||||||
.HV_VCPU_VMCB_PTR = 0x08,
|
|
||||||
.KERNEL_CODE_CAVE = 0x500,
|
|
||||||
.KERNEL_DATA_CAVE = 0xC01300,
|
|
||||||
.IOMMU_SOFTC = 0x33C7680,
|
.IOMMU_SOFTC = 0x33C7680,
|
||||||
.VMSPACE_VM_VMID = 0x1E4,
|
.VMSPACE_VM_VMID = 0x1E4,
|
||||||
.VMSPACE_VM_PMAP = 0x1D0,
|
.VMSPACE_VM_PMAP = 0x1D0,
|
||||||
.PMAP_PM_PML4 = 0x020,
|
|
||||||
.PMAP_PM_CR3 = 0x028,
|
|
||||||
.DATA_BASE_GVMSPACE = 0x064C3F80,
|
.DATA_BASE_GVMSPACE = 0x064C3F80,
|
||||||
.HOOK_ACPI_WAKEUP_MACHDEP = 0x3A7613,
|
.HOOK_ACPI_WAKEUP_MACHDEP = 0x3A7613,
|
||||||
.FUN_PRINTF = 0x4A3240,
|
.FUN_PRINTF = 0x4A3240,
|
||||||
.FUN_VA_TO_PA = 0x85ADC0,
|
.KERNEL_CODE_CAVE = 0x500,
|
||||||
|
.KERNEL_DATA_CAVE = 0xC01300,
|
||||||
.FUN_HV_IOMMU_SET_BUFFERS = 0xB638F0,
|
.FUN_HV_IOMMU_SET_BUFFERS = 0xB638F0,
|
||||||
.FUN_HV_IOMM_WAIT_COMPLETION = 0xB63830,
|
.FUN_HV_IOMM_WAIT_COMPLETION = 0xB63830,
|
||||||
.FUN_SMP_RENDEZVOUS = 0xA6C920,
|
.FUN_SMP_RENDEZVOUS = 0xA6C920,
|
||||||
.FUN_SMP_NO_RENDEVOUS_BARRIER = 0x295488,
|
.FUN_SMP_NO_RENDEVOUS_BARRIER = 0x295488,
|
||||||
.HV_HANDLE_VMEXIT_PA = 0x6282B45D,
|
|
||||||
.HV_CODE_CAVE_PA = 0x62806F00,
|
.HV_CODE_CAVE_PA = 0x62806F00,
|
||||||
.HV_UART_OVERRIDE_PA = 0x62800008,
|
.HV_HANDLE_VMEXIT_PA = 0x6282B45D,
|
||||||
|
.KERNEL_UART_OVERRIDE = 0x1F522A8,
|
||||||
|
.KERNEL_DEBUG_PATCH = 0x77DA70,
|
||||||
|
.KERNEL_CFI_CHECK = 0x45A170,
|
||||||
.G_VBIOS = 0x72B7630,
|
.G_VBIOS = 0x72B7630,
|
||||||
.FUN_TRANSMITTER_CONTROL = 0xB5AD50,
|
.FUN_TRANSMITTER_CONTROL = 0xB5AD50,
|
||||||
.FUN_MP3_INITIALIZE = 0x9805C0,
|
.FUN_MP3_INITIALIZE = 0x9805C0,
|
||||||
.FUN_MP3_INVOKE = 0x97F3E0,
|
.FUN_MP3_INVOKE = 0x97F3E0,
|
||||||
.KERNEL_UART_OVERRIDE = 0x1F522A8,
|
|
||||||
.KERNEL_DEBUG_PATCH = 0x77DA70,
|
|
||||||
.KERNEL_CFI_CHECK = 0x45A170,
|
|
||||||
.PS5_WIFI_FW_OFFSET = 0x1392FB0,
|
.PS5_WIFI_FW_OFFSET = 0x1392FB0,
|
||||||
.PS5_WIFI_FW_SIZE = 493000,
|
.PS5_WIFI_FW_SIZE = 493000,
|
||||||
};
|
};
|
||||||
|
|
||||||
offset_list off_0402 = {
|
offset_list off_0402 = {
|
||||||
.PMAP_STORE = 0x3E57A78,
|
|
||||||
.HV_VCPU_ARRAY_OFF = 0x5D0,
|
|
||||||
.HV_VCPU_STRIDE = 0x320,
|
|
||||||
.HV_VCPU_VMCB_PTR = 0x08,
|
|
||||||
.KERNEL_CODE_CAVE = 0x500,
|
|
||||||
.KERNEL_DATA_CAVE = 0xC01300,
|
|
||||||
.IOMMU_SOFTC = 0x33C7680,
|
.IOMMU_SOFTC = 0x33C7680,
|
||||||
.VMSPACE_VM_VMID = 0x1E4,
|
.VMSPACE_VM_VMID = 0x1E4,
|
||||||
.VMSPACE_VM_PMAP = 0x1D0,
|
.VMSPACE_VM_PMAP = 0x1D0,
|
||||||
.PMAP_PM_PML4 = 0x020,
|
|
||||||
.PMAP_PM_CR3 = 0x028,
|
|
||||||
.DATA_BASE_GVMSPACE = 0x064C3F80,
|
.DATA_BASE_GVMSPACE = 0x064C3F80,
|
||||||
.HOOK_ACPI_WAKEUP_MACHDEP = 0x3A7613,
|
.HOOK_ACPI_WAKEUP_MACHDEP = 0x3A7613,
|
||||||
|
.KERNEL_CODE_CAVE = 0x500,
|
||||||
|
.KERNEL_DATA_CAVE = 0xC01300,
|
||||||
.FUN_PRINTF = 0x4A3240,
|
.FUN_PRINTF = 0x4A3240,
|
||||||
.FUN_VA_TO_PA = 0x85AE10,
|
|
||||||
.FUN_HV_IOMMU_SET_BUFFERS = 0xB63950,
|
.FUN_HV_IOMMU_SET_BUFFERS = 0xB63950,
|
||||||
.FUN_HV_IOMM_WAIT_COMPLETION = 0xB63890,
|
.FUN_HV_IOMM_WAIT_COMPLETION = 0xB63890,
|
||||||
.FUN_SMP_RENDEZVOUS = 0xA6C970,
|
.FUN_SMP_RENDEZVOUS = 0xA6C970,
|
||||||
.FUN_SMP_NO_RENDEVOUS_BARRIER = 0x29A018,
|
.FUN_SMP_NO_RENDEVOUS_BARRIER = 0x29A018,
|
||||||
.HV_HANDLE_VMEXIT_PA = 0x6282B45D,
|
|
||||||
.HV_CODE_CAVE_PA = 0x62806F00,
|
.HV_CODE_CAVE_PA = 0x62806F00,
|
||||||
.HV_UART_OVERRIDE_PA = 0x62800008,
|
.HV_HANDLE_VMEXIT_PA = 0x6282B45D,
|
||||||
|
.KERNEL_UART_OVERRIDE = 0x1F522A8,
|
||||||
|
.KERNEL_DEBUG_PATCH = 0x77DAC0,
|
||||||
|
.KERNEL_CFI_CHECK = 0x45A170,
|
||||||
.G_VBIOS = 0x72B7630,
|
.G_VBIOS = 0x72B7630,
|
||||||
.FUN_TRANSMITTER_CONTROL = 0xB5ADA0,
|
.FUN_TRANSMITTER_CONTROL = 0xB5ADA0,
|
||||||
.FUN_MP3_INITIALIZE = 0x980610,
|
.FUN_MP3_INITIALIZE = 0x980610,
|
||||||
.FUN_MP3_INVOKE = 0x97F430,
|
.FUN_MP3_INVOKE = 0x97F430,
|
||||||
.KERNEL_UART_OVERRIDE = 0x1F522A8,
|
|
||||||
.KERNEL_DEBUG_PATCH = 0x77DAC0,
|
|
||||||
.KERNEL_CFI_CHECK = 0x45A170,
|
|
||||||
.PS5_WIFI_FW_OFFSET = 0x1392FB0,
|
.PS5_WIFI_FW_OFFSET = 0x1392FB0,
|
||||||
.PS5_WIFI_FW_SIZE = 493000,
|
.PS5_WIFI_FW_SIZE = 493000,
|
||||||
};
|
};
|
||||||
|
|
||||||
offset_list off_0403 = {
|
offset_list off_0403 = {
|
||||||
.PMAP_STORE = 0x3E57A78,
|
|
||||||
.HV_VCPU_ARRAY_OFF = 0x5D0,
|
|
||||||
.HV_VCPU_STRIDE = 0x320,
|
|
||||||
.HV_VCPU_VMCB_PTR = 0x08,
|
|
||||||
.KERNEL_CODE_CAVE = 0x500,
|
|
||||||
.KERNEL_DATA_CAVE = 0xC01300,
|
|
||||||
.IOMMU_SOFTC = 0x33C7680,
|
.IOMMU_SOFTC = 0x33C7680,
|
||||||
.VMSPACE_VM_VMID = 0x1E4,
|
.VMSPACE_VM_VMID = 0x1E4,
|
||||||
.VMSPACE_VM_PMAP = 0x1D0,
|
.VMSPACE_VM_PMAP = 0x1D0,
|
||||||
.PMAP_PM_PML4 = 0x020,
|
|
||||||
.PMAP_PM_CR3 = 0x028,
|
|
||||||
.DATA_BASE_GVMSPACE = 0x064C3F80,
|
.DATA_BASE_GVMSPACE = 0x064C3F80,
|
||||||
.HOOK_ACPI_WAKEUP_MACHDEP = 0x3A7613,
|
.HOOK_ACPI_WAKEUP_MACHDEP = 0x3A7613,
|
||||||
|
.KERNEL_CODE_CAVE = 0x500,
|
||||||
|
.KERNEL_DATA_CAVE = 0xC01300,
|
||||||
.FUN_PRINTF = 0x4A3240,
|
.FUN_PRINTF = 0x4A3240,
|
||||||
.FUN_VA_TO_PA = 0x85AEA0,
|
|
||||||
.FUN_HV_IOMMU_SET_BUFFERS = 0xB639F0,
|
.FUN_HV_IOMMU_SET_BUFFERS = 0xB639F0,
|
||||||
.FUN_HV_IOMM_WAIT_COMPLETION = 0xB63930,
|
.FUN_HV_IOMM_WAIT_COMPLETION = 0xB63930,
|
||||||
.FUN_SMP_RENDEZVOUS = 0xA6CA00,
|
.FUN_SMP_RENDEZVOUS = 0xA6CA00,
|
||||||
.FUN_SMP_NO_RENDEVOUS_BARRIER = 0x299F20,
|
.FUN_SMP_NO_RENDEVOUS_BARRIER = 0x299F20,
|
||||||
.HV_HANDLE_VMEXIT_PA = 0x6282B45D,
|
|
||||||
.HV_CODE_CAVE_PA = 0x62806F00,
|
.HV_CODE_CAVE_PA = 0x62806F00,
|
||||||
.HV_UART_OVERRIDE_PA = 0x62800008,
|
.HV_HANDLE_VMEXIT_PA = 0x6282B45D,
|
||||||
|
.KERNEL_UART_OVERRIDE = 0x1F522A8,
|
||||||
|
.KERNEL_DEBUG_PATCH = 0x77DB50,
|
||||||
|
.KERNEL_CFI_CHECK = 0x45A170,
|
||||||
.G_VBIOS = 0x72B7630,
|
.G_VBIOS = 0x72B7630,
|
||||||
.FUN_TRANSMITTER_CONTROL = 0xB5AE30,
|
.FUN_TRANSMITTER_CONTROL = 0xB5AE30,
|
||||||
.FUN_MP3_INITIALIZE = 0x9806A0,
|
.FUN_MP3_INITIALIZE = 0x9806A0,
|
||||||
.FUN_MP3_INVOKE = 0x97F4C0,
|
.FUN_MP3_INVOKE = 0x97F4C0,
|
||||||
.KERNEL_UART_OVERRIDE = 0x1F522A8,
|
|
||||||
.KERNEL_DEBUG_PATCH = 0x77DB50,
|
|
||||||
.KERNEL_CFI_CHECK = 0x45A170,
|
|
||||||
.PS5_WIFI_FW_OFFSET = 0x1392FB0,
|
.PS5_WIFI_FW_OFFSET = 0x1392FB0,
|
||||||
.PS5_WIFI_FW_SIZE = 493000,
|
.PS5_WIFI_FW_SIZE = 493000,
|
||||||
};
|
};
|
||||||
|
|
||||||
offset_list off_0450 = {
|
offset_list off_0450 = {
|
||||||
.PMAP_STORE = 0x3E57A78,
|
|
||||||
.HV_VCPU_ARRAY_OFF = 0x5D0,
|
|
||||||
.HV_VCPU_STRIDE = 0x320,
|
|
||||||
.HV_VCPU_VMCB_PTR = 0x08,
|
|
||||||
.KERNEL_CODE_CAVE = 0x500,
|
|
||||||
.KERNEL_DATA_CAVE = 0xC01300,
|
|
||||||
.IOMMU_SOFTC = 0x33C7680,
|
.IOMMU_SOFTC = 0x33C7680,
|
||||||
.VMSPACE_VM_VMID = 0x1E4,
|
.VMSPACE_VM_VMID = 0x1E4,
|
||||||
.VMSPACE_VM_PMAP = 0x1D0,
|
.VMSPACE_VM_PMAP = 0x1D0,
|
||||||
.PMAP_PM_PML4 = 0x020,
|
|
||||||
.PMAP_PM_CR3 = 0x028,
|
|
||||||
.DATA_BASE_GVMSPACE = 0x064C3F80,
|
.DATA_BASE_GVMSPACE = 0x064C3F80,
|
||||||
.HOOK_ACPI_WAKEUP_MACHDEP = 0x03A75E3,
|
.HOOK_ACPI_WAKEUP_MACHDEP = 0x03A75E3,
|
||||||
|
.KERNEL_CODE_CAVE = 0x500,
|
||||||
|
.KERNEL_DATA_CAVE = 0xC01300,
|
||||||
.FUN_PRINTF = 0x04A3270,
|
.FUN_PRINTF = 0x04A3270,
|
||||||
.FUN_VA_TO_PA = 0x85AFF0,
|
|
||||||
.FUN_HV_IOMMU_SET_BUFFERS = 0xB63BB0,
|
.FUN_HV_IOMMU_SET_BUFFERS = 0xB63BB0,
|
||||||
.FUN_HV_IOMM_WAIT_COMPLETION = 0xB63AF0,
|
.FUN_HV_IOMM_WAIT_COMPLETION = 0xB63AF0,
|
||||||
.FUN_SMP_RENDEZVOUS = 0xA6CBB0,
|
.FUN_SMP_RENDEZVOUS = 0xA6CBB0,
|
||||||
.FUN_SMP_NO_RENDEVOUS_BARRIER = 0x299FC0,
|
.FUN_SMP_NO_RENDEVOUS_BARRIER = 0x299FC0,
|
||||||
.HV_HANDLE_VMEXIT_PA = 0x6282B45D,
|
|
||||||
.HV_CODE_CAVE_PA = 0x62806F00,
|
.HV_CODE_CAVE_PA = 0x62806F00,
|
||||||
.HV_UART_OVERRIDE_PA = 0x62800008,
|
.HV_HANDLE_VMEXIT_PA = 0x6282B45D,
|
||||||
|
.KERNEL_UART_OVERRIDE = 0x1F522A8,
|
||||||
|
.KERNEL_DEBUG_PATCH = 0x77DC80,
|
||||||
|
.KERNEL_CFI_CHECK = 0x45A1A0,
|
||||||
.G_VBIOS = 0x72B7630,
|
.G_VBIOS = 0x72B7630,
|
||||||
.FUN_TRANSMITTER_CONTROL = 0xB5AFF0,
|
.FUN_TRANSMITTER_CONTROL = 0xB5AFF0,
|
||||||
.FUN_MP3_INITIALIZE = 0x980850,
|
.FUN_MP3_INITIALIZE = 0x980850,
|
||||||
.FUN_MP3_INVOKE = 0x97F670,
|
.FUN_MP3_INVOKE = 0x97F670,
|
||||||
.KERNEL_UART_OVERRIDE = 0x1F522A8,
|
|
||||||
.KERNEL_DEBUG_PATCH = 0x77DC80,
|
|
||||||
.KERNEL_CFI_CHECK = 0x45A1A0,
|
|
||||||
.PS5_WIFI_FW_OFFSET = 0x1392FC0,
|
.PS5_WIFI_FW_OFFSET = 0x1392FC0,
|
||||||
.PS5_WIFI_FW_SIZE = 493000,
|
.PS5_WIFI_FW_SIZE = 493000,
|
||||||
};
|
};
|
||||||
|
|
||||||
offset_list off_0451 = {
|
offset_list off_0451 = {
|
||||||
.PMAP_STORE = 0x3E57A78,
|
|
||||||
.HV_VCPU_ARRAY_OFF = 0x5D0,
|
|
||||||
.HV_VCPU_STRIDE = 0x320,
|
|
||||||
.HV_VCPU_VMCB_PTR = 0x08,
|
|
||||||
.KERNEL_CODE_CAVE = 0x500,
|
|
||||||
.KERNEL_DATA_CAVE = 0xC01300,
|
|
||||||
.IOMMU_SOFTC = 0x33C7680,
|
.IOMMU_SOFTC = 0x33C7680,
|
||||||
.VMSPACE_VM_VMID = 0x1E4,
|
.VMSPACE_VM_VMID = 0x1E4,
|
||||||
.VMSPACE_VM_PMAP = 0x1D0,
|
.VMSPACE_VM_PMAP = 0x1D0,
|
||||||
.PMAP_PM_PML4 = 0x020,
|
|
||||||
.PMAP_PM_CR3 = 0x028,
|
|
||||||
.DATA_BASE_GVMSPACE = 0x64C3F80,
|
.DATA_BASE_GVMSPACE = 0x64C3F80,
|
||||||
.HOOK_ACPI_WAKEUP_MACHDEP = 0x3A75E3,
|
.HOOK_ACPI_WAKEUP_MACHDEP = 0x3A75E3,
|
||||||
|
.KERNEL_CODE_CAVE = 0x500,
|
||||||
|
.KERNEL_DATA_CAVE = 0xC01300,
|
||||||
.FUN_PRINTF = 0x4A3270,
|
.FUN_PRINTF = 0x4A3270,
|
||||||
.FUN_VA_TO_PA = 0x85B390,
|
|
||||||
.FUN_HV_IOMMU_SET_BUFFERS = 0xB63FE0,
|
.FUN_HV_IOMMU_SET_BUFFERS = 0xB63FE0,
|
||||||
.FUN_HV_IOMM_WAIT_COMPLETION = 0xB63F20,
|
.FUN_HV_IOMM_WAIT_COMPLETION = 0xB63F20,
|
||||||
.FUN_SMP_RENDEZVOUS = 0xA6CFE0,
|
.FUN_SMP_RENDEZVOUS = 0xA6CFE0,
|
||||||
.FUN_SMP_NO_RENDEVOUS_BARRIER = 0x299FA8,
|
.FUN_SMP_NO_RENDEVOUS_BARRIER = 0x299FA8,
|
||||||
.HV_HANDLE_VMEXIT_PA = 0x6282B45D,
|
|
||||||
.HV_CODE_CAVE_PA = 0x62806F00,
|
.HV_CODE_CAVE_PA = 0x62806F00,
|
||||||
.HV_UART_OVERRIDE_PA = 0x62800008,
|
.HV_HANDLE_VMEXIT_PA = 0x6282B45D,
|
||||||
|
.KERNEL_UART_OVERRIDE = 0x1F522A8,
|
||||||
|
.KERNEL_DEBUG_PATCH = 0x77DC90,
|
||||||
|
.KERNEL_CFI_CHECK = 0x45A1A0,
|
||||||
.G_VBIOS = 0x72B7630,
|
.G_VBIOS = 0x72B7630,
|
||||||
.FUN_TRANSMITTER_CONTROL = 0xB5B420,
|
.FUN_TRANSMITTER_CONTROL = 0xB5B420,
|
||||||
.FUN_MP3_INITIALIZE = 0x980BF0,
|
.FUN_MP3_INITIALIZE = 0x980BF0,
|
||||||
.FUN_MP3_INVOKE = 0x97FA10,
|
.FUN_MP3_INVOKE = 0x97FA10,
|
||||||
.KERNEL_UART_OVERRIDE = 0x1F522A8,
|
|
||||||
.KERNEL_DEBUG_PATCH = 0x77DC90,
|
|
||||||
.KERNEL_CFI_CHECK = 0x45A1A0,
|
|
||||||
.PS5_WIFI_FW_OFFSET = 0x1393000,
|
.PS5_WIFI_FW_OFFSET = 0x1393000,
|
||||||
.PS5_WIFI_FW_SIZE = 493000,
|
.PS5_WIFI_FW_SIZE = 493000,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include "prepare_resume.h"
|
#include "prepare_resume.h"
|
||||||
#include "iommu.h"
|
|
||||||
#include "../shellcode_kernel/shellcode_kernel.h"
|
#include "../shellcode_kernel/shellcode_kernel.h"
|
||||||
|
#include "../shellcode_kernel/shellcode_kernel_args.h"
|
||||||
|
#include "iommu.h"
|
||||||
#include "offsets.h"
|
#include "offsets.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
int prepare_resume(void) {
|
int prepare_resume(void) {
|
||||||
|
|
||||||
@@ -18,16 +19,13 @@ int prepare_resume(void) {
|
|||||||
return -1;
|
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_text = ktext + env_offset.KERNEL_CODE_CAVE;
|
||||||
uint64_t dest_data = ktext + env_offset.KERNEL_DATA_CAVE;
|
uint64_t dest_data = ktext + env_offset.KERNEL_DATA_CAVE;
|
||||||
|
|
||||||
kwrite_large(dest_text, shellcode_kernel_text, shellcode_kernel_text_len);
|
kwrite_large(dest_text, shellcode_kernel_bin, shellcode_kernel_bin_len);
|
||||||
prepare_sck_args(dest_data);
|
prepare_sck_args(dest_data);
|
||||||
|
|
||||||
if(update_sck_data_ptr(shellcode_kernel_text, dest_text, dest_data))
|
if (update_sck_data_ptr(shellcode_kernel_bin, dest_text, dest_data))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
hook_call_near(ktext + env_offset.HOOK_ACPI_WAKEUP_MACHDEP, dest_text);
|
hook_call_near(ktext + env_offset.HOOK_ACPI_WAKEUP_MACHDEP, dest_text);
|
||||||
@@ -38,7 +36,7 @@ int prepare_resume(void) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int update_sck_data_ptr (void* sc, uint64_t dest_text, uint64_t dest_data) {
|
int update_sck_data_ptr(void *sc, uint64_t dest_text, uint64_t dest_data) {
|
||||||
// Find the address 0x11AA11AA11AA11AA used as marker
|
// Find the address 0x11AA11AA11AA11AA used as marker
|
||||||
int offset = -1;
|
int offset = -1;
|
||||||
for (int i = 0; i < 0x40; i++) {
|
for (int i = 0; i < 0x40; i++) {
|
||||||
@@ -57,7 +55,8 @@ 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 hook_call_near(uint64_t hook, uint64_t dst) {
|
||||||
int64_t diff_call = dst - hook;
|
int64_t diff_call = dst - hook;
|
||||||
uint8_t new_instr[5]; new_instr[0] = 0xE8;
|
uint8_t new_instr[5];
|
||||||
|
new_instr[0] = 0xE8;
|
||||||
*((uint32_t *)&new_instr[1]) = (int32_t)(diff_call - 5);
|
*((uint32_t *)&new_instr[1]) = (int32_t)(diff_call - 5);
|
||||||
kernel_copyin(new_instr, hook, 5);
|
kernel_copyin(new_instr, hook, 5);
|
||||||
DEBUG_PRINT("Instruction patched\n");
|
DEBUG_PRINT("Instruction patched\n");
|
||||||
@@ -65,13 +64,12 @@ void hook_call_near(uint64_t hook, uint64_t dst) {
|
|||||||
|
|
||||||
void prepare_sck_args(uint64_t dest_data) {
|
void prepare_sck_args(uint64_t dest_data) {
|
||||||
shellcode_kernel_args args;
|
shellcode_kernel_args args;
|
||||||
args.fw_version = kernel_get_fw_version() & 0xFFFF0000;
|
args.fw_version = fw;
|
||||||
args.ktext = ktext;
|
args.ktext = ktext;
|
||||||
args.kdata = kdata;
|
args.kdata = kdata;
|
||||||
args.dmap_base = dmap;
|
args.dmap_base = dmap;
|
||||||
|
|
||||||
args.fun_printf = ktext + env_offset.FUN_PRINTF;
|
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_set_buffers = ktext + env_offset.FUN_HV_IOMMU_SET_BUFFERS;
|
||||||
args.fun_hv_iommu_wait_completion =
|
args.fun_hv_iommu_wait_completion =
|
||||||
ktext + env_offset.FUN_HV_IOMM_WAIT_COMPLETION;
|
ktext + env_offset.FUN_HV_IOMM_WAIT_COMPLETION;
|
||||||
@@ -93,7 +91,6 @@ void prepare_sck_args(uint64_t dest_data) {
|
|||||||
args.kernel_uart_override = ktext + env_offset.KERNEL_UART_OVERRIDE;
|
args.kernel_uart_override = ktext + env_offset.KERNEL_UART_OVERRIDE;
|
||||||
args.hv_handle_vmexit_pa = env_offset.HV_HANDLE_VMEXIT_PA;
|
args.hv_handle_vmexit_pa = env_offset.HV_HANDLE_VMEXIT_PA;
|
||||||
args.hv_code_cave_pa = env_offset.HV_CODE_CAVE_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;
|
args.linux_info_va = linux_i.linux_info;
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
#include "linux.h"
|
||||||
#include "offsets.h"
|
#include "offsets.h"
|
||||||
#include <ps5/kernel.h>
|
#include <ps5/kernel.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <sys/cpuset.h>
|
#include <sys/cpuset.h>
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include <sys/proc.h>
|
#include <sys/proc.h>
|
||||||
#include <unistd.h>
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
/* Global Variables */
|
/* Global Variables */
|
||||||
offset_list env_offset;
|
offset_list env_offset;
|
||||||
@@ -28,7 +29,7 @@ int setup_env(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int set_offsets(void) {
|
int set_offsets(void) {
|
||||||
fw = kernel_get_fw_version() >> 16;
|
fw = (kernel_get_fw_version() >> 0x10) & 0xFFFF;
|
||||||
if (fw == 0)
|
if (fw == 0)
|
||||||
return -1;
|
return -1;
|
||||||
switch (fw) {
|
switch (fw) {
|
||||||
@@ -70,7 +71,7 @@ int init_global_vars(void) {
|
|||||||
kdata = KERNEL_ADDRESS_DATA_BASE;
|
kdata = KERNEL_ADDRESS_DATA_BASE;
|
||||||
|
|
||||||
flat_pmap kernel_pmap;
|
flat_pmap kernel_pmap;
|
||||||
kread(ktext + env_offset.PMAP_STORE, &kernel_pmap, sizeof(kernel_pmap));
|
kread(getpmap(kernel_get_proc(0)), &kernel_pmap, sizeof(kernel_pmap));
|
||||||
if (kernel_pmap.pm_pml4 == 0 || kernel_pmap.pm_cr3 == 0)
|
if (kernel_pmap.pm_pml4 == 0 || kernel_pmap.pm_cr3 == 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
@@ -91,19 +92,18 @@ uint64_t getpmap(uint64_t proc) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// for ring3
|
// for ring3
|
||||||
uint64_t va_to_pa_user(uint64_t va) {
|
uint64_t vtophys_user(uint64_t va) {
|
||||||
uintptr_t self_pmap = getpmap(kernel_get_proc(getpid()));
|
uintptr_t self_pmap = getpmap(kernel_get_proc(getpid()));
|
||||||
uintptr_t self_pml4 = get_pml4(self_pmap);
|
uintptr_t self_pml4 = get_pml4(self_pmap);
|
||||||
uint64_t pa = va_to_pa_custom(va, self_pml4 & 0xFFFFFFFF);
|
uint64_t pa = vtophys_custom(va, self_pml4 & 0xFFFFFFFF);
|
||||||
return pa;
|
return pa;
|
||||||
}
|
}
|
||||||
|
|
||||||
// for ring0
|
// for ring0
|
||||||
uint64_t va_to_pa_kernel(uint64_t va) { return va_to_pa_custom(va, cr3); }
|
uint64_t vtophys(uint64_t va) { return vtophys_custom(va, cr3); }
|
||||||
|
|
||||||
// Source: PS5_kldload
|
// Source: PS5_kldload
|
||||||
uint64_t va_to_pa_custom(uint64_t va, uint64_t cr3_custom) {
|
uint64_t vtophys_custom(uint64_t va, uint64_t cr3_custom) {
|
||||||
|
|
||||||
uint64_t table_phys = cr3_custom & 0xFFFFFFFF;
|
uint64_t table_phys = cr3_custom & 0xFFFFFFFF;
|
||||||
|
|
||||||
for (int level = 0; level < 4; level++) {
|
for (int level = 0; level < 4; level++) {
|
||||||
@@ -133,7 +133,6 @@ uint64_t pa_to_dmap(uint64_t pa) { return dmap + pa; }
|
|||||||
|
|
||||||
// Set RW bit on all levels if needed and remove eXecute Only bit
|
// Set RW bit on all levels if needed and remove eXecute Only bit
|
||||||
void page_chain_set_rw(uint64_t va) {
|
void page_chain_set_rw(uint64_t va) {
|
||||||
|
|
||||||
uint64_t table_phys = cr3;
|
uint64_t table_phys = cr3;
|
||||||
|
|
||||||
for (int level = 0; level < 4; level++) {
|
for (int level = 0; level < 4; level++) {
|
||||||
@@ -174,7 +173,6 @@ void page_chain_set_rw(uint64_t va) {
|
|||||||
|
|
||||||
// Remove Global bit on last level
|
// Remove Global bit on last level
|
||||||
uint64_t page_remove_global(uint64_t va) {
|
uint64_t page_remove_global(uint64_t va) {
|
||||||
|
|
||||||
uint64_t table_phys = cr3;
|
uint64_t table_phys = cr3;
|
||||||
|
|
||||||
for (int level = 0; level < 4; level++) {
|
for (int level = 0; level < 4; level++) {
|
||||||
@@ -198,7 +196,6 @@ uint64_t page_remove_global(uint64_t va) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (level == 3) {
|
if (level == 3) {
|
||||||
|
|
||||||
PAGE_CLEAR_G(entry);
|
PAGE_CLEAR_G(entry);
|
||||||
kwrite(entry_va, &entry, sizeof(entry));
|
kwrite(entry_va, &entry, sizeof(entry));
|
||||||
|
|
||||||
@@ -246,8 +243,9 @@ void notify_internal(uint8_t *msg) {
|
|||||||
char msg[3075];
|
char msg[3075];
|
||||||
} req;
|
} req;
|
||||||
bzero(&req, sizeof(req));
|
bzero(&req, sizeof(req));
|
||||||
uint64_t len =
|
uint64_t len = strlen((const char *)msg) < (sizeof(req.msg) - 1)
|
||||||
strlen((const char *)msg) < (sizeof(req.msg) - 1) ? strlen((const char *)msg) : (sizeof(req.msg) - 1);
|
? strlen((const char *)msg)
|
||||||
|
: (sizeof(req.msg) - 1);
|
||||||
memcpy(req.msg, msg, len);
|
memcpy(req.msg, msg, len);
|
||||||
sceKernelSendNotificationRequest(0, &req, sizeof(req), 0);
|
sceKernelSendNotificationRequest(0, &req, sizeof(req), 0);
|
||||||
}
|
}
|
||||||
@@ -260,9 +258,8 @@ void enter_rest_mode(void) {
|
|||||||
sceKernelCloseEventFlag(&event);
|
sceKernelCloseEventFlag(&event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Kit type by EchoStretch
|
// Kit type by EchoStretch
|
||||||
bool if_exists(const char* path) {
|
bool if_exists(const char *path) {
|
||||||
struct stat st;
|
struct stat st;
|
||||||
return stat(path, &st) == 0;
|
return stat(path, &st) == 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user