#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/powerpc64/page.h>
typedef struct {
word_t vaddr;
word_t size;
word_t paddr;
word_t mode;
} of1275_map_t;
typedef union {
struct {
L4_Word_t base;
L4_Word_t size;
} u64;
struct u32 {
L4_Word32_t base;
L4_Word32_t size;
L4_Word32_t dummy1;
L4_Word32_t dummy2;
} u32;
} 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 ..." );
prom_exit();
}
static L4_Word32_t cellsize = 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;
puts( "[==== Detecting OpenFirmware Memory ====]" );
range_t *ranges = (range_t *)available->data;
int cnt = available->len / (sizeof(L4_Word32_t) * 2 * cellsize);
L4_Word_t last = 0;
L4_Word_t me = (L4_Word_t)detect_of1275_memory;
for( int i = 0; i < cnt; i++ )
{
switch( cellsize ) {
case 1:
if( ((me < last) || (me > ranges->u32.base)) &&
(ranges->u32.base > last) )
{
print_hex(" reserved : ", last);
print_hex(" - ", ranges->u32.base);
puts("");
kip_manager.dedicate_memory( last, ranges->u32.base,
L4_BootLoaderSpecificMemoryType, 0xe );
}
last = ranges->u32.base + ranges->u32.size;
ranges = (range_t *)((L4_Word_t)ranges + (sizeof(L4_Word32_t) * 2));
break;
case 2:
if( ((me < last) || (me > ranges[i].u64.base)) &&
(ranges[i].u64.base > last) )
{
print_hex(" reserved : ", last);
print_hex(" - ", ranges[i].u64.base);
puts("");
kip_manager.dedicate_memory( last, ranges[i].u64.base,
L4_BootLoaderSpecificMemoryType, 0xe );
}
last = ranges[i].u64.base + ranges[i].u64.size;
break;
}
}
if( (me < last) && (last < tot_mem) )
kip_manager.dedicate_memory( last, tot_mem,
L4_BootLoaderSpecificMemoryType, 0xe );
return true;
}
word_t size_of_memory( char *devtree )
{
device_t *node = device_first( devtree );
L4_Word_t total = 0;
item_t *item_name, *item_data;
item_data = item_find( node, "#size-cells" );
if (!item_data)
{
puts( "No cell size found\n" );
return 0;
}
cellsize = *(L4_Word32_t *)item_data->data;
while( node->handle )
{
item_name = item_first( node );
item_data = item_next( item_name );
if( !strcmp(item_data->data, "memory") )
{
item_t *reg = item_find( node, "reg" );
range_t *ranges = (range_t *)®->data;
L4_Word_t i;
L4_Word_t tot = 0;
L4_Word_t cnt = reg->len / (sizeof(L4_Word32_t) * 2 * cellsize);
for( i = 0; i < cnt; i ++ )
{
switch (cellsize) {
case 1:
tot += ranges->u32.size;
ranges = (range_t *)((L4_Word_t)ranges + (sizeof(L4_Word32_t) * 2));
break;
case 2: tot += ranges[i].u64.size; break;
}
}
total += tot;
}
node = device_next( node );
}
return total;
}
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." );
word_t tot = size_of_memory( devtree );
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 PowerPC64 ]" );
enter_kernel( r3, r4, r5, kernel_start_ip );
}
extern "C" void loader_main( L4_Word_t r3, L4_Word_t r4, L4_Word_t of1275_entry)
{
prom_init( of1275_entry );
puts( "[==== Pistachio PowerPC64 Open Firmware Boot Loader ====]\n" );
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 )
{
register L4_Word32_t result;
asm volatile (
"mtctr %1; "
"mr 3, %2;"
"stdu 1, -1024(1);"
"std 2, -8(1);"
"std 3, -16(1);"
"std 4, -24(1);"
"std 5, -32(1);"
"std 6, -40(1);"
"std 7, -48(1);"
"std 8, -56(1);"
"std 9, -64(1);"
"std 10,-72(1);"
"std 11,-80(1);"
"std 12,-88(1);"
"std 13,-96(1);"
"std 14,-104(1);"
"std 15,-112(1);"
"std 16,-120(1);"
"std 17,-128(1);"
"std 18,-136(1);"
"std 19,-144(1);"
"std 20,-152(1);"
"std 21,-160(1);"
"std 22,-168(1);"
"std 23,-176(1);"
"std 24,-184(1);"
"std 25,-192(1);"
"std 26,-200(1);"
"std 27,-208(1);"
"std 28,-216(1);"
"std 29,-224(1);"
"std 30,-232(1);"
"std 31,-240(1);"
"mfcr 4;"
"std 4,-248(1);"
"mfctr 5;"
"std 5,-256(1);"
"mfxer 6;"
"std 6,-264(1);"
"mfdar 7;"
"std 7,-272(1);"
"mfdsisr 8;"
"std 8,-280(1);"
"mfsrr0 9;"
"std 9,-288(1);"
"mfsrr1 10;"
"std 10,-296(1);"
"mfmsr 11;"
"std 11,-304(1);"
"mtsprg 2,1;"
"mfmsr 11;"
"li 12,1;"
"rldicr 12,12,63,(63-63);"
"andc 11,11,12;"
"li 12,1;"
"rldicr 12,12,61,(63-61);"
"andc 11,11,12;"
"mtmsrd 11;"
"isync;"
"bctrl; "
"mfsprg 1, 2;"
"ld 6,-304(1);"
"mtmsrd 6;"
"isync;"
"ld 2, -8(1);"
"ld 13, -96(1);"
"ld 14,-104(1);"
"ld 15,-112(1);"
"ld 16,-120(1);"
"ld 17,-128(1);"
"ld 18,-136(1);"
"ld 19,-144(1);"
"ld 20,-152(1);"
"ld 21,-160(1);"
"ld 22,-168(1);"
"ld 23,-176(1);"
"ld 24,-184(1);"
"ld 25,-192(1);"
"ld 26,-200(1);"
"ld 27,-208(1);"
"ld 28,-216(1);"
"ld 29,-224(1);"
"ld 30,-232(1);"
"ld 31,-240(1);"
"ld 4,-248(1);"
"mtcr 4;"
"ld 5,-256(1);"
"mtctr 5;"
"ld 6,-264(1);"
"mtxer 6;"
"ld 7,-272(1);"
"mtdar 7;"
"ld 8,-280(1);"
"mtdsisr 8;"
"ld 9,-288(1);"
"mtsrr0 9;"
"ld 10,-296(1);"
"mtsrr1 10;"
"addi 1, 1, 1024;"
: "=r" (result)
: "r" (call_addr),
"r" (args)
: "lr", "memory"
);
return result;
}