#include <piggybacker/piggyback.h>
#include <piggybacker/kip.h>
#include <piggybacker/io.h>
#include <piggybacker/elf.h>
#include <piggybacker/string.h>
#include <piggybacker/ieee1275.h>
#include <piggybacker/1275tree.h>
#include <piggybacker/powerpc/page.h>
typedef struct
{
word_t vaddr;
word_t size;
word_t paddr;
word_t mode;
} of1275_map_t;
typedef struct
{
word_t base;
word_t size;
} range_t;
kip_manager_t kip_manager;
extern "C" void
enter_kernel( L4_Word_t r3, L4_Word_t r4, L4_Word_t r5, L4_Word_t ip );
void boot_fatal( const char *msg )
{
puts( msg );
puts( "Aborting ..." );
while( 1 ) ;
}
bool detect_of1275_memory( device_t *mem_node, L4_Word_t tot_mem )
{
item_t *available = item_find( mem_node, "available" );
if( !available )
return false;
range_t *ranges = (range_t *)available->data;
int cnt = available->len / sizeof(range_t);
L4_Word_t last = 0;
L4_Word_t me = (L4_Word_t)detect_of1275_memory;
for( int i = 0; i < cnt; i++ )
{
if( (me < last) || (me > ranges[i].base) )
{
kip_manager.dedicate_memory( last, ranges[i].base,
L4_BootLoaderSpecificMemoryType, 0xe );
}
last = ranges[i].base + ranges[i].size;
}
if( (me < last) && (last < tot_mem) )
kip_manager.dedicate_memory( last, tot_mem,
L4_BootLoaderSpecificMemoryType, 0xe );
return true;
}
void detect_platform_memory( char *devtree )
{
device_t *node, *list_head = device_first( devtree );
device_t *mem_node;
node = device_find( list_head, "/chosen" );
if( !node )
boot_fatal( "Error: unable to find the OpenFirmware /chosen node." );
item_t *memory = item_find( node, "memory" );
if( !memory )
boot_fatal( "Error: unable to find the OpenFirmware /chosen/memory "
"property." );
L4_Word32_t mem_handle = *(L4_Word32_t *)memory->data;
mem_node = device_find_handle( list_head, mem_handle );
if( !mem_node )
boot_fatal( "Error: unable to lookup the OpenFirmware memory node "
"handle." );
item_t *reg = item_find( mem_node, "reg" );
if( !reg )
boot_fatal( "Error: unable to find the OpenFirmware memory reg "
"property." );
L4_Word_t *ranges = (L4_Word_t *)®->data;
L4_Word_t i, cnt = reg->len / sizeof(L4_Word_t);
L4_Word_t tot = 0;
for( i = 1; i < cnt; i += 2 )
tot += ranges[i];
if( tot == 0 )
boot_fatal( "Error: didn't detect any platform memory." );
print_hex( "Detected memory (bytes)", tot );
puts( "" );
kip_manager.setup_main_memory( 0, tot );
kip_manager.dedicate_memory( 0, tot, L4_ConventionalMemoryType, 0 );
if( !detect_of1275_memory(mem_node, tot) )
puts( "Warning: unable to detect Open Firmware's memory "
"requirements.\n" );
}
void start_kernel( L4_Word_t r3, L4_Word_t r4, L4_Word_t r5 )
{
elf_ehdr_t *ehdr = (elf_ehdr_t *)get_kernel_start();
elf_phdr_t *phdr = (elf_phdr_t *)((L4_Word_t)ehdr + ehdr->e_phoff);
L4_Word_t kernel_start_ip = ehdr->e_entry - phdr->p_vaddr + phdr->p_paddr;
print_hex( "Kernel physical entry point", kernel_start_ip );
puts( "" );
puts( "" );
puts( "[ L4 PowerPC ]" );
enter_kernel( r3, r4, r5, kernel_start_ip );
}
void map_ram()
{
ppc_bat_t bat;
bat.raw.lower = 0;
bat.raw.upper = 0;
bat.x.pp = BAT_PP_READ_WRITE;
bat.x.vs = 1;
bat.x.bl = BAT_BL_256M;
asm volatile ("isync");
ppc_set_dbat3l( bat.raw.lower );
ppc_set_dbat3u( bat.raw.upper );
asm volatile ("isync");
}
extern "C" void loader_main( L4_Word_t r3, L4_Word_t r4, L4_Word_t of1275_entry)
{
prom_init( of1275_entry );
puts( "[==== Pistachio PowerPC Open Firmware Boot Loader ====]" );
map_ram();
kip_manager.init();
kip_manager.install_sigma0( get_sigma0_start(), get_sigma0_end() );
kip_manager.install_root_task( get_root_task_start(), get_root_task_end() );
kip_manager.install_kernel( get_kernel_start(), get_kernel_end() );
L4_Word_t devtree_start = kip_manager.first_avail_page();
L4_Word_t devtree_size = build_device_tree( (char *)devtree_start );
L4_Word_t devtree_end = wrap_up( devtree_start + devtree_size, PAGE_SIZE );
print_hex( "Device tree page", devtree_start );
print_hex( ", length", devtree_size );
puts( "" );
if( !kip_manager.find_kip(get_kernel_start()) )
boot_fatal( "Error: unable to locate the kernel interface page!" );
detect_platform_memory( (char *)devtree_start );
kip_manager.dedicate_memory( devtree_start, devtree_end,
L4_BootLoaderSpecificMemoryType, 0xf );
kip_manager.update_kip();
start_kernel( r3, r4, of1275_entry );
}
extern word_t call_addr;
L4_Word32_t prom_entry ( void * args )
{
return ((L4_Word32_t(*)( void * ))call_addr)( args );
}