Subversion Repositories freemyipod

Rev

Rev 547 | Rev 630 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
366 theseven 1
//
2
//
3
//    Copyright 2010 TheSeven
4
//
5
//
530 theseven 6
//    This file is part of emCORE.
366 theseven 7
//
530 theseven 8
//    emCORE is free software: you can redistribute it and/or
366 theseven 9
//    modify it under the terms of the GNU General Public License as
10
//    published by the Free Software Foundation, either version 2 of the
11
//    License, or (at your option) any later version.
12
//
530 theseven 13
//    emCORE is distributed in the hope that it will be useful,
366 theseven 14
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
15
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16
//    See the GNU General Public License for more details.
17
//
18
//    You should have received a copy of the GNU General Public License along
530 theseven 19
//    with emCORE.  If not, see <http://www.gnu.org/licenses/>.
366 theseven 20
//
21
//
22
 
23
 
530 theseven 24
#include "emcoreapp.h"
25
#include "libpng.h"
26
#include "libui.h"
366 theseven 27
 
28
 
29
void main();
530 theseven 30
EMCORE_APP_HEADER("emCORE installer", main, 127)
366 theseven 31
 
32
 
530 theseven 33
extern char background_png[];
34
extern uint32_t background_png_size;
35
extern char darkener_png[];
36
extern uint32_t darkener_png_size;
37
extern char disclaimer_png[];
38
extern uint32_t disclaimer_png_size;
39
extern char actions_png[];
40
extern uint32_t actions_png_size;
41
extern char f_png_emcorelib[];
42
extern char f_ui_emcorelib[];
43
extern uint32_t flashscript[];
44
extern uint32_t firstinstcost;
45
extern uint32_t firstinstscript[];
46
extern uint32_t commoncost;
47
extern uint32_t commonscript[];
366 theseven 48
 
530 theseven 49
 
366 theseven 50
struct wakeup eventwakeup;
51
volatile int button;
530 theseven 52
volatile int scrollpos;
366 theseven 53
 
54
 
55
#define SHA1CONFIG    (*((volatile uint32_t*)(0x38000000)))
56
#define SHA1RESET     (*((volatile uint32_t*)(0x38000004)))
57
#define SHA1RESULT      ((volatile uint32_t*)(0x38000020))
58
#define SHA1DATAIN      ((volatile uint32_t*)(0x38000040))
59
 
60
void sha1(void* data, uint32_t size, void* hash)
61
{
62
    int i, space;
63
    bool done = false;
64
    uint32_t tmp32[16];
65
    uint8_t* tmp8 = (uint8_t*)tmp32;
66
    uint32_t* databuf = (uint32_t*)data;
67
    uint32_t* hashbuf = (uint32_t*)hash;
68
    clockgate_enable(0, true);
69
    SHA1RESET = 1;
70
    while (SHA1CONFIG & 1) sleep(0);
71
    SHA1RESET = 0;
72
    SHA1CONFIG = 0;
73
    while (!done)
74
    {
75
        space = ((uint32_t)databuf) - ((uint32_t)data) - size + 64;
76
        if (space > 0)
77
        {
78
            for (i = 0; i < 16; i++) tmp32[i] = 0;
79
            if (space <= 64)
80
            {
81
                for (i = 0; i < 64 - space; i++) tmp8[i] = ((uint8_t*)databuf)[i];
82
                tmp8[64 - space] = 0x80;
83
            }
84
            if (space >= 8)
85
            {
86
                tmp8[0x3b] = (size >> 29) & 0xff;
87
                tmp8[0x3c] = (size >> 21) & 0xff;
88
                tmp8[0x3d] = (size >> 13) & 0xff;
89
                tmp8[0x3e] = (size >> 5) & 0xff;
90
                tmp8[0x3f] = (size << 3) & 0xff;
91
                done = true;
92
            }
93
            for (i = 0; i < 16; i++) SHA1DATAIN[i] = tmp32[i];
94
        }
95
        else for (i = 0; i < 16; i++) SHA1DATAIN[i] = databuf[i];
96
        databuf += 16;
97
        SHA1CONFIG |= 2;
98
        while (SHA1CONFIG & 1) sleep(0);
99
        SHA1CONFIG |= 8;
100
    }
101
    for (i = 0; i < 5; i++) hashbuf[i] = SHA1RESULT[i];
102
    clockgate_enable(0, false);
103
}
104
 
105
 
530 theseven 106
void handler(void* user, enum button_event eventtype, int which, int value)
366 theseven 107
{
108
    if (eventtype == BUTTON_PRESS) button |= 1 << which;
530 theseven 109
    if (eventtype == WHEEL_MOVED_ACCEL)
110
        scrollpos = MAX(0, MIN(295, scrollpos + value / 8));
366 theseven 111
    wakeup_signal(&eventwakeup);
112
}
113
 
