├── .gitignore ├── BootMenu.yml ├── LICENSE.md ├── Makefile ├── blit ├── blit.c ├── blit.h └── font.c ├── blit_gadgets.h ├── bm-loader ├── ldr_main.c ├── ldr_main.h ├── payload_bootstrap.S ├── payload_bootstrap.ld └── resume.S ├── config.h └── main.c /.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | /.vscode -------------------------------------------------------------------------------- /BootMenu.yml: -------------------------------------------------------------------------------- 1 | BootMenu: 2 | attributes: 0 3 | version: 4 | major: 1 5 | minor: 2 6 | main: 7 | start: module_start 8 | stop: module_stop 9 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 teakhanirons 4 | Copyright (c) 2020 CreepNT 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 7 | 8 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 9 | 10 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 11 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | TARGET = BootMenu 2 | TARGET_OBJS = main.o blit/blit.o bm-loader/resume.o bm-loader/ldr_main.o blit/font.o 3 | BOOTSTRAP_OBJS = bm-loader/payload_bootstrap.o 4 | 5 | LIBS = -ltaihenForKernel_stub -lSceSysclibForDriver_stub -lSceSysmemForDriver_stub \ 6 | -lSceSysmemForKernel_stub -lSceThreadmgrForDriver_stub -lSceCpuForKernel_stub \ 7 | -lSceCpuForDriver_stub -lSceUartForKernel_stub -lScePervasiveForDriver_stub \ 8 | -lSceSysconForDriver_stub -lScePowerForDriver_stub -lSceIofilemgrForDriver_stub \ 9 | -lSceSysrootForKernel_stub -lSceDebugForDriver_stub -lSceCtrlForDriver_stub \ 10 | -lSceSblAIMgrForDriver_stub -lSceDisplayForDriver_stub -lSceRtcForDriver_stub \ 11 | -lSceKernelSuspendForDriver_stub 12 | 13 | PREFIX = arm-dolce-eabi 14 | CC = $(PREFIX)-gcc 15 | AS = $(PREFIX)-as 16 | OBJCOPY = $(PREFIX)-objcopy 17 | CFLAGS = -Wl,-q -Wall -O0 -nostartfiles -mcpu=cortex-a9 -mthumb-interwork 18 | ASFLAGS = 19 | 20 | all: $(TARGET).skprx 21 | 22 | %.skprx: %.velf 23 | dolce-make-fself -c $< $@ 24 | 25 | %.velf: %.elf 26 | dolce-elf-create -e $(TARGET).yml $< $@ 27 | 28 | payload_bootstrap.elf: $(BOOTSTRAP_OBJS) 29 | $(CC) -T bm-loader/payload_bootstrap.ld -nostartfiles -nostdlib $^ -o $@ -lgcc 30 | 31 | payload_bootstrap.bin: payload_bootstrap.elf 32 | $(OBJCOPY) -S -O binary $^ $@ 33 | 34 | payload_bootstrap_bin.o: payload_bootstrap.bin 35 | $(OBJCOPY) -I binary -O elf32-littlearm --binary-architecture arm $^ $@ 36 | 37 | $(TARGET).elf: $(TARGET_OBJS) payload_bootstrap_bin.o 38 | $(CC) $(CFLAGS) $^ $(LIBS) -o $@ 39 | 40 | .PHONY: all clean send 41 | 42 | clean: 43 | @rm -rf $(TARGET).skprx $(TARGET).velf $(TARGET).elf $(TARGET_OBJS) $(BOOTSTRAP_OBJS) \ 44 | payload_bootstrap.elf payload_bootstrap.bin payload_bootstrap_bin.o 45 | 46 | send: $(TARGET).skprx 47 | curl --ftp-method nocwd -T $(TARGET).skprx ftp://$(PSVITAIP):1337/ux0:/data/tai/kplugin.skprx 48 | @echo "Sent." -------------------------------------------------------------------------------- /blit/blit.c: -------------------------------------------------------------------------------- 1 | /* 2 | PSP VSH 24bpp text bliter 3 | */ 4 | #include "blit.h" 5 | 6 | #define ALPHA_BLEND 1 7 | 8 | extern unsigned char msx[]; 9 | 10 | ///////////////////////////////////////////////////////////////////////////// 11 | ///////////////////////////////////////////////////////////////////////////// 12 | static int pwidth, pheight, bufferwidth, pixelformat; 13 | static unsigned int* vram32; 14 | 15 | static uint32_t fcolor = 0x00ffffff; 16 | static uint32_t bcolor = 0xff000000; 17 | 18 | #if ALPHA_BLEND 19 | ///////////////////////////////////////////////////////////////////////////// 20 | ///////////////////////////////////////////////////////////////////////////// 21 | static uint32_t adjust_alpha(uint32_t col) 22 | { 23 | uint32_t alpha = col>>24; 24 | uint8_t mul; 25 | uint32_t c1,c2; 26 | 27 | if(alpha==0) return col; 28 | if(alpha==0xff) return col; 29 | 30 | c1 = col & 0x00ff00ff; 31 | c2 = col & 0x0000ff00; 32 | mul = (uint8_t)(255-alpha); 33 | c1 = ((c1*mul)>>8)&0x00ff00ff; 34 | c2 = ((c2*mul)>>8)&0x0000ff00; 35 | return (alpha<<24)|c1|c2; 36 | } 37 | #endif 38 | 39 | ///////////////////////////////////////////////////////////////////////////// 40 | ///////////////////////////////////////////////////////////////////////////// 41 | 42 | int blit_set_frame_buf(const SceDisplayFrameBuf *param) 43 | { 44 | 45 | pwidth = param->width; 46 | pheight = param->height; 47 | vram32 = param->base; 48 | bufferwidth = param->pitch; 49 | pixelformat = param->pixelformat; 50 | 51 | if( (bufferwidth==0) || (pixelformat!=0)) return -1; 52 | 53 | fcolor = 0x00ffffff; 54 | bcolor = 0xff000000; 55 | 56 | return 0; 57 | } 58 | 59 | void blit_set_color(int fg_col,int bg_col) 60 | { 61 | fcolor = fg_col; 62 | bcolor = bg_col; 63 | } 64 | 65 | ///////////////////////////////////////////////////////////////////////////// 66 | // blit text 67 | ///////////////////////////////////////////////////////////////////////////// 68 | int blit_string(int sx,int sy,const char *msg) 69 | { 70 | int x,y,p; 71 | int offset; 72 | char code; 73 | unsigned char font; 74 | uint32_t fg_col,bg_col; 75 | 76 | #if ALPHA_BLEND 77 | uint32_t col,c1,c2; 78 | uint32_t alpha; 79 | 80 | fg_col = adjust_alpha(fcolor); 81 | bg_col = adjust_alpha(bcolor); 82 | #else 83 | fg_col = fcolor; 84 | bg_col = bcolor; 85 | #endif 86 | 87 | //Kprintf("MODE %d WIDTH %d\n",pixelformat,bufferwidth); 88 | if( (bufferwidth==0) || (pixelformat!=0)) return -1; 89 | 90 | for(x=0;msg[x] && x<(pwidth/16);x++) 91 | { 92 | code = msg[x] & 0x7f; // 7bit ANK 93 | for(y=0;y<8;y++) 94 | { 95 | offset = (sy+(y*2))*bufferwidth + sx+x*16; 96 | font = y>=7 ? 0x00 : msx[ code*8 + y ]; 97 | for(p=0;p<8;p++) 98 | { 99 | #if ALPHA_BLEND 100 | col = (font & 0x80) ? fg_col : bg_col; 101 | alpha = col>>24; 102 | if(alpha==0) 103 | { 104 | vram32[offset] = col; 105 | vram32[offset + 1] = col; 106 | vram32[offset + bufferwidth] = col; 107 | vram32[offset + bufferwidth + 1] = col; 108 | } 109 | else if(alpha!=0xff) 110 | { 111 | c2 = vram32[offset]; 112 | c1 = c2 & 0x00ff00ff; 113 | c2 = c2 & 0x0000ff00; 114 | c1 = ((c1*alpha)>>8)&0x00ff00ff; 115 | c2 = ((c2*alpha)>>8)&0x0000ff00; 116 | uint32_t color = (col&0xffffff) + c1 + c2; 117 | vram32[offset] = color; 118 | vram32[offset + 1] = color; 119 | vram32[offset + bufferwidth] = color; 120 | vram32[offset + bufferwidth + 1] = color; 121 | } 122 | #else 123 | uint32_t color = (font & 0x80) ? fg_col : bg_col; 124 | vram32[offset] = color; 125 | vram32[offset + 1] = color; 126 | vram32[offset + bufferwidth] = color; 127 | vram32[offset + bufferwidth + 1] = color; 128 | #endif 129 | font <<= 1; 130 | offset+=2; 131 | } 132 | } 133 | } 134 | return x; 135 | } 136 | 137 | int blit_string_ctr(int sy,const char *msg) 138 | { 139 | int sx = 960/2 - strlen(msg)*(16/2); 140 | return blit_string(sx,sy,msg); 141 | } 142 | 143 | int blit_stringf(int sx, int sy, const char *msg, ...) 144 | { 145 | va_list list; 146 | char string[512]; 147 | 148 | va_start(list, msg); 149 | vsnprintf(string, 512, msg, list); 150 | va_end(list); 151 | 152 | return blit_string(sx, sy, string); 153 | } 154 | 155 | 156 | void blit_rect(uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t inColor) 157 | { 158 | int i, j; 159 | uint32_t c1,c2; 160 | uint32_t in_col = adjust_alpha(inColor); 161 | uint32_t alpha = in_col>>24; 162 | for (i = 0; i < h; i++) { 163 | for (j = 0; j < w; j++) { 164 | c2 = vram32[(x + j) + (y + i)*bufferwidth]; 165 | c1 = c2 & 0x00ff00ff; 166 | c2 = c2 & 0x0000ff00; 167 | c1 = ((c1*alpha)>>8)&0x00ff00ff; 168 | c2 = ((c2*alpha)>>8)&0x0000ff00; 169 | uint32_t color = (in_col&0xffffff) + c1 + c2; 170 | ((int *)vram32)[(x + j) + (y + i)*bufferwidth] = color; 171 | } 172 | } 173 | } -------------------------------------------------------------------------------- /blit/blit.h: -------------------------------------------------------------------------------- 1 | #ifndef __BLIT_H__ 2 | #define __BLIT_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | 11 | #define COLOR_CYAN 0x00ffff00 12 | #define COLOR_MAGENDA 0x00ff00ff 13 | #define COLOR_YELLOW 0x0000ffff 14 | 15 | #define RGB(R,G,B) (((B)<<16)|((G)<<8)|(R)) 16 | #define RGBT(R,G,B,T) (((T)<<24)|((B)<<16)|((G)<<8)|(R)) 17 | 18 | #define CENTER(num) ((960/2)-(num*(16/2))) 19 | 20 | int blit_setup(void); 21 | void blit_set_color(int fg_col,int bg_col); 22 | int blit_string(int sx,int sy,const char *msg); 23 | int blit_string_ctr(int sy,const char *msg); 24 | int blit_stringf(int sx, int sy, const char *msg, ...); 25 | int blit_set_frame_buf(const SceDisplayFrameBuf *param); 26 | void blit_rect(uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t color); 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /blit/font.c: -------------------------------------------------------------------------------- 1 | /* 2 | * PSP Software Development Kit - http://www.pspdev.org 3 | * ----------------------------------------------------------------------- 4 | * Licensed under the BSD license, see LICENSE in PSPSDK root for details. 5 | * 6 | * font.c - Debug Font. 7 | * 8 | * Copyright (c) 2005 Marcus R. Brown 9 | * Copyright (c) 2005 James Forshaw 10 | * Copyright (c) 2005 John Kelley 11 | * 12 | * $Id: font.c 339 2005-06-27 02:24:25Z warren $ 13 | */ 14 | #include 15 | 16 | const uint8_t msx[]= 17 | "\x00\x00\x00\x00\x00\x00\x00\x00\x3c\x42\xa5\x81\xa5\x99\x42\x3c" 18 | "\x3c\x7e\xdb\xff\xff\xdb\x66\x3c\x6c\xfe\xfe\xfe\x7c\x38\x10\x00" 19 | "\x10\x38\x7c\xfe\x7c\x38\x10\x00\x10\x38\x54\xfe\x54\x10\x38\x00" 20 | "\x10\x38\x7c\xfe\xfe\x10\x38\x00\x00\x00\x00\x30\x30\x00\x00\x00" 21 | "\xff\xff\xff\xe7\xe7\xff\xff\xff\x38\x44\x82\x82\x82\x44\x38\x00" 22 | "\xc7\xbb\x7d\x7d\x7d\xbb\xc7\xff\x0f\x03\x05\x79\x88\x88\x88\x70" 23 | "\x38\x44\x44\x44\x38\x10\x7c\x10\x30\x28\x24\x24\x28\x20\xe0\xc0" 24 | "\x3c\x24\x3c\x24\x24\xe4\xdc\x18\x10\x54\x38\xee\x38\x54\x10\x00" 25 | "\x10\x10\x10\x7c\x10\x10\x10\x10\x10\x10\x10\xff\x00\x00\x00\x00" 26 | "\x00\x00\x00\xff\x10\x10\x10\x10\x10\x10\x10\xf0\x10\x10\x10\x10" 27 | "\x10\x10\x10\x1f\x10\x10\x10\x10\x10\x10\x10\xff\x10\x10\x10\x10" 28 | "\x10\x10\x10\x10\x10\x10\x10\x10\x00\x00\x00\xff\x00\x00\x00\x00" 29 | "\x00\x00\x00\x1f\x10\x10\x10\x10\x00\x00\x00\xf0\x10\x10\x10\x10" 30 | "\x10\x10\x10\x1f\x00\x00\x00\x00\x10\x10\x10\xf0\x00\x00\x00\x00" 31 | "\x81\x42\x24\x18\x18\x24\x42\x81\x01\x02\x04\x08\x10\x20\x40\x80" 32 | "\x80\x40\x20\x10\x08\x04\x02\x01\x00\x10\x10\xff\x10\x10\x00\x00" 33 | "\x00\x00\x00\x00\x00\x00\x00\x00\x20\x20\x20\x20\x00\x00\x20\x00" 34 | "\x50\x50\x50\x00\x00\x00\x00\x00\x50\x50\xf8\x50\xf8\x50\x50\x00" 35 | "\x20\x78\xa0\x70\x28\xf0\x20\x00\xc0\xc8\x10\x20\x40\x98\x18\x00" 36 | "\x40\xa0\x40\xa8\x90\x98\x60\x00\x10\x20\x40\x00\x00\x00\x00\x00" 37 | "\x10\x20\x40\x40\x40\x20\x10\x00\x40\x20\x10\x10\x10\x20\x40\x00" 38 | "\x20\xa8\x70\x20\x70\xa8\x20\x00\x00\x20\x20\xf8\x20\x20\x00\x00" 39 | "\x00\x00\x00\x00\x00\x20\x20\x40\x00\x00\x00\x78\x00\x00\x00\x00" 40 | "\x00\x00\x00\x00\x00\x60\x60\x00\x00\x00\x08\x10\x20\x40\x80\x00" 41 | "\x70\x88\x98\xa8\xc8\x88\x70\x00\x20\x60\xa0\x20\x20\x20\xf8\x00" 42 | "\x70\x88\x08\x10\x60\x80\xf8\x00\x70\x88\x08\x30\x08\x88\x70\x00" 43 | "\x10\x30\x50\x90\xf8\x10\x10\x00\xf8\x80\xe0\x10\x08\x10\xe0\x00" 44 | "\x30\x40\x80\xf0\x88\x88\x70\x00\xf8\x88\x10\x20\x20\x20\x20\x00" 45 | "\x70\x88\x88\x70\x88\x88\x70\x00\x70\x88\x88\x78\x08\x10\x60\x00" 46 | "\x00\x00\x20\x00\x00\x20\x00\x00\x00\x00\x20\x00\x00\x20\x20\x40" 47 | "\x18\x30\x60\xc0\x60\x30\x18\x00\x00\x00\xf8\x00\xf8\x00\x00\x00" 48 | "\xc0\x60\x30\x18\x30\x60\xc0\x00\x70\x88\x08\x10\x20\x00\x20\x00" 49 | "\x70\x88\x08\x68\xa8\xa8\x70\x00\x20\x50\x88\x88\xf8\x88\x88\x00" 50 | "\xf0\x48\x48\x70\x48\x48\xf0\x00\x30\x48\x80\x80\x80\x48\x30\x00" 51 | "\xe0\x50\x48\x48\x48\x50\xe0\x00\xf8\x80\x80\xf0\x80\x80\xf8\x00" 52 | "\xf8\x80\x80\xf0\x80\x80\x80\x00\x70\x88\x80\xb8\x88\x88\x70\x00" 53 | "\x88\x88\x88\xf8\x88\x88\x88\x00\x70\x20\x20\x20\x20\x20\x70\x00" 54 | "\x38\x10\x10\x10\x90\x90\x60\x00\x88\x90\xa0\xc0\xa0\x90\x88\x00" 55 | "\x80\x80\x80\x80\x80\x80\xf8\x00\x88\xd8\xa8\xa8\x88\x88\x88\x00" 56 | "\x88\xc8\xc8\xa8\x98\x98\x88\x00\x70\x88\x88\x88\x88\x88\x70\x00" 57 | "\xf0\x88\x88\xf0\x80\x80\x80\x00\x70\x88\x88\x88\xa8\x90\x68\x00" 58 | "\xf0\x88\x88\xf0\xa0\x90\x88\x00\x70\x88\x80\x70\x08\x88\x70\x00" 59 | "\xf8\x20\x20\x20\x20\x20\x20\x00\x88\x88\x88\x88\x88\x88\x70\x00" 60 | "\x88\x88\x88\x88\x50\x50\x20\x00\x88\x88\x88\xa8\xa8\xd8\x88\x00" 61 | "\x88\x88\x50\x20\x50\x88\x88\x00\x88\x88\x88\x70\x20\x20\x20\x00" 62 | "\xf8\x08\x10\x20\x40\x80\xf8\x00\x70\x40\x40\x40\x40\x40\x70\x00" 63 | "\x00\x00\x80\x40\x20\x10\x08\x00\x70\x10\x10\x10\x10\x10\x70\x00" 64 | "\x20\x50\x88\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf8\x00" 65 | "\x40\x20\x10\x00\x00\x00\x00\x00\x00\x00\x70\x08\x78\x88\x78\x00" 66 | "\x80\x80\xb0\xc8\x88\xc8\xb0\x00\x00\x00\x70\x88\x80\x88\x70\x00" 67 | "\x08\x08\x68\x98\x88\x98\x68\x00\x00\x00\x70\x88\xf8\x80\x70\x00" 68 | "\x10\x28\x20\xf8\x20\x20\x20\x00\x00\x00\x68\x98\x98\x68\x08\x70" 69 | "\x80\x80\xf0\x88\x88\x88\x88\x00\x20\x00\x60\x20\x20\x20\x70\x00" 70 | "\x10\x00\x30\x10\x10\x10\x90\x60\x40\x40\x48\x50\x60\x50\x48\x00" 71 | "\x60\x20\x20\x20\x20\x20\x70\x00\x00\x00\xd0\xa8\xa8\xa8\xa8\x00" 72 | "\x00\x00\xb0\xc8\x88\x88\x88\x00\x00\x00\x70\x88\x88\x88\x70\x00" 73 | "\x00\x00\xb0\xc8\xc8\xb0\x80\x80\x00\x00\x68\x98\x98\x68\x08\x08" 74 | "\x00\x00\xb0\xc8\x80\x80\x80\x00\x00\x00\x78\x80\xf0\x08\xf0\x00" 75 | "\x40\x40\xf0\x40\x40\x48\x30\x00\x00\x00\x90\x90\x90\x90\x68\x00" 76 | "\x00\x00\x88\x88\x88\x50\x20\x00\x00\x00\x88\xa8\xa8\xa8\x50\x00" 77 | "\x00\x00\x88\x50\x20\x50\x88\x00\x00\x00\x88\x88\x98\x68\x08\x70" 78 | "\x00\x00\xf8\x10\x20\x40\xf8\x00\x18\x20\x20\x40\x20\x20\x18\x00" 79 | "\x20\x20\x20\x00\x20\x20\x20\x00\xc0\x20\x20\x10\x20\x20\xc0\x00" 80 | "\x40\xa8\x10\x00\x00\x00\x00\x00\x00\x00\x20\x50\xf8\x00\x00\x00" 81 | "\x70\x88\x80\x80\x88\x70\x20\x60\x90\x00\x00\x90\x90\x90\x68\x00" 82 | "\x10\x20\x70\x88\xf8\x80\x70\x00\x20\x50\x70\x08\x78\x88\x78\x00" 83 | "\x48\x00\x70\x08\x78\x88\x78\x00\x20\x10\x70\x08\x78\x88\x78\x00" 84 | "\x20\x00\x70\x08\x78\x88\x78\x00\x00\x70\x80\x80\x80\x70\x10\x60" 85 | "\x20\x50\x70\x88\xf8\x80\x70\x00\x50\x00\x70\x88\xf8\x80\x70\x00" 86 | "\x20\x10\x70\x88\xf8\x80\x70\x00\x50\x00\x00\x60\x20\x20\x70\x00" 87 | "\x20\x50\x00\x60\x20\x20\x70\x00\x40\x20\x00\x60\x20\x20\x70\x00" 88 | "\x50\x00\x20\x50\x88\xf8\x88\x00\x20\x00\x20\x50\x88\xf8\x88\x00" 89 | "\x10\x20\xf8\x80\xf0\x80\xf8\x00\x00\x00\x6c\x12\x7e\x90\x6e\x00" 90 | "\x3e\x50\x90\x9c\xf0\x90\x9e\x00\x60\x90\x00\x60\x90\x90\x60\x00" 91 | "\x90\x00\x00\x60\x90\x90\x60\x00\x40\x20\x00\x60\x90\x90\x60\x00" 92 | "\x40\xa0\x00\xa0\xa0\xa0\x50\x00\x40\x20\x00\xa0\xa0\xa0\x50\x00" 93 | "\x90\x00\x90\x90\xb0\x50\x10\xe0\x50\x00\x70\x88\x88\x88\x70\x00" 94 | "\x50\x00\x88\x88\x88\x88\x70\x00\x20\x20\x78\x80\x80\x78\x20\x20" 95 | "\x18\x24\x20\xf8\x20\xe2\x5c\x00\x88\x50\x20\xf8\x20\xf8\x20\x00" 96 | "\xc0\xa0\xa0\xc8\x9c\x88\x88\x8c\x18\x20\x20\xf8\x20\x20\x20\x40" 97 | "\x10\x20\x70\x08\x78\x88\x78\x00\x10\x20\x00\x60\x20\x20\x70\x00" 98 | "\x20\x40\x00\x60\x90\x90\x60\x00\x20\x40\x00\x90\x90\x90\x68\x00" 99 | "\x50\xa0\x00\xa0\xd0\x90\x90\x00\x28\x50\x00\xc8\xa8\x98\x88\x00" 100 | "\x00\x70\x08\x78\x88\x78\x00\xf8\x00\x60\x90\x90\x90\x60\x00\xf0" 101 | "\x20\x00\x20\x40\x80\x88\x70\x00\x00\x00\x00\xf8\x80\x80\x00\x00" 102 | "\x00\x00\x00\xf8\x08\x08\x00\x00\x84\x88\x90\xa8\x54\x84\x08\x1c" 103 | "\x84\x88\x90\xa8\x58\xa8\x3c\x08\x20\x00\x00\x20\x20\x20\x20\x00" 104 | "\x00\x00\x24\x48\x90\x48\x24\x00\x00\x00\x90\x48\x24\x48\x90\x00" 105 | "\x28\x50\x20\x50\x88\xf8\x88\x00\x28\x50\x70\x08\x78\x88\x78\x00" 106 | "\x28\x50\x00\x70\x20\x20\x70\x00\x28\x50\x00\x20\x20\x20\x70\x00" 107 | "\x28\x50\x00\x70\x88\x88\x70\x00\x50\xa0\x00\x60\x90\x90\x60\x00" 108 | "\x28\x50\x00\x88\x88\x88\x70\x00\x50\xa0\x00\xa0\xa0\xa0\x50\x00" 109 | "\xfc\x48\x48\x48\xe8\x08\x50\x20\x00\x50\x00\x50\x50\x50\x10\x20" 110 | "\xc0\x44\xc8\x54\xec\x54\x9e\x04\x10\xa8\x40\x00\x00\x00\x00\x00" 111 | "\x00\x20\x50\x88\x50\x20\x00\x00\x88\x10\x20\x40\x80\x28\x00\x00" 112 | "\x7c\xa8\xa8\x68\x28\x28\x28\x00\x38\x40\x30\x48\x48\x30\x08\x70" 113 | "\x00\x00\x00\x00\x00\x00\xff\xff\xf0\xf0\xf0\xf0\x0f\x0f\x0f\x0f" 114 | "\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00" 115 | "\x00\x00\x00\x3c\x3c\x00\x00\x00\xff\xff\xff\xff\xff\xff\x00\x00" 116 | "\xc0\xc0\xc0\xc0\xc0\xc0\xc0\xc0\x0f\x0f\x0f\x0f\xf0\xf0\xf0\xf0" 117 | "\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\x03\x03\x03\x03\x03\x03\x03\x03" 118 | "\x3f\x3f\x3f\x3f\x3f\x3f\x3f\x3f\x11\x22\x44\x88\x11\x22\x44\x88" 119 | "\x88\x44\x22\x11\x88\x44\x22\x11\xfe\x7c\x38\x10\x00\x00\x00\x00" 120 | "\x00\x00\x00\x00\x10\x38\x7c\xfe\x80\xc0\xe0\xf0\xe0\xc0\x80\x00" 121 | "\x01\x03\x07\x0f\x07\x03\x01\x00\xff\x7e\x3c\x18\x18\x3c\x7e\xff" 122 | "\x81\xc3\xe7\xff\xff\xe7\xc3\x81\xf0\xf0\xf0\xf0\x00\x00\x00\x00" 123 | "\x00\x00\x00\x00\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x00\x00\x00\x00" 124 | "\x00\x00\x00\x00\xf0\xf0\xf0\xf0\x33\x33\xcc\xcc\x33\x33\xcc\xcc" 125 | "\x00\x20\x20\x50\x50\x88\xf8\x00\x20\x20\x70\x20\x70\x20\x20\x00" 126 | "\x00\x00\x00\x50\x88\xa8\x50\x00\xff\xff\xff\xff\xff\xff\xff\xff" 127 | "\x00\x00\x00\x00\xff\xff\xff\xff\xf0\xf0\xf0\xf0\xf0\xf0\xf0\xf0" 128 | "\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\xff\xff\xff\xff\x00\x00\x00\x00" 129 | "\x00\x00\x68\x90\x90\x90\x68\x00\x30\x48\x48\x70\x48\x48\x70\xc0" 130 | "\xf8\x88\x80\x80\x80\x80\x80\x00\xf8\x50\x50\x50\x50\x50\x98\x00" 131 | "\xf8\x88\x40\x20\x40\x88\xf8\x00\x00\x00\x78\x90\x90\x90\x60\x00" 132 | "\x00\x50\x50\x50\x50\x68\x80\x80\x00\x50\xa0\x20\x20\x20\x20\x00" 133 | "\xf8\x20\x70\xa8\xa8\x70\x20\xf8\x20\x50\x88\xf8\x88\x50\x20\x00" 134 | "\x70\x88\x88\x88\x50\x50\xd8\x00\x30\x40\x40\x20\x50\x50\x50\x20" 135 | "\x00\x00\x00\x50\xa8\xa8\x50\x00\x08\x70\xa8\xa8\xa8\x70\x80\x00" 136 | "\x38\x40\x80\xf8\x80\x40\x38\x00\x70\x88\x88\x88\x88\x88\x88\x00" 137 | "\x00\xf8\x00\xf8\x00\xf8\x00\x00\x20\x20\xf8\x20\x20\x00\xf8\x00" 138 | "\xc0\x30\x08\x30\xc0\x00\xf8\x00\x18\x60\x80\x60\x18\x00\xf8\x00" 139 | "\x10\x28\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\xa0\x40" 140 | "\x00\x20\x00\xf8\x00\x20\x00\x00\x00\x50\xa0\x00\x50\xa0\x00\x00" 141 | "\x00\x18\x24\x24\x18\x00\x00\x00\x00\x30\x78\x78\x30\x00\x00\x00" 142 | "\x00\x00\x00\x00\x30\x00\x00\x00\x3e\x20\x20\x20\xa0\x60\x20\x00" 143 | "\xa0\x50\x50\x50\x00\x00\x00\x00\x40\xa0\x20\x40\xe0\x00\x00\x00" 144 | "\x00\x38\x38\x38\x38\x38\x38\x00\x00\x00\x00\x00\x00\x00\x00"; 145 | 146 | 147 | 148 | -------------------------------------------------------------------------------- /blit_gadgets.h: -------------------------------------------------------------------------------- 1 | #ifndef __CRP_BLIT_GADGETS 2 | #define __CRP_BLIT_GADGETS 3 | 4 | #include "blit/blit.h" 5 | 6 | #define BLIT_GADGETS_X 20 7 | #define BLIT_GADGETS_PIXELS_PER_LINE 20 8 | 9 | #define blit_gadgets_init(y) int __blit_gadgets_y = (y) 10 | #define blit_gadgets_setline(y) __blit_gadgets_y = (y) 11 | #define blit_gadgets_getline() __blit_gadgets_y - BLIT_GADGETS_PIXELS_PER_LINE //__blit_gadgets_y has the value of the line where to write next 12 | #define blit_gadgets_newline() __blit_gadgets_y += BLIT_GADGETS_PIXELS_PER_LINE 13 | #define screen_print(s) blit_string(BLIT_GADGETS_X, __blit_gadgets_y, (s)); blit_gadgets_newline() 14 | #define screen_printf(fmt, ...) blit_stringf(BLIT_GADGETS_X, __blit_gadgets_y, (fmt), ##__VA_ARGS__); blit_gadgets_newline() 15 | 16 | #define RED RGBT(255,0,0,0) 17 | #define GREEN RGBT(0,255,0,0) 18 | #define BLUE RGBT(0,0,255,0) 19 | #define WHITE RGBT(255,255,255,0) 20 | #define BLACK RGBT(0,0,0,0) 21 | 22 | //Additional defines go here 23 | #define MENU_Y 20 24 | #define COUNTDOWN_Y 200 //Leave 9 lines for menu 25 | #define ERR_MSG_Y COUNTDOWN_Y + 20 //Leave 1 line for countdown 26 | #define INFO_MSG_Y ERR_MSG_Y + 60 //Leave 2 lines for error messages 27 | 28 | #endif -------------------------------------------------------------------------------- /bm-loader/ldr_main.c: -------------------------------------------------------------------------------- 1 | /* PSVita bare-metal loader by xerpi */ 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "ldr_main.h" 17 | #include "../config.h" 18 | #include "../blit/blit.h" 19 | #include "../blit_gadgets.h" 20 | 21 | static tai_hook_ref_t SceSyscon_ksceSysconResetDevice_ref; 22 | static SceUID SceSyscon_ksceSysconResetDevice_hook_uid = -1; 23 | static tai_hook_ref_t SceSyscon_ksceSysconSendCommand_ref; 24 | static SceUID SceSyscon_ksceSysconSendCommand_hook_uid = -1; 25 | 26 | static tai_hook_ref_t SceLowio_kscePervasiveUartResetEnable_ref; 27 | static SceUID SceLowio_kscePervasiveUartResetEnable_hook_uid = -1; 28 | static tai_hook_ref_t SceLowio_ScePervasiveForDriver_81A155F1_ref; 29 | static SceUID SceLowio_ScePervasiveForDriver_81A155F1_hook_uid = -1; 30 | 31 | static SceSysconResumeContext resume_ctx; 32 | static uintptr_t resume_ctx_paddr; 33 | static unsigned int resume_ctx_buff[32]; 34 | /* 35 | * Global variables used by the resume function. 36 | */ 37 | uintptr_t payload_load_paddr; 38 | unsigned int payload_size; 39 | uintptr_t sysroot_buffer_paddr; 40 | void *lvl1_pt_va; 41 | 42 | 43 | static void setup_payload(void) 44 | { 45 | memset(&resume_ctx, 0, sizeof(resume_ctx)); 46 | resume_ctx.size = sizeof(resume_ctx); 47 | resume_ctx.buff_vaddr = (unsigned int )resume_ctx_buff; 48 | resume_ctx.resume_func_vaddr = (unsigned int)&resume_function; 49 | asm volatile("mrc p15, 0, %0, c1, c0, 0\n\t" : "=r"(resume_ctx.SCTLR)); 50 | asm volatile("mrc p15, 0, %0, c1, c0, 1\n\t" : "=r"(resume_ctx.ACTLR)); 51 | asm volatile("mrc p15, 0, %0, c1, c0, 2\n\t" : "=r"(resume_ctx.CPACR)); 52 | asm volatile("mrc p15, 0, %0, c2, c0, 0\n\t" : "=r"(resume_ctx.TTBR0)); 53 | asm volatile("mrc p15, 0, %0, c2, c0, 1\n\t" : "=r"(resume_ctx.TTBR1)); 54 | asm volatile("mrc p15, 0, %0, c2, c0, 2\n\t" : "=r"(resume_ctx.TTBCR)); 55 | asm volatile("mrc p15, 0, %0, c3, c0, 0\n\t" : "=r"(resume_ctx.DACR)); 56 | asm volatile("mrc p15, 0, %0, c10, c2, 0\n\t" : "=r"(resume_ctx.PRRR)); 57 | asm volatile("mrc p15, 0, %0, c10, c2, 1\n\t" : "=r"(resume_ctx.NMRR)); 58 | asm volatile("mrc p15, 0, %0, c12, c0, 0\n\t" : "=r"(resume_ctx.VBAR)); 59 | asm volatile("mrc p15, 0, %0, c13, c0, 1\n\t" : "=r"(resume_ctx.CONTEXTIDR)); 60 | asm volatile("mrc p15, 0, %0, c13, c0, 2\n\t" : "=r"(resume_ctx.TPIDRURW)); 61 | asm volatile("mrc p15, 0, %0, c13, c0, 3\n\t" : "=r"(resume_ctx.TPIDRURO)); 62 | asm volatile("mrc p15, 0, %0, c13, c0, 4\n\t" : "=r"(resume_ctx.TPIDRPRW)); 63 | resume_ctx.time = ksceKernelGetSystemTimeWide(); 64 | 65 | ksceKernelCpuDcacheAndL2WritebackRange(&resume_ctx, sizeof(resume_ctx)); 66 | 67 | lvl1_pt_va = get_lvl1_page_table_va(); 68 | 69 | LOG("Level 1 page table virtual address: %p\n", lvl1_pt_va); 70 | } 71 | 72 | static int ksceSysconResetDevice_hook_func(int type, int mode) 73 | { 74 | LOG("ksceSysconResetDevice(0x%08X, 0x%08X)\n", type, mode); 75 | 76 | /* 77 | * The Vita OS thinks it's about to poweroff, but we will instead 78 | * setup the payload and trigger a soft reset. 79 | */ 80 | if (type == SCE_SYSCON_RESET_TYPE_POWEROFF) { 81 | setup_payload(); 82 | type = SCE_SYSCON_RESET_TYPE_SOFT_RESET; 83 | } 84 | 85 | LOG("Resetting the device!\n"); 86 | 87 | ksceKernelCpuDcacheWritebackInvalidateAll(); 88 | ksceKernelCpuIcacheInvalidateAll(); 89 | 90 | return TAI_CONTINUE(int, SceSyscon_ksceSysconResetDevice_ref, type, mode); 91 | } 92 | 93 | static int ksceSysconSendCommand_hook_func(int cmd, void *buffer, unsigned int size) 94 | { 95 | LOG("ksceSysconSendCommand(0x%08X, %p, 0x%08X)\n", cmd, buffer, size); 96 | 97 | /* 98 | * Change the resume context to ours. 99 | */ 100 | if (cmd == SCE_SYSCON_CMD_RESET_DEVICE && size == 4) 101 | buffer = &resume_ctx_paddr; 102 | 103 | return TAI_CONTINUE(int, SceSyscon_ksceSysconSendCommand_ref, cmd, buffer, size); 104 | } 105 | 106 | static int kscePervasiveUartResetEnable_hook_func(int uart_bus) 107 | { 108 | /* 109 | * We want to keep the UART enabled... 110 | */ 111 | return 0; 112 | } 113 | 114 | /* 115 | * Returns ScePervasiveMisc vaddr, ScePower uses it to disable the UART 116 | * by writing 0x80000000 to the word 0x20 bytes past the return value. 117 | */ 118 | static void *ScePervasiveForDriver_81A155F1_hook_func(void) 119 | { 120 | static unsigned int tmp[0x24 / 4]; 121 | LOG("ScePervasiveForDriver_81A155F1()\n"); 122 | return tmp; 123 | } 124 | 125 | unsigned int *get_lvl1_page_table_va(void) 126 | { 127 | uint32_t ttbcr; 128 | uint32_t ttbr0; 129 | uint32_t ttbcr_n; 130 | uint32_t lvl1_pt_pa; 131 | void *lvl1_pt_va; 132 | 133 | asm volatile( 134 | "mrc p15, 0, %0, c2, c0, 2\n\t" 135 | "mrc p15, 0, %1, c2, c0, 0\n\t" 136 | : "=r"(ttbcr), "=r"(ttbr0)); 137 | 138 | ttbcr_n = ttbcr & 7; 139 | lvl1_pt_pa = ttbr0 & ~((1 << (14 - ttbcr_n)) - 1); 140 | 141 | if (!find_paddr(lvl1_pt_pa, (void *)0, 0xFFFFFFFF, &lvl1_pt_va)) 142 | return NULL; 143 | 144 | return lvl1_pt_va; 145 | } 146 | 147 | int find_paddr(uint32_t paddr, const void *vaddr_start, unsigned int range, void **found_vaddr) 148 | { 149 | const unsigned int step = 0x1000; 150 | void *vaddr = (void *)vaddr_start; 151 | const void *vaddr_end = vaddr_start + range; 152 | 153 | for (; vaddr < vaddr_end; vaddr += step) { 154 | uintptr_t cur_paddr; 155 | 156 | if (ksceKernelGetPaddr(vaddr, &cur_paddr) < 0) 157 | continue; 158 | 159 | if ((cur_paddr & ~(step - 1)) == (paddr & ~(step - 1))) { 160 | if (found_vaddr) 161 | *found_vaddr = vaddr; 162 | return 1; 163 | } 164 | } 165 | 166 | return 0; 167 | } 168 | 169 | int alloc_phycont(unsigned int size, unsigned int alignment, SceUID *uid, void **addr) 170 | { 171 | int ret; 172 | SceUID mem_uid; 173 | void *mem_addr; 174 | 175 | SceKernelAllocMemBlockKernelOpt opt; 176 | memset(&opt, 0, sizeof(opt)); 177 | opt.size = sizeof(opt); 178 | opt.attr = SCE_KERNEL_ALLOC_MEMBLOCK_ATTR_PHYCONT | SCE_KERNEL_ALLOC_MEMBLOCK_ATTR_HAS_ALIGNMENT; 179 | opt.alignment = ALIGN(alignment, 0x1000); 180 | mem_uid = ksceKernelAllocMemBlock("phycont", 0x30808006, ALIGN(size, 0x1000), &opt); 181 | if (mem_uid < 0) 182 | return mem_uid; 183 | 184 | ret = ksceKernelGetMemBlockBase(mem_uid, &mem_addr); 185 | if (ret < 0) { 186 | ksceKernelFreeMemBlock(mem_uid); 187 | return ret; 188 | } 189 | 190 | if (uid) 191 | *uid = mem_uid; 192 | if (addr) 193 | *addr = mem_addr; 194 | 195 | return 0; 196 | } 197 | 198 | int load_file_phycont(const char *path, SceUID *uid, void **addr, unsigned int *size) 199 | { 200 | int ret; 201 | SceUID fd; 202 | SceUID mem_uid; 203 | void *mem_addr; 204 | unsigned int file_size; 205 | unsigned int aligned_size; 206 | 207 | fd = ksceIoOpen(path, SCE_O_RDONLY, 0); 208 | if (fd < 0) 209 | return fd; 210 | 211 | file_size = ksceIoLseek(fd, 0, SCE_SEEK_END); 212 | aligned_size = ALIGN(file_size, 4096); 213 | 214 | ret = alloc_phycont(aligned_size, 4096, &mem_uid, &mem_addr); 215 | if (ret < 0) { 216 | ksceIoClose(fd); 217 | return ret; 218 | } 219 | 220 | ksceIoLseek(fd, 0, SCE_SEEK_SET); 221 | ksceIoRead(fd, mem_addr, file_size); 222 | 223 | ksceKernelCpuDcacheAndL2WritebackRange(mem_addr, aligned_size); 224 | ksceKernelCpuIcacheInvalidateRange(mem_addr, aligned_size); 225 | 226 | ksceIoClose(fd); 227 | 228 | if (uid) 229 | *uid = mem_uid; 230 | if (addr) 231 | *addr = mem_addr; 232 | if (size) 233 | *size = file_size; 234 | 235 | return 0; 236 | } 237 | 238 | /** 239 | * @return int 0 on success, < 0 otherwise 240 | */ 241 | int baremetal_loader_main(void) { 242 | int ret; 243 | SceUID payload_uid; 244 | SceUID sysroot_buffer_uid; 245 | void *payload_vaddr; 246 | void *sysroot_buffer_vaddr; 247 | struct sysroot_buffer *sysroot; 248 | 249 | blit_gadgets_init(ERR_MSG_Y); 250 | blit_set_color(RED,BLACK); 251 | 252 | LOG("Baremetal loader by xerpi\n"); 253 | 254 | /* 255 | * Load the baremetal payload to physically contiguous memory. 256 | */ 257 | ret = load_file_phycont(BAREMETAL_PAYLOAD_PATH, &payload_uid, &payload_vaddr, &payload_size); 258 | if (ret < 0) { 259 | LOG("Error loading " BAREMETAL_PAYLOAD_PATH ": 0x%08X\n", ret); 260 | screen_printf("Error loading " BAREMETAL_PAYLOAD_PATH ": 0x%08X",ret); 261 | return ret; 262 | } 263 | 264 | ksceKernelGetPaddr(payload_vaddr, &payload_load_paddr); 265 | 266 | LOG("Payload memory UID: 0x%08X\n", payload_uid); 267 | LOG("Payload load vaddr: 0x%08X\n", (unsigned int)payload_vaddr); 268 | LOG("Payload load paddr: 0x%08X\n", payload_load_paddr); 269 | LOG("Payload size: 0x%08X\n", payload_size); 270 | LOG("\n"); 271 | 272 | /* 273 | * Copy the sysroot buffer to physically contiguous memory. 274 | */ 275 | sysroot = ksceKernelGetSysrootBuffer(); 276 | 277 | ret = alloc_phycont(sysroot->size, 4096, &sysroot_buffer_uid, &sysroot_buffer_vaddr); 278 | if (ret < 0) { 279 | LOG("Error allocating memory for Sysroot buffer 0x%08X\n", ret); 280 | screen_printf("Error allocating memory for Sysroot buffer : 0x%08X",ret); 281 | ksceKernelFreeMemBlock(payload_uid); 282 | return ret; 283 | } 284 | 285 | ksceKernelCpuUnrestrictedMemcpy(sysroot_buffer_vaddr, sysroot, sysroot->size); 286 | 287 | ksceKernelGetPaddr(sysroot_buffer_vaddr, &sysroot_buffer_paddr); 288 | 289 | LOG("Sysroot buffer memory UID: 0x%08X\n", sysroot_buffer_uid); 290 | LOG("Sysroot buffer vaddr: 0x%08X\n", (unsigned int)sysroot_buffer_vaddr); 291 | LOG("Sysroot buffer paddr: 0x%08X\n", sysroot_buffer_paddr); 292 | LOG("Sysroot buffer size: 0x%08X\n", sysroot->size); 293 | LOG("\n"); 294 | 295 | SceSyscon_ksceSysconResetDevice_hook_uid = taiHookFunctionExportForKernel(KERNEL_PID, 296 | &SceSyscon_ksceSysconResetDevice_ref, "SceSyscon", 0x60A35F64, 297 | 0x8A95D35C, ksceSysconResetDevice_hook_func); 298 | 299 | SceSyscon_ksceSysconSendCommand_hook_uid = taiHookFunctionExportForKernel(KERNEL_PID, 300 | &SceSyscon_ksceSysconSendCommand_ref, "SceSyscon", 0x60A35F64, 301 | 0xE26488B9, ksceSysconSendCommand_hook_func); 302 | 303 | SceLowio_kscePervasiveUartResetEnable_hook_uid = taiHookFunctionExportForKernel(KERNEL_PID, 304 | &SceLowio_kscePervasiveUartResetEnable_ref, "SceLowio", 0xE692C727, 305 | 0x788B6C61, kscePervasiveUartResetEnable_hook_func); 306 | 307 | SceLowio_ScePervasiveForDriver_81A155F1_hook_uid = taiHookFunctionExportForKernel(KERNEL_PID, 308 | &SceLowio_ScePervasiveForDriver_81A155F1_ref, "SceLowio", 0xE692C727, 309 | 0x81A155F1, ScePervasiveForDriver_81A155F1_hook_func); 310 | 311 | LOG("Hooks installed.\n"); 312 | 313 | ksceKernelGetPaddr(&resume_ctx, &resume_ctx_paddr); 314 | LOG("Resume context pa: 0x%08X\n", resume_ctx_paddr); 315 | 316 | LOG("Requesting standby...\n"); 317 | blit_gadgets_setline(INFO_MSG_Y); 318 | blit_set_color(GREEN,BLACK); 319 | screen_printf("Payload loaded, requesting standby..."); 320 | 321 | kscePowerRequestStandby(); 322 | 323 | return 0; 324 | } -------------------------------------------------------------------------------- /bm-loader/ldr_main.h: -------------------------------------------------------------------------------- 1 | #ifndef __LDR_MAIN_H 2 | #define __LDR_MAIN_H 3 | 4 | #include 5 | #include //For ksceDebugPrintf 6 | 7 | struct sysroot_buffer { 8 | unsigned short version; 9 | unsigned short size; 10 | unsigned int current_firmware_version; 11 | unsigned int firmware_version_shipped_from_factory; 12 | unsigned int unk0c[(0x2c - 0x0c) / 4]; 13 | unsigned long long bitfield_flags; 14 | unsigned int unk34[(0x40 - 0x34) / 4]; 15 | unsigned int devkit_function_address_1; 16 | unsigned int devkit_uid; 17 | unsigned int devkit_function_address_2; 18 | unsigned int aslr_seed; 19 | unsigned int devkit_config_flags; 20 | unsigned int devkit_config_flags2; 21 | unsigned int devkit_config; 22 | unsigned int devkit_config_flags3; 23 | unsigned int dram_base_paddr; 24 | unsigned int dram_size; 25 | unsigned int unk68; 26 | unsigned int boot_type_indicator_1; 27 | unsigned char openpsid[0x10]; 28 | unsigned int secure_kernel_enp_raw_data_paddr; 29 | unsigned int secure_kernel_enp_size; 30 | unsigned int unk88; 31 | unsigned int unk8c; 32 | unsigned int kprx_auth_sm_self_raw_data_paddr; 33 | unsigned int kprx_auth_sm_self_size; 34 | unsigned int prog_rvk_srvk_raw_data_paddr; 35 | unsigned int prog_rvk_srvk_size; 36 | unsigned short model; 37 | unsigned short device_type; 38 | unsigned short device_config; 39 | unsigned short type; 40 | unsigned short unka8[(0xb0 - 0xa8) / 2]; 41 | unsigned char session_id[0x10]; 42 | unsigned int unkc0; 43 | unsigned int boot_type_indicator_2; 44 | unsigned int unkc8[(0xd0 - 0xc8) / 4]; 45 | unsigned int suspend_saved_context_paddr; 46 | unsigned int unkd4[(0xf8 - 0xd4) / 4]; 47 | unsigned int bootloader_revision; 48 | unsigned int sysroot_magic_value; 49 | unsigned char encrypted_session_key[0x20]; 50 | } __attribute__((packed)); 51 | 52 | typedef struct SceSysconResumeContext { 53 | unsigned int size; 54 | unsigned int unk; 55 | unsigned int buff_vaddr; 56 | unsigned int resume_func_vaddr; 57 | unsigned int SCTLR; 58 | unsigned int ACTLR; 59 | unsigned int CPACR; 60 | unsigned int TTBR0; 61 | unsigned int TTBR1; 62 | unsigned int TTBCR; 63 | unsigned int DACR; 64 | unsigned int PRRR; 65 | unsigned int NMRR; 66 | unsigned int VBAR; 67 | unsigned int CONTEXTIDR; 68 | unsigned int TPIDRURW; 69 | unsigned int TPIDRURO; 70 | unsigned int TPIDRPRW; 71 | unsigned int unk2[6]; 72 | unsigned long long time; 73 | } SceSysconResumeContext; 74 | 75 | static unsigned int *get_lvl1_page_table_va(void); 76 | static int find_paddr(uint32_t paddr, const void *vaddr_start, unsigned int range, void **found_vaddr); 77 | static int alloc_phycont(unsigned int size, unsigned int alignment, SceUID *uid, void **addr); 78 | static int load_file_phycont(const char *path, SceUID *uid, void **addr, unsigned int *size); 79 | 80 | #define LOG(fmt, ...) ksceDebugPrintf("[BAREMETAL LOADER]"fmt, ##__VA_ARGS__) 81 | #define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1)) 82 | 83 | extern void resume_function(void); 84 | int baremetal_loader_main(void); 85 | 86 | #endif -------------------------------------------------------------------------------- /bm-loader/payload_bootstrap.S: -------------------------------------------------------------------------------- 1 | @ payload_bootstrap.S by xerpi 2 | @ see https://github.com/xerpi/vita-baremetal-loader 3 | .align 4 4 | .text 5 | .cpu cortex-a9 6 | 7 | .globl _start 8 | @ r0 = payload src paddr, r1 = payload dst paddr, r2 = payload size, r3 = sysroot buffer paddr 9 | _start: 10 | dsb 11 | 12 | @ Disable interrupts and enter System mode 13 | cpsid aif, #0x1F 14 | 15 | mov r8, r0 16 | mov r9, r1 17 | mov r10, r2 18 | mov r11, r3 19 | 20 | @ DACR unrestricted 21 | mov r0, #0xFFFFFFFF 22 | mcr p15, 0, r0, c3, c0, 0 23 | 24 | ldr r0, =sync_point_1 25 | bl cpus_sync 26 | 27 | @ Clean and invalidate the entire Dcache 28 | bl dcache_clean_inv_all 29 | 30 | @ Now we are in an identity-mapped region, let's disable 31 | @ the MMU, the Dcache and the Icache 32 | mrc p15, 0, r0, c1, c0, 0 33 | bic r0, #1 << 0 @ MMU 34 | bic r0, #1 << 2 @ Dcache 35 | bic r0, #1 << 12 @ Icache 36 | mcr p15, 0, r0, c1, c0, 0 37 | 38 | @ Invalidate the entire Dcache 39 | bl dcache_inv_all 40 | 41 | mov r0, #0 42 | mcr p15, 0, r0, c7, c5, 6 @ BPIALL (Branch Predictor Invalidate All) 43 | isb 44 | mcr p15, 0, r0, c7, c5, 0 @ ICIALLU (Icache Invalidate All to PoU) 45 | dsb 46 | mcr p15, 0, r0, c8, c7, 0 @ TLBIALL (Unified TLB Invalidate All) 47 | isb 48 | 49 | @ Get CPU ID 50 | mrc p15, 0, r0, c0, c0, 5 51 | and r0, #0xF 52 | cmp r0, #0 53 | bne cpu1_3_cont 54 | 55 | @ Copy the payload to its destination address 56 | mov r0, r9 57 | mov r1, r8 58 | mov r2, r10 59 | bl memcpy 60 | 61 | cpu1_3_cont: 62 | ldr r0, =sync_point_2 63 | bl cpus_sync 64 | 65 | @ Jump to the payload! 66 | mov r0, r11 67 | mov lr, r9 68 | bx lr 69 | 70 | @ Uses: r0, r1 71 | dcache_clean_inv_all: 72 | mov r0, #0 73 | 1: 74 | mcr p15, 0, r0, c7, c14, 2 @ DCCISW (Data cache clean and invalidate by set/way) 75 | adds r0, r0, #0x40000000 76 | bcc 1b 77 | adds r0, #0x20 78 | lsrs r1, r0, #0xD 79 | beq 1b 80 | dsb 81 | bx lr 82 | 83 | @ Uses: r0, r1 84 | dcache_inv_all: 85 | mov r0, #0 86 | 1: 87 | mcr p15, 0, r0, c7, c6, 2 @ DCISW (Data cache invalidate by set/way) 88 | adds r0, r0, #0x40000000 89 | bcc 1b 90 | adds r0, #0x20 91 | lsrs r1, r0, #0xD 92 | beq 1b 93 | dsb 94 | bx lr 95 | 96 | 97 | @ r0 = sync point address 98 | @ Uses: r0, r1, r2 99 | cpus_sync: 100 | mrc p15, 0, r1, c0, c0, 5 101 | and r1, #0xF 102 | cmp r1, #0 103 | streq r1, [r0] 104 | 1: 105 | ldrb r2, [r0] 106 | cmp r1, r2 107 | wfene 108 | bne 1b 109 | ldrh r2, [r0] 110 | adds r2, #1 111 | adds r2, r2, #0x100 112 | strh r2, [r0] 113 | dsb 114 | sev 115 | 1: 116 | ldrb r2, [r0, #1] 117 | cmp r2, #4 118 | wfene 119 | bne 1b 120 | bx lr 121 | 122 | @ r0 = dst, r1 = src, r2 = size 123 | @ Uses: r0, r1, r2, r3 124 | memcpy: 125 | ldmia r1!, {r3} 126 | stmia r0!, {r3} 127 | subs r2, #4 128 | bne memcpy 129 | bx lr 130 | 131 | .data 132 | sync_point_1: .word 0 133 | sync_point_2: .word 0 -------------------------------------------------------------------------------- /bm-loader/payload_bootstrap.ld: -------------------------------------------------------------------------------- 1 | OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") 2 | OUTPUT_ARCH(arm) 3 | 4 | ENTRY(_start) 5 | 6 | SECTIONS 7 | { 8 | . = 0x1F000000; 9 | .text : { 10 | *(.text) 11 | *(.text*) 12 | } 13 | .data : { 14 | *(.data*) 15 | } 16 | } -------------------------------------------------------------------------------- /bm-loader/resume.S: -------------------------------------------------------------------------------- 1 | @ resume.S by xerpi 2 | @ see https://github.com/xerpi/vita-baremetal-loader 3 | 4 | #include "../config.h" 5 | 6 | .set BOOTSTRAP_PADDR, 0x1F000000 7 | 8 | .align 4 9 | .text 10 | .cpu cortex-a9 11 | 12 | .global resume_function 13 | .type resume_function, %function 14 | resume_function: 15 | dsb 16 | 17 | @ Set CONTEXTIDR (Context ID Register) to zero. 18 | mov r3, #0 19 | mcr p15, 0, r3, c13, c0, 1 20 | isb 21 | 22 | ldr r0, =sync_point_1 23 | bl cpus_sync 24 | 25 | @ Get CPU ID 26 | mrc p15, 0, r0, c0, c0, 5 27 | and r0, #0xF 28 | cmp r0, #0 29 | bne cpu1_3_cont 30 | 31 | @ CPU0: Identity map the scratchpad using a 1MiB section 32 | ldr r2, =lvl1_pt_va 33 | ldr r2, [r2] 34 | add r2, #(BOOTSTRAP_PADDR >> 20) << 2 35 | ldr r3, =((BOOTSTRAP_PADDR >> 20) << 20) | 0x91402 36 | str r3, [r2] 37 | mcr p15, 0, r2, c7, c14, 1 @ DCCIMVAC (Data Cache line Clean and Invalidate by VA to PoC) 38 | dsb 39 | mcr p15, 0, r0, c8, c7, 0 @ TLBIALL (Unified TLB Invalidate All) 40 | dsb 41 | isb 42 | 43 | @ Copy the payload bootstrap to the scratchpad 44 | ldr r0, =BOOTSTRAP_PADDR 45 | ldr r1, =_binary_payload_bootstrap_bin_start 46 | ldr r2, =_binary_payload_bootstrap_bin_size 47 | bl resume_memcpy 48 | 49 | ldr r0, =BOOTSTRAP_PADDR 50 | ldr r1, =_binary_payload_bootstrap_bin_size 51 | bl dcache_clean_range 52 | 53 | cpu1_3_cont: 54 | ldr r0, =sync_point_2 55 | bl cpus_sync 56 | 57 | @ TLBIALL (Unified TLB Invalidate All) 58 | mcr p15, 0, r0, c8, c7, 0 59 | dsb 60 | isb 61 | 62 | @ ICIALLU (Icache Invalidate All to PoU) 63 | mov r0, #0 64 | mcr p15, 0, r0, c7, c5, 0 65 | dsb 66 | 67 | @ Get payload parameters 68 | @ r0 = payload src paddr 69 | @ r1 = payload dst paddr 70 | @ r2 = payload size 71 | @ r3 = sysroot buffer paddr 72 | ldr r0, =payload_load_paddr 73 | ldr r0, [r0] 74 | ldr r1, =BAREMETAL_PAYLOAD_PADDR 75 | ldr r2, =payload_size 76 | ldr r2, [r2] 77 | ldr r3, =sysroot_buffer_paddr 78 | ldr r3, [r3] 79 | 80 | @ Jump to the payload bootsrap! 81 | ldr lr, =BOOTSTRAP_PADDR 82 | bx lr 83 | 84 | @ r0 = sync point address 85 | @ Uses: r0, r1, r2 86 | cpus_sync: 87 | mrc p15, 0, r1, c0, c0, 5 88 | and r1, #0xF 89 | cmp r1, #0 90 | streq r1, [r0] 91 | 1: 92 | ldrb r2, [r0] 93 | cmp r1, r2 94 | wfene 95 | bne 1b 96 | ldrh r2, [r0] 97 | adds r2, #1 98 | adds r2, r2, #0x100 99 | strh r2, [r0] 100 | dsb 101 | sev 102 | 1: 103 | ldrb r2, [r0, #1] 104 | cmp r2, #4 105 | wfene 106 | bne 1b 107 | bx lr 108 | 109 | @ r0 = addr, r1 = size 110 | @ Uses: r0, r1 111 | dcache_clean_range: 112 | add r1, r0 113 | bic r0, #(32 - 1) 114 | dsb 115 | 1: 116 | mcr p15, 0, r0, c7, c10, 1 @ DCCMVAC (Data Cache line Clean by VA to PoC) 117 | add r0, #32 118 | cmp r0, r1 119 | blo 1b 120 | dsb 121 | bx lr 122 | 123 | @ r0 = dst, r1 = src, r2 = size 124 | @ Uses: r0, r1, r2, r3 125 | resume_memcpy: 126 | ldmia r1!, {r3} 127 | stmia r0!, {r3} 128 | subs r2, #4 129 | bne resume_memcpy 130 | bx lr 131 | 132 | .data 133 | sync_point_1: .word 0 134 | sync_point_2: .word 0 -------------------------------------------------------------------------------- /config.h: -------------------------------------------------------------------------------- 1 | #ifndef __CONFIG_H 2 | #define __CONFIG_H 3 | 4 | #define COUNTDOWN_TIME 5 //Countdown time, in seconds. Note that print function expects at most a 2-digit number 5 | #define BACKGROUND_IMG_PATH "ur0:tai/BootMenu.bmp" //Location of the background .bmp 6 | #define LINUX_MODULE_PATH "ux0:linux/bootstrap.skprx" //Location of the kernel module that loads the baremetal loader (DEPRECATED) 7 | #define BAREMETAL_PAYLOAD_PATH "ux0:linux/payload.bin" //Location of the Linux baremetal payload 8 | #define BAREMETAL_PAYLOAD_PADDR 0x40300000 //Phyiscal address at which the payload will be loaded 9 | 10 | 11 | #endif -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #include "blit/blit.h" 22 | 23 | #include "blit_gadgets.h" 24 | #include "bm-loader/ldr_main.h" 25 | #include "config.h" 26 | 27 | int ksceRtcGetCurrentClockLocalTime(SceDateTime*); 28 | 29 | int secs = COUNTDOWN_TIME; //Countdown time 30 | const char menu[4][20] = {"Boot Vita OS", "Boot Linux", "Reboot", "Shutdown"}; 31 | 32 | static SceUID fb_uid = -1; 33 | 34 | SceCtrlData ctrl_peek, ctrl_press; 35 | 36 | void *fb_addr = NULL; 37 | void *bmp_addr = NULL; 38 | int rgbuid, bgfd; 39 | int menusize; 40 | int menu_index = 1; 41 | int hasbg; 42 | 43 | SceDateTime current_time; 44 | int target_time; 45 | int is_pstv = 0; 46 | int do_countdown = 1; 47 | int menu_last_line; 48 | 49 | #define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1)) 50 | 51 | #define SCREEN_PITCH 960 52 | #define SCREEN_W 960 53 | #define SCREEN_H 544 54 | 55 | void drawArrow() { 56 | //ksceDmacMemset(fb_addr, 0x00, SCREEN_PITCH * SCREEN_H * 4); 57 | if (is_pstv) return; //PSTV doesn't have a menu 58 | blit_set_color(BLACK,BLACK); 59 | for(int i = 1; i <= menusize; i++) blit_stringf((strlen(menu[i - 1]) + 2) * 16, i * 20 + menu_last_line, "<"); 60 | blit_set_color(WHITE,BLACK); 61 | blit_stringf((strlen(menu[menu_index - 1]) + 2) * 16, menu_index * 20 + menu_last_line, "<"); 62 | } 63 | 64 | int isSkipComboPressed() { 65 | SceCtrlData ctrl; 66 | 67 | ksceCtrlPeekBufferPositive(0, &ctrl, 1); 68 | 69 | ksceDebugPrintf("Buttons held: 0x%08X\n", ctrl.buttons); 70 | 71 | if(ctrl.buttons & (SCE_CTRL_POWER | SCE_CTRL_TRIANGLE)) { 72 | return 1; 73 | } else { 74 | return 0; 75 | } 76 | 77 | } 78 | 79 | int updateAndDrawCountdown(){ 80 | int ret = 0; 81 | if (!do_countdown){ 82 | blit_rect(20,COUNTDOWN_Y,100,20,0x00000000); 83 | return ret; 84 | } 85 | else { 86 | blit_set_color(RGBT(0,0xFF,0,0), 0x00000000); 87 | blit_stringf(20,COUNTDOWN_Y,"Booting Linux in %1ds ...",--secs); 88 | blit_set_color(0x00FFFFFF,0x00000000); 89 | 90 | ksceDebugPrintf("current_time.second : %d\n",current_time.second); 91 | 92 | target_time = (current_time.second + 1 == 60) ? 0 : current_time.second + 1; 93 | 94 | ksceDebugPrintf("New target time : %d\n",target_time); 95 | if (secs == 0){ 96 | do_countdown = 0; 97 | ret = baremetal_loader_main(); 98 | return ret; 99 | } 100 | } 101 | return ret; 102 | } 103 | 104 | void _start() __attribute__ ((weak, alias ("module_start"))); 105 | int module_start(SceSize argc, const void *args) { 106 | ksceDebugPrintf("-----------------------\n"\ 107 | "VitaBootMenu by CreepNT\n"\ 108 | "Based on EmergencyMount\n"\ 109 | " by Team CBPS \n"\ 110 | "-----------------------\n"); 111 | 112 | menusize = sizeof(menu) / sizeof(menu[0]); 113 | is_pstv = ksceSblAimgrIsGenuineDolce(); 114 | ksceDebugPrintf("is_pstv : %c\n", is_pstv ? 'y' : 'n'); 115 | 116 | if( isSkipComboPressed() ) 117 | return SCE_KERNEL_START_SUCCESS; //Skip menu if Triangle/Power is pressed 118 | 119 | int stat_ret; 120 | SceIoStat stat; 121 | stat_ret = ksceIoGetstat(BACKGROUND_IMG_PATH, &stat); 122 | if ( (stat_ret < 0) || ((uint32_t)stat.st_size != 0x17E836) || (SCE_STM_ISDIR(stat.st_mode) != 0) ) hasbg = 0; 123 | else hasbg = 1; 124 | 125 | unsigned int fb_size = ALIGN(4 * SCREEN_PITCH * SCREEN_H, 256 * 1024); 126 | 127 | fb_uid = ksceKernelAllocMemBlock("fb", 0x40404006 , fb_size, NULL); 128 | 129 | ksceKernelGetMemBlockBase(fb_uid, &fb_addr); 130 | 131 | if(hasbg) { 132 | if( (rgbuid = ksceKernelAllocMemBlock("rgb", 0x1050D006, 0x200000, NULL)) < 0) { 133 | hasbg = 0; 134 | ksceDebugPrintf("background memory allocation failed\n"); 135 | } else ksceDebugPrintf("rgb okke!\n"); 136 | } 137 | 138 | if(hasbg) { 139 | ksceKernelGetMemBlockBase(rgbuid, (void**)&bmp_addr); 140 | bgfd = ksceIoOpen(BACKGROUND_IMG_PATH, SCE_O_RDONLY, 0); 141 | ksceIoLseek(bgfd, 54, SCE_SEEK_SET); // 54 byte bmp header 142 | ksceIoRead(bgfd, bmp_addr, 0x17E7E2); // 0x17E836 - 54 = 0x17E7E2 143 | ksceIoClose(bgfd); 144 | ksceDebugPrintf("bmp read okke!\n"); 145 | 146 | for(int i = 0; i < 544; i++) { 147 | for(int j = 0; j < 960; j++) { 148 | // A B G R 149 | *(uint32_t *)(fb_addr + (((544 - i) * 960) + j) * 4) = 150 | ((((char *)bmp_addr)[((i * 960) + j) * 3 + 2]) << 0) | 151 | ((((char *)bmp_addr)[((i * 960) + j) * 3 + 1]) << 8) | 152 | ((((char *)bmp_addr)[((i * 960) + j) * 3 + 0]) << 16) | 153 | 0xFF000000; 154 | } 155 | } 156 | 157 | ksceDebugPrintf("background okke!\n"); 158 | 159 | ksceKernelFreeMemBlock(rgbuid); 160 | } 161 | 162 | SceDisplayFrameBuf fb; 163 | fb.size = sizeof(fb); 164 | fb.base = fb_addr; 165 | fb.pitch = SCREEN_PITCH; 166 | fb.pixelformat = 0; 167 | fb.width = SCREEN_W; 168 | fb.height = SCREEN_H; 169 | 170 | ksceDisplaySetFrameBuf(&fb, 1); 171 | blit_set_frame_buf(&fb); 172 | 173 | blit_gadgets_init(MENU_Y); 174 | blit_set_color(WHITE,BLACK); 175 | 176 | 177 | screen_print("VitaBootMenu by CreepNT"); 178 | screen_print("Based on EmergencyMount"); 179 | screen_print(" by teakhanirons "); 180 | screen_print("-----------------------"); 181 | if (!is_pstv){ 182 | menu_last_line = blit_gadgets_getline(); 183 | for(int i = 0; i < menusize; i++) { screen_print(menu[i]); } 184 | drawArrow(); 185 | } 186 | else { 187 | screen_print("Press POWER to boot PS Vita OS."); 188 | } 189 | 190 | ksceRtcGetCurrentClockLocalTime(¤t_time); 191 | target_time = (current_time.second + 1 == 60) ? 0 : current_time.second + 1; 192 | 193 | while(1) { 194 | ksceKernelPowerTick(SCE_KERNEL_POWER_TICK_DEFAULT); 195 | 196 | ctrl_press = ctrl_peek; 197 | ksceCtrlPeekBufferPositive(0, &ctrl_peek, 1); 198 | ctrl_press.buttons = ctrl_peek.buttons & ~ctrl_press.buttons; 199 | 200 | if (do_countdown) { 201 | if (ctrl_press.buttons){ 202 | do_countdown = 0; 203 | updateAndDrawCountdown(); 204 | if (is_pstv) 205 | goto exit_inf_loop; //For PSTV, cancelling countdown launches PSVita OS. 206 | } 207 | else { 208 | ksceRtcGetCurrentClockLocalTime(¤t_time); 209 | if (current_time.second >= target_time) 210 | updateAndDrawCountdown(); 211 | continue; //No buttons were pressed, we can safely skip the control handling code 212 | } 213 | } 214 | 215 | if(ctrl_press.buttons == SCE_CTRL_UP) { 216 | menu_index--; 217 | if(menu_index < 1) menu_index = menusize; 218 | drawArrow(); 219 | } 220 | else if(ctrl_press.buttons == SCE_CTRL_DOWN){ 221 | menu_index++; 222 | if(menu_index > menusize) menu_index = 1; 223 | drawArrow(); 224 | } 225 | else if(ctrl_press.buttons == SCE_CTRL_CROSS || ctrl_press.buttons == SCE_CTRL_CIRCLE) { 226 | if(menu_index == 1) { // Vita OS 227 | goto exit_inf_loop; 228 | } 229 | else if(menu_index == 2) { //Boot Linux 230 | int bm_ret; 231 | bm_ret = baremetal_loader_main(); 232 | if (bm_ret < 0){ 233 | blit_gadgets_setline(INFO_MSG_Y); 234 | screen_printf("Exiting to VitaOS..."); 235 | ksceKernelDelayThread(1 * 1000 * 1000); 236 | goto exit_inf_loop; 237 | } 238 | else { 239 | ksceKernelDelayThread(5 * 1000 * 1000); //fallback 240 | } 241 | } 242 | else if(menu_index == 3) { // reboot - kind of broken, sometimes doesnt reboot only shutdown 243 | kscePowerRequestColdReset(); 244 | ksceKernelDelayThread(5 * 1000 * 1000); //fallback 245 | } 246 | else if(menu_index == 4) { // shutdown - may be broken? 247 | kscePowerRequestStandby(); 248 | ksceKernelDelayThread(5 * 1000 * 1000); //fallback 249 | } 250 | } 251 | }; 252 | exit_inf_loop: 253 | ksceDebugPrintf("Exiting loop...\n"); 254 | if (fb_uid) { 255 | ksceKernelFreeMemBlock(fb_uid); 256 | } 257 | 258 | return SCE_KERNEL_START_SUCCESS; 259 | } 260 | 261 | int module_stop(SceSize argc, const void *args) { 262 | if (fb_uid) { 263 | ksceKernelFreeMemBlock(fb_uid); 264 | } 265 | 266 | return SCE_KERNEL_STOP_SUCCESS; 267 | } --------------------------------------------------------------------------------