#include <config.h>
#include <l4io.h>
#include <l4/bootinfo.h>
#include "kickstart.h"
#include "mbi.h"
#include "kipmgr.h"
#include "lib.h"
#include "elf.h"
void install_memory(mbi_t * mbi, kip_manager_t* kip);
#define MAX_MBI_MODULES 32
#define STRING_BUFFER_SIZE 4096
static mbi_t mbi_copy;
static mbi_module_t mbi_modules[MAX_MBI_MODULES];
static mbi_module_t orig_mbi_modules[MAX_MBI_MODULES];
static char strings_copy[STRING_BUFFER_SIZE];
static mbi_t * mbi;
static L4_Word_t max_bootinfo_size;
unsigned int max_phys_mem = 0;
unsigned int additional_kmem_size = 16*1024*1024;
bool decode_all_executables = false;
@returns
bool load_modules (void)
{
if (mbi->flags.mods)
{
if (mbi->modcount >= 3)
{
#define LOADIT(idx) \
if (!elf_load(mbi->mods[idx].start, mbi->mods[idx].end, \
&mbi->mods[idx].start, &mbi->mods[idx].end, \
&mbi->mods[idx].entry)) \
{ \
FAIL(); \
}
l4_printf(" kernel ");
LOADIT(0);
l4_printf(" sigma0 ");
LOADIT(1);
l4_printf(" roottask");
LOADIT(2);
}
else
{
FAIL();
}
if (decode_all_executables)
{
for (L4_Word_t i = 3; i < mbi->modcount; i++)
elf_load (mbi->mods[i].start, mbi->mods[i].end,
&mbi->mods[i].start, &mbi->mods[i].end,
&mbi->mods[i].entry);
}
return true;
}
else
FAIL();
return false;
}
@param
@param
@returns
L4_Word_t find_free_mem_region (L4_Word_t size, kip_manager_t *kip)
{
L4_Word64_t phys_start, phys_end;
phys_end = kip->get_phys_mem_max();
for (phys_start = 0; phys_start < (phys_end - size); phys_start += size)
{
if( !mbi->is_mem_region_free(phys_start, size) )
continue;
if( !kip->is_mem_region_free(phys_start, size) )
continue;
return phys_start;
}
return 0;
}
@param
@returns
mbi_t * install_mbi (kip_manager_t* kip)
{
L4_Word_t mbi_size = mbi->get_size();
if( mbi_size % 4096 )
mbi_size = (mbi_size + 4096) & ~(4096-1);
L4_Word_t target_mbi = find_free_mem_region( mbi_size, kip );
if( target_mbi == 0 )
FAIL();
mbi->copy( (mbi_t *)target_mbi );
kip->dedicate_memory( target_mbi, target_mbi - 1 + mbi_size,
L4_BootLoaderSpecificMemoryType,
kip_manager_t::desc_init_table );
return (mbi_t *)target_mbi;
}
@param
@returns
L4_BootInfo_t * init_bootinfo (kip_manager_t * kip)
{
max_bootinfo_size = kip->get_min_pagesize ();
L4_BootInfo_t * bi = (L4_BootInfo_t *)
find_free_mem_region (max_bootinfo_size, kip);
if (bi == 0)
return NULL;
bi->magic = L4_BOOTINFO_MAGIC;
bi->version = L4_BOOTINFO_VERSION;
bi->size = sizeof (*bi);
bi->first_entry = sizeof (*bi);
bi->num_entries = 0;
kip->dedicate_memory ((L4_Word_t) bi,
(L4_Word_t) bi + max_bootinfo_size - 1,
L4_BootLoaderSpecificMemoryType,
kip_manager_t::desc_init_table);
return bi;
}
@param
@param
@returns
L4_BootRec_t * record_bootinfo_modules (L4_BootInfo_t * bi,
L4_BootRec_t * rec)
{
L4_Word_t sz;
if (mbi->flags.mods)
{
for (L4_Word_t i = 1; i < mbi->modcount; i++)
{
L4_Boot_SimpleExec_t * exec = (L4_Boot_SimpleExec_t *) rec;
if ((decode_all_executables || i < 3) &&
elf_find_sections (orig_mbi_modules[i].start, exec))
{
sz = sizeof (*exec);
exec->cmdline_offset = sz;
strcpy ((char *) exec + sz, mbi->mods[i].cmdline);
sz += strlen (mbi->mods[i].cmdline) + 1;
sz = align_up (sz, sizeof (L4_Word_t));
exec->offset_next = sz;
}
else
{
L4_Boot_Module_t * mod = (L4_Boot_Module_t *) rec;
sz = sizeof (*mod);
mod->type = L4_BootInfo_Module;
mod->version = 1;
mod->offset_next = sz;
mod->start = mbi->mods[i].start;
mod->size = mbi->mods[i].end - mbi->mods[i].start;
mod->cmdline_offset = sz;
strcpy ((char *) exec + sz, mbi->mods[i].cmdline);
sz += strlen (mbi->mods[i].cmdline) + 1;
sz = align_up (sz, sizeof (L4_Word_t));
mod->offset_next = sz;
}
rec = (L4_BootRec_t *) ((L4_Word_t) rec + sz);
bi->num_entries++;
bi->size += sz;
}
}
return rec;
}
bool mbi_probe (void)
{
mbi_t * _mbi = mbi_t::prepare();
if (_mbi == NULL)
return false;
memcopy (&mbi_copy, _mbi, sizeof (mbi_t));
mbi = &mbi_copy;
return true;
}
@returns
L4_Word_t mbi_init (void)
{
kip_manager_t kip;
L4_BootInfo_t * bi = NULL;
L4_BootRec_t * rec = NULL;
bool use_bootinfo = true;
bool use_mbi = true;
if (!kip.find_kip(mbi->mods[0].start, mbi->mods[0].end))
{
FAIL();
}
char * sptr = strings_copy;
L4_Word_t nfree = STRING_BUFFER_SIZE;
L4_Word_t len;
#define COPY_STRING(str) \
do { \
len = strlen (str) + 1; \
if (len > nfree) \
{ \
l4_printf ("String buffer overrun\n"); \
FAIL (); \
} \
strcpy (sptr, str); \
str = sptr; \
nfree -= len; \
sptr += len; \
} while (0)
if (mbi->flags.cmdline)
{
char * p;
COPY_STRING (mbi->cmdline);
#define PARSENUM(name, var, msg, massage...) \
if ((p = strstr(mbi->cmdline, name"=")) != NULL) \
{ \
var = strtoul(p+strlen(name)+1, &p, 10); \
if (*p == 'K') var*=1024; \
if (*p == 'M') var*=1024*1024; \
if (*p == 'G') var*=1024*1024*1024; \
massage; \
l4_printf(msg, \
var >= 1<<30 ? var>>30 : \
var >= 1<<20 ? var>>20 : \
var >= 1<<10 ? var>>10 : var, \
var >= 1<<30 ? "G" : \
var >= 1<<20 ? "M" : \
var >= 1<<10 ? "K" : ""); \
}
#define PARSEBOOL(name, var, msg) \
if ((p = strstr (mbi->cmdline, name"=")) != NULL) \
{ \
p = strchr (p, '=') + 1; \
if (strncmp (p, "yes", 3) == 0 || \
strncmp (p, "on", 2) == 0 || \
strncmp (p, "enable", 6) == 0) \
{ \
if (! var) l4_printf ("Enabling %s\n", msg); \
var = true; \
} \
else if (strncmp (p, "no", 2) == 0 || \
strncmp (p, "off", 3) == 0 || \
strncmp (p, "disable", 7) == 0) \
{ \
if (var) l4_printf ("Disabling %s\n", msg); \
var = false; \
} \
}
PARSENUM("maxmem",
max_phys_mem,
"Limiting physical memory to %d%sB\n");
PARSENUM("kmem",
additional_kmem_size,
"Reserving %d%sB for kernel memory\n",
additional_kmem_size &= ~(kip.get_min_pagesize()-1));
PARSEBOOL ("bootinfo", use_bootinfo, "generic bootinfo");
PARSEBOOL ("mbi", use_mbi, "multiboot info");
PARSEBOOL ("decode-all", decode_all_executables,
"decoding of all executables");
}
if (mbi->flags.mods)
{
if (mbi->modcount > MAX_MBI_MODULES)
{
l4_printf("WARNING: Restrcting number of modules to %d (was %d)\n",
MAX_MBI_MODULES, mbi->modcount);
mbi->modcount = MAX_MBI_MODULES;
}
for (L4_Word_t i = 0; i < mbi->modcount; i++)
{
COPY_STRING (mbi->mods[i].cmdline);
orig_mbi_modules[i] = mbi_modules[i] = mbi->mods[i];
}
mbi->mods = mbi_modules;
if (mbi->modcount > 2)
mbi->cmdline = mbi->mods[2].cmdline;
}
if (!load_modules())
{
l4_printf("Failed to load all necessary modules\n");
FAIL();
}
if (!kip.find_kip(mbi->mods[0].start, mbi->mods[0].end))
FAIL();
install_memory(mbi, &kip);
kip.install_sigma0(mbi->mods[1].start, mbi->mods[1].end,
mbi->mods[1].entry);
kip.install_root_task(mbi->mods[2].start, mbi->mods[2].end,
mbi->mods[2].entry);
for (L4_Word_t i = 3; i < mbi->modcount; i++)
kip.dedicate_memory (mbi->mods[i].start, mbi->mods[i].end - 1,
L4_BootLoaderSpecificMemoryType,
kip_manager_t::desc_boot_module);
if (use_bootinfo)
{
bi = init_bootinfo (&kip);
rec = (L4_BootRec_t *) ((L4_Word_t) bi + bi->size);
if (bi)
rec = record_bootinfo_modules (bi, rec);
else
use_bootinfo = false;
}
if (use_mbi)
mbi = install_mbi(&kip);
if (use_bootinfo && use_mbi)
{
L4_Boot_MBI_t * bimbi = (L4_Boot_MBI_t *) rec;
bimbi->type = L4_BootInfo_Multiboot;
bimbi->version = 1;
bimbi->offset_next = sizeof (*bimbi);
bimbi->address = (L4_Word_t) mbi;
bi->num_entries++;
bi->size += sizeof (*bimbi);
rec = L4_Next (rec);
}
kip.update_kip (use_bootinfo ? (L4_Word_t) bi :
use_mbi ? (L4_Word_t) mbi : 0);
return mbi_modules[0].entry;
}