#include <piggybacker/kip.h>
#include <piggybacker/elf.h>
#include <piggybacker/io.h>
#include <piggybacker/macros.h>
#include PIGGYBACK_ARCH(page.h)
typedef union {
char string[4];
L4_Word32_t raw;
} magic_t;
magic_t l4_magic = {string: {'L', '4', 230, 'K'}};
magic_t kip_magic = {string: {'.', 'k', 'i', 'p'}};
bool kip_manager_t::virt_to_phys( L4_Word_t virt, L4_Word_t elf_start, L4_Word_t *phys )
{
elf_ehdr_t *ehdr = (elf_ehdr_t *)elf_start;
elf_phdr_t *phdr_list, *phdr;
int p_cnt;
phdr_list = (elf_phdr_t *)(elf_start + ehdr->e_phoff);
for( p_cnt = 0; p_cnt < ehdr->e_phnum; p_cnt++ )
{
phdr = &phdr_list[ p_cnt ];
if ((virt >= phdr->p_vaddr) && (virt < (phdr->p_vaddr + phdr->p_memsz)))
{
*phys = virt - phdr->p_vaddr + phdr->p_paddr;
return true;
}
}
return false;
}
bool kip_manager_t::find_kip( L4_Word_t kernel_start )
{
elf_ehdr_t *ehdr = (elf_ehdr_t *)kernel_start;
elf_shdr_t *shdr_list, *shdr, *str_hdr;
int s_cnt;
char *sec_name;
L4_Word_t kip_virt;
L4_Word32_t *kip_start, *kip_end;
shdr_list = (elf_shdr_t *)(kernel_start + ehdr->e_shoff);
str_hdr = &shdr_list[ ehdr->e_shstrndx ];
for( s_cnt = 0; s_cnt < ehdr->e_shnum; s_cnt++ )
{
shdr = &shdr_list[ s_cnt ];
sec_name = (char *)(shdr->sh_name + kernel_start + str_hdr->sh_offset);
if( *(L4_Word32_t *)sec_name != kip_magic.raw )
continue;
kip_start = (L4_Word32_t *)( kernel_start + shdr->sh_offset );
kip_end = (L4_Word32_t *)( (L4_Word_t)kip_start + shdr->sh_size );
while( (*kip_start != l4_magic.raw) && (kip_start < kip_end) )
kip_start++;
if( *kip_start != l4_magic.raw )
continue;
this->kip_src = (struct L4_KernelConfigurationPage *)kip_start;
kip_virt = (L4_Word_t)kip_start - shdr->sh_offset - kernel_start
+ shdr->sh_addr;
if( !this->virt_to_phys(kip_virt, kernel_start,
(L4_Word_t *)&this->kip_dst) )
return false;
puts( "[==== Found the kernel interface page ====]" );
print_hex( "- kip virt", kip_virt );
print_hex( ", kip phys", (L4_Word_t)this->kip_dst );
print_hex( ", kip size", shdr->sh_size );
puts( "" );
return true;
}
return false;
}
void kip_manager_t::install_module( L4_Word_t mod_start, L4_Word_t mod_end,
kip_server_t *server )
{
elf_ehdr_t *ehdr = (elf_ehdr_t *)mod_start;
elf_phdr_t *phdr_list, *phdr;
int p_cnt;
L4_Word_t addr;
if( mod_start == mod_end )
return;
if( mod_start % 4 ) {
puts( "Fatal error: the module is not 4-byte aligned!" );
print_hex( "Module start", mod_start );
while( 1 ) ;
}
server->ip = ehdr->e_entry;
server->start = 0xffffffff;
server->end = 0;
phdr_list = (elf_phdr_t *)(mod_start + ehdr->e_phoff);
for( p_cnt = 0; p_cnt < ehdr->e_phnum; p_cnt++ )
{
phdr = &phdr_list[ p_cnt ];
if( phdr->p_type != PT_LOAD ) {
print_hex( "- skipping an unloadable elf section: virt=", phdr->p_vaddr);
puts( "" );
continue;
}
print_hex( "- virt addr", phdr->p_vaddr );
print( ", " );
print_hex( "phys addr", phdr->p_paddr );
print( ", " );
print_hex( "mem size", phdr->p_memsz );
puts( "" );
print_hex( " file size", phdr->p_filesz );
print( ", " );
print_hex( "file offset", phdr->p_offset );
puts( "" );
memcpy_cache_flush( (L4_Word_t *)phdr->p_paddr,
(L4_Word_t *)(mod_start + phdr->p_offset), phdr->p_filesz );
addr = phdr->p_paddr & PAGE_MASK;
if( addr < server->start )
server->start = addr;
addr = wrap_up( phdr->p_paddr + phdr->p_memsz, PAGE_SIZE );
if( addr > server->end )
server->end = addr;
}
print_hex( "- ip", server->ip );
print( ", " );
print_hex( " start", server->start );
print( ", " );
print_hex( " end", server->end );
puts( "" );
}
void kip_manager_t::install_sigma0( L4_Word_t mod_start, L4_Word_t mod_end )
{
puts( "[==== Installing sigma0 ====]" );
this->install_module( mod_start, mod_end, &this->servers[sigma0] );
}
void kip_manager_t::install_root_task( L4_Word_t mod_start, L4_Word_t mod_end )
{
puts( "[==== Installing the root task ====]" );
this->install_module( mod_start, mod_end, &this->servers[root_task] );
}
void kip_manager_t::install_kernel( L4_Word_t mod_start, L4_Word_t mod_end )
{
puts( "[==== Installing the kernel ====]" );
this->install_module( mod_start, mod_end, &this->servers[kernel] );
}
void kip_manager_t::update_kip()
{
this->kip_dst->sigma0.ip = this->servers[sigma0].ip;
this->kip_dst->sigma0.low = this->servers[sigma0].start;
this->kip_dst->sigma0.high = this->servers[sigma0].end;
this->kip_dst->root_server.ip = this->servers[root_task].ip;
this->kip_dst->root_server.low = this->servers[root_task].start;
this->kip_dst->root_server.high = this->servers[root_task].end;
this->kip_dst->BootInfo = this->boot_info;
this->kip_dst->MemoryInfo.n = this->mem_desc_cnt;
}
inline L4_Word_t addr_align_up (L4_Word_t addr, L4_Word_t align)
{
return (addr + (align-1)) & (~(align-1));
}
void kip_manager_t::setup_main_memory( L4_Word_t start, L4_Word_t end )
{
this->kip_dst->MainMem.low = start;
this->kip_dst->MainMem.high = end;
}
void kip_manager_t::dedicate_memory( L4_Word_t start, L4_Word_t end, L4_Word_t type, L4_Word_t sub_type )
{
L4_MemoryDesc_t *desc =
L4_MemoryDesc( (void *)this->kip_dst, this->mem_desc_cnt );
if( desc == (L4_MemoryDesc_t *)0 )
{
puts( "Error: insufficient memory descriptors in the kernel interface "
"page!" );
puts( "Aborting ..." );
while( 1 ) ;
}
desc->x.type = type;
desc->x.t = sub_type;
desc->x.v = 0;
desc->x.low = start >> 10;
desc->x.high = (addr_align_up(end, 4096) - 1) >> 10;
this->mem_desc_cnt++;
}
L4_Word_t kip_manager_t::first_avail_page()
{
L4_Word_t end = this->servers[0].end;
for( unsigned i = 1; i < kip_manager_t::tot; i++ )
if( this->servers[i].end > end )
end = this->servers[i].end;
return wrap_up( end, PAGE_SIZE );
}
void kip_manager_t::init()
{
this->boot_info = 0;
this->mem_desc_cnt = 0;
for( unsigned i = 0; i < kip_manager_t::tot; i++ )
this->servers[i].clear();
}