Subversion Repositories freemyipod

Rev

Rev 427 | Rev 436 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

//
//
//    Copyright 2010 TheSeven
//
//
//    This file is part of emCORE.
//
//    emCORE is free software: you can redistribute it and/or
//    modify it under the terms of the GNU General Public License as
//    published by the Free Software Foundation, either version 2 of the
//    License, or (at your option) any later version.
//
//    emCORE is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//    See the GNU General Public License for more details.
//
//    You should have received a copy of the GNU General Public License along
//    with emCORE.  If not, see <http://www.gnu.org/licenses/>.
//
//


#include "global.h"
#include "thread.h"
#include "console.h"
#include "power.h"
#include "interrupt.h"
#include "ucl.h"
#include "util.h"
#include "execimage.h"
#include "targetinit.h"
#ifdef HAVE_LCD
#include "lcd.h"
#include "lcdconsole.h"
#endif
#ifdef HAVE_I2C
#include "i2c.h"
#endif
#ifdef HAVE_USB
#include "usb/usb.h"
#endif
#ifdef HAVE_STORAGE
#include "storage.h"
#include "disk.h"
#include "file.h"
#endif
#ifdef HAVE_BOOTFLASH
#include "bootflash.h"
#endif
#ifdef HAVE_BACKLIGHT
#include "backlight.h"
#endif


struct bootinfo_t
{
    char signature[8];
    int version;
    bool trydataflash;
    char dataflashpath[256];
    bool dataflashflags;
    void* dataflashdest;
    bool trybootflash;
    char bootimagename[8];
    bool bootflashflags;
    void* bootflashdest;
    bool trymemmapped;
    void* memmappedaddr;
    int memmappedsize;
    bool memmappedflags;
    void* memmappeddest;
};


static const char welcomestring[] INITCONST_ATTR = "emCORE v" VERSION " r" VERSION_SVN "\n\n";
static const char initthreadname[] INITCONST_ATTR = "Initialization thread";
static struct scheduler_thread initthread_handle INITBSS_ATTR;
static uint32_t initstack[0x400] INITSTACK_ATTR;
extern int _loadspaceend;
#ifdef HAVE_STORAGE
static const char storageinitthreadname[] INITCONST_ATTR = "Storage init thread";
static struct scheduler_thread storageinitthread_handle INITBSS_ATTR;
static uint32_t storageinitstack[0x400] INITBSS_ATTR;
static struct wakeup storageinitwakeup;
#endif
struct bootinfo_t bootinfo_src INITHEAD_ATTR =
{
    .signature = "emCOboot",
    .version = 0,
    .trydataflash = false,
    .trybootflash = false,
    .trymemmapped = false
};


