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
|
||||||
|
|||||||
74
Makefile
74
Makefile
@@ -1,37 +1,37 @@
|
|||||||
.PHONY: all clean
|
.PHONY: all clean
|
||||||
|
|
||||||
ifndef PS5_PAYLOAD_SDK
|
ifndef PS5_PAYLOAD_SDK
|
||||||
PS5_PAYLOAD_SDK = /opt/ps5-payload-sdk/
|
PS5_PAYLOAD_SDK = /opt/ps5-payload-sdk/
|
||||||
endif
|
endif
|
||||||
|
|
||||||
include $(PS5_PAYLOAD_SDK)/toolchain/prospero.mk
|
include $(PS5_PAYLOAD_SDK)/toolchain/prospero.mk
|
||||||
|
|
||||||
BIN := bin/ps5-linux-loader.elf
|
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
|
||||||
|
|
||||||
$(OBJS): %.o: %.c
|
$(OBJS): %.o: %.c
|
||||||
$(CC) $(CFLAGS) -c -o $@ $<
|
$(CC) $(CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
$(BIN): $(OBJS)
|
$(BIN): $(OBJS)
|
||||||
@mkdir -p $(dir $@)
|
@mkdir -p $(dir $@)
|
||||||
$(CC) $(OBJS) $(LDFLAGS) -o $@
|
$(CC) $(OBJS) $(LDFLAGS) -o $@
|
||||||
|
|
||||||
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?
|
||||||
|
|||||||
@@ -1,34 +1,34 @@
|
|||||||
#ifndef CONFIG_H
|
#ifndef CONFIG_H
|
||||||
#define CONFIG_H
|
#define CONFIG_H
|
||||||
|
|
||||||
#define PAGE_SIZE 0x4000ULL
|
#define PAGE_SIZE 0x4000ULL
|
||||||
|
|
||||||
// This is used to allocate resources for HV shellcode and Linux boot
|
// This is used to allocate resources for HV shellcode and Linux boot
|
||||||
#define cave 0x100000000ULL
|
#define cave 0x100000000ULL
|
||||||
#define cave_hv_paging cave
|
#define cave_hv_paging cave
|
||||||
#define cave_hv_code \
|
#define cave_hv_code \
|
||||||
cave_hv_paging + 0x3000ULL // Leave space for 3 pages but we only use 2 for
|
cave_hv_paging + 0x3000ULL // Leave space for 3 pages but we only use 2 for
|
||||||
// 1GB 1:1 mapping
|
// 1GB 1:1 mapping
|
||||||
#define cave_linux_files cave_hv_code + 0x2000ULL
|
#define cave_linux_files cave_hv_code + 0x2000ULL
|
||||||
#define cave_linux_info cave_linux_files
|
#define cave_linux_info cave_linux_files
|
||||||
#define cave_bzImage cave_linux_info + PAGE_SIZE
|
#define cave_bzImage cave_linux_info + PAGE_SIZE
|
||||||
// #define cave_initrd // Allocated dynamically after bzImage
|
// #define cave_initrd // Allocated dynamically after bzImage
|
||||||
|
|
||||||
#define hv_base_rsp (cave + 0x10000000ULL)
|
#define hv_base_rsp (cave + 0x10000000ULL)
|
||||||
#define hv_stack_size 0x1000ULL
|
#define hv_stack_size 0x1000ULL
|
||||||
|
|
||||||
// This is used as transitional storage from ProsperoOS to Kernel shellcode
|
// This is used as transitional storage from ProsperoOS to Kernel shellcode
|
||||||
#define kernel_cave_files 0xFFFF800000000000
|
#define kernel_cave_files 0xFFFF800000000000
|
||||||
#define kernel_cave_linux_info kernel_cave_files
|
#define kernel_cave_linux_info kernel_cave_files
|
||||||
#define kernel_cave_bzImage kernel_cave_linux_info + PAGE_SIZE
|
#define kernel_cave_bzImage kernel_cave_linux_info + PAGE_SIZE
|
||||||
// #define kernel_cave_initrd // Allocated dynamically after bzImage
|
// #define kernel_cave_initrd // Allocated dynamically after bzImage
|
||||||
|
|
||||||
// Linux boot config
|
// Linux boot config
|
||||||
#define VRAM_SIZE (512ULL * 1024 * 1024)
|
#define VRAM_SIZE (512ULL * 1024 * 1024)
|
||||||
#define CMD_LINE \
|
#define CMD_LINE \
|
||||||
"root=/dev/sda2 rw rootwait console=ttyTitania0 console=tty0 " \
|
"root=/dev/sda2 rw rootwait console=ttyTitania0 console=tty0 " \
|
||||||
"video=DP-1:1920x1080@60 mitigations=off idle=halt pci=pcie_bus_perf"
|
"video=DP-1:1920x1080@60 mitigations=off idle=halt pci=pcie_bus_perf"
|
||||||
|
|
||||||
#define DEBUG 0 // Toggle to 0 to disable logs
|
#define DEBUG 0 // Toggle to 0 to disable logs
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
140
include/gpu.h
140
include/gpu.h
@@ -1,70 +1,70 @@
|
|||||||
/*** Source: ps5-hen by cragson ***/
|
/*** Source: ps5-hen by cragson ***/
|
||||||
|
|
||||||
#ifndef GPU_H
|
#ifndef GPU_H
|
||||||
#define GPU_H
|
#define GPU_H
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#define GPU_PDE_VALID_BIT 0
|
#define GPU_PDE_VALID_BIT 0
|
||||||
#define GPU_PDE_IS_PTE_BIT 54
|
#define GPU_PDE_IS_PTE_BIT 54
|
||||||
#define GPU_PDE_TF_BIT 56
|
#define GPU_PDE_TF_BIT 56
|
||||||
#define GPU_PDE_BLOCK_FRAG_BIT 59
|
#define GPU_PDE_BLOCK_FRAG_BIT 59
|
||||||
#define GPU_PDE_ADDR_MASK 0x0000FFFFFFFFFFC0ULL
|
#define GPU_PDE_ADDR_MASK 0x0000FFFFFFFFFFC0ULL
|
||||||
|
|
||||||
#define PROT_GPU_READ 0x10
|
#define PROT_GPU_READ 0x10
|
||||||
#define PROT_GPU_WRITE 0x20
|
#define PROT_GPU_WRITE 0x20
|
||||||
#define MAP_NO_COALESCE 0x00400000
|
#define MAP_NO_COALESCE 0x00400000
|
||||||
|
|
||||||
#define GPU_SUBMIT_IOCTL 0xC0108102
|
#define GPU_SUBMIT_IOCTL 0xC0108102
|
||||||
|
|
||||||
#define PM4_TYPE3 3
|
#define PM4_TYPE3 3
|
||||||
#define PM4_SHADER_COMPUTE 1
|
#define PM4_SHADER_COMPUTE 1
|
||||||
#define PM4_OPCODE_DMA_DATA 0x50
|
#define PM4_OPCODE_DMA_DATA 0x50
|
||||||
#define PM4_OPCODE_INDIRECT_BUF 0x3F
|
#define PM4_OPCODE_INDIRECT_BUF 0x3F
|
||||||
|
|
||||||
struct gpu_kernel_offsets {
|
struct gpu_kernel_offsets {
|
||||||
uint64_t proc_vmspace; // proc->p_vmspace offset
|
uint64_t proc_vmspace; // proc->p_vmspace offset
|
||||||
uint64_t vmspace_vm_vmid; // vmspace->vm_vmid offset
|
uint64_t vmspace_vm_vmid; // vmspace->vm_vmid offset
|
||||||
uint64_t data_base_gvmspace; // offset from kernel data base to gvmspace array
|
uint64_t data_base_gvmspace; // offset from kernel data base to gvmspace array
|
||||||
uint64_t sizeof_gvmspace; // size of each gvmspace entry
|
uint64_t sizeof_gvmspace; // size of each gvmspace entry
|
||||||
uint64_t gvmspace_page_dir_va; // gvmspace->page_dir_va offset (GPU PDB2)
|
uint64_t gvmspace_page_dir_va; // gvmspace->page_dir_va offset (GPU PDB2)
|
||||||
uint64_t gvmspace_size; // gvmspace->size offset
|
uint64_t gvmspace_size; // gvmspace->size offset
|
||||||
uint64_t gvmspace_start_va; // gvmspace->start_va offset
|
uint64_t gvmspace_start_va; // gvmspace->start_va offset
|
||||||
};
|
};
|
||||||
|
|
||||||
struct gpu_ctx {
|
struct gpu_ctx {
|
||||||
int fd; // /dev/gc file descriptor
|
int fd; // /dev/gc file descriptor
|
||||||
int initialized; // 1 if gpu_init() succeeded
|
int initialized; // 1 if gpu_init() succeeded
|
||||||
|
|
||||||
uint64_t victim_va; // CPU VA of victim buffer (GPU PTE remapped)
|
uint64_t victim_va; // CPU VA of victim buffer (GPU PTE remapped)
|
||||||
uint64_t transfer_va; // CPU VA of transfer/staging buffer
|
uint64_t transfer_va; // CPU VA of transfer/staging buffer
|
||||||
uint64_t cmd_va; // CPU VA of PM4 command buffer
|
uint64_t cmd_va; // CPU VA of PM4 command buffer
|
||||||
|
|
||||||
uint64_t victim_real_pa; // original physical address of victim buffer
|
uint64_t victim_real_pa; // original physical address of victim buffer
|
||||||
uint64_t victim_ptbe_va; // kernel VA of the GPU PTE for victim buffer
|
uint64_t victim_ptbe_va; // kernel VA of the GPU PTE for victim buffer
|
||||||
uint64_t cleared_ptbe; // GPU PTE with physical address cleared (template)
|
uint64_t cleared_ptbe; // GPU PTE with physical address cleared (template)
|
||||||
uint64_t page_size; // GPU page size for victim allocation (should be 2MB)
|
uint64_t page_size; // GPU page size for victim allocation (should be 2MB)
|
||||||
uint64_t dmem_size; // allocation size (2MB)
|
uint64_t dmem_size; // allocation size (2MB)
|
||||||
};
|
};
|
||||||
|
|
||||||
void gpu_set_offsets(struct gpu_kernel_offsets *offsets);
|
void gpu_set_offsets(struct gpu_kernel_offsets *offsets);
|
||||||
|
|
||||||
int gpu_init(void);
|
int gpu_init(void);
|
||||||
int gpu_init_internal(void);
|
int gpu_init_internal(void);
|
||||||
|
|
||||||
int gpu_test(void);
|
int gpu_test(void);
|
||||||
|
|
||||||
int gpu_read_phys(uint64_t phys_addr, void *out_buf, uint32_t size);
|
int gpu_read_phys(uint64_t phys_addr, void *out_buf, uint32_t size);
|
||||||
uint8_t gpu_read_phys1(uint64_t phys_addr);
|
uint8_t gpu_read_phys1(uint64_t phys_addr);
|
||||||
uint32_t gpu_read_phys4(uint64_t phys_addr);
|
uint32_t gpu_read_phys4(uint64_t phys_addr);
|
||||||
uint64_t gpu_read_phys8(uint64_t phys_addr);
|
uint64_t gpu_read_phys8(uint64_t phys_addr);
|
||||||
|
|
||||||
int gpu_write_phys(uint64_t phys_addr, const void *in_buf, uint32_t size);
|
int gpu_write_phys(uint64_t phys_addr, const void *in_buf, uint32_t size);
|
||||||
void gpu_write_phys4(uint64_t phys_addr, uint32_t value);
|
void gpu_write_phys4(uint64_t phys_addr, uint32_t value);
|
||||||
void gpu_write_phys8(uint64_t phys_addr, uint64_t value);
|
void gpu_write_phys8(uint64_t phys_addr, uint64_t value);
|
||||||
|
|
||||||
void gpu_cleanup(void);
|
void gpu_cleanup(void);
|
||||||
|
|
||||||
struct gpu_ctx *gpu_get_ctx(void);
|
struct gpu_ctx *gpu_get_ctx(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,19 +1,19 @@
|
|||||||
#ifndef HV_DEFEAT_H
|
#ifndef HV_DEFEAT_H
|
||||||
#define HV_DEFEAT_H
|
#define HV_DEFEAT_H
|
||||||
|
|
||||||
#include "iommu.h"
|
#include "iommu.h"
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
int hv_defeat(void);
|
int hv_defeat(void);
|
||||||
int stage1_tmr_relax(void);
|
int stage1_tmr_relax(void);
|
||||||
int stage2_find_vmcbs(void);
|
int stage2_find_vmcbs(void);
|
||||||
uint64_t get_vmcb(int core);
|
uint64_t get_vmcb(int core);
|
||||||
int iommu_selftest(void);
|
int iommu_selftest(void);
|
||||||
int stage3_patch_vmcbs(void);
|
int stage3_patch_vmcbs(void);
|
||||||
int stage4_force_vmcb_reload(void);
|
int stage4_force_vmcb_reload(void);
|
||||||
int stage5_remove_xotext(void);
|
int stage5_remove_xotext(void);
|
||||||
int stage6_kernel_pmap_invalidate_all(void);
|
int stage6_kernel_pmap_invalidate_all(void);
|
||||||
int stage7_install_kexec(void);
|
int stage7_install_kexec(void);
|
||||||
int kexec(uint64_t fptr);
|
int kexec(uint64_t fptr);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,46 +1,46 @@
|
|||||||
/*** Source: ps5-hen by cragson ***/
|
/*** Source: ps5-hen by cragson ***/
|
||||||
|
|
||||||
#ifndef IOMMU_H
|
#ifndef IOMMU_H
|
||||||
#define IOMMU_H
|
#define IOMMU_H
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
// Command buffer MMIO offsets
|
// Command buffer MMIO offsets
|
||||||
#define IOMMU_MMIO_CB_HEAD 0xa000
|
#define IOMMU_MMIO_CB_HEAD 0xa000
|
||||||
#define IOMMU_MMIO_CB_TAIL 0xa008
|
#define IOMMU_MMIO_CB_TAIL 0xa008
|
||||||
|
|
||||||
// Queue constants
|
// Queue constants
|
||||||
#define IOMMU_CB_SIZE 0x2000
|
#define IOMMU_CB_SIZE 0x2000
|
||||||
#define IOMMU_CB_MASK (IOMMU_CB_SIZE - 1)
|
#define IOMMU_CB_MASK (IOMMU_CB_SIZE - 1)
|
||||||
#define IOMMU_CMD_ENTRY_SIZE 0x10
|
#define IOMMU_CMD_ENTRY_SIZE 0x10
|
||||||
|
|
||||||
// IOMMU softc field offsets
|
// IOMMU softc field offsets
|
||||||
#define IOMMU_SC_MMIO_VA 0x40
|
#define IOMMU_SC_MMIO_VA 0x40
|
||||||
#define IOMMU_SC_CB2_PTR 0x78
|
#define IOMMU_SC_CB2_PTR 0x78
|
||||||
#define IOMMU_SC_CB3_PTR 0x80
|
#define IOMMU_SC_CB3_PTR 0x80
|
||||||
#define IOMMU_SC_EB_PTR 0x60b90
|
#define IOMMU_SC_EB_PTR 0x60b90
|
||||||
|
|
||||||
typedef struct _iommu_ctx {
|
typedef struct _iommu_ctx {
|
||||||
uint64_t cb2_base; // kernel VA of command buffer 2 (hv terminology)
|
uint64_t cb2_base; // kernel VA of command buffer 2 (hv terminology)
|
||||||
uint64_t cb3_base; // kernel VA of command buffer 3 (hv terminology)
|
uint64_t cb3_base; // kernel VA of command buffer 3 (hv terminology)
|
||||||
uint64_t eb_base; // kernel VA of event buffer
|
uint64_t eb_base; // kernel VA of event buffer
|
||||||
uint64_t mmio_va; // DMAP VA of IOMMU MMIO base
|
uint64_t mmio_va; // DMAP VA of IOMMU MMIO base
|
||||||
} iommu_ctx;
|
} iommu_ctx;
|
||||||
|
|
||||||
extern iommu_ctx iommu_store;
|
extern iommu_ctx iommu_store;
|
||||||
extern iommu_ctx *iommu;
|
extern iommu_ctx *iommu;
|
||||||
|
|
||||||
int iommu_init(void);
|
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);
|
||||||
// Write 8 bytes to a physical address using IOMMU completion wait store
|
// Write 8 bytes to a physical address using IOMMU completion wait store
|
||||||
void iommu_write8_pa(uint64_t pa, uint64_t val);
|
void iommu_write8_pa(uint64_t pa, uint64_t val);
|
||||||
|
|
||||||
// Write 4 bytes to a physical address
|
// Write 4 bytes to a physical address
|
||||||
void iommu_write4_pa(uint64_t pa, uint32_t val);
|
void iommu_write4_pa(uint64_t pa, uint32_t val);
|
||||||
|
|
||||||
// Write arbitrary length to a physical address in 8-byte chunks
|
// Write arbitrary length to a physical address in 8-byte chunks
|
||||||
void iommu_write_pa(uint64_t pa, const void *data, uint32_t len);
|
void iommu_write_pa(uint64_t pa, const void *data, uint32_t len);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -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,15 +1,13 @@
|
|||||||
#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, int bits);
|
||||||
void install_page(uintptr_t pml4, vm_offset_t va, vm_paddr_t pa,
|
void pte_store(uintptr_t ptep, uint64_t pte);
|
||||||
int bits);
|
int read_file(const char *path, void *buf, size_t bufsize);
|
||||||
void pte_store(uintptr_t ptep, uint64_t pte);
|
void trim_newline(char *s);
|
||||||
int read_file(const char *path, void *buf, size_t bufsize);
|
int fetch_linux(struct linux_info *info);
|
||||||
void trim_newline(char *s);
|
|
||||||
int fetch_linux(struct linux_info *info);
|
#endif
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|||||||
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
|
||||||
@@ -1,52 +1,48 @@
|
|||||||
#ifndef OFFSETS_H
|
#ifndef OFFSETS_H
|
||||||
#define OFFSETS_H
|
#define OFFSETS_H
|
||||||
|
|
||||||
#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 IOMMU_SOFTC;
|
||||||
uint64_t HV_VCPU_CPUID; // Needed for 1.xx and 2.xx
|
uint64_t VMSPACE_VM_VMID;
|
||||||
uint64_t HV_VCPU_ARRAY_OFF; // Needed for 1.xx and 2.xx
|
uint64_t VMSPACE_VM_PMAP;
|
||||||
uint64_t HV_VCPU_STRIDE; // Needed for 1.xx and 2.xx
|
uint64_t DATA_BASE_GVMSPACE;
|
||||||
uint64_t HV_VCPU_VMCB_PTR; // Needed for 1.xx and 2.xx
|
/* Shellcode Kernel */
|
||||||
uint64_t KERNEL_CODE_CAVE;
|
uint64_t HOOK_ACPI_WAKEUP_MACHDEP;
|
||||||
uint64_t KERNEL_DATA_CAVE;
|
uint64_t KERNEL_CODE_CAVE;
|
||||||
uint64_t IOMMU_SOFTC;
|
uint64_t KERNEL_DATA_CAVE;
|
||||||
uint64_t VMSPACE_VM_VMID;
|
uint64_t FUN_PRINTF;
|
||||||
uint64_t VMSPACE_VM_PMAP;
|
uint64_t FUN_HV_IOMMU_SET_BUFFERS;
|
||||||
uint64_t PMAP_PM_PML4;
|
uint64_t FUN_HV_IOMM_WAIT_COMPLETION;
|
||||||
uint64_t PMAP_PM_CR3;
|
uint64_t FUN_SMP_RENDEZVOUS;
|
||||||
uint64_t DATA_BASE_GVMSPACE;
|
uint64_t FUN_SMP_NO_RENDEVOUS_BARRIER;
|
||||||
uint64_t HOOK_ACPI_WAKEUP_MACHDEP;
|
/* Shellcode HV */
|
||||||
uint64_t FUN_PRINTF;
|
uint64_t HV_CODE_CAVE_PA;
|
||||||
uint64_t FUN_VA_TO_PA;
|
uint64_t HV_HANDLE_VMEXIT_PA;
|
||||||
uint64_t FUN_HV_IOMMU_SET_BUFFERS;
|
/* Patches on Kernel */
|
||||||
uint64_t FUN_HV_IOMM_WAIT_COMPLETION;
|
uint64_t KERNEL_UART_OVERRIDE;
|
||||||
uint64_t FUN_SMP_RENDEZVOUS;
|
uint64_t KERNEL_DEBUG_PATCH;
|
||||||
uint64_t FUN_SMP_NO_RENDEVOUS_BARRIER;
|
uint64_t KERNEL_CFI_CHECK;
|
||||||
uint64_t HV_HANDLE_VMEXIT_PA;
|
/* Internal functions to prepare boot */
|
||||||
uint64_t HV_CODE_CAVE_PA;
|
uint64_t G_VBIOS;
|
||||||
uint64_t HV_UART_OVERRIDE_PA;
|
uint64_t FUN_TRANSMITTER_CONTROL;
|
||||||
uint64_t G_VBIOS;
|
uint64_t FUN_MP3_INITIALIZE;
|
||||||
uint64_t FUN_TRANSMITTER_CONTROL;
|
uint64_t FUN_MP3_INVOKE;
|
||||||
uint64_t FUN_MP3_INITIALIZE;
|
/* Wifi FW */
|
||||||
uint64_t FUN_MP3_INVOKE;
|
uint64_t PS5_WIFI_FW_OFFSET;
|
||||||
uint64_t KERNEL_UART_OVERRIDE;
|
uint64_t PS5_WIFI_FW_SIZE;
|
||||||
uint64_t KERNEL_DEBUG_PATCH;
|
} offset_list;
|
||||||
uint64_t KERNEL_CFI_CHECK;
|
|
||||||
uint64_t PS5_WIFI_FW_OFFSET;
|
extern offset_list off_0300;
|
||||||
uint64_t PS5_WIFI_FW_SIZE;
|
extern offset_list off_0310;
|
||||||
} offset_list;
|
extern offset_list off_0320;
|
||||||
|
extern offset_list off_0321;
|
||||||
extern offset_list off_0300;
|
extern offset_list off_0400;
|
||||||
extern offset_list off_0310;
|
extern offset_list off_0402;
|
||||||
extern offset_list off_0320;
|
extern offset_list off_0403;
|
||||||
extern offset_list off_0321;
|
extern offset_list off_0450;
|
||||||
extern offset_list off_0400;
|
extern offset_list off_0451;
|
||||||
extern offset_list off_0402;
|
|
||||||
extern offset_list off_0403;
|
#endif
|
||||||
extern offset_list off_0450;
|
|
||||||
extern offset_list off_0451;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
#ifndef PREPARE_RESUME_H
|
#ifndef PREPARE_RESUME_H
|
||||||
#define PREPARE_RESUME_H
|
#define PREPARE_RESUME_H
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,19 +1,19 @@
|
|||||||
#ifndef TMR_H
|
#ifndef TMR_H
|
||||||
#define TMR_H
|
#define TMR_H
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#define ECAM_B0D18F2 dmap + (0xF0000000ULL + 0x18ULL * 0x8000 + 2 * 0x1000)
|
#define ECAM_B0D18F2 dmap + (0xF0000000ULL + 0x18ULL * 0x8000 + 2 * 0x1000)
|
||||||
#define TMR_INDEX_OFF 0x80
|
#define TMR_INDEX_OFF 0x80
|
||||||
#define TMR_DATA_OFF 0x84
|
#define TMR_DATA_OFF 0x84
|
||||||
|
|
||||||
#define TMR_BASE(n) ((n) * 0x10 + 0x00)
|
#define TMR_BASE(n) ((n) * 0x10 + 0x00)
|
||||||
#define TMR_LIMIT(n) ((n) * 0x10 + 0x04)
|
#define TMR_LIMIT(n) ((n) * 0x10 + 0x04)
|
||||||
#define TMR_CONFIG(n) ((n) * 0x10 + 0x08)
|
#define TMR_CONFIG(n) ((n) * 0x10 + 0x08)
|
||||||
#define TMR_REQUESTORS(n) ((n) * 0x10 + 0x0C)
|
#define TMR_REQUESTORS(n) ((n) * 0x10 + 0x0C)
|
||||||
#define TMR_CFG_PERMISSIVE 0x3F07
|
#define TMR_CFG_PERMISSIVE 0x3F07
|
||||||
|
|
||||||
uint32_t tmr_read(uint32_t addr);
|
uint32_t tmr_read(uint32_t addr);
|
||||||
void tmr_write(uint32_t addr, uint32_t val);
|
void tmr_write(uint32_t addr, uint32_t val);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
355
include/utils.h
355
include/utils.h
@@ -1,185 +1,170 @@
|
|||||||
#ifndef UTILS_H
|
#ifndef UTILS_H
|
||||||
#define UTILS_H
|
#define UTILS_H
|
||||||
|
|
||||||
#include "offsets.h"
|
#include "linux.h"
|
||||||
#include <ps5/kernel.h>
|
#include "offsets.h"
|
||||||
#include <stdarg.h>
|
#include <ps5/kernel.h>
|
||||||
#include <stdint.h>
|
#include <stdarg.h>
|
||||||
#include <string.h>
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
int sceKernelGetCurrentCpu();
|
|
||||||
int sceKernelSendNotificationRequest(int, void *, size_t, int);
|
int sceKernelGetCurrentCpu();
|
||||||
int sceKernelOpenEventFlag(void*, const char *);
|
int sceKernelSendNotificationRequest(int, void *, size_t, int);
|
||||||
int sceKernelNotifySystemSuspendStart(void);
|
int sceKernelOpenEventFlag(void *, const char *);
|
||||||
int sceKernelSetEventFlag(void *, int);
|
int sceKernelNotifySystemSuspendStart(void);
|
||||||
int sceKernelCloseEventFlag(void*);
|
int sceKernelSetEventFlag(void *, int);
|
||||||
|
int sceKernelCloseEventFlag(void *);
|
||||||
typedef struct _sysent {
|
|
||||||
uint32_t n_arg;
|
typedef struct _sysent {
|
||||||
uint32_t pad;
|
uint32_t n_arg;
|
||||||
uint64_t sy_call;
|
uint32_t pad;
|
||||||
uint64_t sy_auevent;
|
uint64_t sy_call;
|
||||||
uint64_t sy_systrace_args;
|
uint64_t sy_auevent;
|
||||||
uint32_t sy_entry;
|
uint64_t sy_systrace_args;
|
||||||
uint32_t sy_return;
|
uint32_t sy_entry;
|
||||||
uint32_t sy_flags;
|
uint32_t sy_return;
|
||||||
uint32_t sy_thrcnt;
|
uint32_t sy_flags;
|
||||||
} sysent;
|
uint32_t sy_thrcnt;
|
||||||
|
} sysent;
|
||||||
typedef struct __flat_pmap {
|
|
||||||
uint64_t mtx_name_ptr;
|
typedef struct __flat_pmap {
|
||||||
uint64_t mtx_flags;
|
uint64_t mtx_name_ptr;
|
||||||
uint64_t mtx_data;
|
uint64_t mtx_flags;
|
||||||
uint64_t mtx_lock;
|
uint64_t mtx_data;
|
||||||
uint64_t pm_pml4;
|
uint64_t mtx_lock;
|
||||||
uint64_t pm_cr3;
|
uint64_t pm_pml4;
|
||||||
} flat_pmap;
|
uint64_t pm_cr3;
|
||||||
|
} flat_pmap;
|
||||||
struct linux_info {
|
|
||||||
uintptr_t bzimage;
|
/** These vars are global for the payload to simplify things */
|
||||||
size_t bzimage_size;
|
extern offset_list env_offset; // Defined on utils.c
|
||||||
uintptr_t initrd;
|
extern uint64_t ktext; // Defined on utils.c
|
||||||
size_t initrd_size;
|
extern uint64_t kdata; // Defined on utils.c
|
||||||
size_t vram_size;
|
extern uint64_t dmap; // Defined on utils.c
|
||||||
char cmdline[2048];
|
extern uint64_t cr3; // Defined on utils.c
|
||||||
int kit_type;
|
extern uint32_t fw; // Defined on utils.c
|
||||||
uintptr_t linux_info; // PA of linux_info
|
extern uint64_t vmcb_pa[16]; // Defined on hv_defeat.c
|
||||||
};
|
extern struct linux_info linux_i; // Declared on main.c
|
||||||
|
|
||||||
/** These vars are global for the payload to simplify things */
|
int setup_env(void);
|
||||||
extern offset_list env_offset; // Defined on utils.c
|
|
||||||
extern uint64_t ktext; // Defined on utils.c
|
static inline void kwrite_large(uint64_t ka, void *src, uint64_t len) {
|
||||||
extern uint64_t kdata; // Defined on utils.c
|
uint32_t CHUNK = 0x1000;
|
||||||
extern uint64_t dmap; // Defined on utils.c
|
uint64_t written = 0;
|
||||||
extern uint64_t cr3; // Defined on utils.c
|
while (written < len) {
|
||||||
extern uint32_t fw; // Defined on utils.c
|
uint32_t n = (len - written > CHUNK) ? CHUNK : (uint32_t)(len - written);
|
||||||
extern uint64_t vmcb_pa[16]; // Defined on hv_defeat.c
|
kernel_copyin(src + written, ka + written, n);
|
||||||
extern struct linux_info linux_i; // Declared on main.c
|
written += n;
|
||||||
|
}
|
||||||
int setup_env(void);
|
}
|
||||||
|
|
||||||
static inline void kwrite_large(uint64_t ka, void* src, uint64_t len) {
|
static inline void kwrite(uint64_t ka, void *src, uint64_t len) {
|
||||||
uint32_t CHUNK = 0x1000;
|
kernel_copyin(src, ka, len);
|
||||||
uint64_t written = 0;
|
}
|
||||||
while (written < len) {
|
|
||||||
uint32_t n = (len - written > CHUNK) ? CHUNK : (uint32_t)(len - written);
|
static inline void kwrite64(uint64_t dst, uint64_t val) {
|
||||||
kernel_copyin(src + written, ka + written, n);
|
kernel_copyin(&val, dst, 8);
|
||||||
written += n;
|
}
|
||||||
}
|
|
||||||
}
|
static inline void kwrite32(uint64_t dst, uint32_t val) {
|
||||||
|
kernel_copyin(&val, dst, 4);
|
||||||
static inline void kwrite(uint64_t ka, void *src, uint64_t len) {
|
}
|
||||||
kernel_copyin(src, ka, len);
|
|
||||||
}
|
static inline void kwrite8(uint64_t dst, uint8_t val) {
|
||||||
|
kernel_copyin(&val, dst, 1);
|
||||||
static inline void kwrite64(uint64_t dst, uint64_t val) {
|
}
|
||||||
kernel_copyin(&val, dst, 8);
|
|
||||||
}
|
static inline void kread(uint64_t ka, void *dst, uint64_t len) {
|
||||||
|
kernel_copyout(ka, dst, len);
|
||||||
static inline void kwrite32(uint64_t dst, uint32_t val) {
|
}
|
||||||
kernel_copyin(&val, dst, 4);
|
|
||||||
}
|
static inline uint64_t kread64(uint64_t src) {
|
||||||
|
uint64_t val;
|
||||||
static inline void kwrite8(uint64_t dst, uint8_t val) {
|
kernel_copyout(src, &val, 8);
|
||||||
kernel_copyin(&val, dst, 1);
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void kread(uint64_t ka, void *dst, uint64_t len) {
|
static inline uint32_t kread32(uint64_t src) {
|
||||||
kernel_copyout(ka, dst, len);
|
uint32_t val;
|
||||||
}
|
kernel_copyout(src, &val, 4);
|
||||||
|
return val;
|
||||||
static inline uint64_t kread64(uint64_t src) {
|
}
|
||||||
uint64_t val;
|
|
||||||
kernel_copyout(src, &val, 8);
|
static inline uint8_t kread8(uint64_t src) {
|
||||||
return val;
|
uint8_t val;
|
||||||
}
|
kernel_copyout(src, &val, 1);
|
||||||
|
return val;
|
||||||
static inline uint32_t kread32(uint64_t src) {
|
}
|
||||||
uint32_t val;
|
|
||||||
kernel_copyout(src, &val, 4);
|
int set_offsets(void);
|
||||||
return val;
|
int init_global_vars(void);
|
||||||
}
|
uint64_t get_offset_va(uint64_t offset);
|
||||||
|
|
||||||
static inline uint8_t kread8(uint64_t src) {
|
// Defines for Page management
|
||||||
uint8_t val;
|
#define ALIGN_UP(size, align) (((size) + (align) - 1) & ~((align) - 1))
|
||||||
kernel_copyout(src, &val, 1);
|
#define INKERNEL(va) (va & 0xFFFF000000000000)
|
||||||
return val;
|
|
||||||
}
|
enum page_bits {
|
||||||
|
P = 0,
|
||||||
int set_offsets(void);
|
RW,
|
||||||
int init_global_vars(void);
|
US,
|
||||||
uint64_t get_offset_va(uint64_t offset);
|
PWT,
|
||||||
|
PCD,
|
||||||
// Defines for Page management
|
A,
|
||||||
#define ALIGN_UP(size, align) (((size) + (align) - 1) & ~((align) - 1))
|
D,
|
||||||
#define INKERNEL(va) (va & 0xFFFF000000000000)
|
PS,
|
||||||
|
G,
|
||||||
enum page_bits {
|
XO = 58,
|
||||||
P = 0,
|
PK = 59,
|
||||||
RW,
|
NX = 63
|
||||||
US,
|
};
|
||||||
PWT,
|
|
||||||
PCD,
|
#define PG_B_P (1ULL << P)
|
||||||
A,
|
#define PG_B_RW (1ULL << RW)
|
||||||
D,
|
#define PAGE_P(x) (x & (1ULL << P))
|
||||||
PS,
|
#define PAGE_RW(x) (x & (1ULL << RW))
|
||||||
G,
|
#define PAGE_PS(x) (x & (1ULL << PS))
|
||||||
XO = 58,
|
#define PAGE_XO(x) (x & (1ULL << XO))
|
||||||
PK = 59,
|
#define PAGE_CLEAR_XO(x) (x &= ~(1ULL << XO))
|
||||||
NX = 63
|
#define PAGE_CLEAR_G(x) (x &= ~(1ULL << G))
|
||||||
};
|
#define PAGE_SET_RW(x) (x |= (1ULL << RW))
|
||||||
|
#define PAGE_PA(x) (x & 0x000FFFFFFFFFF000ULL)
|
||||||
#define PG_B_P (1ULL << P)
|
#define P_SIZE(l) ((l == 1) ? (1ULL << 30) : (1ULL << 21))
|
||||||
#define PG_B_RW (1ULL << RW)
|
|
||||||
#define PAGE_P(x) (x & (1ULL << P))
|
#define pmap_pml4e_index(va) ((va >> 39) & 0x1FF)
|
||||||
#define PAGE_RW(x) (x & (1ULL << RW))
|
#define pmap_pdpe_index(va) ((va >> 30) & 0x1FF)
|
||||||
#define PAGE_PS(x) (x & (1ULL << PS))
|
#define pmap_pde_index(va) ((va >> 21) & 0x1FF)
|
||||||
#define PAGE_XO(x) (x & (1ULL << XO))
|
#define pmap_pte_index(va) ((va >> 12) & 0x1FF)
|
||||||
#define PAGE_CLEAR_XO(x) (x &= ~(1ULL << XO))
|
|
||||||
#define PAGE_CLEAR_G(x) (x &= ~(1ULL << G))
|
uint64_t vtophys_user(uint64_t va);
|
||||||
#define PAGE_SET_RW(x) (x |= (1ULL << RW))
|
uint64_t vtophys(uint64_t va);
|
||||||
#define PAGE_PA(x) (x & 0x000FFFFFFFFFF000ULL)
|
uint64_t vtophys_custom(uint64_t va, uint64_t cr3_custom);
|
||||||
#define P_SIZE(l) ((l == 1) ? (1ULL << 30) : (1ULL << 21))
|
uint64_t pa_to_dmap(uint64_t pa);
|
||||||
|
void page_chain_set_rw(uint64_t va);
|
||||||
#define pmap_pml4e_index(va) ((va >> 39) & 0x1FF)
|
uint64_t page_remove_global(uint64_t va);
|
||||||
#define pmap_pdpe_index(va) ((va >> 30) & 0x1FF)
|
|
||||||
#define pmap_pde_index(va) ((va >> 21) & 0x1FF)
|
uint64_t getpmap(uint64_t proc_ptr);
|
||||||
#define pmap_pte_index(va) ((va >> 12) & 0x1FF)
|
uint64_t get_pml4(uint64_t pmap);
|
||||||
|
|
||||||
uint64_t va_to_pa_user(uint64_t va);
|
int pin_to_core(int n);
|
||||||
uint64_t va_to_pa_kernel(uint64_t va);
|
int pin_to_first_available_core(void);
|
||||||
uint64_t va_to_pa_custom(uint64_t va, uint64_t cr3_custom);
|
void unpin(void);
|
||||||
uint64_t pa_to_dmap(uint64_t pa);
|
void notify(const char *fmt, ...);
|
||||||
void page_chain_set_rw(uint64_t va);
|
void notify_internal(uint8_t *msg);
|
||||||
uint64_t page_remove_global(uint64_t va);
|
void enter_rest_mode(void);
|
||||||
|
|
||||||
uint64_t getpmap(uint64_t proc_ptr);
|
#if DEBUG
|
||||||
uint64_t get_pml4(uint64_t pmap);
|
#define DEBUG_PRINT(fmt, ...) printf(fmt, ##__VA_ARGS__)
|
||||||
|
#else
|
||||||
int pin_to_core(int n);
|
#define DEBUG_PRINT(fmt, ...)
|
||||||
int pin_to_first_available_core(void);
|
#endif
|
||||||
void unpin(void);
|
|
||||||
void notify(const char *fmt, ...);
|
bool if_exists(const char *path);
|
||||||
void notify_internal(uint8_t *msg);
|
bool sceKernelIsTestKit(void);
|
||||||
void enter_rest_mode(void);
|
bool sceKernelIsDevKit(void);
|
||||||
|
|
||||||
#if DEBUG
|
enum kit_type { KIT_RETAIL, KIT_TESTKIT, KIT_DEVKIT };
|
||||||
#define DEBUG_PRINT(fmt, ...) printf(fmt, ##__VA_ARGS__)
|
|
||||||
#else
|
enum kit_type get_kit_type(void);
|
||||||
#define DEBUG_PRINT(fmt, ...)
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
bool if_exists(const char* path);
|
|
||||||
bool sceKernelIsTestKit(void);
|
|
||||||
bool sceKernelIsDevKit(void);
|
|
||||||
|
|
||||||
enum kit_type {
|
|
||||||
KIT_RETAIL,
|
|
||||||
KIT_TESTKIT,
|
|
||||||
KIT_DEVKIT
|
|
||||||
};
|
|
||||||
|
|
||||||
enum kit_type get_kit_type(void);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -1,39 +1,34 @@
|
|||||||
ifndef PS5_PAYLOAD_SDK
|
ifeq ($(shell uname -m),aarch64)
|
||||||
PS5_PAYLOAD_SDK = /opt/ps5-payload-sdk/
|
CC = x86_64-linux-gnu-gcc
|
||||||
endif
|
LD = x86_64-linux-gnu-ld
|
||||||
|
OBJCOPY = x86_64-linux-gnu-objcopy
|
||||||
# 1. Variables
|
else
|
||||||
ifeq ($(shell uname -m),aarch64)
|
CC = gcc
|
||||||
CC = x86_64-linux-gnu-gcc
|
LD = ld
|
||||||
LD = x86_64-linux-gnu-ld
|
OBJCOPY = objcopy
|
||||||
OBJCOPY = x86_64-linux-gnu-objcopy
|
endif
|
||||||
else
|
CFLAGS = -O2 -fno-stack-protector -ffreestanding -nostdlib -fcf-protection=none -m64
|
||||||
CC = gcc
|
LDFLAGS = -T linker.ld -Wl,--no-warn-rwx-segments
|
||||||
LD = ld
|
TARGET = shellcode_hv.elf
|
||||||
OBJCOPY = objcopy
|
TEXT_BIN = shellcode_hv.bin
|
||||||
endif
|
dump = shellcode_hv.h
|
||||||
CFLAGS = -O2 -fno-stack-protector -ffreestanding -nostdlib -fcf-protection=none -m64 -I$(PS5_PAYLOAD_SDK)/target/include
|
|
||||||
LDFLAGS = -T linker.ld
|
SRC = main.c utils.c boot_linux.c
|
||||||
TARGET = shellcode_hypervisor.elf
|
OBJ = $(SRC:.c=.o)
|
||||||
TEXT_BIN = shellcode_hypervisor.bin
|
|
||||||
dump = shellcode_hypervisor.h
|
all: $(dump)
|
||||||
|
|
||||||
SRC = main.c utils.c boot_linux.c
|
$(TARGET): $(OBJ)
|
||||||
OBJ = $(SRC:.c=.o)
|
$(CC) $(CFLAGS) $(LDFLAGS) $(OBJ) -o $(TARGET)
|
||||||
|
|
||||||
all: $(dump)
|
%.o: %.c
|
||||||
|
$(CC) $(CFLAGS) -c $< -o $@
|
||||||
$(TARGET): $(OBJ)
|
|
||||||
$(CC) $(CFLAGS) $(LDFLAGS) $(OBJ) -o $(TARGET)
|
$(TEXT_BIN): $(TARGET)
|
||||||
|
$(OBJCOPY) -O binary -j .shell_code $(TARGET) $(TEXT_BIN)
|
||||||
%.o: %.c
|
|
||||||
$(CC) $(CFLAGS) -c $< -o $@
|
clean:
|
||||||
|
rm -f $(OBJ) $(TARGET) $(TEXT_BIN) $(dump)
|
||||||
$(TEXT_BIN): $(TARGET)
|
|
||||||
$(OBJCOPY) -O binary -j .shell_code $(TARGET) $(TEXT_BIN)
|
$(dump): $(TEXT_BIN)
|
||||||
|
xxd -i $(TEXT_BIN) > $(dump)
|
||||||
clean:
|
|
||||||
rm -f $(OBJ) $(TARGET) $(TEXT_BIN) $(dump)
|
|
||||||
|
|
||||||
$(dump): $(TEXT_BIN)
|
|
||||||
python3 bin_to_c_hypervisor.py $(TEXT_BIN)
|
|
||||||
@@ -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);
|
||||||
@@ -1,52 +1,48 @@
|
|||||||
|
|
||||||
#define MSR_EFER 0xc0000080
|
#define MSR_EFER 0xc0000080
|
||||||
#define EFER_SVM (1ULL << 12) // Bit 12: Secure Virtual Machine Enable
|
#define EFER_SVM (1ULL << 12) // Bit 12: Secure Virtual Machine Enable
|
||||||
|
|
||||||
// // Virtual Machine Control Register (VM_CR)
|
// // Virtual Machine Control Register (VM_CR)
|
||||||
#define MSR_VM_CR 0xc0010114
|
#define MSR_VM_CR 0xc0010114
|
||||||
#define VM_CR_R_INIT (1ULL << 1) // Bit 1: Intercept INIT
|
#define VM_CR_R_INIT (1ULL << 1) // Bit 1: Intercept INIT
|
||||||
|
|
||||||
// // MTRRs (Memory Type Range Registers)
|
// // MTRRs (Memory Type Range Registers)
|
||||||
#define MSR_MTRR4kBase 0x00000268
|
#define MSR_MTRR4kBase 0x00000268
|
||||||
#define MSR_MTRRVarBase 0x00000200
|
#define MSR_MTRRVarBase 0x00000200
|
||||||
|
|
||||||
#define VRAM_BASE (0x470000000 - info.vram_size)
|
#define VRAM_BASE (0x470000000 - info.vram_size)
|
||||||
|
|
||||||
#define FB_BASE 0xf400000000
|
#define FB_BASE 0xf400000000
|
||||||
|
|
||||||
#define ACPI_RSDP_ADDRESS 0x7fd8e014
|
#define ACPI_RSDP_ADDRESS 0x7fd8e014
|
||||||
|
|
||||||
#define AMDGPU_MMIO_BASE 0xe0600000
|
#define AMDGPU_MMIO_BASE 0xe0600000
|
||||||
|
|
||||||
#define RCC_CONFIG_MEMSIZE 0x378c
|
#define RCC_CONFIG_MEMSIZE 0x378c
|
||||||
|
|
||||||
#define GCMC_VM_FB_OFFSET 0xa5ac
|
#define GCMC_VM_FB_OFFSET 0xa5ac
|
||||||
#define GCMC_VM_LOCAL_HBM_ADDRESS_START 0xa5d4
|
#define GCMC_VM_LOCAL_HBM_ADDRESS_START 0xa5d4
|
||||||
#define GCMC_VM_LOCAL_HBM_ADDRESS_END 0xa5d8
|
#define GCMC_VM_LOCAL_HBM_ADDRESS_END 0xa5d8
|
||||||
#define GCMC_VM_FB_LOCATION_BASE 0xa600
|
#define GCMC_VM_FB_LOCATION_BASE 0xa600
|
||||||
#define GCMC_VM_FB_LOCATION_TOP 0xa604
|
#define GCMC_VM_FB_LOCATION_TOP 0xa604
|
||||||
|
|
||||||
#define MMMC_VM_FB_OFFSET 0x6a15c
|
#define MMMC_VM_FB_OFFSET 0x6a15c
|
||||||
#define MMMC_VM_LOCAL_HBM_ADDRESS_START 0x6a184
|
#define MMMC_VM_LOCAL_HBM_ADDRESS_START 0x6a184
|
||||||
#define MMMC_VM_LOCAL_HBM_ADDRESS_END 0x6a188
|
#define MMMC_VM_LOCAL_HBM_ADDRESS_END 0x6a188
|
||||||
#define MMMC_VM_FB_LOCATION_BASE 0x6a1b0
|
#define MMMC_VM_FB_LOCATION_BASE 0x6a1b0
|
||||||
#define MMMC_VM_FB_LOCATION_TOP 0x6a1b4
|
#define MMMC_VM_FB_LOCATION_TOP 0x6a1b4
|
||||||
|
|
||||||
#define MMHUBBUB_WHITELIST_BASE_ADDR_0 0x24850
|
#define MMHUBBUB_WHITELIST_BASE_ADDR_0 0x24850
|
||||||
#define MMHUBBUB_WHITELIST_TOP_ADDR_0 0x24854
|
#define MMHUBBUB_WHITELIST_TOP_ADDR_0 0x24854
|
||||||
#define DCHUBBUB_WHITELIST_BASE_ADDR_0 0x24878
|
#define DCHUBBUB_WHITELIST_BASE_ADDR_0 0x24878
|
||||||
#define DCHUBBUB_WHITELIST_TOP_ADDR_0 0x2487c
|
#define DCHUBBUB_WHITELIST_TOP_ADDR_0 0x2487c
|
||||||
|
|
||||||
#define AMDIOMMU_MMIO_BASE 0xfdd80000
|
#define AMDIOMMU_MMIO_BASE 0xfdd80000
|
||||||
#define AMDIOMMU_CTRL 0x18
|
#define AMDIOMMU_CTRL 0x18
|
||||||
|
|
||||||
#define MAXCPU 16
|
#define MAXCPU 16
|
||||||
|
|
||||||
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,18 +1,18 @@
|
|||||||
/* linker.ld */
|
/* linker.ld */
|
||||||
ENTRY(main)
|
ENTRY(main)
|
||||||
|
|
||||||
SECTIONS
|
SECTIONS
|
||||||
{
|
{
|
||||||
. = 0x1000; /* 0x1000 to avoid warnings from linker */
|
. = 0x1000; /* 0x1000 to avoid warnings from linker */
|
||||||
/* Place our custom header first */
|
/* Place our custom header first */
|
||||||
.shell_code :
|
.shell_code :
|
||||||
{
|
{
|
||||||
*(.entry_point)
|
*(.entry_point)
|
||||||
*(.text)
|
*(.text)
|
||||||
*(.text.*)
|
*(.text.*)
|
||||||
*(.data*)
|
*(.data*)
|
||||||
*(.rodata*)
|
*(.rodata*)
|
||||||
*(.bss)
|
*(.bss)
|
||||||
*(.bss.*)
|
*(.bss.*)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,29 +1,31 @@
|
|||||||
#include <stdint.h>
|
#include "../include/config.h"
|
||||||
#include "main.h"
|
#include "boot_linux.h"
|
||||||
#include "../include/config.h"
|
#include "utils.h"
|
||||||
#include "boot_linux.h"
|
#include <stdint.h>
|
||||||
#include "utils.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;
|
||||||
|
|
||||||
__asm__ volatile("cpuid"
|
__asm__ volatile("cpuid"
|
||||||
: "=a"(ebax), "=b"(ebx), "=c"(ecx), "=d"(edx)
|
: "=a"(ebax), "=b"(ebx), "=c"(ecx), "=d"(edx)
|
||||||
: "a"(1));
|
: "a"(1));
|
||||||
|
|
||||||
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
|
||||||
uintptr_t new_rsp =
|
// Each CPU should have a different location
|
||||||
(uintptr_t)hv_base_rsp + ((uint64_t)(cpu_id)*hv_stack_size);
|
uintptr_t new_rsp =
|
||||||
|
(uintptr_t)hv_base_rsp + ((uint64_t)(cpu_id)*hv_stack_size);
|
||||||
__asm__ volatile("movq %0, %%rsp \n\t"
|
|
||||||
"movq %%rsp, %%rbp \n\t"
|
// WARNING: This invalidates current local variables
|
||||||
:
|
__asm__ volatile("movq %0, %%rsp \n\t"
|
||||||
: "r"(new_rsp)
|
"movq %%rsp, %%rbp \n\t"
|
||||||
: "rbp", "memory");
|
:
|
||||||
|
: "r"(new_rsp)
|
||||||
entry();
|
: "rbp", "memory");
|
||||||
}
|
|
||||||
|
entry();
|
||||||
|
}
|
||||||
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,112 +1,108 @@
|
|||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "shellcode_hypervisor_args.h"
|
#include <cpuid.h>
|
||||||
#include <cpuid.h>
|
|
||||||
|
__attribute__((noinline, optimize("O0"))) uint32_t putc_uart(uint8_t tx_byte) {
|
||||||
extern shellcode_hypervisor_args args;
|
volatile uint32_t *uart_tx = (volatile uint32_t *)0xc1010104ULL;
|
||||||
|
volatile uint32_t *uart_busy = (volatile uint32_t *)0xc101010cULL;
|
||||||
__attribute__((noinline, optimize("O0"))) uint32_t putc_uart(uint8_t tx_byte) {
|
uint64_t timeout = 0xFFFFFFFF;
|
||||||
volatile uint32_t *uart_tx = (volatile uint32_t *) 0xc1010104ULL;
|
do {
|
||||||
volatile uint32_t *uart_busy = (volatile uint32_t *) 0xc101010cULL;
|
timeout--;
|
||||||
uint64_t timeout = 0xFFFFFFFF;
|
if (timeout == 0)
|
||||||
do {
|
break;
|
||||||
timeout--;
|
} while (((*uart_busy) & 0x20) == 0);
|
||||||
if (timeout == 0)
|
|
||||||
break;
|
if (timeout == 0)
|
||||||
} while (((*uart_busy) & 0x20) == 0);
|
return -1;
|
||||||
|
|
||||||
if (timeout == 0)
|
*uart_tx = (uint32_t)tx_byte & 0xFF;
|
||||||
return -1;
|
return 0;
|
||||||
|
}
|
||||||
*uart_tx = (uint32_t)tx_byte & 0xFF;
|
|
||||||
return 0;
|
// Variable for val to hex
|
||||||
}
|
uint8_t hex_val[17];
|
||||||
|
|
||||||
// Variable for val to hex
|
__attribute__((noinline, optimize("O0"))) uint8_t *
|
||||||
uint8_t hex_val[17];
|
u64_to_hex_custom(uint64_t val, uint8_t *dest) {
|
||||||
|
const uint8_t hex_chars[] = "0123456789abcdef";
|
||||||
__attribute__((noinline, optimize("O0"))) uint8_t *
|
dest[16] = '\0';
|
||||||
u64_to_hex_custom(uint64_t val, uint8_t *dest) {
|
|
||||||
|
for (int i = 15; i >= 0; i--) {
|
||||||
const uint8_t hex_chars[] = "0123456789abcdef";
|
dest[i] = hex_chars[val & 0xf];
|
||||||
dest[16] = '\0';
|
val >>= 4;
|
||||||
|
}
|
||||||
for (int i = 15; i >= 0; i--) {
|
return dest;
|
||||||
dest[i] = hex_chars[val & 0xf];
|
}
|
||||||
val >>= 4;
|
|
||||||
}
|
__attribute__((noinline, optimize("O0"))) int printf(const uint8_t *msg) {
|
||||||
return dest;
|
uint32_t max = 255;
|
||||||
}
|
int ret = 0;
|
||||||
|
|
||||||
__attribute__((noinline, optimize("O0"))) int printf(const uint8_t *msg) {
|
for (int i = 0; i < 255; i++) {
|
||||||
uint32_t max = 255;
|
if (msg[i] == '\0') {
|
||||||
int ret = 0;
|
break;
|
||||||
|
}
|
||||||
for (int i = 0; i < 255; i++) {
|
if (msg[i] == '\n') {
|
||||||
if (msg[i] == '\0') {
|
putc_uart('\r');
|
||||||
break;
|
}
|
||||||
}
|
ret = putc_uart(msg[i]);
|
||||||
if (msg[i] == '\n') {
|
}
|
||||||
putc_uart('\r');
|
|
||||||
}
|
return ret;
|
||||||
ret = putc_uart(msg[i]);
|
}
|
||||||
}
|
|
||||||
|
__attribute__((noinline, optimize("O0"))) void memcpy(void *dest, void *src,
|
||||||
return ret;
|
uint64_t len) {
|
||||||
}
|
uint8_t *d = (uint8_t *)dest;
|
||||||
|
const uint8_t *s = (const uint8_t *)src;
|
||||||
__attribute__((noinline, optimize("O0"))) void memcpy(void *dest, void *src,
|
for (uint64_t i = 0; i < len; i++) {
|
||||||
uint64_t len) {
|
d[i] = s[i];
|
||||||
uint8_t *d = (uint8_t *)dest;
|
}
|
||||||
const uint8_t *s = (const uint8_t *)src;
|
}
|
||||||
for (uint64_t i = 0; i < len; i++) {
|
|
||||||
d[i] = s[i];
|
__attribute__((noinline, optimize("O0"))) char *strcpy(char *dest,
|
||||||
}
|
const char *src) {
|
||||||
}
|
char *d = dest;
|
||||||
|
while ((*d++ = *src++)) {
|
||||||
__attribute__((noinline, optimize("O0"))) char *strcpy(char *dest,
|
}
|
||||||
const char *src) {
|
return dest;
|
||||||
char *d = dest;
|
}
|
||||||
while ((*d++ = *src++)) {
|
|
||||||
}
|
__attribute__((noinline, optimize("O0"))) void *memset(void *s, int c,
|
||||||
return dest;
|
uint64_t n) {
|
||||||
}
|
unsigned char *p = (unsigned char *)s;
|
||||||
|
while (n--) {
|
||||||
__attribute__((noinline, optimize("O0"))) void *memset(void *s, int c,
|
*p++ = (unsigned char)c;
|
||||||
uint64_t n) {
|
}
|
||||||
unsigned char *p = (unsigned char *)s;
|
return s;
|
||||||
while (n--) {
|
}
|
||||||
*p++ = (unsigned char)c;
|
|
||||||
}
|
void disable_intr(void) { __asm__ __volatile__("cli" : : : "memory"); }
|
||||||
return s;
|
|
||||||
}
|
void halt(void) { __asm__ __volatile__("hlt"); }
|
||||||
|
|
||||||
void disable_intr(void) { __asm__ __volatile__("cli" : : : "memory"); }
|
uint64_t rdmsr(uint32_t msr) {
|
||||||
|
uint32_t low, high;
|
||||||
void halt(void) { __asm__ __volatile__("hlt"); }
|
__asm__ __volatile__("rdmsr" : "=a"(low), "=d"(high) : "c"(msr));
|
||||||
|
return ((uint64_t)high << 32) | low;
|
||||||
uint64_t rdmsr(uint32_t msr) {
|
}
|
||||||
uint32_t low, high;
|
|
||||||
__asm__ __volatile__("rdmsr" : "=a"(low), "=d"(high) : "c"(msr));
|
void wrmsr(uint32_t msr, uint64_t val) {
|
||||||
return ((uint64_t)high << 32) | low;
|
uint32_t low = val & 0xFFFFFFFF;
|
||||||
}
|
uint32_t high = val >> 32;
|
||||||
|
__asm__ __volatile__("wrmsr" : : "a"(low), "d"(high), "c"(msr));
|
||||||
void wrmsr(uint32_t msr, uint64_t val) {
|
}
|
||||||
uint32_t low = val & 0xFFFFFFFF;
|
|
||||||
uint32_t high = val >> 32;
|
void atomic_add_32(volatile uint32_t *p, uint32_t v) {
|
||||||
__asm__ __volatile__("wrmsr" : : "a"(low), "d"(high), "c"(msr));
|
__sync_fetch_and_add(p, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
void atomic_add_32(volatile uint32_t *p, uint32_t v) {
|
int atomic_cmpset_32(volatile uint32_t *dst, uint32_t exp, uint32_t src) {
|
||||||
__sync_fetch_and_add(p, v);
|
return __sync_bool_compare_and_swap(dst, exp, src);
|
||||||
}
|
}
|
||||||
|
|
||||||
int atomic_cmpset_32(volatile uint32_t *dst, uint32_t exp, uint32_t src) {
|
uint8_t get_cpu(void) {
|
||||||
return __sync_bool_compare_and_swap(dst, exp, src);
|
uint32_t eax, ebx, ecx, edx;
|
||||||
}
|
__get_cpuid(1, &eax, &ebx, &ecx, &edx);
|
||||||
|
uint8_t cpu_id = (ebx >> 24) & 0xFF;
|
||||||
uint8_t get_cpu(void) {
|
return cpu_id;
|
||||||
uint32_t eax, ebx, ecx, edx;
|
}
|
||||||
__get_cpuid(1, &eax, &ebx, &ecx, &edx);
|
|
||||||
uint8_t cpu_id = (ebx >> 24) & 0xFF;
|
|
||||||
return cpu_id;
|
|
||||||
}
|
|
||||||
@@ -1,28 +1,28 @@
|
|||||||
#ifndef UTILS_H
|
#ifndef UTILS_H
|
||||||
#define UTILS_H
|
#define UTILS_H
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
uint32_t putc_uart(uint8_t tx_byte);
|
uint32_t putc_uart(uint8_t tx_byte);
|
||||||
int printf(const uint8_t *msg);
|
int printf(const uint8_t *msg);
|
||||||
uint8_t *u64_to_hex_custom(uint64_t val, uint8_t *dest);
|
uint8_t *u64_to_hex_custom(uint64_t val, uint8_t *dest);
|
||||||
|
|
||||||
extern uint8_t hex_val[17];
|
extern uint8_t hex_val[17];
|
||||||
|
|
||||||
inline int print_val64(uint64_t val) {
|
inline int print_val64(uint64_t val) {
|
||||||
return printf(u64_to_hex_custom(val, hex_val));
|
return printf(u64_to_hex_custom(val, hex_val));
|
||||||
}
|
}
|
||||||
|
|
||||||
void memcpy(void *dest, void *src, uint64_t len);
|
void memcpy(void *dest, void *src, uint64_t len);
|
||||||
char *strcpy(char *dest, const char *src);
|
char *strcpy(char *dest, const char *src);
|
||||||
void *memset(void *s, int c, uint64_t n);
|
void *memset(void *s, int c, uint64_t n);
|
||||||
|
|
||||||
void disable_intr(void);
|
void disable_intr(void);
|
||||||
void halt(void);
|
void halt(void);
|
||||||
uint64_t rdmsr(uint32_t msr);
|
uint64_t rdmsr(uint32_t msr);
|
||||||
void wrmsr(uint32_t msr, uint64_t val);
|
void wrmsr(uint32_t msr, uint64_t val);
|
||||||
void atomic_add_32(volatile uint32_t *p, uint32_t v);
|
void atomic_add_32(volatile uint32_t *p, uint32_t v);
|
||||||
int atomic_cmpset_32(volatile uint32_t *dst, uint32_t exp, uint32_t src);
|
int atomic_cmpset_32(volatile uint32_t *dst, uint32_t exp, uint32_t src);
|
||||||
uint8_t get_cpu(void);
|
uint8_t get_cpu(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -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,40 +1,34 @@
|
|||||||
ifndef PS5_PAYLOAD_SDK
|
ifeq ($(shell uname -m),aarch64)
|
||||||
PS5_PAYLOAD_SDK = /opt/ps5-payload-sdk/
|
CC = x86_64-linux-gnu-gcc
|
||||||
endif
|
LD = x86_64-linux-gnu-ld
|
||||||
|
OBJCOPY = x86_64-linux-gnu-objcopy
|
||||||
|
else
|
||||||
ifeq ($(shell uname -m),aarch64)
|
CC = gcc
|
||||||
CC = x86_64-linux-gnu-gcc
|
LD = ld
|
||||||
LD = x86_64-linux-gnu-ld
|
OBJCOPY = objcopy
|
||||||
OBJCOPY = x86_64-linux-gnu-objcopy
|
endif
|
||||||
else
|
CFLAGS = -O2 -fno-stack-protector -ffreestanding -nostdlib -fcf-protection=none -m64
|
||||||
CC = gcc
|
LDFLAGS = -T linker.ld -Wl,--no-warn-rwx-segments
|
||||||
LD = ld
|
TARGET = shellcode_kernel.elf
|
||||||
OBJCOPY = objcopy
|
TEXT_BIN = shellcode_kernel.bin
|
||||||
endif
|
dump = shellcode_kernel.h
|
||||||
CFLAGS = -O2 -fno-stack-protector -ffreestanding -nostdlib -m64 -I$(PS5_PAYLOAD_SDK)/target/include
|
|
||||||
LDFLAGS = -T linker.ld
|
SRC = $(wildcard *.c)
|
||||||
TARGET = shellcode_kernel.elf
|
OBJ = $(SRC:.c=.o)
|
||||||
TEXT_BIN = shellcode_text.bin
|
|
||||||
|
all: $(dump)
|
||||||
SRC = main.c utils.c kernel_code.c
|
|
||||||
OBJ = $(SRC:.c=.o)
|
$(TARGET): $(OBJ)
|
||||||
|
$(CC) $(CFLAGS) $(LDFLAGS) $(OBJ) -o $(TARGET)
|
||||||
dump = shellcode_kernel.h
|
|
||||||
|
%.o: %.c
|
||||||
all: $(dump)
|
$(CC) $(CFLAGS) -c $< -o $@
|
||||||
|
|
||||||
$(TARGET): $(OBJ)
|
$(TEXT_BIN): $(TARGET)
|
||||||
$(CC) $(CFLAGS) $(LDFLAGS) $(OBJ) -o $(TARGET)
|
$(OBJCOPY) -O binary -j .shell_code $(TARGET) $(TEXT_BIN)
|
||||||
|
|
||||||
%.o: %.c
|
clean:
|
||||||
$(CC) $(CFLAGS) -c $< -o $@
|
rm -f $(OBJ) $(TARGET) $(TEXT_BIN) $(dump)
|
||||||
|
|
||||||
$(TEXT_BIN): $(TARGET)
|
$(dump): $(TEXT_BIN)
|
||||||
$(OBJCOPY) -O binary -j .text $(TARGET) $(TEXT_BIN)
|
xxd -i $(TEXT_BIN) > $(dump)
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -f $(OBJ) $(TARGET) $(TEXT_BIN) $(dump)
|
|
||||||
|
|
||||||
$(dump): $(TEXT_BIN)
|
|
||||||
python3 bin_to_c_kernel.py $(TEXT_BIN)
|
|
||||||
|
|||||||
@@ -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,18 +1,18 @@
|
|||||||
#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);
|
||||||
extern int (*mp3_initialize)(int vmid);
|
extern int (*mp3_initialize)(int vmid);
|
||||||
extern int (*mp3_invoke)(int cmd_id, void *req, void *rsp);
|
extern int (*mp3_invoke)(int cmd_id, void *req, void *rsp);
|
||||||
|
|
||||||
extern uint64_t g_vbios; // for main.c
|
extern uint64_t g_vbios; // for main.c
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
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
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
/* linker.ld */
|
/* linker.ld */
|
||||||
ENTRY(main)
|
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)
|
{
|
||||||
*(.text)
|
*(.entry_point)
|
||||||
*(.text.*)
|
*(.text)
|
||||||
*(.data)
|
*(.text.*)
|
||||||
*(.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 "utils.h"
|
#include "exploit_0304.h"
|
||||||
#include <stdint.h>
|
#include "utils.h"
|
||||||
|
#include <stddef.h>
|
||||||
shellcode_kernel_args args = {0};
|
#include <stdint.h>
|
||||||
|
|
||||||
__attribute__((section(".entry_point"))) uint32_t main(uint64_t add1,
|
shellcode_kernel_args args = {0};
|
||||||
uint64_t add2) {
|
|
||||||
|
// We are being called instead of AcpiSetFirmwareWakingVector
|
||||||
volatile shellcode_kernel_args *args_ptr =
|
__attribute__((section(".entry_point"))) uint32_t main(uint64_t add1,
|
||||||
(volatile shellcode_kernel_args
|
uint64_t add2) {
|
||||||
*)0x11AA11AA11AA11AA; // To be replaced with proper address in .kdata
|
// We will do main checks on .text only with a reference to .data
|
||||||
// by loader
|
volatile shellcode_kernel_args *args_ptr =
|
||||||
|
(volatile shellcode_kernel_args
|
||||||
// "Hide" the pointer from the optimizer
|
*)0x11AA11AA11AA11AA; // To be replaced with proper address in .kdata
|
||||||
__asm__ volatile("" : "+r"(args_ptr));
|
|
||||||
|
// "Hide" the pointer from the optimizer
|
||||||
if ((args_ptr->fun_printf & 0xFFFF) == 0) {
|
__asm__ volatile("" : "+r"(args_ptr));
|
||||||
goto out;
|
|
||||||
}
|
// We don't have required information - Abort
|
||||||
|
if ((args_ptr->fun_printf & 0xFFFF) == 0) {
|
||||||
uint32_t *uart_va = (uint32_t *)(args_ptr->dmap_base + 0xC0115110ULL);
|
return -1;
|
||||||
*uart_va &= ~0x200;
|
}
|
||||||
uint32_t *override_char_va = (uint32_t *)args_ptr->kernel_uart_override;
|
|
||||||
*override_char_va = 0x0;
|
activate_uart(args_ptr);
|
||||||
|
|
||||||
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 =
|
init_global_pointers(args_ptr);
|
||||||
((uint64_t(*)(uint64_t))args_ptr->fun_va_to_pa)(args_ptr->iommu_eb_va);
|
patch_hv_0304();
|
||||||
|
} else if ((0x0500 <= args_ptr->fw_version) &&
|
||||||
uint64_t unk;
|
(args_ptr->fw_version < 0x0650)) {
|
||||||
int n_devices;
|
// escape_hv_0506();
|
||||||
|
// Now we can R/W on .text
|
||||||
int ret = ((uint64_t(*)(uint64_t, uint64_t, uint64_t, uint64_t,
|
// init_global_pointers(args_ptr);
|
||||||
int *))args_ptr->fun_hv_iommu_set_buffers)(
|
} else {
|
||||||
iommu_cb2_pa, iommu_cb3_pa, iommu_eb_pa, (uint64_t) &unk, &n_devices);
|
return 0;
|
||||||
|
}
|
||||||
if (ret != 0) {
|
|
||||||
putc_uart(args_ptr->dmap_base, 'I');
|
boot_linux();
|
||||||
putc_uart(args_ptr->dmap_base, 'O');
|
printf("Linux prepared OK\n");
|
||||||
putc_uart(args_ptr->dmap_base, 'M');
|
|
||||||
putc_uart(args_ptr->dmap_base, 'M');
|
printf("Good Bye VM :)\n");
|
||||||
putc_uart(args_ptr->dmap_base, 'U');
|
smp_rendezvous(smp_no_rendevous_barrier, vmmcall_dummy,
|
||||||
putc_uart(args_ptr->dmap_base, ' ');
|
smp_no_rendevous_barrier, NULL);
|
||||||
putc_uart(args_ptr->dmap_base, 's');
|
|
||||||
putc_uart(args_ptr->dmap_base, 'b');
|
printf("We shouldn't be here :(\n");
|
||||||
putc_uart(args_ptr->dmap_base, ' ');
|
return 0;
|
||||||
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);
|
|
||||||
|
|
||||||
printf("HV_Defeat: we should be ready for Linux part\n");
|
|
||||||
|
|
||||||
boot_linux();
|
|
||||||
printf("Linux prepared OK\n");
|
|
||||||
|
|
||||||
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 {
|
|
||||||
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, '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:
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,65 +1,13 @@
|
|||||||
#ifndef MAIN_H
|
#ifndef MAIN_H
|
||||||
#define MAIN_H
|
#define MAIN_H
|
||||||
#include "shellcode_kernel_args.h"
|
#include "shellcode_kernel_args.h"
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
void (*printf)(const char *format, ...);
|
void (*printf)(const char *format, ...);
|
||||||
uint32_t (*AcpiSetFirmwareWakingVector)(uint64_t PhysicalAddress,
|
void (*smp_rendezvous)(void (*setup_func)(void), void (*action_func)(void),
|
||||||
uint64_t PhysicalAddress64);
|
void (*teardown_func)(void), void *arg);
|
||||||
uint64_t (*kernel_va_to_pa)(uint64_t va);
|
void (*smp_no_rendevous_barrier)(void);
|
||||||
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 main(uint64_t add1, uint64_t add2);
|
||||||
uint32_t (*hv_iommu_wait_completion)(void);
|
|
||||||
void (*smp_rendezvous)(void (*setup_func)(void), void (*action_func)(void),
|
#endif
|
||||||
void (*teardown_func)(void), void *arg);
|
|
||||||
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);
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|||||||
@@ -1,37 +1,36 @@
|
|||||||
// This file is shared between main payload and kernel shellcode
|
// This file is shared between main payload and kernel shellcode
|
||||||
#ifndef SHELLCODE_KERNEL_ARGS_H
|
#ifndef SHELLCODE_KERNEL_ARGS_H
|
||||||
#define SHELLCODE_KERNEL_ARGS_H
|
#define SHELLCODE_KERNEL_ARGS_H
|
||||||
|
|
||||||
#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;
|
||||||
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 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 g_vbios;
|
uint64_t g_vbios;
|
||||||
uint64_t iommu_mmio_va;
|
uint64_t iommu_mmio_va;
|
||||||
uint64_t iommu_cb2_va;
|
uint64_t iommu_cb2_va;
|
||||||
uint64_t iommu_cb3_va;
|
uint64_t iommu_cb3_va;
|
||||||
uint64_t iommu_eb_va;
|
uint64_t iommu_eb_va;
|
||||||
uint64_t vmcb[16];
|
uint64_t vmcb[16];
|
||||||
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;
|
|
||||||
|
extern shellcode_kernel_args args; // Declared on main.c
|
||||||
extern shellcode_kernel_args args; // Declared on main.c
|
|
||||||
|
#endif
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -1,77 +1,115 @@
|
|||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "shellcode_kernel_args.h"
|
#include "shellcode_kernel_args.h"
|
||||||
|
|
||||||
extern shellcode_kernel_args args;
|
extern shellcode_kernel_args args;
|
||||||
|
|
||||||
uint64_t PHYS_TO_DMAP(uint64_t pa) { return args.dmap_base + pa; }
|
uint64_t PHYS_TO_DMAP(uint64_t pa) { return args.dmap_base + pa; }
|
||||||
|
|
||||||
void memcpy(void *dest, void *src, uint64_t len) {
|
void memcpy(void *dest, void *src, uint64_t len) {
|
||||||
uint8_t *d = (uint8_t *)dest;
|
uint8_t *d = (uint8_t *)dest;
|
||||||
const uint8_t *s = (const uint8_t *)src;
|
const uint8_t *s = (const uint8_t *)src;
|
||||||
for (uint64_t i = 0; i < len; i++) {
|
for (uint64_t i = 0; i < len; i++) {
|
||||||
d[i] = s[i];
|
d[i] = s[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
:
|
}
|
||||||
:
|
|
||||||
);
|
uint64_t vtophys(uint64_t dmap, uint64_t va) {
|
||||||
return cr3;
|
uint64_t cr3 = read_cr3();
|
||||||
}
|
return vtophys_custom(dmap, va, cr3);
|
||||||
|
}
|
||||||
// for ring0
|
|
||||||
uint64_t va_to_pa_kernel(uint64_t va) {
|
uint64_t vtophys_custom(uint64_t dmap, uint64_t va, uint64_t cr3_custom) {
|
||||||
uint64_t cr3 = read_cr3();
|
uint64_t table_phys = cr3_custom & 0xFFFFFFFF;
|
||||||
return va_to_pa_custom(va, cr3);
|
|
||||||
}
|
for (int level = 0; level < 4; level++) {
|
||||||
|
int shift = 39 - (level * 9);
|
||||||
// Source: PS5_kldload
|
uint64_t idx = (va >> shift) & 0x1FF;
|
||||||
uint64_t va_to_pa_custom(uint64_t va, uint64_t cr3_custom) {
|
uint64_t entry;
|
||||||
|
uint64_t entry_va = dmap + PAGE_PA(table_phys) + idx * 8;
|
||||||
uint64_t table_phys = cr3_custom & 0xFFFFFFFF;
|
|
||||||
|
entry = *(uint64_t *)entry_va;
|
||||||
for (int level = 0; level < 4; level++) {
|
|
||||||
int shift = 39 - (level * 9);
|
if (!PAGE_P(entry))
|
||||||
uint64_t idx = (va >> shift) & 0x1FF;
|
return 0;
|
||||||
uint64_t entry;
|
|
||||||
uint64_t entry_va = PHYS_TO_DMAP(PAGE_PA(table_phys) + idx * 8);
|
if ((level == 1 || level == 2) && PAGE_PS(entry)) {
|
||||||
|
uint64_t page_size = P_SIZE(level);
|
||||||
entry = *(uint64_t *)entry_va;
|
return PAGE_PA(entry) | (va & (page_size - 1));
|
||||||
|
}
|
||||||
if (!PAGE_P(entry))
|
|
||||||
return 0;
|
if (level == 3)
|
||||||
|
return PAGE_PA(entry) | (va & 0xFFF);
|
||||||
if ((level == 1 || level == 2) && PAGE_PS(entry)) {
|
|
||||||
uint64_t page_size = P_SIZE(level);
|
table_phys = PAGE_PA(entry);
|
||||||
return PAGE_PA(entry) | (va & (page_size - 1));
|
}
|
||||||
}
|
return 0;
|
||||||
|
}
|
||||||
if (level == 3)
|
|
||||||
return PAGE_PA(entry) | (va & 0xFFF);
|
uint32_t putc_uart(uint64_t dmap, uint8_t tx_byte) {
|
||||||
|
volatile uint32_t *uart_tx = (uint32_t *)(dmap + 0xc1010104ULL);
|
||||||
table_phys = PAGE_PA(entry);
|
volatile uint32_t *uart_busy = (uint32_t *)(dmap + 0xc101010cULL);
|
||||||
}
|
uint64_t timeout = 0xFFFFFFFF;
|
||||||
return 0;
|
do {
|
||||||
}
|
timeout--;
|
||||||
|
if (timeout == 0)
|
||||||
__attribute__((noinline, optimize("O0"))) uint32_t putc_uart(uint64_t dmap,
|
break;
|
||||||
uint8_t tx_byte) {
|
} while (((*uart_busy) & 0x20) == 0);
|
||||||
volatile uint32_t *uart_tx = (uint32_t *) (dmap + 0xc1010104ULL);
|
|
||||||
volatile uint32_t *uart_busy = (uint32_t *) (dmap + 0xc101010cULL);
|
if (timeout == 0)
|
||||||
uint64_t timeout = 0xFFFFFFFF;
|
return -1;
|
||||||
do {
|
|
||||||
timeout--;
|
*uart_tx = (uint32_t)tx_byte & 0xFF;
|
||||||
if (timeout == 0)
|
return 0;
|
||||||
break;
|
}
|
||||||
} while (((*uart_busy) & 0x20) == 0);
|
|
||||||
|
int puts_uart(uint64_t dmap, const uint8_t *msg) {
|
||||||
if (timeout == 0)
|
uint32_t max = 255;
|
||||||
return -1;
|
int ret = 0;
|
||||||
|
|
||||||
*uart_tx = (uint32_t)tx_byte & 0xFF;
|
for (int i = 0; i < 255; i++) {
|
||||||
return 0;
|
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,43 +1,56 @@
|
|||||||
#ifndef UTILS_H
|
#ifndef UTILS_H
|
||||||
#define UTILS_H
|
#define UTILS_H
|
||||||
#include "shellcode_kernel_args.h"
|
#include "boot_linux.h"
|
||||||
#include <stdint.h>
|
#include "shellcode_kernel_args.h"
|
||||||
|
#include <stdint.h>
|
||||||
extern void (*printf)(const char *format, ...);
|
|
||||||
uint64_t PHYS_TO_DMAP(uint64_t pa);
|
extern void (*printf)(const char *format, ...);
|
||||||
void memcpy(void *dest, void *src, uint64_t len);
|
extern void (*smp_rendezvous)(void (*setup_func)(void),
|
||||||
|
void (*action_func)(void),
|
||||||
// Defines for Page management
|
void (*teardown_func)(void), void *arg);
|
||||||
enum page_bits {
|
extern void (*smp_no_rendevous_barrier)(void);
|
||||||
P = 0,
|
extern int (*transmitter_control)(int cmd, void *control);
|
||||||
RW,
|
extern int (*mp3_initialize)(int vmid);
|
||||||
US,
|
extern int (*mp3_invoke)(int cmd_id, void *req, void *rsp);
|
||||||
PWT,
|
extern uint64_t g_vbios;
|
||||||
PCD,
|
|
||||||
A,
|
// Defines for Page management
|
||||||
D,
|
enum page_bits {
|
||||||
PS,
|
P = 0,
|
||||||
G,
|
RW,
|
||||||
XO = 58,
|
US,
|
||||||
PK = 59,
|
PWT,
|
||||||
NX = 63
|
PCD,
|
||||||
};
|
A,
|
||||||
|
D,
|
||||||
#define PG_B_P (1ULL << P)
|
PS,
|
||||||
#define PG_B_RW (1ULL << RW)
|
G,
|
||||||
#define PAGE_P(x) (x & (1ULL << P))
|
XO = 58,
|
||||||
#define PAGE_RW(x) (x & (1ULL << RW))
|
PK = 59,
|
||||||
#define PAGE_PS(x) (x & (1ULL << PS))
|
NX = 63
|
||||||
#define PAGE_XO(x) (x & (1ULL << XO))
|
};
|
||||||
#define PAGE_CLEAR_XO(x) (x &= ~(1ULL << XO))
|
|
||||||
#define PAGE_CLEAR_G(x) (x &= ~(1ULL << G))
|
#define PG_B_P (1ULL << P)
|
||||||
#define PAGE_SET_RW(x) (x |= (1ULL << RW))
|
#define PG_B_RW (1ULL << RW)
|
||||||
#define PAGE_PA(x) (x & 0x000FFFFFFFFFF000ULL)
|
#define PAGE_P(x) (x & (1ULL << P))
|
||||||
#define P_SIZE(l) ((l == 1) ? (1ULL << 30) : (1ULL << 21))
|
#define PAGE_RW(x) (x & (1ULL << RW))
|
||||||
|
#define PAGE_PS(x) (x & (1ULL << PS))
|
||||||
uint64_t read_cr3(void);
|
#define PAGE_XO(x) (x & (1ULL << XO))
|
||||||
uint64_t va_to_pa_kernel(uint64_t va);
|
#define PAGE_CLEAR_XO(x) (x &= ~(1ULL << XO))
|
||||||
uint64_t va_to_pa_custom(uint64_t va, uint64_t cr3_custom);
|
#define PAGE_CLEAR_G(x) (x &= ~(1ULL << G))
|
||||||
uint32_t putc_uart(uint64_t dmap, uint8_t tx_byte);
|
#define PAGE_SET_RW(x) (x |= (1ULL << RW))
|
||||||
|
#define PAGE_PA(x) (x & 0x000FFFFFFFFFF000ULL)
|
||||||
#endif
|
#define P_SIZE(l) ((l == 1) ? (1ULL << 30) : (1ULL << 21))
|
||||||
|
|
||||||
|
uint64_t read_cr3(void);
|
||||||
|
uint64_t vtophys(uint64_t dmap, uint64_t va);
|
||||||
|
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);
|
||||||
|
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
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
990
source/gpu.c
990
source/gpu.c
@@ -1,495 +1,495 @@
|
|||||||
#include "gpu.h"
|
#include "gpu.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <ps5/kernel.h>
|
#include <ps5/kernel.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
int sceKernelAllocateMainDirectMemory(size_t size, size_t alignment,
|
int sceKernelAllocateMainDirectMemory(size_t size, size_t alignment,
|
||||||
int mem_type, uint64_t *phys_out);
|
int mem_type, uint64_t *phys_out);
|
||||||
int sceKernelMapNamedDirectMemory(void **va_out, size_t size, int prot,
|
int sceKernelMapNamedDirectMemory(void **va_out, size_t size, int prot,
|
||||||
int flags, uint64_t phys, size_t alignment,
|
int flags, uint64_t phys, size_t alignment,
|
||||||
const char *name);
|
const char *name);
|
||||||
int sceKernelSleep(int secs);
|
int sceKernelSleep(int secs);
|
||||||
|
|
||||||
static struct gpu_ctx s_gpu = {0};
|
static struct gpu_ctx s_gpu = {0};
|
||||||
static struct gpu_kernel_offsets s_gpu_offsets = {0};
|
static struct gpu_kernel_offsets s_gpu_offsets = {0};
|
||||||
static int s_offsets_set = 0;
|
static int s_offsets_set = 0;
|
||||||
|
|
||||||
struct gpu_ctx *gpu_get_ctx(void) { return &s_gpu; }
|
struct gpu_ctx *gpu_get_ctx(void) { return &s_gpu; }
|
||||||
|
|
||||||
void gpu_set_offsets(struct gpu_kernel_offsets *offsets) {
|
void gpu_set_offsets(struct gpu_kernel_offsets *offsets) {
|
||||||
memcpy(&s_gpu_offsets, offsets, sizeof(s_gpu_offsets));
|
memcpy(&s_gpu_offsets, offsets, sizeof(s_gpu_offsets));
|
||||||
s_offsets_set = 1;
|
s_offsets_set = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint64_t gpu_pde_field(uint64_t pde, int shift, uint64_t mask) {
|
static uint64_t gpu_pde_field(uint64_t pde, int shift, uint64_t mask) {
|
||||||
return (pde >> shift) & mask;
|
return (pde >> shift) & mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int gpu_get_vmid(void) {
|
static int gpu_get_vmid(void) {
|
||||||
uint64_t curproc = kernel_get_proc(getpid());
|
uint64_t curproc = kernel_get_proc(getpid());
|
||||||
uint64_t vmspace;
|
uint64_t vmspace;
|
||||||
uint32_t vmid;
|
uint32_t vmid;
|
||||||
|
|
||||||
kernel_copyout(curproc + s_gpu_offsets.proc_vmspace, &vmspace,
|
kernel_copyout(curproc + s_gpu_offsets.proc_vmspace, &vmspace,
|
||||||
sizeof(vmspace));
|
sizeof(vmspace));
|
||||||
kernel_copyout(vmspace + s_gpu_offsets.vmspace_vm_vmid, &vmid, sizeof(vmid));
|
kernel_copyout(vmspace + s_gpu_offsets.vmspace_vm_vmid, &vmid, sizeof(vmid));
|
||||||
|
|
||||||
return (int)vmid;
|
return (int)vmid;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint64_t gpu_get_pdb2_addr(int vmid) {
|
static uint64_t gpu_get_pdb2_addr(int vmid) {
|
||||||
uint64_t gvmspace = KERNEL_ADDRESS_DATA_BASE +
|
uint64_t gvmspace = KERNEL_ADDRESS_DATA_BASE +
|
||||||
s_gpu_offsets.data_base_gvmspace +
|
s_gpu_offsets.data_base_gvmspace +
|
||||||
(uint64_t)vmid * s_gpu_offsets.sizeof_gvmspace;
|
(uint64_t)vmid * s_gpu_offsets.sizeof_gvmspace;
|
||||||
|
|
||||||
uint64_t pdb2_va;
|
uint64_t pdb2_va;
|
||||||
kernel_copyout(gvmspace + s_gpu_offsets.gvmspace_page_dir_va, &pdb2_va,
|
kernel_copyout(gvmspace + s_gpu_offsets.gvmspace_page_dir_va, &pdb2_va,
|
||||||
sizeof(pdb2_va));
|
sizeof(pdb2_va));
|
||||||
return pdb2_va;
|
return pdb2_va;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint64_t gpu_get_relative_va(int vmid, uint64_t va) {
|
static uint64_t gpu_get_relative_va(int vmid, uint64_t va) {
|
||||||
uint64_t gvmspace = KERNEL_ADDRESS_DATA_BASE +
|
uint64_t gvmspace = KERNEL_ADDRESS_DATA_BASE +
|
||||||
s_gpu_offsets.data_base_gvmspace +
|
s_gpu_offsets.data_base_gvmspace +
|
||||||
(uint64_t)vmid * s_gpu_offsets.sizeof_gvmspace;
|
(uint64_t)vmid * s_gpu_offsets.sizeof_gvmspace;
|
||||||
|
|
||||||
uint64_t start_va, size;
|
uint64_t start_va, size;
|
||||||
kernel_copyout(gvmspace + s_gpu_offsets.gvmspace_start_va, &start_va,
|
kernel_copyout(gvmspace + s_gpu_offsets.gvmspace_start_va, &start_va,
|
||||||
sizeof(start_va));
|
sizeof(start_va));
|
||||||
kernel_copyout(gvmspace + s_gpu_offsets.gvmspace_size, &size, sizeof(size));
|
kernel_copyout(gvmspace + s_gpu_offsets.gvmspace_size, &size, sizeof(size));
|
||||||
|
|
||||||
if (va >= start_va && va < start_va + size)
|
if (va >= start_va && va < start_va + size)
|
||||||
return va - start_va;
|
return va - start_va;
|
||||||
|
|
||||||
return (uint64_t)-1;
|
return (uint64_t)-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint64_t gpu_walk_pt(int vmid, uint64_t gpu_va,
|
static uint64_t gpu_walk_pt(int vmid, uint64_t gpu_va,
|
||||||
uint64_t *out_page_size) {
|
uint64_t *out_page_size) {
|
||||||
uint64_t pdb2_addr = gpu_get_pdb2_addr(vmid);
|
uint64_t pdb2_addr = gpu_get_pdb2_addr(vmid);
|
||||||
|
|
||||||
uint64_t pml4e_idx = (gpu_va >> 39) & 0x1FF;
|
uint64_t pml4e_idx = (gpu_va >> 39) & 0x1FF;
|
||||||
uint64_t pdpe_idx = (gpu_va >> 30) & 0x1FF;
|
uint64_t pdpe_idx = (gpu_va >> 30) & 0x1FF;
|
||||||
uint64_t pde_idx = (gpu_va >> 21) & 0x1FF;
|
uint64_t pde_idx = (gpu_va >> 21) & 0x1FF;
|
||||||
|
|
||||||
// PDB2 (PML4 equivalent)
|
// PDB2 (PML4 equivalent)
|
||||||
uint64_t pml4e;
|
uint64_t pml4e;
|
||||||
kernel_copyout(pdb2_addr + pml4e_idx * 8, &pml4e, sizeof(pml4e));
|
kernel_copyout(pdb2_addr + pml4e_idx * 8, &pml4e, sizeof(pml4e));
|
||||||
|
|
||||||
if (gpu_pde_field(pml4e, GPU_PDE_VALID_BIT, 1) != 1)
|
if (gpu_pde_field(pml4e, GPU_PDE_VALID_BIT, 1) != 1)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
// PDB1 (PDPT equivalent)
|
// PDB1 (PDPT equivalent)
|
||||||
uint64_t pdp_pa = pml4e & GPU_PDE_ADDR_MASK;
|
uint64_t pdp_pa = pml4e & GPU_PDE_ADDR_MASK;
|
||||||
uint64_t pdpe_va = dmap + pdp_pa + pdpe_idx * 8;
|
uint64_t pdpe_va = dmap + pdp_pa + pdpe_idx * 8;
|
||||||
uint64_t pdpe;
|
uint64_t pdpe;
|
||||||
kernel_copyout(pdpe_va, &pdpe, sizeof(pdpe));
|
kernel_copyout(pdpe_va, &pdpe, sizeof(pdpe));
|
||||||
|
|
||||||
if (gpu_pde_field(pdpe, GPU_PDE_VALID_BIT, 1) != 1)
|
if (gpu_pde_field(pdpe, GPU_PDE_VALID_BIT, 1) != 1)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
// PDB0 (PD equivalent)
|
// PDB0 (PD equivalent)
|
||||||
uint64_t pd_pa = pdpe & GPU_PDE_ADDR_MASK;
|
uint64_t pd_pa = pdpe & GPU_PDE_ADDR_MASK;
|
||||||
uint64_t pde_va = dmap + pd_pa + pde_idx * 8;
|
uint64_t pde_va = dmap + pd_pa + pde_idx * 8;
|
||||||
uint64_t pde;
|
uint64_t pde;
|
||||||
kernel_copyout(pde_va, &pde, sizeof(pde));
|
kernel_copyout(pde_va, &pde, sizeof(pde));
|
||||||
|
|
||||||
if (gpu_pde_field(pde, GPU_PDE_VALID_BIT, 1) != 1)
|
if (gpu_pde_field(pde, GPU_PDE_VALID_BIT, 1) != 1)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
// If IS_PTE bit set, this is a 2MB leaf
|
// If IS_PTE bit set, this is a 2MB leaf
|
||||||
if (gpu_pde_field(pde, GPU_PDE_IS_PTE_BIT, 1) == 1) {
|
if (gpu_pde_field(pde, GPU_PDE_IS_PTE_BIT, 1) == 1) {
|
||||||
*out_page_size = 0x200000;
|
*out_page_size = 0x200000;
|
||||||
return pde_va;
|
return pde_va;
|
||||||
}
|
}
|
||||||
|
|
||||||
// PTB (page table block)
|
// PTB (page table block)
|
||||||
uint64_t frag_size = gpu_pde_field(pde, GPU_PDE_BLOCK_FRAG_BIT, 0x1F);
|
uint64_t frag_size = gpu_pde_field(pde, GPU_PDE_BLOCK_FRAG_BIT, 0x1F);
|
||||||
uint64_t offset = gpu_va & 0x1FFFFF;
|
uint64_t offset = gpu_va & 0x1FFFFF;
|
||||||
uint64_t pt_pa = pde & GPU_PDE_ADDR_MASK;
|
uint64_t pt_pa = pde & GPU_PDE_ADDR_MASK;
|
||||||
|
|
||||||
uint64_t pte_idx, pte_va;
|
uint64_t pte_idx, pte_va;
|
||||||
|
|
||||||
if (frag_size == 4) {
|
if (frag_size == 4) {
|
||||||
pte_idx = offset >> 16;
|
pte_idx = offset >> 16;
|
||||||
pte_va = dmap + pt_pa + pte_idx * 8;
|
pte_va = dmap + pt_pa + pte_idx * 8;
|
||||||
|
|
||||||
uint64_t pte;
|
uint64_t pte;
|
||||||
kernel_copyout(pte_va, &pte, sizeof(pte));
|
kernel_copyout(pte_va, &pte, sizeof(pte));
|
||||||
|
|
||||||
if (gpu_pde_field(pte, GPU_PDE_VALID_BIT, 1) == 1 &&
|
if (gpu_pde_field(pte, GPU_PDE_VALID_BIT, 1) == 1 &&
|
||||||
gpu_pde_field(pte, GPU_PDE_TF_BIT, 1) == 1) {
|
gpu_pde_field(pte, GPU_PDE_TF_BIT, 1) == 1) {
|
||||||
pte_idx = (gpu_va & 0xFFFF) >> 13;
|
pte_idx = (gpu_va & 0xFFFF) >> 13;
|
||||||
pte_va = dmap + pt_pa + pte_idx * 8;
|
pte_va = dmap + pt_pa + pte_idx * 8;
|
||||||
*out_page_size = 0x2000; // 8KB
|
*out_page_size = 0x2000; // 8KB
|
||||||
} else {
|
} else {
|
||||||
*out_page_size = 0x10000; // 64KB
|
*out_page_size = 0x10000; // 64KB
|
||||||
}
|
}
|
||||||
} else if (frag_size == 1) {
|
} else if (frag_size == 1) {
|
||||||
pte_idx = offset >> 13;
|
pte_idx = offset >> 13;
|
||||||
pte_va = dmap + pt_pa + pte_idx * 8;
|
pte_va = dmap + pt_pa + pte_idx * 8;
|
||||||
*out_page_size = 0x2000; // 8KB
|
*out_page_size = 0x2000; // 8KB
|
||||||
} else {
|
} else {
|
||||||
// Unknown fragment size - use 64KB as default
|
// Unknown fragment size - use 64KB as default
|
||||||
pte_idx = offset >> 16;
|
pte_idx = offset >> 16;
|
||||||
pte_va = dmap + pt_pa + pte_idx * 8;
|
pte_va = dmap + pt_pa + pte_idx * 8;
|
||||||
*out_page_size = 0x10000;
|
*out_page_size = 0x10000;
|
||||||
}
|
}
|
||||||
|
|
||||||
return pte_va;
|
return pte_va;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint64_t gpu_alloc_dmem(uint64_t size, int gpu_write) {
|
static uint64_t gpu_alloc_dmem(uint64_t size, int gpu_write) {
|
||||||
uint64_t phys_out = 0;
|
uint64_t phys_out = 0;
|
||||||
void *va_out = NULL;
|
void *va_out = NULL;
|
||||||
|
|
||||||
int prot = PROT_READ | PROT_WRITE | PROT_GPU_READ;
|
int prot = PROT_READ | PROT_WRITE | PROT_GPU_READ;
|
||||||
if (gpu_write)
|
if (gpu_write)
|
||||||
prot |= PROT_GPU_WRITE;
|
prot |= PROT_GPU_WRITE;
|
||||||
|
|
||||||
int ret = sceKernelAllocateMainDirectMemory(size, size, 1, &phys_out);
|
int ret = sceKernelAllocateMainDirectMemory(size, size, 1, &phys_out);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
printf("[gpu] sceKernelAllocateMainDirectMemory failed: 0x%d\n", ret);
|
printf("[gpu] sceKernelAllocateMainDirectMemory failed: 0x%d\n", ret);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = sceKernelMapNamedDirectMemory(&va_out, size, prot, MAP_NO_COALESCE,
|
ret = sceKernelMapNamedDirectMemory(&va_out, size, prot, MAP_NO_COALESCE,
|
||||||
phys_out, size, "gpudma");
|
phys_out, size, "gpudma");
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
printf("[gpu] sceKernelMapNamedDirectMemory failed: 0x%d\n", ret);
|
printf("[gpu] sceKernelMapNamedDirectMemory failed: 0x%d\n", ret);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (uint64_t)va_out;
|
return (uint64_t)va_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t pm4_type3_header(uint32_t opcode, uint32_t count) {
|
static uint32_t pm4_type3_header(uint32_t opcode, uint32_t count) {
|
||||||
return ((PM4_TYPE3 & 0x3) << 30) | (((count - 1) & 0x3FFF) << 16) |
|
return ((PM4_TYPE3 & 0x3) << 30) | (((count - 1) & 0x3FFF) << 16) |
|
||||||
((opcode & 0xFF) << 8) | ((PM4_SHADER_COMPUTE & 0x1) << 1);
|
((opcode & 0xFF) << 8) | ((PM4_SHADER_COMPUTE & 0x1) << 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pm4_build_dma_data(void *buf, uint64_t dst_va, uint64_t src_va,
|
static int pm4_build_dma_data(void *buf, uint64_t dst_va, uint64_t src_va,
|
||||||
uint32_t length) {
|
uint32_t length) {
|
||||||
uint32_t *pkt = (uint32_t *)buf;
|
uint32_t *pkt = (uint32_t *)buf;
|
||||||
uint32_t count = 6;
|
uint32_t count = 6;
|
||||||
|
|
||||||
uint32_t dma_hdr = (1u << 31) // cp_sync
|
uint32_t dma_hdr = (1u << 31) // cp_sync
|
||||||
| (2u << 25) // dst_cache_policy
|
| (2u << 25) // dst_cache_policy
|
||||||
| (1u << 27) // dst_volatile
|
| (1u << 27) // dst_volatile
|
||||||
| (2u << 13) // src_cache_policy
|
| (2u << 13) // src_cache_policy
|
||||||
| (1u << 15); // src_volatile
|
| (1u << 15); // src_volatile
|
||||||
|
|
||||||
pkt[0] = pm4_type3_header(PM4_OPCODE_DMA_DATA, count);
|
pkt[0] = pm4_type3_header(PM4_OPCODE_DMA_DATA, count);
|
||||||
pkt[1] = dma_hdr;
|
pkt[1] = dma_hdr;
|
||||||
pkt[2] = (uint32_t)(src_va & 0xFFFFFFFF);
|
pkt[2] = (uint32_t)(src_va & 0xFFFFFFFF);
|
||||||
pkt[3] = (uint32_t)(src_va >> 32);
|
pkt[3] = (uint32_t)(src_va >> 32);
|
||||||
pkt[4] = (uint32_t)(dst_va & 0xFFFFFFFF);
|
pkt[4] = (uint32_t)(dst_va & 0xFFFFFFFF);
|
||||||
pkt[5] = (uint32_t)(dst_va >> 32);
|
pkt[5] = (uint32_t)(dst_va >> 32);
|
||||||
pkt[6] = length & 0x1FFFFF;
|
pkt[6] = length & 0x1FFFFF;
|
||||||
|
|
||||||
return 7 * sizeof(uint32_t);
|
return 7 * sizeof(uint32_t);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gpu_build_cmd_descriptor(void *desc, uint64_t gpu_addr,
|
static void gpu_build_cmd_descriptor(void *desc, uint64_t gpu_addr,
|
||||||
uint32_t size_bytes) {
|
uint32_t size_bytes) {
|
||||||
uint64_t *d = (uint64_t *)desc;
|
uint64_t *d = (uint64_t *)desc;
|
||||||
uint32_t size_dwords = size_bytes >> 2;
|
uint32_t size_dwords = size_bytes >> 2;
|
||||||
|
|
||||||
d[0] = ((gpu_addr & 0xFFFFFFFFULL) << 32) | 0xC0023F00ULL;
|
d[0] = ((gpu_addr & 0xFFFFFFFFULL) << 32) | 0xC0023F00ULL;
|
||||||
d[1] =
|
d[1] =
|
||||||
(((uint64_t)size_dwords & 0xFFFFF) << 32) | ((gpu_addr >> 32) & 0xFFFF);
|
(((uint64_t)size_dwords & 0xFFFFF) << 32) | ((gpu_addr >> 32) & 0xFFFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int gpu_submit_commands(int fd, uint32_t pipe_id, uint32_t cmd_count,
|
static int gpu_submit_commands(int fd, uint32_t pipe_id, uint32_t cmd_count,
|
||||||
uint64_t descriptors_ptr) {
|
uint64_t descriptors_ptr) {
|
||||||
struct {
|
struct {
|
||||||
uint32_t pipe_id;
|
uint32_t pipe_id;
|
||||||
uint32_t count;
|
uint32_t count;
|
||||||
uint64_t cmd_buf_ptr;
|
uint64_t cmd_buf_ptr;
|
||||||
} submit;
|
} submit;
|
||||||
|
|
||||||
submit.pipe_id = pipe_id;
|
submit.pipe_id = pipe_id;
|
||||||
submit.count = cmd_count;
|
submit.count = cmd_count;
|
||||||
submit.cmd_buf_ptr = descriptors_ptr;
|
submit.cmd_buf_ptr = descriptors_ptr;
|
||||||
|
|
||||||
return ioctl(fd, GPU_SUBMIT_IOCTL, &submit);
|
return ioctl(fd, GPU_SUBMIT_IOCTL, &submit);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int gpu_transfer_physical(uint64_t phys_addr, void *local_buf,
|
static int gpu_transfer_physical(uint64_t phys_addr, void *local_buf,
|
||||||
uint32_t size, int is_write) {
|
uint32_t size, int is_write) {
|
||||||
if (!s_gpu.initialized)
|
if (!s_gpu.initialized)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
uint64_t aligned_pa = phys_addr & ~(s_gpu.dmem_size - 1);
|
uint64_t aligned_pa = phys_addr & ~(s_gpu.dmem_size - 1);
|
||||||
uint64_t offset = phys_addr - aligned_pa;
|
uint64_t offset = phys_addr - aligned_pa;
|
||||||
|
|
||||||
if (offset + size > s_gpu.dmem_size) {
|
if (offset + size > s_gpu.dmem_size) {
|
||||||
printf("[gpu] transfer exceeds dmem_size\n");
|
printf("[gpu] transfer exceeds dmem_size\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int prot_ro = PROT_READ | PROT_WRITE | PROT_GPU_READ;
|
int prot_ro = PROT_READ | PROT_WRITE | PROT_GPU_READ;
|
||||||
int prot_rw = prot_ro | PROT_GPU_WRITE;
|
int prot_rw = prot_ro | PROT_GPU_WRITE;
|
||||||
|
|
||||||
mprotect((void *)s_gpu.victim_va, s_gpu.dmem_size, prot_ro);
|
mprotect((void *)s_gpu.victim_va, s_gpu.dmem_size, prot_ro);
|
||||||
|
|
||||||
uint64_t new_ptbe = s_gpu.cleared_ptbe | aligned_pa;
|
uint64_t new_ptbe = s_gpu.cleared_ptbe | aligned_pa;
|
||||||
kernel_setlong(s_gpu.victim_ptbe_va, new_ptbe);
|
kernel_setlong(s_gpu.victim_ptbe_va, new_ptbe);
|
||||||
|
|
||||||
mprotect((void *)s_gpu.victim_va, s_gpu.dmem_size, prot_rw);
|
mprotect((void *)s_gpu.victim_va, s_gpu.dmem_size, prot_rw);
|
||||||
uint64_t src, dst;
|
uint64_t src, dst;
|
||||||
|
|
||||||
if (is_write) {
|
if (is_write) {
|
||||||
memcpy((void *)s_gpu.transfer_va, local_buf, size);
|
memcpy((void *)s_gpu.transfer_va, local_buf, size);
|
||||||
src = s_gpu.transfer_va;
|
src = s_gpu.transfer_va;
|
||||||
dst = s_gpu.victim_va + offset;
|
dst = s_gpu.victim_va + offset;
|
||||||
} else {
|
} else {
|
||||||
src = s_gpu.victim_va + offset;
|
src = s_gpu.victim_va + offset;
|
||||||
dst = s_gpu.transfer_va;
|
dst = s_gpu.transfer_va;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cmd_size = pm4_build_dma_data((void *)s_gpu.cmd_va, dst, src, size);
|
int cmd_size = pm4_build_dma_data((void *)s_gpu.cmd_va, dst, src, size);
|
||||||
|
|
||||||
uint8_t desc[16];
|
uint8_t desc[16];
|
||||||
gpu_build_cmd_descriptor(desc, s_gpu.cmd_va, cmd_size);
|
gpu_build_cmd_descriptor(desc, s_gpu.cmd_va, cmd_size);
|
||||||
|
|
||||||
uint64_t desc_va = s_gpu.cmd_va + 0x1000;
|
uint64_t desc_va = s_gpu.cmd_va + 0x1000;
|
||||||
memcpy((void *)desc_va, desc, 16);
|
memcpy((void *)desc_va, desc, 16);
|
||||||
|
|
||||||
int ret = gpu_submit_commands(s_gpu.fd, 0, 1, desc_va);
|
int ret = gpu_submit_commands(s_gpu.fd, 0, 1, desc_va);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
printf("[gpu] ioctl submit failed: %d\n", ret);
|
printf("[gpu] ioctl submit failed: %d\n", ret);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for GPU DMA completion
|
// Wait for GPU DMA completion
|
||||||
// TODO: proper fence/signal wait
|
// TODO: proper fence/signal wait
|
||||||
usleep(100000);
|
usleep(100000);
|
||||||
|
|
||||||
if (!is_write) {
|
if (!is_write) {
|
||||||
memcpy(local_buf, (void *)s_gpu.transfer_va, size);
|
memcpy(local_buf, (void *)s_gpu.transfer_va, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restore victim PTE to original physical address
|
// Restore victim PTE to original physical address
|
||||||
uint64_t orig_ptbe = s_gpu.cleared_ptbe | s_gpu.victim_real_pa;
|
uint64_t orig_ptbe = s_gpu.cleared_ptbe | s_gpu.victim_real_pa;
|
||||||
kernel_setlong(s_gpu.victim_ptbe_va, orig_ptbe);
|
kernel_setlong(s_gpu.victim_ptbe_va, orig_ptbe);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int gpu_init(void) {
|
int gpu_init(void) {
|
||||||
// init GPU DMA
|
// init GPU DMA
|
||||||
struct gpu_kernel_offsets go = {};
|
struct gpu_kernel_offsets go = {};
|
||||||
go.proc_vmspace = KERNEL_OFFSET_PROC_P_VMSPACE;
|
go.proc_vmspace = KERNEL_OFFSET_PROC_P_VMSPACE;
|
||||||
go.vmspace_vm_vmid = env_offset.VMSPACE_VM_VMID;
|
go.vmspace_vm_vmid = env_offset.VMSPACE_VM_VMID;
|
||||||
go.sizeof_gvmspace = 0x100;
|
go.sizeof_gvmspace = 0x100;
|
||||||
go.gvmspace_page_dir_va = 0x38;
|
go.gvmspace_page_dir_va = 0x38;
|
||||||
go.gvmspace_size = 0x10;
|
go.gvmspace_size = 0x10;
|
||||||
go.gvmspace_start_va = 0x08;
|
go.gvmspace_start_va = 0x08;
|
||||||
go.data_base_gvmspace = env_offset.DATA_BASE_GVMSPACE;
|
go.data_base_gvmspace = env_offset.DATA_BASE_GVMSPACE;
|
||||||
|
|
||||||
gpu_set_offsets(&go);
|
gpu_set_offsets(&go);
|
||||||
|
|
||||||
if (gpu_init_internal())
|
if (gpu_init_internal())
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int gpu_init_internal(void) {
|
int gpu_init_internal(void) {
|
||||||
if (s_gpu.initialized) {
|
if (s_gpu.initialized) {
|
||||||
DEBUG_PRINT("[gpu] Already initialized\n");
|
DEBUG_PRINT("[gpu] Already initialized\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!s_offsets_set) {
|
if (!s_offsets_set) {
|
||||||
DEBUG_PRINT("[gpu] ERROR: call gpu_set_offsets() first\n");
|
DEBUG_PRINT("[gpu] ERROR: call gpu_set_offsets() first\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG_PRINT("[gpu] init\n");
|
DEBUG_PRINT("[gpu] init\n");
|
||||||
|
|
||||||
s_gpu.dmem_size = 2 * 0x100000; // 2MB
|
s_gpu.dmem_size = 2 * 0x100000; // 2MB
|
||||||
|
|
||||||
// Step 1: Open GPU device
|
// Step 1: Open GPU device
|
||||||
DEBUG_PRINT("[gpu] Opening /dev/gc\n");
|
DEBUG_PRINT("[gpu] Opening /dev/gc\n");
|
||||||
s_gpu.fd = open("/dev/gc", O_RDWR);
|
s_gpu.fd = open("/dev/gc", O_RDWR);
|
||||||
if (s_gpu.fd < 0) {
|
if (s_gpu.fd < 0) {
|
||||||
DEBUG_PRINT("[gpu] ERROR: failed to open /dev/gc (fd=%d)\n", s_gpu.fd);
|
DEBUG_PRINT("[gpu] ERROR: failed to open /dev/gc (fd=%d)\n", s_gpu.fd);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
DEBUG_PRINT("[gpu] /dev/gc fd=%d\n", s_gpu.fd);
|
DEBUG_PRINT("[gpu] /dev/gc fd=%d\n", s_gpu.fd);
|
||||||
|
|
||||||
// Step 2: Allocate 3 GPU-mapped buffers
|
// Step 2: Allocate 3 GPU-mapped buffers
|
||||||
DEBUG_PRINT("[gpu] Allocating GPU direct memory (3 x 2MB)\n");
|
DEBUG_PRINT("[gpu] Allocating GPU direct memory (3 x 2MB)\n");
|
||||||
|
|
||||||
s_gpu.victim_va = gpu_alloc_dmem(s_gpu.dmem_size, 1);
|
s_gpu.victim_va = gpu_alloc_dmem(s_gpu.dmem_size, 1);
|
||||||
if (!s_gpu.victim_va) {
|
if (!s_gpu.victim_va) {
|
||||||
DEBUG_PRINT("[gpu] victim alloc failed\n");
|
DEBUG_PRINT("[gpu] victim alloc failed\n");
|
||||||
return -2;
|
return -2;
|
||||||
}
|
}
|
||||||
|
|
||||||
s_gpu.transfer_va = gpu_alloc_dmem(s_gpu.dmem_size, 1);
|
s_gpu.transfer_va = gpu_alloc_dmem(s_gpu.dmem_size, 1);
|
||||||
if (!s_gpu.transfer_va) {
|
if (!s_gpu.transfer_va) {
|
||||||
DEBUG_PRINT("[gpu] transfer alloc failed\n");
|
DEBUG_PRINT("[gpu] transfer alloc failed\n");
|
||||||
return -2;
|
return -2;
|
||||||
}
|
}
|
||||||
|
|
||||||
s_gpu.cmd_va = gpu_alloc_dmem(s_gpu.dmem_size, 1);
|
s_gpu.cmd_va = gpu_alloc_dmem(s_gpu.dmem_size, 1);
|
||||||
if (!s_gpu.cmd_va) {
|
if (!s_gpu.cmd_va) {
|
||||||
DEBUG_PRINT("[gpu] cmd alloc failed\n");
|
DEBUG_PRINT("[gpu] cmd alloc failed\n");
|
||||||
return -2;
|
return -2;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG_PRINT("[gpu] victim_va = 0x%lx\n", s_gpu.victim_va);
|
DEBUG_PRINT("[gpu] victim_va = 0x%lx\n", s_gpu.victim_va);
|
||||||
DEBUG_PRINT("[gpu] transfer_va = 0x%lx\n", s_gpu.transfer_va);
|
DEBUG_PRINT("[gpu] transfer_va = 0x%lx\n", s_gpu.transfer_va);
|
||||||
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
|
||||||
int vmid = gpu_get_vmid();
|
int vmid = gpu_get_vmid();
|
||||||
DEBUG_PRINT("[gpu] GPU VMID = %d\n", vmid);
|
DEBUG_PRINT("[gpu] GPU VMID = %d\n", vmid);
|
||||||
|
|
||||||
if (s_gpu_offsets.data_base_gvmspace == 0) {
|
if (s_gpu_offsets.data_base_gvmspace == 0) {
|
||||||
DEBUG_PRINT("[gpu] ERROR: data_base_gvmspace not set\n");
|
DEBUG_PRINT("[gpu] ERROR: data_base_gvmspace not set\n");
|
||||||
return -3;
|
return -3;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t rel_va = gpu_get_relative_va(vmid, s_gpu.victim_va);
|
uint64_t rel_va = gpu_get_relative_va(vmid, s_gpu.victim_va);
|
||||||
if (rel_va == (uint64_t)-1) {
|
if (rel_va == (uint64_t)-1) {
|
||||||
DEBUG_PRINT("[gpu] ERROR: could not get relative VA for victim\n");
|
DEBUG_PRINT("[gpu] ERROR: could not get relative VA for victim\n");
|
||||||
return -3;
|
return -3;
|
||||||
}
|
}
|
||||||
DEBUG_PRINT("[gpu] victim relative GPU VA = 0x%lx\n", rel_va);
|
DEBUG_PRINT("[gpu] victim relative GPU VA = 0x%lx\n", rel_va);
|
||||||
|
|
||||||
s_gpu.victim_ptbe_va = gpu_walk_pt(vmid, rel_va, &s_gpu.page_size);
|
s_gpu.victim_ptbe_va = gpu_walk_pt(vmid, rel_va, &s_gpu.page_size);
|
||||||
if (s_gpu.victim_ptbe_va == 0) {
|
if (s_gpu.victim_ptbe_va == 0) {
|
||||||
DEBUG_PRINT("[gpu] ERROR: GPU page table walk failed\n");
|
DEBUG_PRINT("[gpu] ERROR: GPU page table walk failed\n");
|
||||||
return -4;
|
return -4;
|
||||||
}
|
}
|
||||||
DEBUG_PRINT("[gpu] victim GPU PTE VA = 0x%lx\n", s_gpu.victim_ptbe_va);
|
DEBUG_PRINT("[gpu] victim GPU PTE VA = 0x%lx\n", s_gpu.victim_ptbe_va);
|
||||||
DEBUG_PRINT("[gpu] victim GPU page sz = 0x%lx\n", s_gpu.page_size);
|
DEBUG_PRINT("[gpu] victim GPU page sz = 0x%lx\n", s_gpu.page_size);
|
||||||
|
|
||||||
if (s_gpu.page_size != s_gpu.dmem_size) {
|
if (s_gpu.page_size != s_gpu.dmem_size) {
|
||||||
DEBUG_PRINT("[gpu] WARNING: page size 0x%lx != dmem_size 0x%lx\n",
|
DEBUG_PRINT("[gpu] WARNING: page size 0x%lx != dmem_size 0x%lx\n",
|
||||||
s_gpu.page_size, s_gpu.dmem_size);
|
s_gpu.page_size, s_gpu.dmem_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 5: Prepare the cleared PTE template
|
// Step 5: Prepare the cleared PTE template
|
||||||
int prot_ro = PROT_READ | PROT_WRITE | PROT_GPU_READ;
|
int prot_ro = PROT_READ | PROT_WRITE | PROT_GPU_READ;
|
||||||
mprotect((void *)s_gpu.victim_va, s_gpu.dmem_size, prot_ro);
|
mprotect((void *)s_gpu.victim_va, s_gpu.dmem_size, prot_ro);
|
||||||
|
|
||||||
uint64_t current_ptbe;
|
uint64_t current_ptbe;
|
||||||
kernel_copyout(s_gpu.victim_ptbe_va, ¤t_ptbe, sizeof(current_ptbe));
|
kernel_copyout(s_gpu.victim_ptbe_va, ¤t_ptbe, sizeof(current_ptbe));
|
||||||
s_gpu.cleared_ptbe = current_ptbe & ~s_gpu.victim_real_pa;
|
s_gpu.cleared_ptbe = current_ptbe & ~s_gpu.victim_real_pa;
|
||||||
|
|
||||||
DEBUG_PRINT("[gpu] current PTE = 0x%lx\n", current_ptbe);
|
DEBUG_PRINT("[gpu] current PTE = 0x%lx\n", current_ptbe);
|
||||||
DEBUG_PRINT("[gpu] cleared PTE = 0x%lx\n", s_gpu.cleared_ptbe);
|
DEBUG_PRINT("[gpu] cleared PTE = 0x%lx\n", s_gpu.cleared_ptbe);
|
||||||
|
|
||||||
int prot_rw = prot_ro | PROT_GPU_WRITE;
|
int prot_rw = prot_ro | PROT_GPU_WRITE;
|
||||||
mprotect((void *)s_gpu.victim_va, s_gpu.dmem_size, prot_rw);
|
mprotect((void *)s_gpu.victim_va, s_gpu.dmem_size, prot_rw);
|
||||||
|
|
||||||
s_gpu.initialized = 1;
|
s_gpu.initialized = 1;
|
||||||
DEBUG_PRINT("[gpu] ready\n");
|
DEBUG_PRINT("[gpu] ready\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int gpu_test(void) {
|
int gpu_test(void) {
|
||||||
if (!s_gpu.initialized) {
|
if (!s_gpu.initialized) {
|
||||||
printf("[gpu] ERROR: not initialized\n");
|
printf("[gpu] ERROR: not initialized\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG_PRINT("[gpu] test\n");
|
DEBUG_PRINT("[gpu] test\n");
|
||||||
|
|
||||||
// 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);
|
||||||
DEBUG_PRINT("[gpu] kernel_read8 = 0x%lx\n", kernel_val);
|
DEBUG_PRINT("[gpu] kernel_read8 = 0x%lx\n", kernel_val);
|
||||||
|
|
||||||
uint64_t gpu_val = gpu_read_phys8(test_pa);
|
uint64_t gpu_val = gpu_read_phys8(test_pa);
|
||||||
DEBUG_PRINT("[gpu] gpu_read8 = 0x%lx\n", gpu_val);
|
DEBUG_PRINT("[gpu] gpu_read8 = 0x%lx\n", gpu_val);
|
||||||
|
|
||||||
if (kernel_val == gpu_val) {
|
if (kernel_val == gpu_val) {
|
||||||
printf("[gpu] *** TEST PASSED: values match ***\n");
|
printf("[gpu] *** TEST PASSED: values match ***\n");
|
||||||
} else {
|
} else {
|
||||||
printf("[gpu] *** TEST FAILED: values differ ***\n");
|
printf("[gpu] *** TEST FAILED: values differ ***\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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);
|
||||||
gpu_write_phys8(test_write_pa, magic);
|
gpu_write_phys8(test_write_pa, magic);
|
||||||
|
|
||||||
uint64_t readback = gpu_read_phys8(test_write_pa);
|
uint64_t readback = gpu_read_phys8(test_write_pa);
|
||||||
DEBUG_PRINT("[gpu] Readback = 0x%lx\n", readback);
|
DEBUG_PRINT("[gpu] Readback = 0x%lx\n", readback);
|
||||||
|
|
||||||
if (readback == magic) {
|
if (readback == magic) {
|
||||||
printf("[gpu] *** WRITE TEST PASSED ***\n");
|
printf("[gpu] *** WRITE TEST PASSED ***\n");
|
||||||
} else {
|
} else {
|
||||||
printf("[gpu] *** WRITE TEST FAILED ***\n");
|
printf("[gpu] *** WRITE TEST FAILED ***\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("[gpu] tests ok\n");
|
printf("[gpu] tests ok\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int gpu_read_phys(uint64_t phys_addr, void *out_buf, uint32_t size) {
|
int gpu_read_phys(uint64_t phys_addr, void *out_buf, uint32_t size) {
|
||||||
return gpu_transfer_physical(phys_addr, out_buf, size, 0);
|
return gpu_transfer_physical(phys_addr, out_buf, size, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t gpu_read_phys1(uint64_t phys_addr) {
|
uint8_t gpu_read_phys1(uint64_t phys_addr) {
|
||||||
uint8_t val = 0;
|
uint8_t val = 0;
|
||||||
gpu_transfer_physical(phys_addr, &val, sizeof(val), 0);
|
gpu_transfer_physical(phys_addr, &val, sizeof(val), 0);
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t gpu_read_phys4(uint64_t phys_addr) {
|
uint32_t gpu_read_phys4(uint64_t phys_addr) {
|
||||||
uint32_t val = 0;
|
uint32_t val = 0;
|
||||||
gpu_transfer_physical(phys_addr, &val, sizeof(val), 0);
|
gpu_transfer_physical(phys_addr, &val, sizeof(val), 0);
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t gpu_read_phys8(uint64_t phys_addr) {
|
uint64_t gpu_read_phys8(uint64_t phys_addr) {
|
||||||
uint64_t val = 0;
|
uint64_t val = 0;
|
||||||
gpu_transfer_physical(phys_addr, &val, sizeof(val), 0);
|
gpu_transfer_physical(phys_addr, &val, sizeof(val), 0);
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
int gpu_write_phys(uint64_t phys_addr, const void *in_buf, uint32_t size) {
|
int gpu_write_phys(uint64_t phys_addr, const void *in_buf, uint32_t size) {
|
||||||
return gpu_transfer_physical(phys_addr, (void *)in_buf, size, 1);
|
return gpu_transfer_physical(phys_addr, (void *)in_buf, size, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void gpu_write_phys4(uint64_t phys_addr, uint32_t value) {
|
void gpu_write_phys4(uint64_t phys_addr, uint32_t value) {
|
||||||
gpu_transfer_physical(phys_addr, &value, sizeof(value), 1);
|
gpu_transfer_physical(phys_addr, &value, sizeof(value), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void gpu_write_phys8(uint64_t phys_addr, uint64_t value) {
|
void gpu_write_phys8(uint64_t phys_addr, uint64_t value) {
|
||||||
gpu_transfer_physical(phys_addr, &value, sizeof(value), 1);
|
gpu_transfer_physical(phys_addr, &value, sizeof(value), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void gpu_cleanup(void) {
|
void gpu_cleanup(void) {
|
||||||
if (s_gpu.fd >= 0) {
|
if (s_gpu.fd >= 0) {
|
||||||
close(s_gpu.fd);
|
close(s_gpu.fd);
|
||||||
s_gpu.fd = -1;
|
s_gpu.fd = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
s_gpu.initialized = 0;
|
s_gpu.initialized = 0;
|
||||||
printf("[gpu] Cleaned up\n");
|
printf("[gpu] Cleaned up\n");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,294 +1,261 @@
|
|||||||
#include "hv_defeat.h"
|
#include "hv_defeat.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "gpu.h"
|
#include "gpu.h"
|
||||||
#include "iommu.h"
|
#include "iommu.h"
|
||||||
#include "tmr.h"
|
#include "tmr.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <setjmp.h>
|
#include <setjmp.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
uint64_t vmcb_pa[16];
|
uint64_t vmcb_pa[16];
|
||||||
|
|
||||||
int hv_defeat(void) {
|
int hv_defeat(void) {
|
||||||
if (gpu_init())
|
if (gpu_init())
|
||||||
return -1;
|
return -1;
|
||||||
if (stage1_tmr_relax())
|
if (stage1_tmr_relax())
|
||||||
return -1;
|
return -1;
|
||||||
if (stage2_find_vmcbs())
|
if (stage2_find_vmcbs())
|
||||||
return -1;
|
return -1;
|
||||||
iommu_selftest();
|
iommu_selftest();
|
||||||
if (stage3_patch_vmcbs())
|
if (stage3_patch_vmcbs())
|
||||||
return -1;
|
return -1;
|
||||||
if (stage4_force_vmcb_reload())
|
if (stage4_force_vmcb_reload())
|
||||||
return -1;
|
return -1;
|
||||||
if (stage5_remove_xotext())
|
if (stage5_remove_xotext())
|
||||||
return -1;
|
return -1;
|
||||||
if (stage6_kernel_pmap_invalidate_all())
|
if (stage6_kernel_pmap_invalidate_all())
|
||||||
return -1;
|
return -1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int stage1_tmr_relax(void) {
|
int stage1_tmr_relax(void) {
|
||||||
DEBUG_PRINT("\nHV-defeat [stage1] tmr relax: ");
|
DEBUG_PRINT("\nHV-defeat [stage1] tmr relax: ");
|
||||||
|
|
||||||
DEBUG_PRINT("Firmware version: %04x\n", fw);
|
DEBUG_PRINT("Firmware version: %04x\n", fw);
|
||||||
|
|
||||||
for (int t = 0; t < 22; t++) {
|
for (int t = 0; t < 22; t++) {
|
||||||
uint32_t b = tmr_read(TMR_BASE(t));
|
uint32_t b = tmr_read(TMR_BASE(t));
|
||||||
uint32_t l = tmr_read(TMR_LIMIT(t));
|
uint32_t l = tmr_read(TMR_LIMIT(t));
|
||||||
uint32_t c = tmr_read(TMR_CONFIG(t));
|
uint32_t c = tmr_read(TMR_CONFIG(t));
|
||||||
if (c == 0 && b == 0 && l == 0)
|
if (c == 0 && b == 0 && l == 0)
|
||||||
continue;
|
continue;
|
||||||
DEBUG_PRINT(" tmr[%02d] 0x%012lx-0x%012lx cfg=0x%08x\n", t,
|
DEBUG_PRINT(" tmr[%02d] 0x%012lx-0x%012lx cfg=0x%08x\n", t,
|
||||||
(uint64_t)b << 16, ((uint64_t)l << 16) | 0xFFFF, c);
|
(uint64_t)b << 16, ((uint64_t)l << 16) | 0xFFFF, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fw < 0x0300) {
|
if (fw < 0x0300) {
|
||||||
tmr_write(TMR_CONFIG(16), TMR_CFG_PERMISSIVE);
|
tmr_write(TMR_CONFIG(16), TMR_CFG_PERMISSIVE);
|
||||||
|
|
||||||
if (tmr_read(TMR_CONFIG(16)) != TMR_CFG_PERMISSIVE)
|
if (tmr_read(TMR_CONFIG(16)) != TMR_CFG_PERMISSIVE)
|
||||||
goto no_ok;
|
goto no_ok;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
tmr_write(TMR_CONFIG(5), TMR_CFG_PERMISSIVE);
|
tmr_write(TMR_CONFIG(5), TMR_CFG_PERMISSIVE);
|
||||||
tmr_write(TMR_CONFIG(16), TMR_CFG_PERMISSIVE);
|
tmr_write(TMR_CONFIG(16), TMR_CFG_PERMISSIVE);
|
||||||
tmr_write(TMR_CONFIG(17), TMR_CFG_PERMISSIVE);
|
tmr_write(TMR_CONFIG(17), TMR_CFG_PERMISSIVE);
|
||||||
tmr_write(TMR_CONFIG(18), TMR_CFG_PERMISSIVE);
|
tmr_write(TMR_CONFIG(18), TMR_CFG_PERMISSIVE);
|
||||||
|
|
||||||
if (tmr_read(TMR_CONFIG(5)) != TMR_CFG_PERMISSIVE)
|
if (tmr_read(TMR_CONFIG(5)) != TMR_CFG_PERMISSIVE)
|
||||||
goto no_ok;
|
goto no_ok;
|
||||||
if (tmr_read(TMR_CONFIG(16)) != TMR_CFG_PERMISSIVE)
|
if (tmr_read(TMR_CONFIG(16)) != TMR_CFG_PERMISSIVE)
|
||||||
goto no_ok;
|
goto no_ok;
|
||||||
if (tmr_read(TMR_CONFIG(17)) != TMR_CFG_PERMISSIVE)
|
if (tmr_read(TMR_CONFIG(17)) != TMR_CFG_PERMISSIVE)
|
||||||
goto no_ok;
|
goto no_ok;
|
||||||
if (tmr_read(TMR_CONFIG(18)) != TMR_CFG_PERMISSIVE)
|
if (tmr_read(TMR_CONFIG(18)) != TMR_CFG_PERMISSIVE)
|
||||||
goto no_ok;
|
goto no_ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG_PRINT("OK\n");
|
DEBUG_PRINT("OK\n");
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
no_ok:
|
no_ok:
|
||||||
DEBUG_PRINT("No OK\n");
|
DEBUG_PRINT("No OK\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
for (int c = 0; c < 16; c++) {
|
||||||
uint64_t stride = env_offset.HV_VCPU_CPUID;
|
vmcb_pa[c] = get_vmcb(c);
|
||||||
// Testing direct VMCB on 04.03
|
DEBUG_PRINT(" core %02d: pa=0x%016lx\n", c, vmcb_pa[c]);
|
||||||
if ((!vcpu_off || !stride) && fw < 0x0300) {
|
}
|
||||||
DEBUG_PRINT(" missing HV_VCPU offsets for fw 0x%04x\n", fw);
|
|
||||||
return -1;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int c = 0; c < 16; c++) {
|
uint64_t get_vmcb(int core) {
|
||||||
vmcb_pa[c] = get_vmcb(c);
|
switch (fw) {
|
||||||
DEBUG_PRINT(" core %02d: pa=0x%016lx\n", c, vmcb_pa[c]);
|
case 0x0300:
|
||||||
}
|
case 0x0310:
|
||||||
|
case 0x0320:
|
||||||
return 0;
|
case 0x0321:
|
||||||
}
|
return (uint64_t)0x6290B000 + (uint64_t)core * 0x3000;
|
||||||
|
break;
|
||||||
// Only valid for 3.xx and 4.xx
|
case 0x0400:
|
||||||
// 1.xx and 2.xx have dynamic page alloc for VMCB
|
case 0x0402:
|
||||||
// TODO: add 1.xx and 2.xx logic
|
case 0x0403:
|
||||||
uint64_t get_vmcb(int core) {
|
case 0x0450:
|
||||||
switch (fw) {
|
case 0x0451:
|
||||||
case 0x0300:
|
return (uint64_t)0x62A05000 + (uint64_t)core * 0x3000;
|
||||||
case 0x0310:
|
break;
|
||||||
case 0x0320:
|
default:
|
||||||
case 0x0321:
|
return -1;
|
||||||
return (uint64_t)0x6290B000 + (uint64_t)core * 0x3000;
|
}
|
||||||
break;
|
}
|
||||||
case 0x0400:
|
|
||||||
case 0x0402:
|
int iommu_selftest(void) {
|
||||||
case 0x0403:
|
DEBUG_PRINT("\n[iommu] self-test\n");
|
||||||
case 0x0450:
|
|
||||||
case 0x0451:
|
uint64_t scratch = 0xAAAAAAAABBBBBBBBULL;
|
||||||
return (uint64_t)0x62A05000 + (uint64_t)core * 0x3000;
|
uint64_t scratch_pa = vtophys_user((uint64_t)&scratch);
|
||||||
break;
|
|
||||||
default:
|
if (!scratch_pa || scratch_pa >= 0x100000000ULL) {
|
||||||
return -1;
|
DEBUG_PRINT(" bad scratch PA 0x%016lx\n", scratch_pa);
|
||||||
}
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int iommu_selftest(void) {
|
uint64_t pattern = 0xDEADCAFE12345678ULL;
|
||||||
DEBUG_PRINT("\n[iommu] self-test\n");
|
DEBUG_PRINT(" scratch pa=0x%016lx before=0x%016lx\n", scratch_pa, scratch);
|
||||||
|
|
||||||
uint64_t scratch = 0xAAAAAAAABBBBBBBBULL;
|
iommu_write8_pa(scratch_pa, pattern);
|
||||||
uint64_t scratch_pa = va_to_pa_user((uint64_t)&scratch);
|
uint64_t readback = kread64(dmap + scratch_pa);
|
||||||
|
|
||||||
if (!scratch_pa || scratch_pa >= 0x100000000ULL) {
|
DEBUG_PRINT(" wrote=0x%016lx read=0x%016lx %s\n", pattern, readback,
|
||||||
DEBUG_PRINT(" bad scratch PA 0x%016lx\n", scratch_pa);
|
(readback == pattern) ? "OK" : "FAIL");
|
||||||
return -1;
|
|
||||||
}
|
return (readback == pattern) ? 0 : -1;
|
||||||
|
}
|
||||||
uint64_t pattern = 0xDEADCAFE12345678ULL;
|
|
||||||
DEBUG_PRINT(" scratch pa=0x%016lx before=0x%016lx\n", scratch_pa, scratch);
|
int stage3_patch_vmcbs(void) {
|
||||||
|
DEBUG_PRINT("\nHV-defeat [stage3-iommu] vmcb patch via IOMMU\n");
|
||||||
iommu_write8_pa(scratch_pa, pattern);
|
|
||||||
uint64_t readback = kread64(dmap + scratch_pa);
|
int cur = sceKernelGetCurrentCpu();
|
||||||
|
pin_to_core(cur);
|
||||||
DEBUG_PRINT(" wrote=0x%016lx read=0x%016lx %s\n", pattern, readback,
|
|
||||||
(readback == pattern) ? "OK" : "FAIL");
|
for (int i = 0; i < 16; i++) {
|
||||||
|
uint64_t pa = vmcb_pa[i];
|
||||||
return (readback == pattern) ? 0 : -1;
|
|
||||||
}
|
iommu_write8_pa(pa + 0x00, 0x0000000000000000ULL);
|
||||||
|
iommu_write8_pa(pa + 0x08, 0x0004000000000000ULL);
|
||||||
int stage3_patch_vmcbs(void) {
|
iommu_write8_pa(pa + 0x10, 0x000000000000000FULL);
|
||||||
DEBUG_PRINT("\nHV-defeat [stage3-iommu] vmcb patch via IOMMU\n");
|
iommu_write8_pa(pa + 0x58, 0x0000000000000001ULL);
|
||||||
|
iommu_write8_pa(pa + 0x90, 0x0000000000000000ULL);
|
||||||
int cur = sceKernelGetCurrentCpu();
|
|
||||||
pin_to_core(cur);
|
DEBUG_PRINT(" vmcb[%2d] patched (pa=0x%016lx)\n", i, pa);
|
||||||
|
|
||||||
for (int i = 0; i < 16; i++) {
|
usleep(1000);
|
||||||
uint64_t pa = vmcb_pa[i];
|
}
|
||||||
|
|
||||||
iommu_write8_pa(pa + 0x00, 0x0000000000000000ULL);
|
pin_to_core(9);
|
||||||
iommu_write8_pa(pa + 0x08, 0x0004000000000000ULL);
|
|
||||||
iommu_write8_pa(pa + 0x10, 0x000000000000000FULL);
|
DEBUG_PRINT(" done, 16 cores\n");
|
||||||
iommu_write8_pa(pa + 0x58, 0x0000000000000001ULL);
|
return 0;
|
||||||
iommu_write8_pa(pa + 0x90, 0x0000000000000000ULL);
|
}
|
||||||
|
|
||||||
DEBUG_PRINT(" vmcb[%2d] patched (pa=0x%016lx)\n", i, pa);
|
static jmp_buf jmp_env;
|
||||||
|
static volatile int vmmcall_faulted = 0;
|
||||||
// uint64_t vmcb_00 = gpu_read_phys8(pa + 0x00);
|
|
||||||
// uint64_t vmcb_08 = gpu_read_phys8(pa + 0x08);
|
void handle_sigill(int sig) {
|
||||||
// uint64_t vmcb_10 = gpu_read_phys8(pa + 0x10);
|
vmmcall_faulted = 1;
|
||||||
// uint64_t vmcb_58 = gpu_read_phys8(pa + 0x58);
|
longjmp(jmp_env, 1);
|
||||||
// uint64_t vmcb_90 = gpu_read_phys8(pa + 0x90);
|
}
|
||||||
|
|
||||||
// printf("Values read from VMCB: %016lx %016lx %016lx %016lx %016lx\n",
|
int stage4_force_vmcb_reload(void) {
|
||||||
// vmcb_00, vmcb_08, vmcb_10, vmcb_58, vmcb_90
|
int ret = 0;
|
||||||
// );
|
|
||||||
|
auto old_handler = signal(SIGILL, handle_sigill);
|
||||||
usleep(1000);
|
|
||||||
}
|
for (int i = 0; i < 16; i++) {
|
||||||
|
pin_to_core(i);
|
||||||
pin_to_core(9);
|
vmmcall_faulted = 0;
|
||||||
|
|
||||||
DEBUG_PRINT(" done, 16 cores\n");
|
if (setjmp(jmp_env) == 0) {
|
||||||
return 0;
|
__asm__ volatile("vmmcall");
|
||||||
}
|
}
|
||||||
|
|
||||||
static jmp_buf jmp_env;
|
usleep(1000);
|
||||||
static volatile int vmmcall_faulted = 0;
|
DEBUG_PRINT("[vmmcall] core: %02d %s\n", i,
|
||||||
|
vmmcall_faulted ? "SIGILL (caught)" : "ok");
|
||||||
void handle_sigill(int sig) {
|
|
||||||
vmmcall_faulted = 1;
|
// Accumulate results
|
||||||
longjmp(jmp_env, 1);
|
ret |= vmmcall_faulted;
|
||||||
}
|
}
|
||||||
|
|
||||||
int stage4_force_vmcb_reload(void) {
|
signal(SIGILL, old_handler);
|
||||||
|
|
||||||
int ret = 0;
|
// Return -1 if we didn't caught them
|
||||||
|
return ret ? 0 : -1;
|
||||||
auto old_handler = signal(SIGILL, handle_sigill);
|
}
|
||||||
|
|
||||||
for (int i = 0; i < 16; i++) {
|
int stage5_remove_xotext(void) {
|
||||||
pin_to_core(i);
|
DEBUG_PRINT("\nHV-Defeat [stage5] xotext removal\n");
|
||||||
vmmcall_faulted = 0;
|
|
||||||
|
uint64_t start = ktext;
|
||||||
if (setjmp(jmp_env) == 0) {
|
uint64_t end = kdata;
|
||||||
__asm__ volatile("vmmcall");
|
int n __attribute__((unused)) = 0;
|
||||||
}
|
|
||||||
|
for (uint64_t a = start; a < end; a += 0x1000) {
|
||||||
usleep(1000);
|
page_chain_set_rw(a);
|
||||||
DEBUG_PRINT("[vmmcall] core: %02d %s\n", i,
|
n++;
|
||||||
vmmcall_faulted ? "SIGILL (caught)" : "ok");
|
}
|
||||||
|
DEBUG_PRINT(" %d pages on ktext\n", n);
|
||||||
// Accumulate results
|
|
||||||
ret |= vmmcall_faulted;
|
start = kdata;
|
||||||
}
|
end = kdata + 0x08000000;
|
||||||
|
n = 0;
|
||||||
signal(SIGILL, old_handler);
|
for (uint64_t a = start; a < end; a += 0x1000) {
|
||||||
|
page_chain_set_rw(a);
|
||||||
// Return -1 if we didn't caught them
|
n++;
|
||||||
return ret ? 0 : -1;
|
}
|
||||||
}
|
DEBUG_PRINT(" %d pages on kdata\n", n);
|
||||||
|
return 0;
|
||||||
int stage5_remove_xotext(void) {
|
}
|
||||||
DEBUG_PRINT("\nHV-Defeat [stage5] xotext removal\n");
|
|
||||||
|
int stage6_kernel_pmap_invalidate_all(void) {
|
||||||
uint64_t start = ktext;
|
DEBUG_PRINT("HV-Defeat [stage6] invalidate paging entries\n");
|
||||||
uint64_t end = kdata;
|
|
||||||
int n __attribute__((unused)) = 0;
|
static uint64_t two_zero_pages[PAGE_SIZE * 2] = {0};
|
||||||
|
|
||||||
for (uint64_t a = start; a < end; a += 0x1000) {
|
int pipe_fds[2];
|
||||||
page_chain_set_rw(a);
|
|
||||||
n++;
|
if (pipe2(pipe_fds, O_NONBLOCK)) {
|
||||||
}
|
return -1;
|
||||||
DEBUG_PRINT(" %d pages on ktext\n", n);
|
}
|
||||||
|
|
||||||
start = kdata;
|
if (write(pipe_fds[1], two_zero_pages, PAGE_SIZE * 2) < 0) {
|
||||||
end = kdata + 0x08000000;
|
close(pipe_fds[0]);
|
||||||
n = 0;
|
close(pipe_fds[1]);
|
||||||
for (uint64_t a = start; a < end; a += 0x1000) {
|
return -1;
|
||||||
page_chain_set_rw(a);
|
}
|
||||||
n++;
|
|
||||||
}
|
close(pipe_fds[1]);
|
||||||
DEBUG_PRINT(" %d pages on kdata\n", n);
|
|
||||||
return 0;
|
uint64_t read_fd_file_data = kernel_get_proc_file(-1, pipe_fds[0]);
|
||||||
}
|
|
||||||
|
if (!INKERNEL(read_fd_file_data)) {
|
||||||
int stage6_kernel_pmap_invalidate_all(void) {
|
close(pipe_fds[0]);
|
||||||
|
return -1;
|
||||||
DEBUG_PRINT("HV-Defeat [stage6] invalidate paging entries\n");
|
}
|
||||||
|
|
||||||
static uint64_t two_zero_pages[PAGE_SIZE * 2] = {0};
|
uint64_t read_fd_buffer;
|
||||||
|
kernel_copyout(read_fd_file_data + 0x10, &read_fd_buffer,
|
||||||
int pipe_fds[2];
|
sizeof(read_fd_buffer));
|
||||||
// set O_NONBLOCK to avoid PIPE_DIRECTW
|
|
||||||
if (pipe2(pipe_fds, O_NONBLOCK)) {
|
if (!INKERNEL(read_fd_buffer)) {
|
||||||
return -1;
|
close(pipe_fds[0]);
|
||||||
}
|
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
|
if (!page_remove_global(read_fd_buffer)) {
|
||||||
// use the one page fast path
|
close(pipe_fds[0]);
|
||||||
if (write(pipe_fds[1], two_zero_pages, PAGE_SIZE * 2) < 0) {
|
return -1;
|
||||||
close(pipe_fds[0]);
|
}
|
||||||
close(pipe_fds[1]);
|
|
||||||
return -1;
|
close(pipe_fds[0]);
|
||||||
}
|
return 0;
|
||||||
|
}
|
||||||
// dont need this anymore
|
|
||||||
close(pipe_fds[1]);
|
|
||||||
|
|
||||||
uint64_t read_fd_file_data = kernel_get_proc_file(-1, pipe_fds[0]);
|
|
||||||
|
|
||||||
if (!INKERNEL(read_fd_file_data)) {
|
|
||||||
close(pipe_fds[0]);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t read_fd_buffer;
|
|
||||||
kernel_copyout(read_fd_file_data + 0x10, &read_fd_buffer,
|
|
||||||
sizeof(read_fd_buffer));
|
|
||||||
|
|
||||||
if (!INKERNEL(read_fd_buffer)) {
|
|
||||||
close(pipe_fds[0]);
|
|
||||||
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)) {
|
|
||||||
close(pipe_fds[0]);
|
|
||||||
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]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|||||||
205
source/iommu.c
205
source/iommu.c
@@ -1,103 +1,102 @@
|
|||||||
#include "iommu.h"
|
#include "iommu.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
iommu_ctx iommu_store;
|
iommu_ctx iommu_store;
|
||||||
iommu_ctx *iommu = &iommu_store;
|
iommu_ctx *iommu = &iommu_store;
|
||||||
|
|
||||||
int iommu_init(void) {
|
int iommu_init(void) {
|
||||||
uint64_t softc_ptr = get_offset_va(env_offset.IOMMU_SOFTC);
|
uint64_t softc_ptr = get_offset_va(env_offset.IOMMU_SOFTC);
|
||||||
if (softc_ptr == ktext) {
|
if (softc_ptr == ktext) {
|
||||||
DEBUG_PRINT("[iommu] no IOMMU_SOFTC offset");
|
DEBUG_PRINT("[iommu] no IOMMU_SOFTC offset");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t softc = kread64(softc_ptr);
|
uint64_t softc = kread64(softc_ptr);
|
||||||
if (!softc) {
|
if (!softc) {
|
||||||
DEBUG_PRINT("[iommu] softc is NULL\n");
|
DEBUG_PRINT("[iommu] softc is NULL\n");
|
||||||
return -2;
|
return -2;
|
||||||
}
|
}
|
||||||
|
|
||||||
iommu->mmio_va = kread64(softc + IOMMU_SC_MMIO_VA);
|
iommu->mmio_va = kread64(softc + IOMMU_SC_MMIO_VA);
|
||||||
iommu->cb2_base = kread64(softc + IOMMU_SC_CB2_PTR);
|
iommu->cb2_base = kread64(softc + IOMMU_SC_CB2_PTR);
|
||||||
iommu->cb3_base = kread64(softc + IOMMU_SC_CB3_PTR);
|
iommu->cb3_base = kread64(softc + IOMMU_SC_CB3_PTR);
|
||||||
iommu->eb_base = kread64(softc + IOMMU_SC_EB_PTR);
|
iommu->eb_base = kread64(softc + IOMMU_SC_EB_PTR);
|
||||||
|
|
||||||
if (!iommu->cb2_base || !iommu->mmio_va) {
|
if (!iommu->cb2_base || !iommu->mmio_va) {
|
||||||
DEBUG_PRINT("[iommu] cb=0x%016lx mmio=0x%016lx - not initialized\n",
|
DEBUG_PRINT("[iommu] cb=0x%016lx mmio=0x%016lx - not initialized\n",
|
||||||
iommu->cb2_base, iommu->mmio_va);
|
iommu->cb2_base, iommu->mmio_va);
|
||||||
return -3;
|
return -3;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG_PRINT("[iommu] softc=0x%016lx cb=0x%016lx mmio=0x%016lx\n", softc,
|
DEBUG_PRINT("[iommu] softc=0x%016lx cb=0x%016lx mmio=0x%016lx\n", softc,
|
||||||
iommu->cb2_base, iommu->mmio_va);
|
iommu->cb2_base, iommu->mmio_va);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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();
|
|
||||||
|
uint64_t curr_tail = kread64(iommu->mmio_va + IOMMU_MMIO_CB_TAIL);
|
||||||
uint64_t curr_tail = kread64(iommu->mmio_va + IOMMU_MMIO_CB_TAIL);
|
uint64_t next_tail = (curr_tail + IOMMU_CMD_ENTRY_SIZE) & IOMMU_CB_MASK;
|
||||||
uint64_t next_tail = (curr_tail + IOMMU_CMD_ENTRY_SIZE) & IOMMU_CB_MASK;
|
|
||||||
|
kwrite(iommu->cb2_base + curr_tail, (void *)cmd, IOMMU_CMD_ENTRY_SIZE);
|
||||||
kwrite(iommu->cb2_base + curr_tail, (void *)cmd, IOMMU_CMD_ENTRY_SIZE);
|
kwrite64(iommu->mmio_va + IOMMU_MMIO_CB_TAIL, next_tail);
|
||||||
kwrite64(iommu->mmio_va + IOMMU_MMIO_CB_TAIL, next_tail);
|
|
||||||
|
while (kread64(iommu->mmio_va + IOMMU_MMIO_CB_HEAD) !=
|
||||||
while (kread64(iommu->mmio_va + IOMMU_MMIO_CB_HEAD) !=
|
kread64(iommu->mmio_va + IOMMU_MMIO_CB_TAIL))
|
||||||
kread64(iommu->mmio_va + IOMMU_MMIO_CB_TAIL))
|
;
|
||||||
;
|
}
|
||||||
}
|
|
||||||
|
// Write 8 bytes to a physical address using IOMMU completion wait store
|
||||||
// Write 8 bytes to a physical address using IOMMU completion wait store
|
void iommu_write8_pa(uint64_t pa, uint64_t val) {
|
||||||
void iommu_write8_pa(uint64_t pa, uint64_t val) {
|
uint32_t cmd[4];
|
||||||
uint32_t cmd[4];
|
cmd[0] = (uint32_t)(pa & 0xFFFFFFF8) | 0x05;
|
||||||
cmd[0] = (uint32_t)(pa & 0xFFFFFFF8) | 0x05;
|
cmd[1] = ((uint32_t)(pa >> 32) & 0xFFFFF) | 0x10000000;
|
||||||
cmd[1] = ((uint32_t)(pa >> 32) & 0xFFFFF) | 0x10000000;
|
cmd[2] = (uint32_t)(val);
|
||||||
cmd[2] = (uint32_t)(val);
|
cmd[3] = (uint32_t)(val >> 32);
|
||||||
cmd[3] = (uint32_t)(val >> 32);
|
iommu_submit_cmd(cmd);
|
||||||
iommu_submit_cmd(cmd);
|
}
|
||||||
}
|
|
||||||
|
// Write 4 bytes to a physical address
|
||||||
// Write 4 bytes to a physical address
|
void iommu_write4_pa(uint64_t pa, uint32_t val) {
|
||||||
void iommu_write4_pa(uint64_t pa, uint32_t val) {
|
uint64_t aligned = pa & ~7ULL;
|
||||||
uint64_t aligned = pa & ~7ULL;
|
uint64_t existing = kread64(dmap + aligned);
|
||||||
uint64_t existing = kread64(dmap + aligned);
|
uint32_t off = (uint32_t)(pa & 7);
|
||||||
uint32_t off = (uint32_t)(pa & 7);
|
memcpy((uint8_t *)&existing + off, &val, 4);
|
||||||
memcpy((uint8_t *)&existing + off, &val, 4);
|
iommu_write8_pa(aligned, existing);
|
||||||
iommu_write8_pa(aligned, existing);
|
}
|
||||||
}
|
|
||||||
|
// Write arbitrary length to a physical address in 8-byte chunks
|
||||||
// Write arbitrary length to a physical address in 8-byte chunks
|
void iommu_write_pa(uint64_t pa, const void *data, uint32_t len) {
|
||||||
void iommu_write_pa(uint64_t pa, const void *data, uint32_t len) {
|
const uint8_t *src = (const uint8_t *)data;
|
||||||
const uint8_t *src = (const uint8_t *)data;
|
uint32_t off = 0;
|
||||||
uint32_t off = 0;
|
|
||||||
|
if (pa & 7) {
|
||||||
if (pa & 7) {
|
uint32_t head = 8 - (uint32_t)(pa & 7);
|
||||||
uint32_t head = 8 - (uint32_t)(pa & 7);
|
if (head > len)
|
||||||
if (head > len)
|
head = len;
|
||||||
head = len;
|
uint64_t aligned = pa & ~7ULL;
|
||||||
uint64_t aligned = pa & ~7ULL;
|
uint64_t existing = kread64(dmap + aligned);
|
||||||
uint64_t existing = kread64(dmap + aligned);
|
memcpy((uint8_t *)&existing + (pa & 7), src, head);
|
||||||
memcpy((uint8_t *)&existing + (pa & 7), src, head);
|
iommu_write8_pa(aligned, existing);
|
||||||
iommu_write8_pa(aligned, existing);
|
off += head;
|
||||||
off += head;
|
}
|
||||||
}
|
|
||||||
|
while (off + 8 <= len) {
|
||||||
while (off + 8 <= len) {
|
uint64_t val;
|
||||||
uint64_t val;
|
memcpy(&val, src + off, 8);
|
||||||
memcpy(&val, src + off, 8);
|
iommu_write8_pa(pa + off, val);
|
||||||
iommu_write8_pa(pa + off, val);
|
off += 8;
|
||||||
off += 8;
|
}
|
||||||
}
|
|
||||||
|
if (off < len) {
|
||||||
if (off < len) {
|
uint64_t aligned = pa + off;
|
||||||
uint64_t aligned = pa + off;
|
uint64_t existing = kread64(dmap + aligned);
|
||||||
uint64_t existing = kread64(dmap + aligned);
|
memcpy(&existing, src + off, len - off);
|
||||||
memcpy(&existing, src + off, len - off);
|
iommu_write8_pa(aligned, existing);
|
||||||
iommu_write8_pa(aligned, existing);
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|||||||
@@ -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,41 +1,41 @@
|
|||||||
#include <unistd.h>
|
#include "hv_defeat.h"
|
||||||
#include "utils.h"
|
#include "loader.h"
|
||||||
#include "hv_defeat.h"
|
#include "prepare_resume.h"
|
||||||
#include "prepare_resume.h"
|
#include "utils.h"
|
||||||
#include "loader.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.");
|
return -1;
|
||||||
return -1;
|
}
|
||||||
}
|
if (hv_defeat()) {
|
||||||
if (hv_defeat()) {
|
notify("Something went wrong while defeating Hypervisor.\nPlease make sure "
|
||||||
notify("Something went wrong while defeating Hypervisor.\nPlease make sure "
|
"your fw is supported.");
|
||||||
"your fw is supported.");
|
return -1;
|
||||||
return -1;
|
}
|
||||||
}
|
|
||||||
|
if (fetch_linux(&linux_i)) {
|
||||||
if (fetch_linux(&linux_i)) {
|
notify("Something went wrong while installing linux files.\n");
|
||||||
notify("Something went wrong while installing linux files.\n");
|
return -1;
|
||||||
return -1;
|
}
|
||||||
}
|
|
||||||
|
if (prepare_resume()) {
|
||||||
if (prepare_resume()) {
|
notify("Something went wrong while preparing resume.\n");
|
||||||
notify("Something went wrong while preparing resume.\n");
|
return -1;
|
||||||
return -1;
|
}
|
||||||
}
|
|
||||||
|
notify("Finished preparation. Going to rest mode in 5 seconds.\nPlease wait "
|
||||||
notify("Finished preparation. Going to rest mode in 5 seconds.\nPlease wait for the orange light to stop "
|
"for the orange light to stop "
|
||||||
"blinking and then wakeup to Linux :)\n");
|
"blinking and then wakeup to Linux :)\n");
|
||||||
|
|
||||||
sleep(5);
|
sleep(5);
|
||||||
enter_rest_mode();
|
enter_rest_mode();
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
sleep(30);
|
sleep(30);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
542
source/offsets.c
542
source/offsets.c
@@ -1,307 +1,235 @@
|
|||||||
#include "offsets.h"
|
#include "offsets.h"
|
||||||
|
|
||||||
offset_list off_0300 = {
|
offset_list off_0300 = {
|
||||||
.PMAP_STORE = 0x3D8E218,
|
.IOMMU_SOFTC = 0x33175E0,
|
||||||
.HV_VCPU_ARRAY_OFF = 0x5D0,
|
.VMSPACE_VM_VMID = 0x1E4,
|
||||||
.HV_VCPU_STRIDE = 0x320,
|
.VMSPACE_VM_PMAP = 0x1D0,
|
||||||
.HV_VCPU_VMCB_PTR = 0x08,
|
.DATA_BASE_GVMSPACE = 0x06423F80,
|
||||||
.KERNEL_CODE_CAVE = 0x500,
|
.HOOK_ACPI_WAKEUP_MACHDEP = 0x0390E73,
|
||||||
.KERNEL_DATA_CAVE = 0xC01300,
|
.KERNEL_CODE_CAVE = 0x500,
|
||||||
.IOMMU_SOFTC = 0x33175E0,
|
.KERNEL_DATA_CAVE = 0xC01300,
|
||||||
.VMSPACE_VM_VMID = 0x1E4,
|
.FUN_PRINTF = 0x048B9A0,
|
||||||
.VMSPACE_VM_PMAP = 0x1D0,
|
.FUN_HV_IOMMU_SET_BUFFERS = 0x0B33E20,
|
||||||
.PMAP_PM_PML4 = 0x020,
|
.FUN_HV_IOMM_WAIT_COMPLETION = 0x0B33D50,
|
||||||
.PMAP_PM_CR3 = 0x028,
|
.FUN_SMP_RENDEZVOUS = 0x0A3E850,
|
||||||
.DATA_BASE_GVMSPACE = 0x06423F80,
|
.FUN_SMP_NO_RENDEVOUS_BARRIER = 0x0287E50,
|
||||||
.HOOK_ACPI_WAKEUP_MACHDEP = 0x0390E73,
|
.HV_CODE_CAVE_PA = 0x62806F00,
|
||||||
.FUN_PRINTF = 0x048B9A0,
|
.HV_HANDLE_VMEXIT_PA = 0x6282CBCB,
|
||||||
.FUN_VA_TO_PA = 0x0831410,
|
.KERNEL_UART_OVERRIDE = 0x1EB0258,
|
||||||
.FUN_HV_IOMMU_SET_BUFFERS = 0x0B33E20,
|
.KERNEL_DEBUG_PATCH = 0x0752460,
|
||||||
.FUN_HV_IOMM_WAIT_COMPLETION = 0x0B33D50,
|
.KERNEL_CFI_CHECK = 0x0441DD0,
|
||||||
.FUN_SMP_RENDEZVOUS = 0x0A3E850,
|
.G_VBIOS = 0x0734B5D0,
|
||||||
.FUN_SMP_NO_RENDEVOUS_BARRIER = 0x0287E50,
|
.FUN_TRANSMITTER_CONTROL = 0x0B2A560,
|
||||||
.HV_HANDLE_VMEXIT_PA = 0x6282CBCB,
|
.FUN_MP3_INITIALIZE = 0x0953890,
|
||||||
.HV_CODE_CAVE_PA = 0x62806F00,
|
.FUN_MP3_INVOKE = 0x0952670,
|
||||||
.HV_UART_OVERRIDE_PA = 0x62800008,
|
.PS5_WIFI_FW_OFFSET = 0x1274460,
|
||||||
.G_VBIOS = 0x0734B5D0,
|
.PS5_WIFI_FW_SIZE = 492304,
|
||||||
.FUN_TRANSMITTER_CONTROL = 0x0B2A560,
|
};
|
||||||
.FUN_MP3_INITIALIZE = 0x0953890,
|
|
||||||
.FUN_MP3_INVOKE = 0x0952670,
|
offset_list off_0310 = {
|
||||||
.KERNEL_UART_OVERRIDE = 0x1EB0258,
|
.IOMMU_SOFTC = 0x33175E0,
|
||||||
.KERNEL_DEBUG_PATCH = 0x0752460,
|
.VMSPACE_VM_VMID = 0x1E4,
|
||||||
.KERNEL_CFI_CHECK = 0x0441DD0,
|
.VMSPACE_VM_PMAP = 0x1D0,
|
||||||
.PS5_WIFI_FW_OFFSET = 0x1274460,
|
.DATA_BASE_GVMSPACE = 0x06423F80,
|
||||||
.PS5_WIFI_FW_SIZE = 492304,
|
.HOOK_ACPI_WAKEUP_MACHDEP = 0x0390EB3,
|
||||||
};
|
.KERNEL_CODE_CAVE = 0x500,
|
||||||
|
.KERNEL_DATA_CAVE = 0xC01300,
|
||||||
offset_list off_0310 = {
|
.FUN_PRINTF = 0x048B9E0,
|
||||||
.PMAP_STORE = 0x3D8E218,
|
.FUN_HV_IOMMU_SET_BUFFERS = 0x0B33E60,
|
||||||
.HV_VCPU_ARRAY_OFF = 0x5D0,
|
.FUN_HV_IOMM_WAIT_COMPLETION = 0x0B33D90,
|
||||||
.HV_VCPU_STRIDE = 0x320,
|
.FUN_SMP_RENDEZVOUS = 0x0A3E890,
|
||||||
.HV_VCPU_VMCB_PTR = 0x08,
|
.FUN_SMP_NO_RENDEVOUS_BARRIER = 0x0287EA8,
|
||||||
.KERNEL_CODE_CAVE = 0x500,
|
.HV_CODE_CAVE_PA = 0x62806F00,
|
||||||
.KERNEL_DATA_CAVE = 0xC01300,
|
.HV_HANDLE_VMEXIT_PA = 0x6282CBCB,
|
||||||
.IOMMU_SOFTC = 0x33175E0,
|
.KERNEL_UART_OVERRIDE = 0x1EB0258,
|
||||||
.VMSPACE_VM_VMID = 0x1E4,
|
.KERNEL_DEBUG_PATCH = 0x07524A0,
|
||||||
.VMSPACE_VM_PMAP = 0x1D0,
|
.KERNEL_CFI_CHECK = 0x0441E10,
|
||||||
.PMAP_PM_PML4 = 0x020,
|
.G_VBIOS = 0x0734B5D0,
|
||||||
.PMAP_PM_CR3 = 0x028,
|
.FUN_TRANSMITTER_CONTROL = 0x0B2A5A0,
|
||||||
.DATA_BASE_GVMSPACE = 0x06423F80,
|
.FUN_MP3_INITIALIZE = 0x09538D0,
|
||||||
.HOOK_ACPI_WAKEUP_MACHDEP = 0x0390EB3,
|
.FUN_MP3_INVOKE = 0x09526B0,
|
||||||
.FUN_PRINTF = 0x048B9E0,
|
.PS5_WIFI_FW_OFFSET = 0x1274490,
|
||||||
.FUN_VA_TO_PA = 0x0831450,
|
.PS5_WIFI_FW_SIZE = 492304,
|
||||||
.FUN_HV_IOMMU_SET_BUFFERS = 0x0B33E60,
|
};
|
||||||
.FUN_HV_IOMM_WAIT_COMPLETION = 0x0B33D90,
|
|
||||||
.FUN_SMP_RENDEZVOUS = 0x0A3E890,
|
offset_list off_0320 = {
|
||||||
.FUN_SMP_NO_RENDEVOUS_BARRIER = 0x0287EA8,
|
.IOMMU_SOFTC = 0x33175E0,
|
||||||
.HV_HANDLE_VMEXIT_PA = 0x6282CBCB,
|
.VMSPACE_VM_VMID = 0x1E4,
|
||||||
.HV_CODE_CAVE_PA = 0x62806F00,
|
.VMSPACE_VM_PMAP = 0x1D0,
|
||||||
.HV_UART_OVERRIDE_PA = 0x62800008,
|
.DATA_BASE_GVMSPACE = 0x06423F80,
|
||||||
.G_VBIOS = 0x0734B5D0,
|
.HOOK_ACPI_WAKEUP_MACHDEP = 0x391203,
|
||||||
.FUN_TRANSMITTER_CONTROL = 0x0B2A5A0,
|
.KERNEL_CODE_CAVE = 0x500,
|
||||||
.FUN_MP3_INITIALIZE = 0x09538D0,
|
.KERNEL_DATA_CAVE = 0xC01300,
|
||||||
.FUN_MP3_INVOKE = 0x09526B0,
|
.FUN_PRINTF = 0x48BD30,
|
||||||
.KERNEL_UART_OVERRIDE = 0x1EB0258,
|
.FUN_HV_IOMMU_SET_BUFFERS = 0xB34320,
|
||||||
.KERNEL_DEBUG_PATCH = 0x07524A0,
|
.FUN_HV_IOMM_WAIT_COMPLETION = 0xB34250,
|
||||||
.KERNEL_CFI_CHECK = 0x0441E10,
|
.FUN_SMP_RENDEZVOUS = 0xA3ED50,
|
||||||
.PS5_WIFI_FW_OFFSET = 0x1274490,
|
.FUN_SMP_NO_RENDEVOUS_BARRIER = 0x288230,
|
||||||
.PS5_WIFI_FW_SIZE = 492304,
|
.HV_CODE_CAVE_PA = 0x62806F00,
|
||||||
};
|
.HV_HANDLE_VMEXIT_PA = 0x6282CBCB,
|
||||||
|
.KERNEL_UART_OVERRIDE = 0x1EB0258,
|
||||||
offset_list off_0320 = {
|
.KERNEL_DEBUG_PATCH = 0x7527F0,
|
||||||
.PMAP_STORE = 0x3D8E218,
|
.KERNEL_CFI_CHECK = 0x442160,
|
||||||
.HV_VCPU_ARRAY_OFF = 0x5D0,
|
.G_VBIOS = 0x734B5D0,
|
||||||
.HV_VCPU_STRIDE = 0x320,
|
.FUN_TRANSMITTER_CONTROL = 0xB2AA60,
|
||||||
.HV_VCPU_VMCB_PTR = 0x08,
|
.FUN_MP3_INITIALIZE = 0x953D30,
|
||||||
.KERNEL_CODE_CAVE = 0x500,
|
.FUN_MP3_INVOKE = 0x952B10,
|
||||||
.KERNEL_DATA_CAVE = 0xC01300,
|
.PS5_WIFI_FW_OFFSET = 0x1274550,
|
||||||
.IOMMU_SOFTC = 0x33175E0,
|
.PS5_WIFI_FW_SIZE = 492304,
|
||||||
.VMSPACE_VM_VMID = 0x1E4,
|
};
|
||||||
.VMSPACE_VM_PMAP = 0x1D0,
|
|
||||||
.PMAP_PM_PML4 = 0x020,
|
offset_list off_0321 = {
|
||||||
.PMAP_PM_CR3 = 0x028,
|
.IOMMU_SOFTC = 0x33175E0,
|
||||||
.DATA_BASE_GVMSPACE = 0x06423F80,
|
.VMSPACE_VM_VMID = 0x1E4,
|
||||||
.HOOK_ACPI_WAKEUP_MACHDEP = 0x391203,
|
.VMSPACE_VM_PMAP = 0x1D0,
|
||||||
.FUN_PRINTF = 0x48BD30,
|
.DATA_BASE_GVMSPACE = 0x06423F80,
|
||||||
.FUN_VA_TO_PA = 0x8317A0,
|
.HOOK_ACPI_WAKEUP_MACHDEP = 0x391203,
|
||||||
.FUN_HV_IOMMU_SET_BUFFERS = 0xB34320,
|
.KERNEL_CODE_CAVE = 0x500,
|
||||||
.FUN_HV_IOMM_WAIT_COMPLETION = 0xB34250,
|
.KERNEL_DATA_CAVE = 0xC01300,
|
||||||
.FUN_SMP_RENDEZVOUS = 0xA3ED50,
|
.FUN_PRINTF = 0x48BD30,
|
||||||
.FUN_SMP_NO_RENDEVOUS_BARRIER = 0x288230,
|
.FUN_HV_IOMMU_SET_BUFFERS = 0xB34320,
|
||||||
.HV_HANDLE_VMEXIT_PA = 0x6282CBCB,
|
.FUN_HV_IOMM_WAIT_COMPLETION = 0xB34250,
|
||||||
.HV_CODE_CAVE_PA = 0x62806F00,
|
.FUN_SMP_RENDEZVOUS = 0xA3ED50,
|
||||||
.HV_UART_OVERRIDE_PA = 0x62800008,
|
.FUN_SMP_NO_RENDEVOUS_BARRIER = 0x288250,
|
||||||
.G_VBIOS = 0x734B5D0,
|
.HV_CODE_CAVE_PA = 0x62806F00,
|
||||||
.FUN_TRANSMITTER_CONTROL = 0xB2AA60,
|
.HV_HANDLE_VMEXIT_PA = 0x6282CBCB,
|
||||||
.FUN_MP3_INITIALIZE = 0x953D30,
|
.KERNEL_UART_OVERRIDE = 0x1EB0258,
|
||||||
.FUN_MP3_INVOKE = 0x952B10,
|
.KERNEL_DEBUG_PATCH = 0x7527F0,
|
||||||
.KERNEL_UART_OVERRIDE = 0x1EB0258,
|
.KERNEL_CFI_CHECK = 0x442160,
|
||||||
.KERNEL_DEBUG_PATCH = 0x7527F0,
|
.G_VBIOS = 0x734B5D0,
|
||||||
.KERNEL_CFI_CHECK = 0x442160,
|
.FUN_TRANSMITTER_CONTROL = 0xB2AA60,
|
||||||
.PS5_WIFI_FW_OFFSET = 0x1274550,
|
.FUN_MP3_INITIALIZE = 0x953D30,
|
||||||
.PS5_WIFI_FW_SIZE = 492304,
|
.FUN_MP3_INVOKE = 0x952B10,
|
||||||
};
|
.PS5_WIFI_FW_OFFSET = 0x1274550,
|
||||||
|
.PS5_WIFI_FW_SIZE = 492304,
|
||||||
offset_list off_0321 = {
|
};
|
||||||
.PMAP_STORE = 0x3D8E218,
|
|
||||||
.HV_VCPU_ARRAY_OFF = 0x5D0,
|
offset_list off_0400 = {
|
||||||
.HV_VCPU_STRIDE = 0x320,
|
.IOMMU_SOFTC = 0x33C7680,
|
||||||
.HV_VCPU_VMCB_PTR = 0x08,
|
.VMSPACE_VM_VMID = 0x1E4,
|
||||||
.KERNEL_CODE_CAVE = 0x500,
|
.VMSPACE_VM_PMAP = 0x1D0,
|
||||||
.KERNEL_DATA_CAVE = 0xC01300,
|
.DATA_BASE_GVMSPACE = 0x064C3F80,
|
||||||
.IOMMU_SOFTC = 0x33175E0,
|
.HOOK_ACPI_WAKEUP_MACHDEP = 0x3A7613,
|
||||||
.VMSPACE_VM_VMID = 0x1E4,
|
.FUN_PRINTF = 0x4A3240,
|
||||||
.VMSPACE_VM_PMAP = 0x1D0,
|
.KERNEL_CODE_CAVE = 0x500,
|
||||||
.PMAP_PM_PML4 = 0x020,
|
.KERNEL_DATA_CAVE = 0xC01300,
|
||||||
.PMAP_PM_CR3 = 0x028,
|
.FUN_HV_IOMMU_SET_BUFFERS = 0xB638F0,
|
||||||
.DATA_BASE_GVMSPACE = 0x06423F80,
|
.FUN_HV_IOMM_WAIT_COMPLETION = 0xB63830,
|
||||||
.HOOK_ACPI_WAKEUP_MACHDEP = 0x391203,
|
.FUN_SMP_RENDEZVOUS = 0xA6C920,
|
||||||
.FUN_PRINTF = 0x48BD30,
|
.FUN_SMP_NO_RENDEVOUS_BARRIER = 0x295488,
|
||||||
.FUN_VA_TO_PA = 0x8317A0,
|
.HV_CODE_CAVE_PA = 0x62806F00,
|
||||||
.FUN_HV_IOMMU_SET_BUFFERS = 0xB34320,
|
.HV_HANDLE_VMEXIT_PA = 0x6282B45D,
|
||||||
.FUN_HV_IOMM_WAIT_COMPLETION = 0xB34250,
|
.KERNEL_UART_OVERRIDE = 0x1F522A8,
|
||||||
.FUN_SMP_RENDEZVOUS = 0xA3ED50,
|
.KERNEL_DEBUG_PATCH = 0x77DA70,
|
||||||
.FUN_SMP_NO_RENDEVOUS_BARRIER = 0x288250,
|
.KERNEL_CFI_CHECK = 0x45A170,
|
||||||
.HV_HANDLE_VMEXIT_PA = 0x6282CBCB,
|
.G_VBIOS = 0x72B7630,
|
||||||
.HV_CODE_CAVE_PA = 0x62806F00,
|
.FUN_TRANSMITTER_CONTROL = 0xB5AD50,
|
||||||
.HV_UART_OVERRIDE_PA = 0x62800008,
|
.FUN_MP3_INITIALIZE = 0x9805C0,
|
||||||
.G_VBIOS = 0x734B5D0,
|
.FUN_MP3_INVOKE = 0x97F3E0,
|
||||||
.FUN_TRANSMITTER_CONTROL = 0xB2AA60,
|
.PS5_WIFI_FW_OFFSET = 0x1392FB0,
|
||||||
.FUN_MP3_INITIALIZE = 0x953D30,
|
.PS5_WIFI_FW_SIZE = 493000,
|
||||||
.FUN_MP3_INVOKE = 0x952B10,
|
};
|
||||||
.KERNEL_UART_OVERRIDE = 0x1EB0258,
|
|
||||||
.KERNEL_DEBUG_PATCH = 0x7527F0,
|
offset_list off_0402 = {
|
||||||
.KERNEL_CFI_CHECK = 0x442160,
|
.IOMMU_SOFTC = 0x33C7680,
|
||||||
.PS5_WIFI_FW_OFFSET = 0x1274550,
|
.VMSPACE_VM_VMID = 0x1E4,
|
||||||
.PS5_WIFI_FW_SIZE = 492304,
|
.VMSPACE_VM_PMAP = 0x1D0,
|
||||||
};
|
.DATA_BASE_GVMSPACE = 0x064C3F80,
|
||||||
|
.HOOK_ACPI_WAKEUP_MACHDEP = 0x3A7613,
|
||||||
offset_list off_0400 = {
|
.KERNEL_CODE_CAVE = 0x500,
|
||||||
.PMAP_STORE = 0x3E57A78,
|
.KERNEL_DATA_CAVE = 0xC01300,
|
||||||
.HV_VCPU_ARRAY_OFF = 0x5D0,
|
.FUN_PRINTF = 0x4A3240,
|
||||||
.HV_VCPU_STRIDE = 0x320,
|
.FUN_HV_IOMMU_SET_BUFFERS = 0xB63950,
|
||||||
.HV_VCPU_VMCB_PTR = 0x08,
|
.FUN_HV_IOMM_WAIT_COMPLETION = 0xB63890,
|
||||||
.KERNEL_CODE_CAVE = 0x500,
|
.FUN_SMP_RENDEZVOUS = 0xA6C970,
|
||||||
.KERNEL_DATA_CAVE = 0xC01300,
|
.FUN_SMP_NO_RENDEVOUS_BARRIER = 0x29A018,
|
||||||
.IOMMU_SOFTC = 0x33C7680,
|
.HV_CODE_CAVE_PA = 0x62806F00,
|
||||||
.VMSPACE_VM_VMID = 0x1E4,
|
.HV_HANDLE_VMEXIT_PA = 0x6282B45D,
|
||||||
.VMSPACE_VM_PMAP = 0x1D0,
|
.KERNEL_UART_OVERRIDE = 0x1F522A8,
|
||||||
.PMAP_PM_PML4 = 0x020,
|
.KERNEL_DEBUG_PATCH = 0x77DAC0,
|
||||||
.PMAP_PM_CR3 = 0x028,
|
.KERNEL_CFI_CHECK = 0x45A170,
|
||||||
.DATA_BASE_GVMSPACE = 0x064C3F80,
|
.G_VBIOS = 0x72B7630,
|
||||||
.HOOK_ACPI_WAKEUP_MACHDEP = 0x3A7613,
|
.FUN_TRANSMITTER_CONTROL = 0xB5ADA0,
|
||||||
.FUN_PRINTF = 0x4A3240,
|
.FUN_MP3_INITIALIZE = 0x980610,
|
||||||
.FUN_VA_TO_PA = 0x85ADC0,
|
.FUN_MP3_INVOKE = 0x97F430,
|
||||||
.FUN_HV_IOMMU_SET_BUFFERS = 0xB638F0,
|
.PS5_WIFI_FW_OFFSET = 0x1392FB0,
|
||||||
.FUN_HV_IOMM_WAIT_COMPLETION = 0xB63830,
|
.PS5_WIFI_FW_SIZE = 493000,
|
||||||
.FUN_SMP_RENDEZVOUS = 0xA6C920,
|
};
|
||||||
.FUN_SMP_NO_RENDEVOUS_BARRIER = 0x295488,
|
|
||||||
.HV_HANDLE_VMEXIT_PA = 0x6282B45D,
|
offset_list off_0403 = {
|
||||||
.HV_CODE_CAVE_PA = 0x62806F00,
|
.IOMMU_SOFTC = 0x33C7680,
|
||||||
.HV_UART_OVERRIDE_PA = 0x62800008,
|
.VMSPACE_VM_VMID = 0x1E4,
|
||||||
.G_VBIOS = 0x72B7630,
|
.VMSPACE_VM_PMAP = 0x1D0,
|
||||||
.FUN_TRANSMITTER_CONTROL = 0xB5AD50,
|
.DATA_BASE_GVMSPACE = 0x064C3F80,
|
||||||
.FUN_MP3_INITIALIZE = 0x9805C0,
|
.HOOK_ACPI_WAKEUP_MACHDEP = 0x3A7613,
|
||||||
.FUN_MP3_INVOKE = 0x97F3E0,
|
.KERNEL_CODE_CAVE = 0x500,
|
||||||
.KERNEL_UART_OVERRIDE = 0x1F522A8,
|
.KERNEL_DATA_CAVE = 0xC01300,
|
||||||
.KERNEL_DEBUG_PATCH = 0x77DA70,
|
.FUN_PRINTF = 0x4A3240,
|
||||||
.KERNEL_CFI_CHECK = 0x45A170,
|
.FUN_HV_IOMMU_SET_BUFFERS = 0xB639F0,
|
||||||
.PS5_WIFI_FW_OFFSET = 0x1392FB0,
|
.FUN_HV_IOMM_WAIT_COMPLETION = 0xB63930,
|
||||||
.PS5_WIFI_FW_SIZE = 493000,
|
.FUN_SMP_RENDEZVOUS = 0xA6CA00,
|
||||||
};
|
.FUN_SMP_NO_RENDEVOUS_BARRIER = 0x299F20,
|
||||||
|
.HV_CODE_CAVE_PA = 0x62806F00,
|
||||||
offset_list off_0402 = {
|
.HV_HANDLE_VMEXIT_PA = 0x6282B45D,
|
||||||
.PMAP_STORE = 0x3E57A78,
|
.KERNEL_UART_OVERRIDE = 0x1F522A8,
|
||||||
.HV_VCPU_ARRAY_OFF = 0x5D0,
|
.KERNEL_DEBUG_PATCH = 0x77DB50,
|
||||||
.HV_VCPU_STRIDE = 0x320,
|
.KERNEL_CFI_CHECK = 0x45A170,
|
||||||
.HV_VCPU_VMCB_PTR = 0x08,
|
.G_VBIOS = 0x72B7630,
|
||||||
.KERNEL_CODE_CAVE = 0x500,
|
.FUN_TRANSMITTER_CONTROL = 0xB5AE30,
|
||||||
.KERNEL_DATA_CAVE = 0xC01300,
|
.FUN_MP3_INITIALIZE = 0x9806A0,
|
||||||
.IOMMU_SOFTC = 0x33C7680,
|
.FUN_MP3_INVOKE = 0x97F4C0,
|
||||||
.VMSPACE_VM_VMID = 0x1E4,
|
.PS5_WIFI_FW_OFFSET = 0x1392FB0,
|
||||||
.VMSPACE_VM_PMAP = 0x1D0,
|
.PS5_WIFI_FW_SIZE = 493000,
|
||||||
.PMAP_PM_PML4 = 0x020,
|
};
|
||||||
.PMAP_PM_CR3 = 0x028,
|
|
||||||
.DATA_BASE_GVMSPACE = 0x064C3F80,
|
offset_list off_0450 = {
|
||||||
.HOOK_ACPI_WAKEUP_MACHDEP = 0x3A7613,
|
.IOMMU_SOFTC = 0x33C7680,
|
||||||
.FUN_PRINTF = 0x4A3240,
|
.VMSPACE_VM_VMID = 0x1E4,
|
||||||
.FUN_VA_TO_PA = 0x85AE10,
|
.VMSPACE_VM_PMAP = 0x1D0,
|
||||||
.FUN_HV_IOMMU_SET_BUFFERS = 0xB63950,
|
.DATA_BASE_GVMSPACE = 0x064C3F80,
|
||||||
.FUN_HV_IOMM_WAIT_COMPLETION = 0xB63890,
|
.HOOK_ACPI_WAKEUP_MACHDEP = 0x03A75E3,
|
||||||
.FUN_SMP_RENDEZVOUS = 0xA6C970,
|
.KERNEL_CODE_CAVE = 0x500,
|
||||||
.FUN_SMP_NO_RENDEVOUS_BARRIER = 0x29A018,
|
.KERNEL_DATA_CAVE = 0xC01300,
|
||||||
.HV_HANDLE_VMEXIT_PA = 0x6282B45D,
|
.FUN_PRINTF = 0x04A3270,
|
||||||
.HV_CODE_CAVE_PA = 0x62806F00,
|
.FUN_HV_IOMMU_SET_BUFFERS = 0xB63BB0,
|
||||||
.HV_UART_OVERRIDE_PA = 0x62800008,
|
.FUN_HV_IOMM_WAIT_COMPLETION = 0xB63AF0,
|
||||||
.G_VBIOS = 0x72B7630,
|
.FUN_SMP_RENDEZVOUS = 0xA6CBB0,
|
||||||
.FUN_TRANSMITTER_CONTROL = 0xB5ADA0,
|
.FUN_SMP_NO_RENDEVOUS_BARRIER = 0x299FC0,
|
||||||
.FUN_MP3_INITIALIZE = 0x980610,
|
.HV_CODE_CAVE_PA = 0x62806F00,
|
||||||
.FUN_MP3_INVOKE = 0x97F430,
|
.HV_HANDLE_VMEXIT_PA = 0x6282B45D,
|
||||||
.KERNEL_UART_OVERRIDE = 0x1F522A8,
|
.KERNEL_UART_OVERRIDE = 0x1F522A8,
|
||||||
.KERNEL_DEBUG_PATCH = 0x77DAC0,
|
.KERNEL_DEBUG_PATCH = 0x77DC80,
|
||||||
.KERNEL_CFI_CHECK = 0x45A170,
|
.KERNEL_CFI_CHECK = 0x45A1A0,
|
||||||
.PS5_WIFI_FW_OFFSET = 0x1392FB0,
|
.G_VBIOS = 0x72B7630,
|
||||||
.PS5_WIFI_FW_SIZE = 493000,
|
.FUN_TRANSMITTER_CONTROL = 0xB5AFF0,
|
||||||
};
|
.FUN_MP3_INITIALIZE = 0x980850,
|
||||||
|
.FUN_MP3_INVOKE = 0x97F670,
|
||||||
offset_list off_0403 = {
|
.PS5_WIFI_FW_OFFSET = 0x1392FC0,
|
||||||
.PMAP_STORE = 0x3E57A78,
|
.PS5_WIFI_FW_SIZE = 493000,
|
||||||
.HV_VCPU_ARRAY_OFF = 0x5D0,
|
};
|
||||||
.HV_VCPU_STRIDE = 0x320,
|
|
||||||
.HV_VCPU_VMCB_PTR = 0x08,
|
offset_list off_0451 = {
|
||||||
.KERNEL_CODE_CAVE = 0x500,
|
.IOMMU_SOFTC = 0x33C7680,
|
||||||
.KERNEL_DATA_CAVE = 0xC01300,
|
.VMSPACE_VM_VMID = 0x1E4,
|
||||||
.IOMMU_SOFTC = 0x33C7680,
|
.VMSPACE_VM_PMAP = 0x1D0,
|
||||||
.VMSPACE_VM_VMID = 0x1E4,
|
.DATA_BASE_GVMSPACE = 0x64C3F80,
|
||||||
.VMSPACE_VM_PMAP = 0x1D0,
|
.HOOK_ACPI_WAKEUP_MACHDEP = 0x3A75E3,
|
||||||
.PMAP_PM_PML4 = 0x020,
|
.KERNEL_CODE_CAVE = 0x500,
|
||||||
.PMAP_PM_CR3 = 0x028,
|
.KERNEL_DATA_CAVE = 0xC01300,
|
||||||
.DATA_BASE_GVMSPACE = 0x064C3F80,
|
.FUN_PRINTF = 0x4A3270,
|
||||||
.HOOK_ACPI_WAKEUP_MACHDEP = 0x3A7613,
|
.FUN_HV_IOMMU_SET_BUFFERS = 0xB63FE0,
|
||||||
.FUN_PRINTF = 0x4A3240,
|
.FUN_HV_IOMM_WAIT_COMPLETION = 0xB63F20,
|
||||||
.FUN_VA_TO_PA = 0x85AEA0,
|
.FUN_SMP_RENDEZVOUS = 0xA6CFE0,
|
||||||
.FUN_HV_IOMMU_SET_BUFFERS = 0xB639F0,
|
.FUN_SMP_NO_RENDEVOUS_BARRIER = 0x299FA8,
|
||||||
.FUN_HV_IOMM_WAIT_COMPLETION = 0xB63930,
|
.HV_CODE_CAVE_PA = 0x62806F00,
|
||||||
.FUN_SMP_RENDEZVOUS = 0xA6CA00,
|
.HV_HANDLE_VMEXIT_PA = 0x6282B45D,
|
||||||
.FUN_SMP_NO_RENDEVOUS_BARRIER = 0x299F20,
|
.KERNEL_UART_OVERRIDE = 0x1F522A8,
|
||||||
.HV_HANDLE_VMEXIT_PA = 0x6282B45D,
|
.KERNEL_DEBUG_PATCH = 0x77DC90,
|
||||||
.HV_CODE_CAVE_PA = 0x62806F00,
|
.KERNEL_CFI_CHECK = 0x45A1A0,
|
||||||
.HV_UART_OVERRIDE_PA = 0x62800008,
|
.G_VBIOS = 0x72B7630,
|
||||||
.G_VBIOS = 0x72B7630,
|
.FUN_TRANSMITTER_CONTROL = 0xB5B420,
|
||||||
.FUN_TRANSMITTER_CONTROL = 0xB5AE30,
|
.FUN_MP3_INITIALIZE = 0x980BF0,
|
||||||
.FUN_MP3_INITIALIZE = 0x9806A0,
|
.FUN_MP3_INVOKE = 0x97FA10,
|
||||||
.FUN_MP3_INVOKE = 0x97F4C0,
|
.PS5_WIFI_FW_OFFSET = 0x1393000,
|
||||||
.KERNEL_UART_OVERRIDE = 0x1F522A8,
|
.PS5_WIFI_FW_SIZE = 493000,
|
||||||
.KERNEL_DEBUG_PATCH = 0x77DB50,
|
};
|
||||||
.KERNEL_CFI_CHECK = 0x45A170,
|
|
||||||
.PS5_WIFI_FW_OFFSET = 0x1392FB0,
|
|
||||||
.PS5_WIFI_FW_SIZE = 493000,
|
|
||||||
};
|
|
||||||
|
|
||||||
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,
|
|
||||||
.VMSPACE_VM_VMID = 0x1E4,
|
|
||||||
.VMSPACE_VM_PMAP = 0x1D0,
|
|
||||||
.PMAP_PM_PML4 = 0x020,
|
|
||||||
.PMAP_PM_CR3 = 0x028,
|
|
||||||
.DATA_BASE_GVMSPACE = 0x064C3F80,
|
|
||||||
.HOOK_ACPI_WAKEUP_MACHDEP = 0x03A75E3,
|
|
||||||
.FUN_PRINTF = 0x04A3270,
|
|
||||||
.FUN_VA_TO_PA = 0x85AFF0,
|
|
||||||
.FUN_HV_IOMMU_SET_BUFFERS = 0xB63BB0,
|
|
||||||
.FUN_HV_IOMM_WAIT_COMPLETION = 0xB63AF0,
|
|
||||||
.FUN_SMP_RENDEZVOUS = 0xA6CBB0,
|
|
||||||
.FUN_SMP_NO_RENDEVOUS_BARRIER = 0x299FC0,
|
|
||||||
.HV_HANDLE_VMEXIT_PA = 0x6282B45D,
|
|
||||||
.HV_CODE_CAVE_PA = 0x62806F00,
|
|
||||||
.HV_UART_OVERRIDE_PA = 0x62800008,
|
|
||||||
.G_VBIOS = 0x72B7630,
|
|
||||||
.FUN_TRANSMITTER_CONTROL = 0xB5AFF0,
|
|
||||||
.FUN_MP3_INITIALIZE = 0x980850,
|
|
||||||
.FUN_MP3_INVOKE = 0x97F670,
|
|
||||||
.KERNEL_UART_OVERRIDE = 0x1F522A8,
|
|
||||||
.KERNEL_DEBUG_PATCH = 0x77DC80,
|
|
||||||
.KERNEL_CFI_CHECK = 0x45A1A0,
|
|
||||||
.PS5_WIFI_FW_OFFSET = 0x1392FC0,
|
|
||||||
.PS5_WIFI_FW_SIZE = 493000,
|
|
||||||
};
|
|
||||||
|
|
||||||
offset_list off_0451 = {
|
|
||||||
.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,
|
|
||||||
.VMSPACE_VM_VMID = 0x1E4,
|
|
||||||
.VMSPACE_VM_PMAP = 0x1D0,
|
|
||||||
.PMAP_PM_PML4 = 0x020,
|
|
||||||
.PMAP_PM_CR3 = 0x028,
|
|
||||||
.DATA_BASE_GVMSPACE = 0x64C3F80,
|
|
||||||
.HOOK_ACPI_WAKEUP_MACHDEP = 0x3A75E3,
|
|
||||||
.FUN_PRINTF = 0x4A3270,
|
|
||||||
.FUN_VA_TO_PA = 0x85B390,
|
|
||||||
.FUN_HV_IOMMU_SET_BUFFERS = 0xB63FE0,
|
|
||||||
.FUN_HV_IOMM_WAIT_COMPLETION = 0xB63F20,
|
|
||||||
.FUN_SMP_RENDEZVOUS = 0xA6CFE0,
|
|
||||||
.FUN_SMP_NO_RENDEVOUS_BARRIER = 0x299FA8,
|
|
||||||
.HV_HANDLE_VMEXIT_PA = 0x6282B45D,
|
|
||||||
.HV_CODE_CAVE_PA = 0x62806F00,
|
|
||||||
.HV_UART_OVERRIDE_PA = 0x62800008,
|
|
||||||
.G_VBIOS = 0x72B7630,
|
|
||||||
.FUN_TRANSMITTER_CONTROL = 0xB5B420,
|
|
||||||
.FUN_MP3_INITIALIZE = 0x980BF0,
|
|
||||||
.FUN_MP3_INVOKE = 0x97FA10,
|
|
||||||
.KERNEL_UART_OVERRIDE = 0x1F522A8,
|
|
||||||
.KERNEL_DEBUG_PATCH = 0x77DC90,
|
|
||||||
.KERNEL_CFI_CHECK = 0x45A1A0,
|
|
||||||
.PS5_WIFI_FW_OFFSET = 0x1393000,
|
|
||||||
.PS5_WIFI_FW_SIZE = 493000,
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -1,101 +1,98 @@
|
|||||||
#include <stdio.h>
|
#include "prepare_resume.h"
|
||||||
#include <stdint.h>
|
#include "../shellcode_kernel/shellcode_kernel.h"
|
||||||
#include "prepare_resume.h"
|
#include "../shellcode_kernel/shellcode_kernel_args.h"
|
||||||
#include "iommu.h"
|
#include "iommu.h"
|
||||||
#include "../shellcode_kernel/shellcode_kernel.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) {
|
||||||
if (env_offset.KERNEL_CODE_CAVE == 0) {
|
|
||||||
printf("Error: missing code cave offset\n");
|
if (env_offset.KERNEL_CODE_CAVE == 0) {
|
||||||
return -1;
|
printf("Error: missing code cave offset\n");
|
||||||
}
|
return -1;
|
||||||
|
}
|
||||||
if (env_offset.KERNEL_DATA_CAVE == 0) {
|
|
||||||
printf("Error: missing data cave offset\n");
|
if (env_offset.KERNEL_DATA_CAVE == 0) {
|
||||||
return -1;
|
printf("Error: missing data cave offset\n");
|
||||||
}
|
return -1;
|
||||||
|
}
|
||||||
printf("\nWriting Shell Code for WakeUp path and patching "
|
|
||||||
"AcpiSetFirmwareWakingVector in acpi_wakeup_machdep\n");
|
uint64_t dest_text = ktext + env_offset.KERNEL_CODE_CAVE;
|
||||||
|
uint64_t dest_data = ktext + env_offset.KERNEL_DATA_CAVE;
|
||||||
uint64_t dest_text = ktext + env_offset.KERNEL_CODE_CAVE;
|
|
||||||
uint64_t dest_data = ktext + env_offset.KERNEL_DATA_CAVE;
|
kwrite_large(dest_text, shellcode_kernel_bin, shellcode_kernel_bin_len);
|
||||||
|
prepare_sck_args(dest_data);
|
||||||
kwrite_large(dest_text, shellcode_kernel_text, shellcode_kernel_text_len);
|
|
||||||
prepare_sck_args(dest_data);
|
if (update_sck_data_ptr(shellcode_kernel_bin, dest_text, dest_data))
|
||||||
|
return -1;
|
||||||
if(update_sck_data_ptr(shellcode_kernel_text, dest_text, dest_data))
|
|
||||||
return -1;
|
hook_call_near(ktext + env_offset.HOOK_ACPI_WAKEUP_MACHDEP, dest_text);
|
||||||
|
|
||||||
hook_call_near(ktext + env_offset.HOOK_ACPI_WAKEUP_MACHDEP, dest_text);
|
kwrite8(ktext + env_offset.KERNEL_DEBUG_PATCH, 0xC3);
|
||||||
|
kwrite8(ktext + env_offset.KERNEL_CFI_CHECK, 0xC3);
|
||||||
kwrite8(ktext + env_offset.KERNEL_DEBUG_PATCH, 0xC3);
|
|
||||||
kwrite8(ktext + env_offset.KERNEL_CFI_CHECK, 0xC3);
|
return 0;
|
||||||
|
}
|
||||||
return 0;
|
|
||||||
}
|
int update_sck_data_ptr(void *sc, uint64_t dest_text, uint64_t dest_data) {
|
||||||
|
// Find the address 0x11AA11AA11AA11AA used as marker
|
||||||
int update_sck_data_ptr (void* sc, uint64_t dest_text, uint64_t dest_data) {
|
int offset = -1;
|
||||||
// Find the address 0x11AA11AA11AA11AA used as marker
|
for (int i = 0; i < 0x40; i++) {
|
||||||
int offset = -1;
|
if (*(uint64_t *)((uint64_t)sc + i) == 0x11AA11AA11AA11AA) {
|
||||||
for (int i = 0; i < 0x40; i++) {
|
offset = i;
|
||||||
if (*(uint64_t *)((uint64_t)sc + i) == 0x11AA11AA11AA11AA) {
|
break;
|
||||||
offset = i;
|
}
|
||||||
break;
|
}
|
||||||
}
|
if (offset == -1) {
|
||||||
}
|
notify("Could not find offset of args_ptr address - Aborting\n");
|
||||||
if (offset == -1) {
|
return -1;
|
||||||
notify("Could not find offset of args_ptr address - Aborting\n");
|
}
|
||||||
return -1;
|
kwrite64(dest_text + offset, dest_data);
|
||||||
}
|
return 0;
|
||||||
kwrite64(dest_text + offset, dest_data);
|
}
|
||||||
return 0;
|
|
||||||
}
|
void hook_call_near(uint64_t hook, uint64_t dst) {
|
||||||
|
int64_t diff_call = dst - hook;
|
||||||
void hook_call_near(uint64_t hook, uint64_t dst) {
|
uint8_t new_instr[5];
|
||||||
int64_t diff_call = dst - hook;
|
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");
|
}
|
||||||
}
|
|
||||||
|
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 = fw;
|
||||||
args.fw_version = kernel_get_fw_version() & 0xFFFF0000;
|
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_hv_iommu_set_buffers = ktext + env_offset.FUN_HV_IOMMU_SET_BUFFERS;
|
||||||
args.fun_va_to_pa = ktext + env_offset.FUN_VA_TO_PA;
|
args.fun_hv_iommu_wait_completion =
|
||||||
args.fun_hv_iommu_set_buffers = ktext + env_offset.FUN_HV_IOMMU_SET_BUFFERS;
|
ktext + env_offset.FUN_HV_IOMM_WAIT_COMPLETION;
|
||||||
args.fun_hv_iommu_wait_completion =
|
args.fun_smp_rendezvous = ktext + env_offset.FUN_SMP_RENDEZVOUS;
|
||||||
ktext + env_offset.FUN_HV_IOMM_WAIT_COMPLETION;
|
args.fun_smp_no_rendevous_barrier =
|
||||||
args.fun_smp_rendezvous = ktext + env_offset.FUN_SMP_RENDEZVOUS;
|
ktext + env_offset.FUN_SMP_NO_RENDEVOUS_BARRIER;
|
||||||
args.fun_smp_no_rendevous_barrier =
|
args.g_vbios = ktext + env_offset.G_VBIOS;
|
||||||
ktext + env_offset.FUN_SMP_NO_RENDEVOUS_BARRIER;
|
|
||||||
args.g_vbios = ktext + env_offset.G_VBIOS;
|
args.fun_transmitter_control = ktext + env_offset.FUN_TRANSMITTER_CONTROL;
|
||||||
|
args.fun_mp3_initialize = ktext + env_offset.FUN_MP3_INITIALIZE;
|
||||||
args.fun_transmitter_control = ktext + env_offset.FUN_TRANSMITTER_CONTROL;
|
args.fun_mp3_invoke = ktext + env_offset.FUN_MP3_INVOKE;
|
||||||
args.fun_mp3_initialize = ktext + env_offset.FUN_MP3_INITIALIZE;
|
|
||||||
args.fun_mp3_invoke = ktext + env_offset.FUN_MP3_INVOKE;
|
args.iommu_mmio_va = iommu->mmio_va;
|
||||||
|
args.iommu_cb2_va = iommu->cb2_base;
|
||||||
args.iommu_mmio_va = iommu->mmio_va;
|
args.iommu_cb3_va = iommu->cb3_base;
|
||||||
args.iommu_cb2_va = iommu->cb2_base;
|
args.iommu_eb_va = iommu->eb_base;
|
||||||
args.iommu_cb3_va = iommu->cb3_base;
|
memcpy(&args.vmcb[0], &vmcb_pa[0], sizeof(args.vmcb[0]) * 16);
|
||||||
args.iommu_eb_va = iommu->eb_base;
|
|
||||||
memcpy(&args.vmcb[0], &vmcb_pa[0], sizeof(args.vmcb[0]) * 16);
|
args.kernel_uart_override = ktext + env_offset.KERNEL_UART_OVERRIDE;
|
||||||
|
args.hv_handle_vmexit_pa = env_offset.HV_HANDLE_VMEXIT_PA;
|
||||||
args.kernel_uart_override = ktext + env_offset.KERNEL_UART_OVERRIDE;
|
args.hv_code_cave_pa = env_offset.HV_CODE_CAVE_PA;
|
||||||
args.hv_handle_vmexit_pa = env_offset.HV_HANDLE_VMEXIT_PA;
|
|
||||||
args.hv_code_cave_pa = env_offset.HV_CODE_CAVE_PA;
|
args.linux_info_va = linux_i.linux_info;
|
||||||
args.hv_uart_override_pa = env_offset.HV_UART_OVERRIDE_PA;
|
|
||||||
|
kernel_copyin(&args, dest_data, sizeof(args));
|
||||||
args.linux_info_va = linux_i.linux_info;
|
|
||||||
|
|
||||||
kernel_copyin(&args, dest_data, sizeof(args));
|
|
||||||
}
|
}
|
||||||
24
source/tmr.c
24
source/tmr.c
@@ -1,12 +1,12 @@
|
|||||||
#include "tmr.h"
|
#include "tmr.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
uint32_t tmr_read(uint32_t addr) {
|
uint32_t tmr_read(uint32_t addr) {
|
||||||
kwrite32(ECAM_B0D18F2 + TMR_INDEX_OFF, addr);
|
kwrite32(ECAM_B0D18F2 + TMR_INDEX_OFF, addr);
|
||||||
return kread32(ECAM_B0D18F2 + TMR_DATA_OFF);
|
return kread32(ECAM_B0D18F2 + TMR_DATA_OFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
void tmr_write(uint32_t addr, uint32_t val) {
|
void tmr_write(uint32_t addr, uint32_t val) {
|
||||||
kwrite32(ECAM_B0D18F2 + TMR_INDEX_OFF, addr);
|
kwrite32(ECAM_B0D18F2 + TMR_INDEX_OFF, addr);
|
||||||
kwrite32(ECAM_B0D18F2 + TMR_DATA_OFF, val);
|
kwrite32(ECAM_B0D18F2 + TMR_DATA_OFF, val);
|
||||||
}
|
}
|
||||||
|
|||||||
575
source/utils.c
575
source/utils.c
@@ -1,289 +1,286 @@
|
|||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "offsets.h"
|
#include "linux.h"
|
||||||
#include <ps5/kernel.h>
|
#include "offsets.h"
|
||||||
#include <stdio.h>
|
#include <ps5/kernel.h>
|
||||||
#include <sys/cpuset.h>
|
#include <stdio.h>
|
||||||
#include <sys/param.h>
|
#include <sys/cpuset.h>
|
||||||
#include <sys/proc.h>
|
#include <sys/param.h>
|
||||||
#include <unistd.h>
|
#include <sys/proc.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
/* Global Variables */
|
|
||||||
offset_list env_offset;
|
/* Global Variables */
|
||||||
uint64_t ktext;
|
offset_list env_offset;
|
||||||
uint64_t kdata;
|
uint64_t ktext;
|
||||||
uint64_t dmap;
|
uint64_t kdata;
|
||||||
uint64_t cr3;
|
uint64_t dmap;
|
||||||
uint32_t fw;
|
uint64_t cr3;
|
||||||
struct linux_info linux_i;
|
uint32_t fw;
|
||||||
|
struct linux_info linux_i;
|
||||||
int setup_env(void) {
|
|
||||||
notify("Welcome to ps5-linux-loader. We'll defeat HV and prepare the system "
|
int setup_env(void) {
|
||||||
"to boot Linux on sleep resume.\n");
|
notify("Welcome to ps5-linux-loader. We'll defeat HV and prepare the system "
|
||||||
if (set_offsets())
|
"to boot Linux on sleep resume.\n");
|
||||||
return -1;
|
if (set_offsets())
|
||||||
if (init_global_vars())
|
return -1;
|
||||||
return -1;
|
if (init_global_vars())
|
||||||
return 0;
|
return -1;
|
||||||
}
|
return 0;
|
||||||
|
}
|
||||||
int set_offsets(void) {
|
|
||||||
fw = kernel_get_fw_version() >> 16;
|
int set_offsets(void) {
|
||||||
if (fw == 0)
|
fw = (kernel_get_fw_version() >> 0x10) & 0xFFFF;
|
||||||
return -1;
|
if (fw == 0)
|
||||||
switch (fw) {
|
return -1;
|
||||||
case 0x0300:
|
switch (fw) {
|
||||||
env_offset = off_0300;
|
case 0x0300:
|
||||||
break;
|
env_offset = off_0300;
|
||||||
case 0x0310:
|
break;
|
||||||
env_offset = off_0310;
|
case 0x0310:
|
||||||
break;
|
env_offset = off_0310;
|
||||||
case 0x0320:
|
break;
|
||||||
env_offset = off_0320;
|
case 0x0320:
|
||||||
break;
|
env_offset = off_0320;
|
||||||
case 0x0321:
|
break;
|
||||||
env_offset = off_0321;
|
case 0x0321:
|
||||||
break;
|
env_offset = off_0321;
|
||||||
case 0x0400:
|
break;
|
||||||
env_offset = off_0400;
|
case 0x0400:
|
||||||
break;
|
env_offset = off_0400;
|
||||||
case 0x0402:
|
break;
|
||||||
env_offset = off_0402;
|
case 0x0402:
|
||||||
break;
|
env_offset = off_0402;
|
||||||
case 0x0403:
|
break;
|
||||||
env_offset = off_0403;
|
case 0x0403:
|
||||||
break;
|
env_offset = off_0403;
|
||||||
case 0x0450:
|
break;
|
||||||
env_offset = off_0450;
|
case 0x0450:
|
||||||
break;
|
env_offset = off_0450;
|
||||||
case 0x0451:
|
break;
|
||||||
env_offset = off_0451;
|
case 0x0451:
|
||||||
break;
|
env_offset = off_0451;
|
||||||
default:
|
break;
|
||||||
return -1;
|
default:
|
||||||
}
|
return -1;
|
||||||
return 0;
|
}
|
||||||
}
|
return 0;
|
||||||
|
}
|
||||||
int init_global_vars(void) {
|
|
||||||
ktext = KERNEL_ADDRESS_TEXT_BASE;
|
int init_global_vars(void) {
|
||||||
kdata = KERNEL_ADDRESS_DATA_BASE;
|
ktext = KERNEL_ADDRESS_TEXT_BASE;
|
||||||
|
kdata = KERNEL_ADDRESS_DATA_BASE;
|
||||||
flat_pmap kernel_pmap;
|
|
||||||
kread(ktext + env_offset.PMAP_STORE, &kernel_pmap, sizeof(kernel_pmap));
|
flat_pmap kernel_pmap;
|
||||||
if (kernel_pmap.pm_pml4 == 0 || kernel_pmap.pm_cr3 == 0)
|
kread(getpmap(kernel_get_proc(0)), &kernel_pmap, sizeof(kernel_pmap));
|
||||||
return -1;
|
if (kernel_pmap.pm_pml4 == 0 || kernel_pmap.pm_cr3 == 0)
|
||||||
|
return -1;
|
||||||
cr3 = kernel_pmap.pm_cr3;
|
|
||||||
dmap = kernel_pmap.pm_pml4 - kernel_pmap.pm_cr3;
|
cr3 = kernel_pmap.pm_cr3;
|
||||||
|
dmap = kernel_pmap.pm_pml4 - kernel_pmap.pm_cr3;
|
||||||
return 0;
|
|
||||||
}
|
return 0;
|
||||||
|
}
|
||||||
uint64_t get_offset_va(uint64_t offset) { return ktext + offset; }
|
|
||||||
|
uint64_t get_offset_va(uint64_t offset) { return ktext + offset; }
|
||||||
uint64_t get_pml4(uint64_t pmap) { return kread64(pmap + 0x20); }
|
|
||||||
|
uint64_t get_pml4(uint64_t pmap) { return kread64(pmap + 0x20); }
|
||||||
uint64_t getpmap(uint64_t proc) {
|
|
||||||
uint64_t vm = kread64(proc + KERNEL_OFFSET_PROC_P_VMSPACE);
|
uint64_t getpmap(uint64_t proc) {
|
||||||
uint64_t vm_pmap = kread64(vm + env_offset.VMSPACE_VM_PMAP);
|
uint64_t vm = kread64(proc + KERNEL_OFFSET_PROC_P_VMSPACE);
|
||||||
return vm_pmap;
|
uint64_t vm_pmap = kread64(vm + env_offset.VMSPACE_VM_PMAP);
|
||||||
}
|
return vm_pmap;
|
||||||
|
}
|
||||||
// for ring3
|
|
||||||
uint64_t va_to_pa_user(uint64_t va) {
|
// for ring3
|
||||||
uintptr_t self_pmap = getpmap(kernel_get_proc(getpid()));
|
uint64_t vtophys_user(uint64_t va) {
|
||||||
uintptr_t self_pml4 = get_pml4(self_pmap);
|
uintptr_t self_pmap = getpmap(kernel_get_proc(getpid()));
|
||||||
uint64_t pa = va_to_pa_custom(va, self_pml4 & 0xFFFFFFFF);
|
uintptr_t self_pml4 = get_pml4(self_pmap);
|
||||||
return pa;
|
uint64_t pa = vtophys_custom(va, self_pml4 & 0xFFFFFFFF);
|
||||||
}
|
return pa;
|
||||||
|
}
|
||||||
// for ring0
|
|
||||||
uint64_t va_to_pa_kernel(uint64_t va) { return va_to_pa_custom(va, cr3); }
|
// for ring0
|
||||||
|
uint64_t vtophys(uint64_t va) { return vtophys_custom(va, cr3); }
|
||||||
// Source: PS5_kldload
|
|
||||||
uint64_t va_to_pa_custom(uint64_t va, uint64_t cr3_custom) {
|
// Source: PS5_kldload
|
||||||
|
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++) {
|
||||||
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;
|
||||||
|
|
||||||
kread(dmap + PAGE_PA(table_phys) + idx * 8, &entry, sizeof(entry));
|
kread(dmap + PAGE_PA(table_phys) + idx * 8, &entry, sizeof(entry));
|
||||||
|
|
||||||
if (!PAGE_P(entry))
|
if (!PAGE_P(entry))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if ((level == 1 || level == 2) && PAGE_PS(entry)) {
|
if ((level == 1 || level == 2) && PAGE_PS(entry)) {
|
||||||
uint64_t page_size = P_SIZE(level);
|
uint64_t page_size = P_SIZE(level);
|
||||||
return PAGE_PA(entry) | (va & (page_size - 1));
|
return PAGE_PA(entry) | (va & (page_size - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (level == 3)
|
if (level == 3)
|
||||||
return PAGE_PA(entry) | (va & 0xFFF);
|
return PAGE_PA(entry) | (va & 0xFFF);
|
||||||
|
|
||||||
table_phys = PAGE_PA(entry);
|
table_phys = PAGE_PA(entry);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t pa_to_dmap(uint64_t pa) { return dmap + pa; }
|
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++) {
|
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_va = dmap + PAGE_PA(table_phys) + idx * 8;
|
||||||
uint64_t entry_va = dmap + PAGE_PA(table_phys) + idx * 8;
|
uint64_t entry;
|
||||||
uint64_t entry;
|
|
||||||
|
// Read Level X entry
|
||||||
// Read Level X entry
|
kread(entry_va, &entry, sizeof(entry));
|
||||||
kread(entry_va, &entry, sizeof(entry));
|
|
||||||
|
if (!PAGE_P(entry))
|
||||||
if (!PAGE_P(entry))
|
return;
|
||||||
return;
|
|
||||||
|
uint8_t update = 0;
|
||||||
uint8_t update = 0;
|
// Set RW bit on this level
|
||||||
// Set RW bit on this level
|
if (!PAGE_RW(entry)) {
|
||||||
if (!PAGE_RW(entry)) {
|
PAGE_SET_RW(entry);
|
||||||
PAGE_SET_RW(entry);
|
update = 1;
|
||||||
update = 1;
|
}
|
||||||
}
|
// Unset XO on this level
|
||||||
// Unset XO on this level
|
if (PAGE_XO(entry)) {
|
||||||
if (PAGE_XO(entry)) {
|
PAGE_CLEAR_XO(entry);
|
||||||
PAGE_CLEAR_XO(entry);
|
update = 1;
|
||||||
update = 1;
|
}
|
||||||
}
|
if (update) {
|
||||||
if (update) {
|
kwrite(entry_va, &entry, sizeof(entry));
|
||||||
kwrite(entry_va, &entry, sizeof(entry));
|
}
|
||||||
}
|
|
||||||
|
if (((level == 1 || level == 2) && PAGE_PS(entry)) || (level == 3)) {
|
||||||
if (((level == 1 || level == 2) && PAGE_PS(entry)) || (level == 3)) {
|
return;
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
|
table_phys = PAGE_PA(entry);
|
||||||
table_phys = PAGE_PA(entry);
|
}
|
||||||
}
|
return;
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
|
// 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++) {
|
||||||
|
int shift = 39 - (level * 9);
|
||||||
for (int level = 0; level < 4; level++) {
|
uint64_t idx = (va >> shift) & 0x1FF;
|
||||||
int shift = 39 - (level * 9);
|
uint64_t entry_va = dmap + PAGE_PA(table_phys) + idx * 8;
|
||||||
uint64_t idx = (va >> shift) & 0x1FF;
|
uint64_t entry;
|
||||||
uint64_t entry_va = dmap + PAGE_PA(table_phys) + idx * 8;
|
|
||||||
uint64_t entry;
|
// Read Level X entry
|
||||||
|
kread(entry_va, &entry, sizeof(entry));
|
||||||
// Read Level X entry
|
|
||||||
kread(entry_va, &entry, sizeof(entry));
|
if (!PAGE_P(entry))
|
||||||
|
return 0;
|
||||||
if (!PAGE_P(entry))
|
|
||||||
return 0;
|
if ((level == 1 || level == 2) && PAGE_PS(entry)) {
|
||||||
|
PAGE_CLEAR_G(entry);
|
||||||
if ((level == 1 || level == 2) && PAGE_PS(entry)) {
|
kwrite(entry_va, &entry, sizeof(entry));
|
||||||
PAGE_CLEAR_G(entry);
|
|
||||||
kwrite(entry_va, &entry, sizeof(entry));
|
uint64_t page_size = P_SIZE(level);
|
||||||
|
return PAGE_PA(entry) | (va & (page_size - 1));
|
||||||
uint64_t page_size = P_SIZE(level);
|
}
|
||||||
return PAGE_PA(entry) | (va & (page_size - 1));
|
|
||||||
}
|
if (level == 3) {
|
||||||
|
PAGE_CLEAR_G(entry);
|
||||||
if (level == 3) {
|
kwrite(entry_va, &entry, sizeof(entry));
|
||||||
|
|
||||||
PAGE_CLEAR_G(entry);
|
return PAGE_PA(entry) | (va & 0xFFF);
|
||||||
kwrite(entry_va, &entry, sizeof(entry));
|
}
|
||||||
|
|
||||||
return PAGE_PA(entry) | (va & 0xFFF);
|
table_phys = PAGE_PA(entry);
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
table_phys = PAGE_PA(entry);
|
}
|
||||||
}
|
|
||||||
return 0;
|
int pin_to_core(int n) {
|
||||||
}
|
uint64_t m[2] = {0};
|
||||||
|
m[0] = (1 << n);
|
||||||
int pin_to_core(int n) {
|
return cpuset_setaffinity(3, 1, -1, 0x10, (const cpuset_t *)m);
|
||||||
uint64_t m[2] = {0};
|
}
|
||||||
m[0] = (1 << n);
|
|
||||||
return cpuset_setaffinity(3, 1, -1, 0x10, (const cpuset_t *)m);
|
int pin_to_first_available_core(void) {
|
||||||
}
|
for (int i = 0; i < 16; i++)
|
||||||
|
if (pin_to_core(i) == 0)
|
||||||
int pin_to_first_available_core(void) {
|
return i;
|
||||||
for (int i = 0; i < 16; i++)
|
return -1;
|
||||||
if (pin_to_core(i) == 0)
|
}
|
||||||
return i;
|
|
||||||
return -1;
|
void unpin(void) {
|
||||||
}
|
uint64_t m[2] = {0xFFFF, 0};
|
||||||
|
cpuset_setaffinity(3, 1, -1, 0x10, (const cpuset_t *)m);
|
||||||
void unpin(void) {
|
}
|
||||||
uint64_t m[2] = {0xFFFF, 0};
|
|
||||||
cpuset_setaffinity(3, 1, -1, 0x10, (const cpuset_t *)m);
|
void notify(const char *fmt, ...) {
|
||||||
}
|
static char buffer[2048];
|
||||||
|
va_list args;
|
||||||
void notify(const char *fmt, ...) {
|
|
||||||
static char buffer[2048];
|
va_start(args, fmt);
|
||||||
va_list args;
|
vsnprintf(buffer, sizeof(buffer), fmt, args);
|
||||||
|
va_end(args);
|
||||||
va_start(args, fmt);
|
|
||||||
vsnprintf(buffer, sizeof(buffer), fmt, args);
|
notify_internal((uint8_t *)buffer);
|
||||||
va_end(args);
|
printf("%s", buffer);
|
||||||
|
}
|
||||||
notify_internal((uint8_t *)buffer);
|
|
||||||
printf("%s", buffer);
|
void notify_internal(uint8_t *msg) {
|
||||||
}
|
struct {
|
||||||
|
char pad[45];
|
||||||
void notify_internal(uint8_t *msg) {
|
char msg[3075];
|
||||||
struct {
|
} req;
|
||||||
char pad[45];
|
bzero(&req, sizeof(req));
|
||||||
char msg[3075];
|
uint64_t len = strlen((const char *)msg) < (sizeof(req.msg) - 1)
|
||||||
} req;
|
? strlen((const char *)msg)
|
||||||
bzero(&req, sizeof(req));
|
: (sizeof(req.msg) - 1);
|
||||||
uint64_t len =
|
memcpy(req.msg, msg, len);
|
||||||
strlen((const char *)msg) < (sizeof(req.msg) - 1) ? strlen((const char *)msg) : (sizeof(req.msg) - 1);
|
sceKernelSendNotificationRequest(0, &req, sizeof(req), 0);
|
||||||
memcpy(req.msg, msg, len);
|
}
|
||||||
sceKernelSendNotificationRequest(0, &req, sizeof(req), 0);
|
|
||||||
}
|
void enter_rest_mode(void) {
|
||||||
|
void *event = NULL;
|
||||||
void enter_rest_mode(void) {
|
sceKernelOpenEventFlag(&event, "SceSystemStateMgrStatus");
|
||||||
void *event = NULL;
|
sceKernelNotifySystemSuspendStart();
|
||||||
sceKernelOpenEventFlag(&event, "SceSystemStateMgrStatus");
|
sceKernelSetEventFlag(event, 0x400);
|
||||||
sceKernelNotifySystemSuspendStart();
|
sceKernelCloseEventFlag(&event);
|
||||||
sceKernelSetEventFlag(event, 0x400);
|
}
|
||||||
sceKernelCloseEventFlag(&event);
|
|
||||||
}
|
// Kit type by EchoStretch
|
||||||
|
bool if_exists(const char *path) {
|
||||||
|
struct stat st;
|
||||||
// Kit type by EchoStretch
|
return stat(path, &st) == 0;
|
||||||
bool if_exists(const char* path) {
|
}
|
||||||
struct stat st;
|
|
||||||
return stat(path, &st) == 0;
|
bool sceKernelIsTestKit(void) {
|
||||||
}
|
return if_exists("/system/priv/lib/libSceDeci5Ttyp.sprx");
|
||||||
|
}
|
||||||
bool sceKernelIsTestKit(void) {
|
|
||||||
return if_exists("/system/priv/lib/libSceDeci5Ttyp.sprx");
|
bool sceKernelIsDevKit(void) {
|
||||||
}
|
return if_exists("/system/priv/lib/libSceDeci5Dtracep.sprx");
|
||||||
|
}
|
||||||
bool sceKernelIsDevKit(void) {
|
|
||||||
return if_exists("/system/priv/lib/libSceDeci5Dtracep.sprx");
|
enum kit_type get_kit_type(void) {
|
||||||
}
|
if (sceKernelIsDevKit()) {
|
||||||
|
notify("DevKit detected\n");
|
||||||
enum kit_type get_kit_type(void) {
|
return KIT_DEVKIT;
|
||||||
if (sceKernelIsDevKit()) {
|
}
|
||||||
notify("DevKit detected\n");
|
if (sceKernelIsTestKit()) {
|
||||||
return KIT_DEVKIT;
|
notify("TestKit detected\n");
|
||||||
}
|
return KIT_TESTKIT;
|
||||||
if (sceKernelIsTestKit()) {
|
}
|
||||||
notify("TestKit detected\n");
|
notify("Retail console detected\n");
|
||||||
return KIT_TESTKIT;
|
return KIT_RETAIL;
|
||||||
}
|
}
|
||||||
notify("Retail console detected\n");
|
|
||||||
return KIT_RETAIL;
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user