#include <lib/libsa/stand.h>
#include <lib/libsa/loadfile.h>
#include <lib/libkern/libkern.h>
#include <sys/param.h>
#include <sys/exec.h>
#include <sys/exec_elf.h>
#include <sys/reboot.h>
#include <machine/emipsreg.h>
#include "common.h"
#include "bootinfo.h"
#include "start.h"
#include "prom_iface.h"
#if _DEBUG
#define TRACE(x) printf x
#else
#define TRACE(x)
#endif
void epmc_halt(void);
void save_locore(void);
void restore_locore(void);
static void *nope(void) {return NULL;}
int getchar(void){return GetChar();}
static void
real_halt(void *arg)
{
int howto = (int)arg;
u_int ps = GetPsr();
#define EMIPS_SR_RP 0x08000000
#define EMIPS_SR_TS 0x00200000
#define EMIPS_SR_RST 0x00000080
#define EMIPS_SR_INT 0x0000ff00
#define EMIPS_SR_IEc 0x00000001
ps &= ~(EMIPS_SR_INT | EMIPS_SR_IEc);
ps |= EMIPS_SR_TS;
SetPsr(ps);
restore_locore();
for (;howto & RB_HALT;) {
epmc_halt();
ps |= EMIPS_SR_RP | EMIPS_SR_INT;
SetPsr(ps);
}
for (;;) {
ps |= EMIPS_SR_RST;
SetPsr(ps);
}
}
static void
halt(int *unused, int howto)
{
switch_stack_and_call((void *)howto,real_halt);
}
struct callback cb = {
nope,
nope,
nope,
nope,
nope,
nope,
nope,
nope,
nope,
getchar,
nope,
nope,
printf,
nope,
nope,
nope,
nope,
nope,
nope,
nope,
nope,
nope,
nope,
nope,
nope,
nope,
nope,
nope,
nope,
nope,
nope,
nope,
getsysid,
nope,
nope,
nope,
nope,
nope,
nope,
halt
};
typedef char *string_t;
void epmc_halt(void)
{
struct _Pmc *pm = (struct _Pmc *)0xfff00000;
pm->SystemPowerDisable = PMCSC_CPU;
}
int init_usart(void)
{
struct _Usart *us = (struct _Usart *)0xfff90000;
us->Baud = 0x29;
us->Control = (USC_RXEN|USC_TXEN|USC_BPC_8|USC_NONE|USC_1STOP|USC_CLKDIV_4);
return 1;
}
typedef struct _Sram *ram_controller_t;
# define RAMBT_TAG SRAMBT_TAG
# define RAMBT_BASE SRAMBT_BASE
# define RAMST_SIZE SRAMST_SIZE
int init_memory(void)
{
struct _Pmt *Pmt;
ram_controller_t Ram, Ours, First;
uint32_t base, addr, moi = (uint32_t)(&init_memory) & 0x3ffff000;
size_t size;
uint16_t tag;
int nsr, ndr, nfl;
nsr = ndr = nfl = 0;
First = Ours = NULL;
base = ~0;
for (Pmt = ThePmt;;Pmt--) {
tag = Pmt->Tag;
switch (tag) {
case PMTTAG_END_OF_TABLE:
goto DoneFirst;
case PMTTAG_SRAM:
case PMTTAG_DDRAM:
case PMTTAG_FLASH:
Ram = (ram_controller_t)(Pmt->TopOfPhysicalAddress << 16);
for (;;) {
if (tag != (Ram->BaseAddressAndTag & RAMBT_TAG))
break;
addr = Ram->BaseAddressAndTag & RAMBT_BASE;
if ((tag != PMTTAG_FLASH) && (addr < base)) {
base = addr;
First = Ram;
}
size = Ram->Control & RAMST_SIZE;
if ((moi >= addr) && (moi < (addr + size))) {
Ours = Ram;
}
Ram++;
switch (tag) {
case PMTTAG_SRAM:
nsr++;
break;
case PMTTAG_FLASH:
nfl++;
break;
case PMTTAG_DDRAM:
Ram++;
ndr++;
break;
}
}
break;
default:
break;
}
}
DoneFirst:
if ((First == NULL) || (Ours == NULL)) {
printf("Bad memory layout (%p, %p), wont work.\n", First, Ours);
return 0;
}
base += First->BaseAddressAndTag & RAMBT_BASE;
for (Pmt = ThePmt;;Pmt--) {
tag = Pmt->Tag;
switch (tag) {
case PMTTAG_END_OF_TABLE:
goto DoneSecond;
case PMTTAG_SRAM:
case PMTTAG_DDRAM:
case PMTTAG_FLASH:
Ram = (ram_controller_t)(Pmt->TopOfPhysicalAddress << 16);
for (;;) {
if (tag != (Ram->BaseAddressAndTag & RAMBT_TAG))
break;
if (Ram == Ours)
goto Next;
if (Ram == First)
goto Next;
if (tag == PMTTAG_FLASH)
goto Next;
addr = Ram->BaseAddressAndTag & RAMBT_BASE;
size = Ram->Control & RAMST_SIZE;
if ((moi >= base) && (moi < (base + size)))
base += Ours->Control & RAMST_SIZE;
if (addr != base) {
printf("remapping %x+%zx to %x\n", addr, size, base);
Ram->BaseAddressAndTag = base;
}
base += size;
Next:
Ram++;
if (tag == PMTTAG_DDRAM) Ram++;
}
break;
default:
break;
}
}
DoneSecond:
for (Pmt = ThePmt;;Pmt--) {
tag = Pmt->Tag;
switch (tag) {
case PMTTAG_END_OF_TABLE:
goto DoneThird;
case PMTTAG_FLASH:
Ram = (ram_controller_t)(Pmt->TopOfPhysicalAddress << 16);
for (;;Ram++) {
if (tag != (Ram->BaseAddressAndTag & RAMBT_TAG))
break;
if (Ram == Ours)
continue;
addr = Ram->BaseAddressAndTag & RAMBT_BASE;
size = Ram->Control & RAMST_SIZE;
if (addr >= base)
continue;
printf("remapping FLASH %x+%x to %x\n", addr, size, base);
Ram->BaseAddressAndTag = base;
base += size;
}
break;
default:
break;
}
}
DoneThird:
return (nfl<<16) | (nsr << 8) | (ndr << 0);
}
u_int startjump[2];
u_int exceptioncode[(0x200-0x080)/4];
void save_locore(void)
{
memcpy(startjump,start,sizeof startjump);
memcpy(exceptioncode,ExceptionHandler,sizeof exceptioncode);
}
void restore_locore(void)
{
memcpy(start,startjump,sizeof startjump);
memcpy(ExceptionHandler,exceptioncode,sizeof exceptioncode);
}
void call_kernel(uint32_t addr, char *kname, char *kargs, u_int bim, char *bip)
{
int argc = 0;
string_t argv[3];
int code = PROM_MAGIC;
struct callback * cv = &cb;
save_locore();
if (kargs == NULL) kargs = "";
argv[0] = kname;
argv[1] = kargs;
argv[2] = NULL;
argc = 2;
TRACE(("Geronimo(%x,%s %s)!\n",addr,kname,kargs));
((void(*)(int,char**,int,struct callback *,u_int,char*))addr)
(argc,argv,code,cv,bim,bip);
}