#include <config.h>
#include <l4/thread.h>
#include <l4/space.h>
#include <l4/message.h>
#include <l4/ipc.h>
#include <l4/sigma0.h>
#include <l4/bootinfo.h>
#include <new>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sdi/log.h>
#include <sdi/locator.h>
#include <sdi/util.h>
#include <sdi/panic.h>
#include <sdi/elfexec.h>
#include "root.h"
#include <idl4glue.h>
#include <if/iflocator.h>
#include <elf.h>
L4_ThreadId_t roottaskid = L4_nilthread;
L4_ThreadId_t sigma0id = L4_nilthread;
L4_ThreadId_t loggerid = L4_nilthread;
L4_ThreadId_t syscallServerId = L4_nilthread;
L4_ThreadId_t ramdiskid = L4_nilthread;
L4_ThreadId_t new_locatorid = L4_nilthread;
L4_ThreadId_t sigma1id = L4_nilthread;
L4_Word_t pagesize = 0;
L4_Word_t utcbsize = 0;
static L4_KernelInterfacePage_t* KIP;
L4_Fpage_t kiparea;
L4_Fpage_t utcbarea;
extern char __elf_start;
extern char __elf_end;
char **environ = NULL;
static const size_t DEFAULT_STACK_SIZE = 4096;
char logger_stack[DEFAULT_STACK_SIZE];
char ramdisk_stack[DEFAULT_STACK_SIZE];
char syscall_stack[DEFAULT_STACK_SIZE];
char elfexec_stack[DEFAULT_STACK_SIZE];
char sigma1_stack[DEFAULT_STACK_SIZE];
extern void pager_main();
static const size_t MAX_RAMDISK_COUNT = 10;
int nextid = 1;
typedef void (*function_ptr) ();
#define UTCBaddress(x) ((void*)(((L4_Word_t)L4_MyLocalId().raw + utcbsize * (x)) & ~(utcbsize - 1)))
static L4_ThreadId_t start_thread(function_ptr function, void* stack, L4_ThreadId_t newthreadid = L4_nilthread)
{
void* utcblocation = UTCBaddress(nextid);
if(L4_IsNilThread(newthreadid))
newthreadid = L4_GlobalId ( L4_ThreadNo (L4_Myself ()) + nextid, 1);
nextid++;
L4_Word_t ip = reinterpret_cast<L4_Word_t> (function);
L4_Word_t sp = reinterpret_cast<L4_Word_t> (stack);
if (!L4_ThreadControl(newthreadid,
L4_Myself(),
L4_Myself(),
sigma0id,
(void*)utcblocation))
{
panic("ThreadControl failed in start_thread");
}
L4_Start(newthreadid, sp, ip);
return newthreadid;
}
static L4_ThreadId_t start_task(function_ptr function, void* stack, L4_ThreadId_t newthreadid = L4_nilthread)
{
void* utcblocation = UTCBaddress(nextid);
if(L4_IsNilThread(newthreadid))
newthreadid = L4_GlobalId ( L4_ThreadNo (L4_Myself ()) + nextid, 1);
nextid++;
L4_Word_t ip = reinterpret_cast<L4_Word_t> (function);
L4_Word_t sp = reinterpret_cast<L4_Word_t> (stack);
if (!L4_ThreadControl(newthreadid,
newthreadid,
L4_Myself(),
L4_nilthread,
(void*)-1UL))
{
panic("ThreadControl failed in start_task\n");
}
L4_Word_t dummy;
if (!L4_SpaceControl(newthreadid,
0,
kiparea,
L4_FpageLog2((L4_Word_t)utcblocation, 14),
L4_anythread,
&dummy))
{
printf("SpaceControl: L4_ErrorCode() = %lu\n", L4_ErrorCode());
panic("SpaceControl failed in start_task\n");
}
if (!L4_ThreadControl(newthreadid,
newthreadid,
L4_nilthread,
L4_Myself(),
utcblocation))
{
panic("ThreadControl failed\n");
}
L4_Msg_t msg;
L4_Clear(&msg);
L4_Append(&msg, ip);
L4_Append(&msg, sp);
L4_Load(&msg);
L4_Send(newthreadid);
return newthreadid;
}
static inline L4_Bool_t request_page(L4_Word_t addr)
{
return !(L4_IsNilFpage( L4_Sigma0_GetPage(sigma0id, L4_Fpage(addr, pagesize)) ) );
}
static void pin_module_memory()
{
const L4_BootInfo_t* bootinfo = get_bootinfo();
L4_BootRec_t* bootrec = L4_BootInfo_FirstEntry(bootinfo);
for (unsigned int i=0; i < L4_BootInfo_Entries(bootinfo); i++)
{
printf("Module: start %lx size %lx type: %d\n",
L4_Module_Start(bootrec),
L4_Module_Size(bootrec),
(int)L4_Type(bootrec) );
if(L4_Type(bootrec) == L4_BootInfo_Module)
{
for (L4_Word_t addr = L4_Module_Start(bootrec);
addr < L4_Module_Start(bootrec) + L4_Module_Size(bootrec);
addr += pagesize)
{
if (!request_page(addr)) {
panic("root: could not get module pages from sigma0");
}
}
}
bootrec = L4_Next(bootrec);
}
}
static void elfexec_module(const L4_BootRec_t* mod, L4_ThreadId_t threadid = L4_nilthread)
{
char* argv[] = { "testargv", NULL };
char* envp[] =
{ "SDI=way-cool",
"HOME=/minixfs0",
"CWD=/",
"USER=sdi",
"GROUPS=users",
"OSTYPE=SDI/L4",
NULL };
void* start = reinterpret_cast<void*> (L4_Module_Start(mod));
size_t len = static_cast<size_t> (L4_Module_Size(mod));
L4_ThreadId_t newthr = sdi_elfexecve(start, len, sigma1id, threadid, argv, envp);
printf("Module elfexeced as thread %lx\n", newthr.raw);
}
static bool is_elffile(const L4_BootRec_t* bootrec)
{
if(L4_Type (bootrec) != L4_BootInfo_Module)
return false;
if(L4_Module_Size(bootrec) < sizeof(Elf32_Ehdr))
return false;
L4_Word_t addr = L4_Module_Start(bootrec);
Elf32_Ehdr* hdr = reinterpret_cast<Elf32_Ehdr*> (addr);
if ((hdr->e_ident[EI_MAG0] != ELFMAG0) ||
(hdr->e_ident[EI_MAG1] != ELFMAG1) ||
(hdr->e_ident[EI_MAG2] != ELFMAG2) ||
(hdr->e_ident[EI_MAG3] != ELFMAG3)) {
return false;
}
return true;
}
const L4_BootInfo_t* get_bootinfo()
{
static const L4_BootInfo_t* bootinfo = NULL;
if(bootinfo != NULL)
return bootinfo;
bootinfo = reinterpret_cast<const L4_BootInfo_t*> (L4_BootInfo(KIP));
if (!request_page((L4_Word_t) bootinfo)) {
panic ("Was not able to get bootinfo");
}
if (!L4_BootInfo_Valid(bootinfo))
panic("Bootinfo not found");
return bootinfo;
}
static void elfexec_thread()
{
const L4_BootInfo_t* bootinfo = get_bootinfo();
bool islocator = true;
const L4_BootRec_t* bootrec = L4_BootInfo_FirstEntry(bootinfo);
for(L4_Word_t i = 0; i < L4_BootInfo_Entries(bootinfo); ++i,
bootrec = L4_BootRec_Next(bootrec)) {
if(!is_elffile(bootrec))
continue;
printf("Module %lu is an elffile\n", i);
if(islocator) {
elfexec_module(bootrec, new_locatorid);
islocator = false;
} else {
elfexec_module(bootrec);
}
sleep(1);
}
printf("elfexec_thread finished loading boot modules\n");
L4_Stop(L4_Myself());
panic("This shouldn't happen");
}
void showlogo()
{
#define S(x) printf("%s", x)
S("\33[32m ___ ___ ___ ___\n");
S(" /\\ \\ /\\ \\ ___ /\\ \\ /\\ \\\n");
S(" /::\\ \\ /::\\ \\ /\\ \\ /::\\ \\ /::\\ \\\n");
S(" /:/\\ \\ \\ /:/\\:\\ \\ \\:\\ \\ /:/\\:\\ \\ /:/\\ \\ \\\n");
S(" _\\:\\~\\ \\ \\ /:/ \\:\\__\\ /::\\__\\ /:/ \\:\\ \\ _\\:\\~\\ \\ \\\n");
S(" /\\ \\:\\ \\ \\__\\ /:/__/ \\:|__| __/:/\\/__/ /:/__/ \\:\\__\\ /\\ \\:\\ \\ \\__\\\n");
S(" \\:\\ \\:\\ \\/__/ \\:\\ \\ /:/ / /\\/:/ / \\:\\ \\ /:/ / \\:\\ \\:\\ \\/__/\n");
S(" \\:\\ \\:\\__\\ \\:\\ /:/ / \\::/__/ \\:\\ /:/ / \\:\\ \\:\\__\\\n");
S(" \\:\\/:/ / \\:\\/:/ / \\:\\__\\ \\:\\/:/ / \\:\\/:/ /\n");
S(" \\::/ / \\::/__/ \\/__/ \\::/ / \\::/ /\n");
S(" \\/__/ ~~ \\/__/ \\/__/\n");
S("\n");
S(" \33[31m(c) 2006 Timo Bingmann, Matthias Braun, Torsten Geiger, Andreas Maehler\n");
S("\33[00m\n");
S("\n");
}
int main()
{
KIP = (L4_KernelInterfacePage_t*)L4_KernelInterface ();
roottaskid = L4_Myself();
sigma0id = L4_Pager();
showlogo();
printf ("Early system infos:\n");
printf ("Threads: Myself:0x%lx Sigma0:0x%lx\n", L4_Myself().raw, L4_Pager().raw);
pagesize = 1 << lsBit(L4_PageSizeMask(KIP));
printf ("Pagesize: %d\n", (int)pagesize);
kiparea = L4_FpageLog2 ((L4_Word_t)KIP, L4_KipAreaSizeLog2(KIP));
printf ("KernelInterfacePage: 0x%lx size: %d\n", L4_Address(kiparea), (int)L4_Size(kiparea));
printf ("Bootinfo: 0x%lx\n", L4_BootInfo(KIP));
printf ("ELFimage: from %p to %p\n", &__elf_start, &__elf_end);
utcbsize = L4_UtcbSize(KIP);
utcbarea = L4_FpageLog2((L4_Word_t)L4_MyLocalId().raw,
L4_UtcbAreaSizeLog2(KIP) + 1);
for (const char* addr = &__elf_start; addr < &__elf_end; addr += pagesize)
{
if (!request_page((L4_Word_t)addr)) {
panic("root: could not get roottask pages from sigma0.");
}
}
pin_module_memory();
sigma1id = L4_GlobalId(0x3ffff - 1, 1);
new_locatorid = L4_GlobalId(0x3ffff - 2, 1);
loggerid = L4_GlobalId(0x3ffff - 3, 1);
syscallServerId = L4_GlobalId(0x3ffff - 4, 1);
loggerid = start_thread (&logger_server,
&logger_stack[sizeof(logger_stack) - 1],
loggerid);
printf ("Started logger with id %lx\n", loggerid.raw);
sigma1id = start_task(&pager_main,
&sigma1_stack[sizeof(sigma1_stack) - 1],
sigma1id);
printf ("Started sigma1 pager with id %lx (Stack %p)\n",
sigma1id.raw, &sigma1_stack[sizeof(sigma1_stack) - 1]);
syscallServerId = start_thread(&syscall_server,
&syscall_stack[sizeof(syscall_stack)-1],
syscallServerId);
printf ("Started syscallServer with id %lx\n", syscallServerId.raw);
ramdiskid = start_thread(&ramdisk_server,
&ramdisk_stack[sizeof(ramdisk_stack)-1]);
printf ("Started ramdisk with id %lx\n", ramdiskid.raw);
L4_ThreadId_t elfexecid = start_thread(&elfexec_thread,
&elfexec_stack[sizeof(elfexec_stack) - 1]);
printf ("Started ElfExecThread with id %lx (Stack %p)\n",
elfexecid.raw,
&elfexec_stack[sizeof(elfexec_stack) - 1]);
printf("Going into pager loop\n");
pager_loop();
panic("Unexpected return from PagerLoop()");
}