Add missing files
[install-bootos.git] / source / main.c
blobca3457c59062c4d3e8dd17dc7c9f58027d9a35bc
1 #include <psl1ght/lv2.h>
2 #include <errno.h>
3 #include <stdio.h>
4 #include <sysutil/video.h>
5 #include <rsx/gcm.h>
6 #include <rsx/reality.h>
7 #include <io/pad.h>
8 #include "sconsole.h"
9 #include <unistd.h>
10 #include <assert.h>
11 #include <malloc.h>
12 #include <string.h>
13 #include "hvcall.h"
14 #include "peek_poke.h"
15 #include "mm.h"
17 #define CHUNK 65536
18 #define QUICK_SCAN 0
20 void xputs(const char *msg);
22 VideoConfiguration vconfig;
23 VideoState state;
25 unsigned char *read_file(FILE * f, size_t * sz)
27 if (!f) {
28 return NULL;
30 fseek(f, 0, SEEK_END);
31 *sz = ftell(f);
32 fseek(f, 0, SEEK_SET);
34 unsigned char *userlandBuffer = malloc(*sz);
35 if (!userlandBuffer) {
36 return NULL;
38 fread(userlandBuffer, 1, *sz, f);
39 fclose(f);
40 if (*((u32 *) userlandBuffer) == 0) {
41 free(userlandBuffer);
42 userlandBuffer = NULL;
44 return userlandBuffer;
47 PadInfo padinfo;
48 PadData paddata;
50 typedef struct {
51 int height;
52 int width;
53 uint32_t *ptr;
54 // Internal stuff
55 uint32_t offset;
56 } buffer;
58 gcmContextData *context;
59 VideoResolution res;
60 int currentBuffer = 0;
61 buffer *buffers[2];
63 void waitFlip()
65 // Block the PPU thread untill the previous flip operation has finished.
66 while (gcmGetFlipStatus() != 0) {
67 usleep(200);
69 gcmResetFlipStatus();
72 void flip(s32 buffer)
74 assert(gcmSetFlip(context, buffer) == 0);
75 realityFlushBuffer(context);
76 gcmSetWaitFlip(context);
79 void makeBuffer(int id, int size)
81 buffer *buf = malloc(sizeof(buffer));
82 buf->ptr = rsxMemAlign(16, size);
83 assert(buf->ptr != NULL);
85 assert(realityAddressToOffset(buf->ptr, &buf->offset) == 0);
86 assert(gcmSetDisplayBuffer
87 (id, buf->offset, res.width * 4, res.width, res.height) == 0);
89 buf->width = res.width;
90 buf->height = res.height;
91 buffers[id] = buf;
94 u64 mmap_lpar_addr;
96 int map_lv1()
98 char buf[256];
99 int result =
100 lv1_undocumented_function_114(0, 0xC, HV_SIZE, &mmap_lpar_addr);
101 if (result != 0) {
102 snprintf(buf, sizeof(buf),
103 "Error code %d calling lv1_undocumented_function_114",
104 result);
105 xputs(buf);
106 return 0;
108 result =
109 mm_map_lpar_memory_region(mmap_lpar_addr, HV_BASE, HV_SIZE, 0xC, 0);
110 if (result) {
111 snprintf(buf, sizeof(buf),
112 "Error code %d calling mm_map_lpar_memory_region",
113 result);
114 xputs(buf);
115 return 0;
117 return 1;
120 void unmap_lv1()
122 if (mmap_lpar_addr != 0) {
123 lv1_undocumented_function_115(mmap_lpar_addr);
127 void init_screen()
129 void *host_addr = memalign(1024 * 1024, 1024 * 1024);
130 assert(host_addr != NULL);
132 context = realityInit(0x10000, 1024 * 1024, host_addr);
133 assert(context != NULL);
135 assert(videoGetState(0, 0, &state) == 0);
136 assert(state.state == 0);
138 assert(videoGetResolution(state.displayMode.resolution, &res) == 0);
140 memset(&vconfig, 0, sizeof(VideoConfiguration));
141 vconfig.resolution = state.displayMode.resolution;
142 vconfig.format = VIDEO_BUFFER_FORMAT_XRGB;
143 vconfig.pitch = res.width * 4;
145 assert(videoConfigure(0, &vconfig, NULL, 0) == 0);
146 assert(videoGetState(0, 0, &state) == 0);
148 s32 buffer_size = 4 * res.width * res.height;
150 gcmSetFlipMode(GCM_FLIP_VSYNC);
151 makeBuffer(0, buffer_size);
152 makeBuffer(1, buffer_size);
154 gcmResetFlipStatus();
155 flip(1);
158 static const struct {
159 uint64_t offset;
160 const char *type;
161 const char *fw;
162 } s_known_platforms[] = {
164 0x1600C0ULL, "FAT 16M", "3.55"}, {
165 0x0980C0ULL, "FAT 256M", "3.55"}, {
166 0x0A7E60ULL, "Slim", "3.55"}, {
167 0x12A0C0ULL, "FAT 256M", "3.15"},};
169 #define NBELMS(a) (sizeof((a))/sizeof((a)[0]))
171 void install_bootos()
173 char ts[400];
175 uint64_t lv2_kernel_filename_offset = 0;
176 int found = 0;
177 int i;
179 xputs("Mapping LV1...");
180 install_new_poke();
181 if (!map_lv1()) {
182 xputs("Cannot map LV1!");
183 return;
186 /* First try quickscanning the PS3_LPAR kernel filename */
187 if (QUICK_SCAN) {
188 xputs
189 ("Quickscanning LV1 PS3_LPAR kernel filename at known offsets...");
190 found = 0;
191 for (i = 0; i < NBELMS(s_known_platforms); i++) {
192 if (lv1_peek(s_known_platforms[i].offset) ==
193 0x2F666C682F6F732FULL
194 && lv1_peek(s_known_platforms[i].offset + 8) ==
195 0x6C76325F6B65726EULL) {
196 lv2_kernel_filename_offset =
197 s_known_platforms[i].offset;
198 found = 1;
199 break;
203 if (!found) {
204 uint64_t q1 = 0;
205 uint64_t q2 = 0;
206 uint64_t ten = 0;
207 for (i = 0; i < HV_SIZE; i += 8) {
208 if (10 * ten > HV_SIZE) {
209 snprintf(ts, sizeof(ts),
210 "Scanning LV1 PS3_LPAR kernel filename on full LV1 "
211 "address space... %08llX %02d%%",
212 i & 0xFFFFFFFFULL,
213 (int)(i * (uint64_t) 100 / HV_SIZE));
214 xputs(ts);
215 ten -= HV_SIZE / 10;
217 q2 = lv1_peek(i);
218 if (q1 == 0x2F666C682F6F732FULL
219 && q2 == 0x6C76325F6B65726EULL) {
220 lv2_kernel_filename_offset = i - 8;
221 found = 1;
222 break;
224 q1 = q2;
225 ten += 8;
228 xputs("Unmapping LV1...");
229 unmap_lv1();
230 remove_new_poke();
232 if (!found) {
233 xputs("No LV1 PS3_LPAR kernel filename found.");
234 return;
237 snprintf(ts, sizeof(ts),
238 "LV1 PS3_LPAR kernel filename offset at %08llX.",
239 lv2_kernel_filename_offset & 0xFFFFFFFFULL);
240 xputs(ts);
241 found = 0;
242 for (i = 0; i < NBELMS(s_known_platforms); i++) {
243 if (lv2_kernel_filename_offset == s_known_platforms[i].offset) {
244 snprintf(ts, sizeof(ts),
245 "Detected a PS3 %s running FW %s",
246 s_known_platforms[i].type,
247 s_known_platforms[i].fw);
248 xputs(ts);
249 found = 1;
250 break;
253 if (!found) {
254 xputs
255 ("Please report your PS3 model, its firmware version and the offset found.");
257 // Lv2Patcher works on mapped memory for lv1, and doesn't account for base offset (1<<63)
258 lv2_kernel_filename_offset += HV_BASE;
259 lv2_kernel_filename_offset &= 0xFFFFFFFFULL;
261 if (Lv2Syscall8
262 (837, (u64) "CELL_FS_IOS:BUILTIN_FLSH1", (u64) "CELL_FS_FAT",
263 (u64) "/dev_rwflash", 0, 0, 0, 0, 0)) {
264 xputs("Flash remap failed!");
266 xputs("Reading BootOS...");
267 FILE *f = fopen("/dev_hdd0/game/LNX000001/USRDIR/bootos.bin", "r");
268 if (!f) {
269 xputs("Cannot open BootOS binary!");
270 return;
272 size_t sz, sz1;
273 u8 *data = (u8 *) read_file(f, &sz);
274 if (!data) {
275 xputs("Cannot read BootOS binary!");
276 fclose(f);
277 return;
279 unlink("/dev_rwflash/lv2_kernel.self");
281 FILE *g = fopen("/dev_rwflash/lv2_kernel.self", "w");
282 if (!g) {
283 fclose(f);
284 xputs("Cannot open flash!");
285 return;
287 sz1 = sz;
288 while (sz > 0) {
289 sprintf(ts, "Writing BootOS: %02d%%",
290 (int)((sz1 - sz) * 100 / sz1));
291 xputs(ts);
292 if (sz >= CHUNK) {
293 fwrite(data + (sz1 - sz), CHUNK, 1, g);
294 sz -= CHUNK;
295 } else {
296 fwrite(data + (sz1 - sz), sz, 1, g);
297 sz = 0;
300 fclose(f);
301 fclose(g);
303 xputs("Adding \"Linux\" entry...");
304 f = fopen("/dev_hdd0/game/LV2000000/USRDIR/linux.txt", "w");
305 if (!f) {
306 xputs("Cannot add a new patchset to LV2 patcher!");
307 return;
309 fputs("# Linux\nlv1en\n", f);
310 fprintf(f, "%08lX: 2f6c6f63616c5f73\n", lv2_kernel_filename_offset);
311 fprintf(f, "%08lX: 7973302f6c76325f\n", lv2_kernel_filename_offset + 8);
312 fprintf(f, "%08lX: 6b65726e656c2e73\n",
313 lv2_kernel_filename_offset + 16);
314 fprintf(f, "%08lX: 656c6600\n", lv2_kernel_filename_offset + 24);
315 fprintf(f, "%08lX: 000000000000001b\n",
316 lv2_kernel_filename_offset + 0x120);
317 fputs("lv1dis\n", f);
318 fputs("panic\n", f);
319 fclose(f);
321 xputs("Creating kboot configuration file...");
322 f = fopen("/dev_hdd0/kboot.conf", "w");
323 fputs
324 ("Install Debian GNU/Linux=http://ftp.debian.org/debian/dists/squeeze/main/installer-powerpc/current/images/powerpc64/netboot/vmlinux initrd=http://ftp.debian.org/debian/dists/squeeze/main/installer-powerpc/current/images/powerpc64/netboot/initrd.gz preseed/url=http://boot.khore.org/mod/preseed.cfg auto=true interface=auto priority=critical\n",
326 fclose(f);
329 xputs("Creating 10G file...");
330 f = fopen("/dev_hdd0/linux.img", "w");
331 data = malloc(1 << 20);
332 for(i = 0; i < 10240; i++)
333 fwrite(data, 1 << 20, 1, f);
334 fclose(f);
335 free(data);
338 xputs("All done.");
339 xputs("Please run the LV2 patcher.");
340 xputs("");
343 void xputs(const char *msg)
345 static int y = 150;
346 int i, j;
348 waitFlip();
349 if (y == 150) {
350 for (i = 0; i < res.height; i++) {
351 for (j = 0; j < res.width; j++) {
352 buffers[currentBuffer]->ptr[i * res.width + j] =
353 FONT_COLOR_BLACK;
356 } else {
357 memcpy(buffers[currentBuffer]->ptr,
358 buffers[!currentBuffer]->ptr,
359 res.width * res.height * sizeof(u32));
361 if (y >= 470) {
362 memmove(buffers[currentBuffer]->ptr,
363 buffers[currentBuffer]->ptr + res.width * 40,
364 res.width * (res.height - 40) * sizeof(u32));
365 y -= 40;
367 for (i = y; i < y + 32; i++) {
368 for (j = 0; j < res.width; j++) {
369 buffers[currentBuffer]->ptr[i * res.width + j] =
370 FONT_COLOR_BLACK;
373 print(150, y, msg, buffers[currentBuffer]->ptr);
374 if (msg[strlen(msg + 1)] != '%') {
375 y += 40;
377 flip(currentBuffer);
378 currentBuffer = !currentBuffer;
381 int main()
383 int i;
385 init_screen();
386 ioPadInit(7);
387 sconsoleInit(FONT_COLOR_BLACK, FONT_COLOR_WHITE, res.width, res.height);
389 xputs("== BootOS Installer ==");
390 install_bootos();
391 Lv2Syscall1(838, (u64) "/dev_rwflash");
393 xputs("Press [X] to exit.");
394 while (1) {
395 ioPadGetInfo(&padinfo);
396 for (i = 0; i < MAX_PADS; i++) {
397 if (padinfo.status[i]) {
398 ioPadGetData(i, &paddata);
399 if (paddata.BTN_CROSS) {
400 return 0;
404 usleep(100000);
406 return 0;