blob: 54f2b8df91bd86ef2d3faa607276476ad20c0eda [file] [log] [blame]
/******************************************************************************
* Copyright (c) 2004, 2011 IBM Corporation
* All rights reserved.
* This program and the accompanying materials
* are made available under the terms of the BSD License
* which accompanies this distribution, and is available at
* http://www.opensource.org/licenses/bsd-license.php
*
* Contributors:
* IBM Corporation - initial implementation
*****************************************************************************/
#include <stdint.h>
#include <xvect.h>
#include <hw.h>
#include <stdio.h>
#include <romfs.h>
#include "memmap.h"
#include "stage2.h"
#include <termctrl.h>
#include "product.h"
#include "calculatecrc.h"
#include <cpu.h>
#include <libelf.h>
#include <string.h>
#define DEBUG(fmt...)
//#define DEBUG(fmt...) printf(fmt)
uint64_t gVecNum;
uint64_t exception_stack_frame;
typedef void (*pInterruptFunc_t) (void);
pInterruptFunc_t vectorTable[0x2E << 1];
extern void proceedInterrupt(void);
/* Prototypes for functions of this file */
void c_interrupt(uint64_t vecNum);
void set_exceptionVector(int num, void *func);
void early_c_entry(uint64_t start_addr, uint64_t fdt_addr);
static void exception_forward(void)
{
uint64_t val;
if (*(uint64_t *) XVECT_M_HANDLER) {
proceedInterrupt();
}
printf("\r\n exception %llx ", gVecNum);
asm volatile ("mfsrr0 %0":"=r" (val):);
printf("\r\nSRR0 = %08llx%08llx ", val >> 32, val);
asm volatile ("mfsrr1 %0":"=r" (val):);
printf(" SRR1 = %08llx%08llx ", val >> 32, val);
asm volatile ("mfsprg %0,2":"=r" (val):);
printf("\r\nSPRG2 = %08llx%08llx ", val >> 32, val);
asm volatile ("mfsprg %0,3":"=r" (val):);
printf(" SPRG3 = %08llx%08llx \r\n", val >> 32, val);
while (1);
}
void c_interrupt(uint64_t vecNum)
{
gVecNum = vecNum;
if (vectorTable[vecNum >> 7]) {
vectorTable[vecNum >> 7] ();
} else {
exception_forward();
}
}
void set_exceptionVector(int num, void *func)
{
vectorTable[num >> 7] = (pInterruptFunc_t) func;
}
static void load_file(uint64_t destAddr, char *name, uint64_t maxSize,
uint64_t romfs_base)
{
uint64_t cnt;
struct romfs_lookup_t fileInfo;
int rc;
rc = c_romfs_lookup(name, romfs_base, &fileInfo);
if (rc) {
printf("Cannot find romfs file %s\n", name);
return;
}
DEBUG("Found romfs file %s\n", name);
if (maxSize) {
cnt = maxSize;
} else {
cnt = fileInfo.size_data;
}
memcpy((void *)destAddr, (void *)fileInfo.addr_data, cnt);
flush_cache((void *) destAddr, fileInfo.size_data);
}
/***************************************************************************
* Function: early_c_entry
* Input : start_addr
*
* Description:
**************************************************************************/
void early_c_entry(uint64_t start_addr, uint64_t fdt_addr)
{
struct romfs_lookup_t fileInfo;
void (*ofw_start) (uint64_t, uint64_t, uint64_t, uint64_t, uint64_t);
uint64_t *boot_info;
uint64_t romfs_base, paflof_base;
// romfs header values
// struct stH *header = (struct stH *) (start_addr + 0x28);
// uint64_t flashlen = header->flashlen;
unsigned long ofw_addr[2];
int rc;
if (fdt_addr == 0) {
puts("ERROR: Flatten device tree not available!");
}
/* Hack: Determine base for "ROM filesystem" in memory...
* QEMU loads the FDT at the top of the available RAM, so we place
* the ROMFS just underneath. */
romfs_base = (fdt_addr - 0x410000) & ~0xffffLL;
memcpy((char *)romfs_base, 0, 0x400000);
exception_stack_frame = 0;
printf(" Press \"s\" to enter Open Firmware.\r\n\r\n");
DEBUG(" [c_romfs_lookup at %p]\n", c_romfs_lookup);
rc = c_romfs_lookup("bootinfo", romfs_base, &fileInfo);
if (rc)
printf(" !!! roomfs lookup(bootinfo) = %d\n", rc);
boot_info = (uint64_t *) fileInfo.addr_data;
boot_info[1] = start_addr;
load_file(0x100, "xvect", 0, romfs_base);
rc = c_romfs_lookup("ofw_main", romfs_base, &fileInfo);
if (rc)
printf(" !!! roomfs lookup(bootinfo) = %d\n", rc);
DEBUG(" [ofw_main addr hdr 0x%lx]\n", fileInfo.addr_header);
DEBUG(" [ofw_main addr data 0x%lx]\n", fileInfo.addr_data);
DEBUG(" [ofw_main size data 0x%lx]\n", fileInfo.size_data);
DEBUG(" [ofw_main flags 0x%lx]\n", fileInfo.flags);
DEBUG(" [hdr: 0x%08lx 0x%08lx]\n [ 0x%08lx 0x%08lx]\n",
((uint64_t *)fileInfo.addr_header)[0],
((uint64_t *)fileInfo.addr_header)[1],
((uint64_t *)fileInfo.addr_header)[2],
((uint64_t *)fileInfo.addr_header)[3]);
/* Assume that paflof and SNK need ca. 31 MiB RAM right now.
* TODO: Use value from ELF file instead */
paflof_base = romfs_base - 0x1F00000 + 0x100;
if ((int64_t)paflof_base <= 0LL) {
puts("ERROR: Not enough memory for Open Firmware");
}
rc = elf_load_file_to_addr((void *)fileInfo.addr_data, (void*)paflof_base,
ofw_addr, NULL, flush_cache);
DEBUG(" [load_elf_file returned %d]\n", rc);
ofw_start =
(void (*)(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t))
&ofw_addr;
// re-enable the cursor
printf("%s%s", TERM_CTRL_RESET, TERM_CTRL_CRSON);
DEBUG(" [ofw_start=%p ofw_addr=0x%lx]\n", ofw_start, ofw_addr[0]);
ofw_addr[1] = ofw_addr[0];
/* Call the Open Firmware layer with ePAPR-style calling conventions:
* r3 = R3 Effective address of the device tree image. Note: this
* address must be 8-byte aligned in memory.
* r4 = implementation dependent, we use it for ROMFS base address
* r5 = 0
* r6 = 0x65504150 -- ePAPR magic value-to distinguish from
* non-ePAPR-compliant firmware
* r7 = size of Initially Mapped Area
* (right now we assume everything from 0 to the FDT is the IMA)
*/
asm volatile("isync; sync;" : : : "memory");
ofw_start(fdt_addr, romfs_base, 0, 0x65504150, fdt_addr);
asm volatile("isync; sync;" : : : "memory");
// never return
}