root/sys/arch/epoc32/stand/e32boot/exe/e32boot.cpp
/*      $NetBSD: e32boot.cpp,v 1.3 2013/06/20 15:30:00 kiyohara Exp $   */
/*
 * Copyright (c) 2012, 2013 KIYOHARA Takashi
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <e32base.h>
#include <e32cons.h>
#include <e32def.h>
#include <e32hal.h>
#include <e32svr.h>     /* XXXXX */
#include <w32std.h>

#include "e32boot.h"
#include "netbsd.h"
#include "../../../include/bootinfo.h"

CConsoleBase *console;
LOCAL_C NetBSD *LoadNetBSDL(void);
LOCAL_C struct btinfo_common *CreateBootInfo(TAny *);
LOCAL_C struct btinfo_common *FindBootInfoL(struct btinfo_common *, int);
TUint SummaryBootInfoMemory(struct btinfo_common *);
LOCAL_C void E32BootL(void);

struct memmap {
        TUint address;
        TUint size;     /* KB */
};
struct memmap series5_4m[] = {{ 0xc0000000, 512 }, { 0xc0100000, 512 },
                              { 0xc0400000, 512 }, { 0xc0500000, 512 },
                              { 0xc1000000, 512 }, { 0xc1100000, 512 },
                              { 0xc1400000, 512 }, { 0xc1500000, 512 }};
struct memmap series5_8m[] = {{ 0xc0000000, 512 }, { 0xc0100000, 512 },
                              { 0xc0400000, 512 }, { 0xc0500000, 512 },
                              { 0xc1000000, 512 }, { 0xc1100000, 512 },
                              { 0xc1400000, 512 }, { 0xc1500000, 512 },
                              { 0xd0000000, 512 }, { 0xd0100000, 512 },
                              { 0xd0400000, 512 }, { 0xd0500000, 512 },
                              { 0xd1000000, 512 }, { 0xd1100000, 512 },
                              { 0xd1400000, 512 }, { 0xd1500000, 512 }};
struct memmap revo[] = {{ 0xc0000000, 4096 }, { 0xc0800000, 4096 }};
struct memmap revopuls[] = {{ 0xc0000000, 4096 }, { 0xc0800000, 4096 },
                            { 0xd0000000, 4096 }, { 0xd0800000, 4096 }};
struct memmap series5mx_16m[] = {{ 0xc0000000, 8192 }, { 0xc1000000, 8192 }};
struct memmap series5mxpro_24m[] = {{ 0xc0000000, 8192 }, { 0xc1000000, 8192 },
                                    { 0xd0000000, 4096 }, { 0xd0800000, 4096 }};
struct memmap series5mxpro_32m[] = {{ 0xc0000000, 8192 }, { 0xc1000000, 8192 },
                                    { 0xd0000000, 8192 }, { 0xd1000000, 8192 }};
struct memmap series7_16m[] = {{ 0xc0000000, 16384 }};
struct memmap series7_32m[] = {{ 0xc0000000, 16384 }, { 0xc8000000, 16384 }};

struct {
        char *model;
        TInt width;
        TInt height;
        TUint memsize;
        struct memmap *memmaps;
} memmaps[] = {
        { "SERIES5 R1", 640, 240,  4096, series5_4m },
        { "SERIES5 R1", 640, 240,  8192, series5_8m },
        { "SERIES5 R1", 640, 320,  4096, series5_4m },  /* Geofox One */
        { "SERIES5 R1", 640, 320,  8192, series5_8m },  /* Geofox One */
//      { "SERIES5 R1", 640, 320, 16384, one_16m },
        { "SERIES5 R1", 320, 200,  4096, series5_4m },  /* Osaris */
//      { "SERIES5 R1", 320, 200, 16384, osaris_16m },
        { "SERIES5mx",  480, 160,  8192, revo },
        { "SERIES5mx",  480, 160, 16384, revopuls },
        { "SERIES5mx",  640, 240, 16384, series5mx_16m },
        { "SERIES5mx",  640, 240, 24576, series5mxpro_24m },
        { "SERIES5mx",  640, 240, 32768, series5mxpro_32m },
        { "SERIES7",    800, 600, 16384, series7_16m },
        { "SERIES7",    800, 600, 32768, series7_32m },
};

