├── source ├── embed.s ├── defines.h └── main.c ├── README.md └── Makefile /source/embed.s: -------------------------------------------------------------------------------- 1 | .section .rodata 2 | .global kexec_data 3 | .type kexec_data, @object 4 | .align 4 5 | kexec_data: 6 | .incbin "kexec.bin" 7 | 8 | kexec_end: 9 | .global kexec_size 10 | .type kexec_size, @object 11 | .align 4 12 | kexec_size: 13 | .int kexec_end - kexec_data 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PS4 Linux Loader 2 | A simple payload that let you run Linux on your 5.05 PS4 3 | 4 | ## How to build 5 | I use https://github.com/valentinbreiz/ps4-payload-sdk to compile it. You also need to compile https://github.com/fail0verflow/ps4-kexec and place 'kexec.bin' into this folder. Compile kexec with 'make CFLAG='-DPS4_5_05 -DKASLR -DNO_SYMTAB'. 6 | 7 | ## How to use 8 | 9 | You need a FAT32 formatted USB drive plugged in on any PS4's USB port with the following files on the root directory : bzImage and initramfs.cpio.gz. You can download [them here](https://mega.nz/#!hEh1QI4B!gCDA5l7GyTekQ-fURvKw6WRieSbHETb3tYHb--SkmhM). 10 | 11 | Then you will need to send the payload (PS4-Linux-Loader.bin) to your PS4. For that go to your PS4 web browser, go to darbness.com/ps4 and send the payload to your PS4 using netcat or other.. (You can also use my tool: [PS4 Payload Sender](https://github.com/valentinbreiz/PS4-Payload-Sender)). 12 | 13 | For 4.05: 14 | 15 | https://github.com/valentinbreiz/PS4-Linux-Loader/tree/master 16 | 17 | For 4.55: 18 | 19 | https://github.com/valentinbreiz/PS4-Linux-Loader/tree/4.55 20 | 21 | For 5.01: 22 | 23 | https://github.com/valentinbreiz/PS4-Linux-Loader/tree/5.01 24 | 25 | For PS4 Pro / Slim / FAT: 26 | 27 | https://github.com/eeply/ps4-linux/tree/ps4pro 28 | 29 | ## Credits and links 30 | Thanks to 2much4u, Darbnes and jiangwei. 31 | 32 | Useful links: 33 | 34 | - For the kexec execution: https://github.com/kR105-zz/PS4-dlclose/tree/linux-loader 35 | 36 | - For kexec: https://github.com/fail0verflow/ps4-kexec 37 | 38 | - For more explanations: https://cturt.github.io/ps4-3.html 39 | 40 | - For executing code in kernel space: https://github.com/VV1LD/405-KernelDumper 41 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | LIBPS4 := $(PS4SDK)/libPS4 2 | 3 | CC := gcc 4 | AS := gcc 5 | OBJCOPY := objcopy 6 | ODIR := build 7 | SDIR := source 8 | IDIRS := -I$(LIBPS4)/include -I. -Iinclude 9 | LDIRS := -L$(LIBPS4) -L. -Llib 10 | CFLAGS := $(IDIRS) -Os -std=gnu11 -ffunction-sections -fdata-sections -fno-stack-protector -fno-builtin -nostartfiles -nostdlib -Wall -masm=intel -march=btver2 -mtune=btver2 -m64 -mabi=sysv -mcmodel=small -fpie 11 | SFLAGS := -nostartfiles -nostdlib -masm=intel -march=btver2 -mtune=btver2 -m64 -mabi=sysv -mcmodel=large 12 | LFLAGS := $(LDIRS) -Xlinker -T $(LIBPS4)/linker.x -Wl,--build-id=none 13 | CFILES := $(wildcard $(SDIR)/*.c) 14 | SFILES := $(wildcard $(SDIR)/*.s) 15 | OBJS := $(patsubst $(SDIR)/%.c, $(ODIR)/%_normal.o, $(CFILES)) $(patsubst $(SDIR)/%.s, $(ODIR)/%_normal.o, $(SFILES)) 16 | OBJS_DEBUG := $(patsubst $(SDIR)/%.c, $(ODIR)/%_debug.o, $(CFILES)) $(patsubst $(SDIR)/%.s, $(ODIR)/%_debug.o, $(SFILES)) 17 | 18 | 19 | DIP_1 = 192 20 | DIP_2 = 168 21 | DIP_3 = 1 22 | DIP_4 = 12 23 | 24 | LIBS := -lPS4 25 | 26 | TARGET = everything 27 | 28 | everything: $(shell basename $(CURDIR))_normal.bin $(shell basename $(CURDIR))_debug.bin 29 | 30 | 31 | $(shell basename $(CURDIR))_normal.bin: $(ODIR) $(OBJS) 32 | $(CC) $(LIBPS4)/crt0.s $(ODIR)/*_normal.o -o temp.t $(CFLAGS) $(LFLAGS) $(LIBS) 33 | $(OBJCOPY) -O binary temp.t $(shell basename $(CURDIR))_normal.bin 34 | rm -f temp.t 35 | 36 | $(shell basename $(CURDIR))_debug.bin: $(ODIR) $(OBJS_DEBUG) 37 | $(CC) $(LIBPS4)/crt0.s $(ODIR)/*_debug.o -o temp.t $(CFLAGS) $(LFLAGS) $(LIBS) 38 | $(OBJCOPY) -O binary temp.t $(shell basename $(CURDIR))_debug.bin 39 | rm -f temp.t 40 | 41 | 42 | 43 | $(ODIR)/%_normal.o: $(SDIR)/%.c 44 | $(CC) -c -o $@ $< $(CFLAGS) 45 | 46 | $(ODIR)/%_normal.o: $(SDIR)/%.s 47 | $(AS) -c -o $@ $< $(SFLAGS) 48 | 49 | $(ODIR)/%_debug.o: $(SDIR)/%.c 50 | $(CC) -c -o $@ $< $(CFLAGS) -D DEBUG_SOCKET=1 -D DIP_1=$(DIP_1) -D DIP_2=$(DIP_2) -D DIP_3=$(DIP_3) -D DIP_4=$(DIP_4) 51 | 52 | $(ODIR)/%_debug.o: $(SDIR)/%.s 53 | $(AS) -c -o $@ $< $(SFLAGS) 54 | 55 | $(ODIR): 56 | @mkdir $@ 57 | 58 | .PHONY: clean 59 | 60 | clean: 61 | rm -f $(TARGET) $(ODIR)/*.o 62 | -------------------------------------------------------------------------------- /source/defines.h: -------------------------------------------------------------------------------- 1 | #if DEBUG_SOCKET 2 | #define printfsocket(format, ...)\ 3 | do {\ 4 | char buffer[512];\ 5 | int size = sprintf(buffer, format, ##__VA_ARGS__);\ 6 | sceNetSend(sock, buffer, size, 0);\ 7 | } while(0) 8 | 9 | int (*printfkernel)(const char *fmt, ...) = (void*)0xFFFFFFFF8246E340; 10 | 11 | #else 12 | #define printfsocket(format, ...) (void)0 13 | int printfkernel(const char *fmt, ...) 14 | { 15 | return 0; 16 | } 17 | #endif 18 | 19 | #define SLIST_ENTRY(type) \ 20 | struct { \ 21 | struct type *sle_next; /* next element */ \ 22 | } 23 | 24 | #define SLIST_HEAD(name, type) \ 25 | struct name { \ 26 | struct type *slh_first; /* first element */ \ 27 | } 28 | 29 | #define TRACEBUF 30 | 31 | #define TAILQ_ENTRY(type) \ 32 | struct { \ 33 | struct type *tqe_next; /* next element */ \ 34 | struct type **tqe_prev; /* address of previous next element */ \ 35 | TRACEBUF \ 36 | } 37 | 38 | struct knote; 39 | 40 | struct kevent { 41 | uintptr_t ident; /* identifier for this event */ 42 | short filter; /* filter for event */ 43 | unsigned short flags; 44 | unsigned int fflags; 45 | intptr_t data; 46 | void *udata; /* opaque user data identifier */ 47 | }; 48 | 49 | struct filterops { 50 | int f_isfd; /* true if ident == filedescriptor */ 51 | int (*f_attach)(struct knote *kn); 52 | void (*f_detach)(struct knote *kn); 53 | int (*f_event)(struct knote *kn, long hint); 54 | void (*f_touch)(struct knote *kn, struct kevent *kev, unsigned long type); 55 | }; 56 | 57 | struct knote { 58 | SLIST_ENTRY(knote) kn_link; /* for kq */ 59 | SLIST_ENTRY(knote) kn_selnext; /* for struct selinfo */ 60 | struct knlist *kn_knlist; /* f_attach populated */ 61 | TAILQ_ENTRY(knote) kn_tqe; 62 | struct kqueue *kn_kq; /* which queue we are on */ 63 | struct kevent kn_kevent; 64 | int kn_status; /* protected by kq lock */ 65 | int kn_sfflags; /* saved filter flags */ 66 | intptr_t kn_sdata; /* saved data field */ 67 | union { 68 | struct file *p_fp; /* file data pointer */ 69 | struct proc *p_proc; /* proc pointer */ 70 | struct aiocblist *p_aio; /* AIO job pointer */ 71 | struct aioliojob *p_lio; /* LIO job pointer */ 72 | } kn_ptr; 73 | struct filterops *kn_fop; 74 | void *kn_hook; 75 | int kn_hookid; 76 | }; 77 | 78 | SLIST_HEAD(klist, knote); 79 | 80 | struct knlist { 81 | struct klist kl_list; 82 | void (*kl_lock)(void *); /* lock function */ 83 | void (*kl_unlock)(void *); 84 | void (*kl_assert_locked)(void *); 85 | void (*kl_assert_unlocked)(void *); 86 | void *kl_lockarg; /* argument passed to kl_lockf() */ 87 | }; 88 | 89 | struct sendto_args { 90 | int s; 91 | void * buf; 92 | size_t len; 93 | int flags; 94 | void * to; 95 | int tolen; 96 | }; 97 | 98 | struct auditinfo_addr { 99 | /* 100 | 4 ai_auid; 101 | 8 ai_mask; 102 | 24 ai_termid; 103 | 4 ai_asid; 104 | 8 ai_flags;r 105 | */ 106 | char useless[184]; 107 | }; 108 | 109 | //struct ucred { 110 | // u_int cr_ref; /* reference count */ 111 | // uid_t cr_uid; /* effective user id */ 112 | // uid_t cr_ruid; /* real user id */ 113 | // uid_t cr_svuid; /* saved user id */ 114 | // int cr_ngroups; /* number of groups */ 115 | // gid_t cr_rgid; /* real group id */ 116 | // gid_t cr_svgid; /* saved group id */ 117 | // struct uidinfo *cr_uidinfo; /* per euid resource consumption */ 118 | // struct uidinfo *cr_ruidinfo; /* per ruid resource consumption */ 119 | // struct prison *cr_prison; /* jail(2) */ 120 | // struct loginclass *cr_loginclass; /* login class */ 121 | // u_int cr_flags; /* credential flags */ 122 | // void *cr_pspare2[2]; /* general use 2 */ 123 | // struct label *cr_label; /* MAC label */ 124 | // struct auditinfo_addr cr_audit; /* Audit properties. */ 125 | // gid_t *cr_groups; /* groups */ 126 | // int cr_agroups; /* Available groups */ 127 | //}; 128 | 129 | struct ucred { 130 | uint32_t useless1; 131 | uint32_t cr_uid; // effective user id 132 | uint32_t cr_ruid; // real user id 133 | uint32_t useless2; 134 | uint32_t useless3; 135 | uint32_t cr_rgid; // real group id 136 | uint32_t useless4; 137 | void *useless5; 138 | void *useless6; 139 | void *cr_prison; // jail(2) 140 | void *useless7; 141 | uint32_t useless8; 142 | void *useless9[2]; 143 | void *useless10; 144 | struct auditinfo_addr useless11; 145 | uint32_t *cr_groups; // groups 146 | uint32_t useless12; 147 | }; 148 | 149 | struct proc { 150 | char useless[64]; 151 | struct ucred *p_ucred; 152 | struct filedesc *p_fd; 153 | }; 154 | 155 | struct thread { 156 | void *useless; 157 | struct proc *td_proc; 158 | }; 159 | 160 | struct fileops { 161 | void *fo_read; 162 | void *fo_write; 163 | void *fo_truncate; 164 | void *fo_ioctl; 165 | void *fo_poll; 166 | void *fo_kqfilter; 167 | void *fo_stat; 168 | void *fo_close; 169 | void *fo_chmod; 170 | void *fo_chown; 171 | int fo_flags; /* DFLAG_* below */ 172 | }; 173 | 174 | struct filedesc { 175 | void *useless1[3]; 176 | void *fd_rdir; 177 | void *fd_jdir; 178 | }; 179 | 180 | struct kpayload_args{ 181 | uint64_t user_arg; 182 | }; 183 | 184 | struct kdump_args{ 185 | uint64_t argArrayPtr; 186 | }; 187 | 188 | #define X86_CR0_WP (1 << 16) 189 | 190 | static inline __attribute__((always_inline)) uint64_t readCr0(void) { 191 | uint64_t cr0; 192 | 193 | asm volatile ( 194 | "movq %0, %%cr0" 195 | : "=r" (cr0) 196 | : : "memory" 197 | ); 198 | 199 | return cr0; 200 | } 201 | 202 | static inline __attribute__((always_inline)) void writeCr0(uint64_t cr0) { 203 | asm volatile ( 204 | "movq %%cr0, %0" 205 | : : "r" (cr0) 206 | : "memory" 207 | ); 208 | } 209 | 210 | -------------------------------------------------------------------------------- /source/main.c: -------------------------------------------------------------------------------- 1 | #include "ps4.h" 2 | #include "defines.h" 3 | 4 | #define KERN_XFAST_SYSCALL 0x1c0 5 | 6 | #define CTL_KERN 1 /* "high kernel": proc, limits */ 7 | #define KERN_PROC 14 /* struct: process entries */ 8 | #define KERN_PROC_VMMAP 32 /* VM map entries for process */ 9 | #define KERN_PROC_PID 1 /* by process id */ 10 | 11 | extern char kexec_data[]; 12 | extern unsigned kexec_size; 13 | 14 | static int sock; 15 | 16 | void usbthing(); 17 | 18 | unsigned int long long __readmsr(unsigned long __register) { 19 | // Loads the contents of a 64-bit model specific register (MSR) specified in 20 | // the ECX register into registers EDX:EAX. The EDX register is loaded with 21 | // the high-order 32 bits of the MSR and the EAX register is loaded with the 22 | // low-order 32 bits. If less than 64 bits are implemented in the MSR being 23 | // read, the values returned to EDX:EAX in unimplemented bit locations are 24 | // undefined. 25 | unsigned long __edx; 26 | unsigned long __eax; 27 | __asm__ ("rdmsr" : "=d"(__edx), "=a"(__eax) : "c"(__register)); 28 | return (((unsigned int long long)__edx) << 32) | (unsigned int long long)__eax; 29 | } 30 | 31 | int kpayload(struct thread *td, struct kpayload_args* args){ 32 | 33 | //Starting kpayload... 34 | struct ucred* cred; 35 | struct filedesc* fd; 36 | 37 | fd = td->td_proc->p_fd; 38 | cred = td->td_proc->p_ucred; 39 | 40 | //Reading kernel_base... 41 | void* kernel_base = &((uint8_t*)__readmsr(0xC0000082))[-KERN_XFAST_SYSCALL]; 42 | uint8_t* kernel_ptr = (uint8_t*)kernel_base; 43 | void** got_prison0 = (void**)&kernel_ptr[0x10986a0]; 44 | void** got_rootvnode = (void**)&kernel_ptr[0x22c1a70]; 45 | 46 | //Resolve kernel functions... 47 | int (*copyout)(const void *kaddr, void *uaddr, size_t len) = (void *)(kernel_base + 0x1ea630); 48 | int (*printfkernel)(const char *fmt, ...) = (void *)(kernel_base + 0x436040); 49 | int (*set_nclk_mem_spd)(int val) = (void *)(kernel_base + 0x30C270); 50 | int (*set_pstate)(int val) = (void *)(kernel_base + 0x4CC8A0); 51 | int (*set_gpu_freq)(int cu, unsigned int freq) = (void *)(kernel_base + 0x4D2530); 52 | int (*update_vddnp)(unsigned int cu) = (void *)(kernel_base + 0x4D2AA0); 53 | int (*set_cu_power_gate)(unsigned int cu) = (void *)(kernel_base + 0x4D2C40); 54 | 55 | cred->cr_uid = 0; 56 | cred->cr_ruid = 0; 57 | cred->cr_rgid = 0; 58 | cred->cr_groups[0] = 0; 59 | 60 | cred->cr_prison = *got_prison0; 61 | fd->fd_rdir = fd->fd_jdir = *got_rootvnode; 62 | 63 | //CLK, CU, .. 64 | set_pstate(3); 65 | set_nclk_mem_spd(8); 66 | 67 | set_gpu_freq(0, 800); // ACLK 68 | set_gpu_freq(1, 674); // 69 | set_gpu_freq(2, 610); 70 | set_gpu_freq(3, 800); 71 | set_gpu_freq(4, 800); 72 | set_gpu_freq(5, 720); 73 | set_gpu_freq(6, 720); 74 | 75 | update_vddnp(0x12); 76 | set_cu_power_gate(0x12); 77 | 78 | //Disable write protection... 79 | uint64_t cr0 = readCr0(); 80 | writeCr0(cr0 & ~X86_CR0_WP); 81 | 82 | kernel_ptr[0x10D97E] = 3; //5.05 pstate when shutdown 83 | 84 | //Kexec init 85 | void *DT_HASH_SEGMENT = (void *)(kernel_base+ 0xB1D820); // I know it's for 4.55 but I think it will works 86 | memcpy(DT_HASH_SEGMENT, kexec_data, kexec_size); 87 | 88 | void (*kexec_init)(void *, void *) = DT_HASH_SEGMENT; 89 | 90 | kexec_init((void *)(kernel_base+0x436040), NULL); 91 | 92 | // Say hello and put the kernel base in userland to we can use later 93 | printfkernel("PS4 Linux Loader for 5.05 by valentinbreiz\n"); 94 | 95 | printfkernel("kernel base is:0x%016llx\n", kernel_base); 96 | 97 | void* uaddr; 98 | memcpy(&uaddr,&args[2],8); 99 | 100 | printfkernel("uaddr is:0x%016llx\n", uaddr); 101 | 102 | copyout(&kernel_base, uaddr, 8); 103 | 104 | return 0; 105 | } 106 | 107 | int _main(struct thread *td) { 108 | 109 | initKernel(); 110 | initLibc(); 111 | initNetwork(); 112 | initPthread(); 113 | initSysUtil(); 114 | 115 | #ifdef DEBUG_SOCKET 116 | struct sockaddr_in server; 117 | 118 | server.sin_len = sizeof(server); 119 | server.sin_family = AF_INET; 120 | server.sin_addr.s_addr = IP(DIP_1, DIP_2, DIP_3, DIP_4); //DEBUG_IPADDRESS); 121 | server.sin_port = sceNetHtons(9023); 122 | memset(server.sin_zero, 0, sizeof(server.sin_zero)); 123 | sock = sceNetSocket("debug", AF_INET, SOCK_STREAM, 0); 124 | sceNetConnect(sock, (struct sockaddr *)&server, sizeof(server)); 125 | int flag = 1; 126 | sceNetSetsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(int)); 127 | #endif 128 | printfsocket("Connected!\n"); 129 | 130 | uint64_t* dump = mmap(NULL, 0x1000, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); 131 | 132 | printfsocket("Starting kernel patch...\n"); 133 | 134 | syscall(11,kpayload,td,dump); 135 | 136 | printfsocket("Kernel patched, Kexec initialized!\n"); 137 | 138 | printfsocket("Starting PS4 Linux Loader\n"); 139 | 140 | usbthing(); 141 | 142 | printfsocket("Done!\n"); 143 | 144 | sceNetSocketClose(sock); 145 | 146 | return 0; 147 | 148 | } 149 | 150 | void notify(char *message) 151 | { 152 | char buffer[512]; 153 | sprintf(buffer, "%s\n\n\n\n\n\n\n", message); 154 | sceSysUtilSendSystemNotificationWithText(0x81, buffer); 155 | } 156 | 157 | void usbthing() 158 | { 159 | 160 | printfsocket("Open bzImage file from USB\n"); 161 | FILE *fkernel = fopen("/mnt/usb0/bzImage", "r"); 162 | if(!fkernel) 163 | { 164 | notify("Error: open /mnt/usb0/bzImage."); 165 | return; 166 | } 167 | fseek(fkernel, 0L, SEEK_END); 168 | int kernelsize = ftell(fkernel); 169 | fseek(fkernel, 0L, SEEK_SET); 170 | 171 | printfsocket("Open initramfs file from USB\n"); 172 | FILE *finitramfs = fopen("/mnt/usb0/initramfs.cpio.gz", "r"); 173 | if(!finitramfs) 174 | { 175 | notify("Error: open /mnt/usb0/initramfs.cpio.gz"); 176 | fclose(fkernel); 177 | return; 178 | } 179 | fseek(finitramfs, 0L, SEEK_END); 180 | int initramfssize = ftell(finitramfs); 181 | fseek(finitramfs, 0L, SEEK_SET); 182 | 183 | printfsocket("kernelsize = %d\n", kernelsize); 184 | printfsocket("initramfssize = %d\n", initramfssize); 185 | 186 | printfsocket("Checks if the files are here\n"); 187 | if(kernelsize == 0 || initramfssize == 0) { 188 | printfsocket("no file error im dead"); 189 | fclose(fkernel); 190 | fclose(finitramfs); 191 | return; 192 | } 193 | 194 | void *kernel, *initramfs; 195 | 196 | /* if you want edid loading add this cmd: 197 | drm_kms_helper.edid_firmware=edid/my_edid.bin 198 | */ 199 | 200 | char *cmd_line = "panic=0 clocksource=tsc console=tty0 console=ttyS0,115200n8 " 201 | "console=uart8250,mmio32,0xd0340000 video=HDMI-A-1:1920x1080-24@60 " 202 | "consoleblank=0 net.ifnames=0 drm.debug=0 amdgpu.dpm=0"; 203 | 204 | kernel = malloc(kernelsize); 205 | initramfs = malloc(initramfssize); 206 | 207 | printfsocket("kernel = %llp\n", kernel); 208 | printfsocket("initramfs = %llp\n", initramfs); 209 | 210 | fread(kernel, kernelsize, 1, fkernel); 211 | fread(initramfs, initramfssize, 1, finitramfs); 212 | 213 | fclose(fkernel); 214 | fclose(finitramfs); 215 | 216 | //Call sys_kexec (153 syscall) 217 | syscall(153, kernel, kernelsize, initramfs, initramfssize, cmd_line); 218 | 219 | free(kernel); 220 | free(initramfs); 221 | 222 | //Reboot PS4 223 | int evf = syscall(540, "SceSysCoreReboot"); 224 | syscall(546, evf, 0x4000, 0); 225 | syscall(541, evf); 226 | syscall(37, 1, 30); 227 | 228 | } 229 | --------------------------------------------------------------------------------