114
void mkfat32(struct progressbar_state* progressbar)
115
{
116
    uint32_t i, j, rc;
117
    uint32_t rootdirclus = 2;
118
    uint32_t secperclus = 1;
119
    uint32_t fatsectors = 1;
120
    uint32_t oldfatsectors = 0;
121
    uint32_t clustercount;
122
    uint32_t reserved = 2;
123
    struct storage_info storageinfo;
124
    storage_get_info(0, &storageinfo);
125
    uint32_t totalsectors = storageinfo.num_sectors;
126
    disk_unmount(0);
127
    while (fatsectors != oldfatsectors)
128
    {
129
        oldfatsectors = fatsectors;
130
        clustercount = (totalsectors - fatsectors - reserved) / secperclus;
131
        fatsectors = (clustercount + 1025) >> 10;
132
    }
133
    uint32_t database = fatsectors + reserved;
134
    uint32_t clusoffset = 0;
546 theseven 135
    uint32_t* buf = memalign(0x10, 0x20000);
366 theseven 136
    memset(buf, 0, 0x800);
137
    memcpy(buf, "\xeb\x58\x00MSWIN5.0\0\x10", 0xd);
138
    ((uint8_t*)buf)[0xd] = secperclus;
139
    ((uint16_t*)buf)[7] = reserved;
140
    memcpy(&((uint8_t*)buf)[0x10], "\x01\0\0\0\0\xf8\0\0\x3f\0\xff", 0xb);
141
    buf[8] = totalsectors;
142
    buf[9] = fatsectors;
143
    buf[0xb] = rootdirclus + clusoffset;
144
    ((uint16_t*)buf)[0x18] = 1;
145
    ((uint8_t*)buf)[0x40] = 0x80;
146
    ((uint8_t*)buf)[0x42] = 0x29;
147
    memcpy(&((uint8_t*)buf)[0x43], "\0\0\0\0iPodClassic", 0xf);
148
    memcpy(&((uint8_t*)buf)[0x52], "FAT32   ", 8);
149
    ((uint16_t*)buf)[0xff] = 0xaa55;
150
    if (rc = storage_write_sectors_md(0, 0, 1, buf))
551 theseven 151
        panicf(PANIC_KILLTHREAD, "Error writing MBR: %08X", rc);
366 theseven 152
    memset(buf, 0, 0x800);
153
    buf[0] = 0x41615252;
154
    buf[0x79] = 0x61417272;
155
    buf[0x7a] = clustercount - 1;
156
    buf[0x7b] = 2;
157
    buf[0x7f] = 0xaa550000;
158
    if (rc = storage_write_sectors_md(0, 1, 1, buf))
551 theseven 159
        panicf(PANIC_KILLTHREAD, "Error writing FSINFO: %08X", rc);
530 theseven 160
    progressbar_init(progressbar, 15, 304, 135, 159, 0x77ff, 0xe8, 0x125f, 0, fatsectors);
366 theseven 161
    uint32_t cursect = 0;
162
    for (i = 0; i < fatsectors; i += 32)
163
    {
164
        memset(buf, 0, 0x20000);
165
        if (!i) memcpy(buf, "\xf8\xff\xff\x0f\xff\xff\xff\xff\xff\xff\xff\x0f", 12);
166
        if (rc = storage_write_sectors_md(0, reserved + i, MIN(fatsectors - i, 32), buf))
551 theseven 167
            panicf(PANIC_KILLTHREAD, "Error writing FAT sectors %d-%d: %08X",
530 theseven 168
                   i, MIN(fatsectors - 1, i + 31), rc);
366 theseven 169
        progressbar_setpos(progressbar, i, false);
170
    }
171
    memset(buf, 0, secperclus * 0x1000);
172
    memcpy(buf, "iPodClassic\x08", 12);
173
    if (rc = storage_write_sectors_md(0, database, secperclus, buf))
551 theseven 174
        panicf(PANIC_KILLTHREAD, "Error writing root directory sectors: %08X", i, rc);
366 theseven 175
    free(buf);
176
    disk_mount(0);
177
}
178
 