class E32BootLogicalChannel : public RLogicalChannel {
public:
        TInt DoCreate(const TDesC *aChan, TInt aUnit, const TDesC *aDriver,
                                                        const TDesC8 *anInfo)
        {

                return RLogicalChannel::DoCreate(E32BootName, TVersion(0, 0, 0),
                                                aChan, aUnit, aDriver, anInfo);
        }

        TInt DoControl(TInt aFunction, TAny *a1)
        {

                return RLogicalChannel::DoControl(aFunction, a1);
        }

        TInt DoControl(TInt aFunction, TAny *a1, TAny *a2)
        {

                return RLogicalChannel::DoControl(aFunction, a1, a2);
        }
};


LOCAL_C void
E32BootL(void)
{
        E32BootLogicalChannel *E32BootChannel = new E32BootLogicalChannel;
        NetBSD *netbsd = NULL;
        TScreenInfoV01 screenInfo;
        TPckg<TScreenInfoV01> sI(screenInfo);
        TBuf<32> ldd;
        TInt err;
        TUint membytes;
        TAny *buf, *safeAddress;
        struct btinfo_common *bootinfo;
        struct btinfo_model *model;
        struct btinfo_video *video;
        struct btinfo_bootargs *bootargs;

        console =
            Console::NewL(E32BootName, TSize(KConsFullScreen, KConsFullScreen));

        buf = User::AllocL(ALIGN_SAFE_PAGE_SIZE);       /* bootinfo buffer */

        /* Put banner */
        console->Printf(_L("\n"));
        console->Printf(_L(">> %s, Revision %s\n"),
            bootprog_name, bootprog_rev);

        UserSvr::ScreenInfo(sI);
        if (!screenInfo.iScreenAddressValid)
                User::Leave(KErrNotSupported);
        safeAddress = screenInfo.iScreenAddress;

        bootinfo = CreateBootInfo((TAny *)PAGE_ALIGN(buf));

        model = (struct btinfo_model *)FindBootInfoL(bootinfo, BTINFO_MODEL);
        console->Printf(_L(">> Model %s\n"), model->model);

        membytes = SummaryBootInfoMemory(bootinfo);
        console->Printf(_L(">> Memory %d k\n"), membytes / 1024);

        video = (struct btinfo_video *)FindBootInfoL(bootinfo, BTINFO_VIDEO);
        console->Printf(_L(">> Video %d x %d\n"), video->width, video->height);

        console->Printf(_L("\n"));

        bootargs =
            (struct btinfo_bootargs *)FindBootInfoL(bootinfo, BTINFO_BOOTARGS);
        TRAP(err, netbsd = LoadNetBSDL());
        if (err != KErrNone)
                User::Leave(err);
        else if (netbsd == NULL)
                return;
        console->Printf(_L("\nLoaded\n"));

        int n, m;
        n = sizeof(bootargs->bootargs);
        m = (*netbsd->GetArgs()).Length();
        if (m > 0)
                Mem::Copy(bootargs->bootargs, &(*netbsd->GetArgs())[0],
                    n < m ? n : m);
        bootargs->bootargs[n < m ? n - 1 : m] = '\0';

        netbsd->ParseHeader();

        /* Load logical device(kernel part of e32boot). */
        if (_L(model->model).CompareF(_L("SERIES5 R1")) == 0)
                ldd = _L("e32boot-s5.ldd");
        else if (_L(model->model).CompareF(_L("SERIES5mx")) == 0)
                ldd = _L("e32boot-s5mx.ldd");
//      else if (_L(model->model).CompareF(_L("SERIES7")) == 0)
//              ldd = _L("e32boot-s7.ldd");     // not yet.
        else {
                console->Printf(_L("Not Supported machine\n"));
                console->Getch();
                User::Leave(KErrNotSupported);
        }
        err = User::LoadLogicalDevice(ldd);
        if (err != KErrNone && err != KErrAlreadyExists) {
                console->Printf(_L("LoadLogicalDevice failed: %d\n"), err);
                console->Getch();
                User::Leave(err);
        }
        /* Create channel to kernel part. */
        err = E32BootChannel->DoCreate(NULL, KNullUnit, NULL, NULL);
        if (err == KErrNone) {
                E32BootChannel->DoControl(KE32BootSetSafeAddress, safeAddress);
                E32BootChannel->DoControl(KE32BootBootNetBSD, netbsd, bootinfo);
        } else {
                console->Printf(_L("DoCreate failed: %d\n"), err);
                console->Getch();
        }

        User::FreeLogicalDevice(ldd);
        if (err != KErrNone)
                User::Leave(err);
}