void boot()
{
    struct bootinfo_t bootinfo = bootinfo_src;
#ifdef HAVE_STORAGE
    if (bootinfo.trydataflash)
    {
        int fd = file_open(bootinfo.dataflashpath, O_RDONLY);
        if (fd < 0) goto dataflashfailed;
        int size = filesize(fd);
        if (size < 0) goto dataflashfailed;
        if (bootinfo.dataflashflags & 1)
        {
            void* addr = (void*)((((uint32_t)&_loadspaceend) - size) & ~(CACHEALIGN_SIZE - 1));
            if (read(fd, addr, size) != size) goto dataflashfailed;
            if (ucl_decompress(addr, size, bootinfo.dataflashdest, (uint32_t*)&size))
                goto dataflashfailed;
        }
        else if (read(fd, bootinfo.dataflashdest, size) != size) goto dataflashfailed;
        if (execimage(bootinfo.dataflashdest) >= 0) return;
    }
dataflashfailed:
#endif
#ifdef HAVE_BOOTFLASH
    if (bootinfo.trybootflash)
    {
        int size = bootflash_filesize(bootinfo.bootimagename);
        if (size < 0) goto bootflashfailed;
#ifdef BOOTFLASH_IS_MEMMAPPED
        void* addr = bootflash_getaddr(bootinfo.bootimagename);
        if (!addr) goto bootflashfailed;
        if (bootinfo.bootflashflags & 1)
        {
            if (ucl_decompress(addr, size, bootinfo.bootflashdest, (uint32_t*)&size))
                goto bootflashfailed;
            if (execimage(bootinfo.bootflashdest) >= 0) return;
        }
        else if (bootinfo.bootflashflags & 2)
        {
            memcpy(bootinfo.bootflashdest, addr, size);
            if (execimage(bootinfo.bootflashdest) >= 0) return;
        }
        else if (execimage(addr) >= 0) return;
#else
        if (bootinfo.bootflashflags & 1)
        {
            void* addr = (void*)((((uint32_t)&_loadspaceend) - size) & ~(CACHEALIGN_SIZE - 1));
            if (bootflash_read(bootinfo.bootimagename, addr, 0, size) != size)
                goto bootflashfailed;
            if (ucl_decompress(addr, size, bootinfo.bootflashdest, (uint32_t*)&size))
                goto bootflashfailed;
        }
        else if (bootflash_read(bootinfo.bootimagename, bootinfo.bootflashdest, 0, size) != size)
            goto bootflashfailed;
        if (execimage(bootinfo.bootflashdest) >= 0) return;
#endif
    }
bootflashfailed:
#endif
    if (bootinfo.trymemmapped)
    {
        int size = bootinfo.memmappedsize;
        if (bootinfo.memmappedflags & 1)
        {
            if (ucl_decompress(bootinfo.memmappedaddr, size,
                               bootinfo.memmappeddest, (uint32_t*)&size))
                goto memmappedfailed;
            if (execimage(bootinfo.memmappeddest) >= 0) return;
        }
        else if (bootinfo.memmappedflags & 2)
        {
            memcpy(bootinfo.memmappeddest, bootinfo.memmappedaddr, size);
            if (execimage(bootinfo.memmappeddest) >= 0) return;
        }
        else if (execimage(bootinfo.memmappedaddr) >= 0) return;
    }
memmappedfailed:
    if (bootinfo.trydataflash || bootinfo.trybootflash || bootinfo.trymemmapped)
        cputs(CONSOLE_BOOT, "Could not find a usable boot image!\n");
    cputs(CONSOLE_BOOT, "Waiting for USB commands\n\n");
}

#ifdef HAVE_STORAGE
void storageinitthread() INITCODE_ATTR;
void storageinitthread()
{
    DEBUGF("Initializing storage drivers...");
    storage_init();
    DEBUGF("Initializing storage subsystem...");
    disk_init_subsystem();
    DEBUGF("Reading partition tables...");
    disk_init();
    DEBUGF("Mounting partitions...");
    disk_mount_all();
    DEBUGF("Storage init finished.");
    wakeup_signal(&storageinitwakeup);
}
#endif

void initthread() INITCODE_ATTR;
void initthread()
{
#ifdef HAVE_I2C
    i2c_init();
#endif
    power_init();
    cputs(CONSOLE_BOOT, welcomestring);
#ifdef HAVE_STORAGE
    wakeup_init(&storageinitwakeup);
    thread_create(&storageinitthread_handle, storageinitthreadname,
                  storageinitthread, storageinitstack,
                  sizeof(storageinitstack), USER_THREAD, 127, true);
#endif
#ifdef HAVE_USB
    usb_init();
#endif
#ifdef HAVE_BACKLIGHT
    backlight_init();
#endif
#ifdef HAVE_BUTTON
    button_init();
#endif
#ifdef HAVE_TARGETINIT_LATE
    targetinit_late();
#endif
#ifdef HAVE_STORAGE
    while (true)
    {
        if (wakeup_wait(&storageinitwakeup, 100000) == THREAD_OK) break;
        enum thread_state state = thread_get_state(&storageinitthread_handle);
        if (state == THREAD_DEFUNCT || state == THREAD_DEFUNCT_ACK)
        {
            if (wakeup_wait(&storageinitwakeup, 0) == THREAD_OK) break;
            thread_terminate(&storageinitthread_handle);
            break;
        }
    }
#endif
#ifdef HAVE_TARGETINIT_VERYLATE
    targetinit_verylate();
#endif
    DEBUGF("Finished initialisation sequence");
    boot();
}

void init() INITCODE_ATTR;
void init()
{
#ifdef HAVE_TARGETINIT_VERYEARLY
    targetinit_veryearly();
#endif
    scheduler_init();
    console_init();
#ifdef HAVE_LCD
    lcd_init();
    lcdconsole_init();
#endif
#ifdef HAVE_TARGETINIT_EARLY
    targetinit_early();
#endif
    interrupt_init();
    thread_create(&initthread_handle, initthreadname, initthread, initstack,
                  sizeof(initstack), USER_THREAD, 127, true);
}