179
void main(void)
180
{
181
    uint32_t i, j, k, rc;
182
    uint32_t dummy;
183
    struct progressbar_state progressbar;
184
    bool appleflash;
185
    void* syscfgptr;
186
    uint8_t* norbuf;
187
#define norbufword ((uint32_t*)norbuf)
188
    uint8_t* oldnor;
189
#define oldnorword ((uint32_t*)oldnor)
190
 
530 theseven 191
    cputc(3, '.');
192
    struct emcorelib_header* libpng = get_library(0x64474e50, LIBPNG_API_VERSION, LIBSOURCE_RAM_NEEDCOPY, f_png_emcorelib);
551 theseven 193
    if (!libpng) panicf(PANIC_KILLTHREAD, "Could not load PNG decoder library!");
530 theseven 194
    struct libpng_api* png = (struct libpng_api*)libpng->api;
195
    cputc(3, '.');
196
    struct emcorelib_header* libui = get_library(0x49554365, LIBUI_API_VERSION, LIBSOURCE_RAM_NEEDCOPY, f_ui_emcorelib);
551 theseven 197
    if (!libui) panicf(PANIC_KILLTHREAD, "Could not load user interface library!");
530 theseven 198
    struct libui_api* ui = (struct libui_api*)libui->api;
199
    cputc(3, '.');
366 theseven 200
 
530 theseven 201
    struct png_info* handle = png->png_open(background_png, background_png_size);
551 theseven 202
    if (!handle) panicf(PANIC_KILLTHREAD, "Could not parse background image!");
530 theseven 203
    cputc(3, '.');
204
    struct png_rgb* bg = png->png_decode_rgb(handle);
551 theseven 205
    if (!bg) panicf(PANIC_KILLTHREAD, "Could not decode background image!");
530 theseven 206
    png->png_destroy(handle);
207
    cputc(3, '.');
208
    handle = png->png_open(actions_png, actions_png_size);
551 theseven 209
    if (!handle) panicf(PANIC_KILLTHREAD, "Could not parse actions image!");
530 theseven 210
    cputc(3, '.');
211
    struct png_rgba* actions = png->png_decode_rgba(handle);
551 theseven 212
    if (!actions) panicf(PANIC_KILLTHREAD, "Could not decode actions image!");
530 theseven 213
    png->png_destroy(handle);
214
    cputc(3, '.');
215
    void* framebuf = malloc(290 * 165 * 3);
551 theseven 216
    if (!framebuf) panicf(PANIC_KILLTHREAD, "Could not allocate frame buffer!");
530 theseven 217
    cputc(3, '.');
366 theseven 218
 
530 theseven 219
    disk_unmount(0);
220
    bool updating = disk_mount(0);
221
    cputc(3, '.');
366 theseven 222
 
546 theseven 223
    norbuf = memalign(0x10, 0x100000);
224
    oldnor = memalign(0x10, 0x100000);
385 theseven 225
    memset(norbuf, 0xff, 0x100000);
530 theseven 226
    cputc(3, '.');
366 theseven 227
    bootflash_readraw(oldnor, 0, 0x100000);
530 theseven 228
    cputc(3, '.');
366 theseven 229
    if (oldnorword[0x400] == 0x53436667) appleflash = false;
230
    else
231
    {
530 theseven 232
        updating = false;
374 theseven 233
        if (oldnorword[0] == 0x53436667) appleflash = true;
551 theseven 234
        else panic(PANIC_KILLTHREAD, "Boot flash contents are damaged! "
366 theseven 235
                                     "(No SYSCFG found)\n\nPlease ask for help.\n");
236
    }
385 theseven 237
    memcpy(&norbuf[0x1000], &oldnor[appleflash ? 0 : 0x1000], 0x1000);
530 theseven 238
    cputc(3, '.');
239
 
240
    uint32_t* script = flashscript;
366 theseven 241
    uint32_t sp = 0;
242
    uint32_t beginptr = 0x2000;
243
    uint32_t endptr = 0x100000;
244
    uint32_t dirptr = 0;
245
    while (script[sp])
246
    {
247
        uint32_t file = script[sp] & 0xff;
248
        uint32_t flags = (script[sp] >> 8) & 0xff;
249
        uint32_t align = (script[sp] >> 16) & 0xff;
250
        void* data;
251
        uint32_t size;
252
        sp++;
253
        switch (file)
254
        {
255
            default:
530 theseven 256
                data = (void*)(script[sp++]);
366 theseven 257
                size = script[sp++];
258
        }
259
        if (size)
260
        {
261
            if (align && !(flags & 1))
262
            {
263
                if ((align << 12) < beginptr)
551 theseven 264
                    panicf(PANIC_KILLTHREAD, "Error: Align failed! (%02X)", align);
366 theseven 265
                beginptr = align << 12;
266
            }
267
            if (endptr - beginptr < size)
551 theseven 268
                panicf(PANIC_KILLTHREAD, "Error: Flash is full!");
366 theseven 269
            uint32_t storesize = size;
270
            if (flags & 2) storesize |= 0x80000000;
271
            int offs = 0;
272
            if (flags & 8)
273
            {
274
                offs = 0x800;
275
                size = ((size + 0xf) & ~0xf) + offs;
276
            }
277
            if (flags & 1)
278
            {
279
                endptr -= ((size + 0xfff) & ~0xfff);
280
                memcpy(&norbuf[endptr + offs], data, size);
281
                file = endptr;
282
            }
283
            else
284
            {
285
                memcpy(&norbuf[beginptr + offs], data, size);
286
                file = beginptr;
287
                beginptr += ((size + 0xfff) & ~0xfff);
288
            }
289
            if (!(flags & 4))
290
            {
291
                if (dirptr >= 0x1000)
551 theseven 292
                    panicf(PANIC_KILLTHREAD, "Error: Directory is full!");
366 theseven 293
                memcpy(&norbuf[dirptr], &script[sp], 8);
294
                norbufword[(dirptr >> 2) + 2] = file;
295
                norbufword[(dirptr >> 2) + 3] = storesize;
296
                dirptr += 0x10;
297
                sp += 2;
298
            }
299
            if (flags & 8)
300
            {
301
                size -= offs;
302
                memset(&norbuf[file], 0, 0x800);
303
                memcpy(&norbuf[file], "87021.0\x01", 8);
304
                *((uint32_t*)&norbuf[file + 0xc]) = size;
305
                sha1(&norbuf[file + 0x800], size, &norbuf[file + 0x10]);
306
                *((uint32_t*)&norbuf[file + 0x20]) = 0;
307
                hwkeyaes(HWKEYAES_ENCRYPT, 2, &norbuf[file + 0x10], 0x10);
308
                sha1(&norbuf[file], 0x40, &norbuf[file + 0x40]);
309
                *((uint32_t*)&norbuf[file + 0x50]) = 0;
310
                hwkeyaes(HWKEYAES_ENCRYPT, 2, &norbuf[file + 0x40], 0x10);
311
                hwkeyaes(HWKEYAES_ENCRYPT, 2, &norbuf[file + 0x800], size);
312
            }
313
        }
314
        else if (!(flags & 4)) sp += 2;
530 theseven 315
        cputc(3, '.');
366 theseven 316
    }
317
 
318
    if (!updating)
319
    {
530 theseven 320
        void* darkened = malloc(320 * 240 * 3);
551 theseven 321
        if (!darkened) panicf(PANIC_KILLTHREAD, "Could not allocate darkened image!");
530 theseven 322
        cputc(3, '.');
323
        handle = png->png_open(darkener_png, darkener_png_size);
551 theseven 324
        if (!handle) panicf(PANIC_KILLTHREAD, "Could not parse darkener image!");
530 theseven 325
        cputc(3, '.');
326
        struct png_rgba* darkener = png->png_decode_rgba(handle);
551 theseven 327
        if (!darkener) panicf(PANIC_KILLTHREAD, "Could not decode darkener image!");
530 theseven 328
        png->png_destroy(handle);
329
        cputc(3, '.');
330
        ui->blenda(320, 240, 255, darkened, 0, 0, 320, bg, 0, 0, 320, darkener, 0, 0, 320);
331
        free(darkener);
332
        cputc(3, '.');
333
        handle = png->png_open(disclaimer_png, disclaimer_png_size);
551 theseven 334
        if (!handle) panicf(PANIC_KILLTHREAD, "Could not parse disclaimer image!");
530 theseven 335
        cputc(3, '.');
336
        struct png_rgba* disclaimer = png->png_decode_rgba(handle);
551 theseven 337
        if (!disclaimer) panicf(PANIC_KILLTHREAD, "Could not decode disclaimer image!");
530 theseven 338
        png->png_destroy(handle);
339
        cputc(3, '.');
340
 
341
        button = 0;
342
        wakeup_init(&eventwakeup);
343
        struct button_hook_entry* hook = button_register_handler(handler, NULL);
551 theseven 344
        if (!hook) panicf(PANIC_KILLTHREAD, "Could not register button hook!");
530 theseven 345
 
346
        displaylcd(0, 0, 320, 240, darkened, 0, 0, 320);
347
        backlight_set_fade(32);
348
        backlight_set_brightness(177);
349
        backlight_on(true);
350
        scrollpos = 0;
351
 
366 theseven 352
        while (true)
353
        {
530 theseven 354
            ui->blenda(290, 165, 255, framebuf, 0, 0, 290,
355
                       darkened, 15, 50, 320, disclaimer, 0, scrollpos, 290);
356
            displaylcd(15, 50, 290, 165, framebuf, 0, 0, 290);
357
 
366 theseven 358
            wakeup_wait(&eventwakeup, TIMEOUT_BLOCK);
530 theseven 359
            if (button == 0x18) break;
366 theseven 360
            else if (button == 4)
361
            {
385 theseven 362
                shutdown(false);
366 theseven 363
                reset();
364
            }
365
            button = 0;
366
        }
530 theseven 367
 
368
        button_unregister_handler(hook);
369
        free(darkened);
370
        free(disclaimer);
371
 
372
        ui->blenda(165, 36, 255, framebuf, 0, 0, 165, bg, 77, 100, 320, actions, 0, 0, 165);
373
        displaylcd(0, 0, 320, 240, bg, 0, 0, 320);
374
        displaylcd(77, 100, 165, 36, framebuf, 0, 0, 165);
375
 
366 theseven 376
        mkfat32(&progressbar);
377
    }
378
 
530 theseven 379
    ui->blenda(165, 36, 255, framebuf, 0, 0, 165, bg, 77, 100, 320, actions, 0, 36, 165);
380
    displaylcd(0, 0, 320, 240, bg, 0, 0, 320);
381
    displaylcd(77, 100, 165, 36, framebuf, 0, 0, 165);
382
    backlight_set_fade(32);
383
    backlight_set_brightness(177);
384
    backlight_on(true);
551 theseven 385
 
530 theseven 386
    int cost;
366 theseven 387
    if (updating)
388
    {
530 theseven 389
        cost = commoncost;
390
        script = commonscript;
366 theseven 391
    }
392
    else
393
    {
530 theseven 394
        cost = firstinstcost + commoncost;
395
        script = firstinstscript;
366 theseven 396
    }
547 theseven 397
    progressbar_init(&progressbar, 15, 304, 135, 159, 0x77ff, 0xe8, 0x125f, 0, cost);
530 theseven 398
    sp = 0;
399
    cost = 0;
366 theseven 400
    while (script[sp])
401
    {
402
        int fd;
403
        void* data;
404
        switch (script[sp])
405
        {
406
            case 1:
530 theseven 407
                mkdir((char*)(script[sp + 1]));
366 theseven 408
                sp += 2;
409
                break;
410
            case 2:
411
                if (script[sp + 2] == 0xfffffffe && appleflash)
412
                {
413
                    data = oldnor;
414
                    script[sp + 3] = 0x100000;
415
                }
385 theseven 416
                else if (script[sp + 2] == 0xfffffffe) script[sp + 3] = 0;
366 theseven 417
                if (!script[sp + 3])
418
                {
419
                    sp += 4;
420
                    break;
421
                }
422
            case 3:
530 theseven 423
                fd = file_open((char*)(script[sp + 1]), O_RDONLY);
366 theseven 424
                if (fd >= 0)
425
                {
426
                    close(fd);
427
                    sp += 4;
428
                    break;
429
                }
430
            case 4:
530 theseven 431
                if (script[sp + 2] < 0xfffffffe) data = (void*)(script[sp + 2]);
432
                fd = file_creat((char*)(script[sp + 1]));
366 theseven 433
                if (fd >= 0)
434
                {
435
                    write(fd, data, script[sp + 3]);
436
                    close(fd);
437
                }
438
                sp += 4;
439
                break;
440
            default:
551 theseven 441
                panic(PANIC_KILLTHREAD, "Bad installation script!");
366 theseven 442
        }
530 theseven 443
        cost += script[sp++];
444
        progressbar_setpos(&progressbar, cost, false);
366 theseven 445
    }
546 theseven 446
 
447
    if (oldnor) free(oldnor);
448
 
530 theseven 449
    ui->blenda(165, 36, 255, framebuf, 0, 0, 165, bg, 77, 100, 320, actions, 0, 72, 165);
450
    displaylcd(77, 100, 165, 36, framebuf, 0, 0, 165);
451
    progressbar_init(&progressbar, 15, 304, 135, 159, 0x77ff, 0xe8, 0x125f, 0, 256);
366 theseven 452
    for (i = 0; i < 256; i++)
453
    {
454
        bootflash_writeraw(&norbuf[i << 12], i << 12, 1 << 12);
455
        progressbar_setpos(&progressbar, i, false);
456
    }
457
 
546 theseven 458
    free(norbuf);
459
    free(framebuf);
460
    free(actions);
461
    free(bg);
462
 
463
    release_library(libui);
464
    release_library(libpng);
465
    library_unload(libui);
466
    library_unload(libpng);
467
 
385 theseven 468
    shutdown(false);
366 theseven 469
    reset();
470
}