GLDEF_C TInt E32Main(void)      /* main function called by E32 */
{

        __UHEAP_MARK;
        CTrapCleanup *cleanup = CTrapCleanup::New();

        TRAPD(error, E32BootL());
        __ASSERT_ALWAYS(!error, User::Panic(E32BootName, error));

        delete cleanup;
        __UHEAP_MARKEND;
        return 0;
}

LOCAL_C NetBSD *
LoadNetBSDL(void)
{
        NetBSD *netbsd = NULL;
        TBuf<KMaxCommandLine> input, *args;
        TPtrC Default = _L("C:\\netbsd");
        TPtrC Prompt = _L("Boot: ");
        TInt pos, err;
        TBool retry;

        input.Zero();
        args = new TBuf<KMaxCommandLine>;
        args->Zero();
        retry = false;
        console->Printf(Prompt);
        console->Printf(_L("["));
        console->Printf(Default);
        console->Printf(_L("]: "));
        console->SetPos(Prompt.Length() +
                        _L("[").Length() +
                        Default.Length() +
                        _L("]: ").Length());
        pos = 0;
        while (1) {
                TChar gChar = console->Getch();
                switch (gChar) {
                case EKeyEscape:
                        return NULL;

                case EKeyEnter:
                        break;

                case EKeyBackspace:
                        if (pos > 0) {
                                pos--;
                                input.Delete(pos, 1);
                        }
                        break;

                default:
                        if (gChar.IsPrint()) {
                                if (input.Length() < KMaxCommandLine) {
                                        TBuf<0x02> b;
                                        b.Append(gChar);
                                        input.Insert(pos++, b);
                                }
                        }
                        break;
                }
                if (gChar == EKeyEnter) {
                        input.TrimAll();
                        if (input[0] == '-')
                                input.Swap(*args);
                        for (int i = 0; i < input.Length(); i++)
                                if (input[i] == ' ') {
                                        args->Copy(input);
                                        input.SetLength(i);
                                        args->Delete(0, i + 1);
                                        break;
                                }
                        args->ZeroTerminate();

                        if (input.Length() > 0) {
                                TRAP(err, netbsd = NetBSD::New(input, *args));
                        } else {
                                TRAP(err, netbsd = NetBSD::New(Default, *args));
                        }
                        if (err == 0 && netbsd != NULL)
                                break;
                        console->Printf(_L("\nLoad failed: %d\n"), err);

                        input.Zero();
                        args->Zero();
                        console->Printf(Prompt);
                        pos = 0;
                        retry = true;
                }
                TInt base = Prompt.Length();
                if (!retry)
                        base += (_L("[").Length() + Default.Length() +
                                                        _L("]: ").Length());
                console->SetPos(base + pos);
                console->ClearToEndOfLine();
                console->SetPos(base);
                console->Write(input);
                console->SetPos(base + pos);
        }

        return netbsd;
}

#define KB      * 1024

LOCAL_C struct btinfo_common *
CreateBootInfo(TAny *buf)
{
        TMachineInfoV1Buf MachInfo;
        TMemoryInfoV1Buf MemInfo;
        struct btinfo_common *bootinfo, *common;
        struct btinfo_model *model;
        struct btinfo_memory *memory;
        struct btinfo_video *video;
        struct btinfo_bootargs *bootargs;
        struct memmap *memmap;
        TUint memsize;
        TUint i;

        UserHal::MachineInfo(MachInfo);
        UserHal::MemoryInfo(MemInfo);

        common = bootinfo = (struct btinfo_common *)buf;

        /* Set machine name to bootinfo. */
        common->len = sizeof(struct btinfo_model);
        common->type = BTINFO_MODEL;
        model = (struct btinfo_model *)common;
        Mem::Copy(model->model, &MachInfo().iMachineName[0],
            sizeof(model->model));
        common = &(model + 1)->common;

        /* Set video width/height to bootinfo. */
        common->len = sizeof(struct btinfo_video);
        common->type = BTINFO_VIDEO;
        video = (struct btinfo_video *)common;
        video->width = MachInfo().iDisplaySizeInPixels.iWidth;
        video->height = MachInfo().iDisplaySizeInPixels.iHeight;
        common = &(video + 1)->common;

        /* Set memory size to bootinfo. */
        memsize = MemInfo().iTotalRamInBytes / 1024;
        for (i = 0; i < sizeof(memmaps) / sizeof(memmaps[0]); i++) {
                if (_L(memmaps[i].model).CompareF(_L(model->model)) == 0 &&
                    memmaps[i].width == video->width &&
                    memmaps[i].height == video->height &&
                    memmaps[i].memsize == memsize) {
                        memmap = memmaps[i].memmaps;
                        while (memsize > 0) {
                                common->len = sizeof(struct btinfo_memory);
                                common->type = BTINFO_MEMORY;
                                memory = (struct btinfo_memory *)common;
                                memory->address = memmap->address;
                                memory->size = memmap->size KB;
                                common = &(memory + 1)->common;
                                memsize -= memmap->size;
                                memmap++;
                        }
                        break;
                }
        }
        if (i == sizeof(memmaps) / sizeof(memmaps[0])) {
                common->len = sizeof(struct btinfo_memory);
                common->type = BTINFO_MEMORY;
                memory = (struct btinfo_memory *)common;
                memory->address = 0xc0000000;           /* default is here */
                memory->size = 4096 KB;                 /* XXXXX */
                common = &(memory + 1)->common;
        }

        common->len = sizeof(struct btinfo_bootargs);
        common->type = BTINFO_BOOTARGS;
        bootargs = (struct btinfo_bootargs *)common;
        bootargs->bootargs[0] = '\0';
        common = &(bootargs + 1)->common;

        common->len = 0;
        common->type = BTINFO_NONE;

        /* Terminate bootinfo. */
        return bootinfo;
}

#undef KB

LOCAL_C struct btinfo_common *
FindBootInfoL(struct btinfo_common *bootinfo, int type)
{
        struct btinfo_common *entry;

        entry = bootinfo;
        while (entry->type != BTINFO_NONE) {
                if (entry->type == type)
                        return entry;
                entry = (struct btinfo_common *)((int)entry + entry->len);
        }
        User::Leave(KErrNotFound);

        /* NOTREACHED */

        return NULL;
}

TUint
SummaryBootInfoMemory(struct btinfo_common *bootinfo)
{
        struct btinfo_common *entry;
        struct btinfo_memory *memory;
        TUint memsize = 0;

        entry = bootinfo;
        while (entry->type != BTINFO_NONE) {
                if (entry->type == BTINFO_MEMORY) {
                        memory = (struct btinfo_memory *)entry;
                        memsize += memory->size;
                }
                entry = (struct btinfo_common *)((int)entry + entry->len);
        }
        return memsize;
}