ref: 94443daf8e248e65afc8d3f17f26efea22748b51
dir: /os/boot/mpc/flash.c/
#include "boot.h"
typedef struct Flashdev Flashdev;
struct Flashdev {
uchar* base;
int size;
uchar* exec;
char* config;
int conflen;
};
enum {
FLASHSEG = 256*1024,
CONFIGLIM = FLASHSEG,
BOOTOFF = FLASHSEG,
BOOTLEN = 3*FLASHSEG, /* third segment might be filsys */
/* rest of flash is free */
};
static Flashdev flash;
/*
* configuration data is written between the bootstrap and
* the end of region 0. the region ends with allocation descriptors
* of the following form:
*
* byte order is big endian
*
* the last valid region found that starts with the string "#plan9.ini\n" is plan9.ini
*/
typedef struct Flalloc Flalloc;
struct Flalloc {
ulong check; /* checksum of data, or ~0 */
ulong base; /* base of region; ~0 if unallocated, 0 if deleted */
uchar len[3];
uchar tag; /* see below */
uchar sig[4];
};
enum {
/* tags */
Tdead= 0,
Tboot= 0x01, /* space reserved for boot */
Tconf= 0x02, /* configuration data */
Tnone= 0xFF,
Noval= ~0,
};
static char flashsig[] = {0xF1, 0xA5, 0x5A, 0x1F};
static char conftag[] = "#plan9.ini\n";
static ulong
checksum(uchar* p, int n)
{
ulong s;
for(s=0; --n >= 0;)
s += *p++;
return s;
}
static int
validptr(Flalloc *ap, uchar *p)
{
return p > (uchar*)&end && p < (uchar*)ap;
}
static int
flashcheck(Flalloc *ap, char **val, int *len)
{
uchar *base;
int n;
if(ap->base == Noval || ap->base >= FLASHSEG || ap->tag == Tnone)
return 0;
base = flash.base+ap->base;
if(!validptr(ap, base))
return 0;
n = (((ap->len[0]<<8)|ap->len[1])<<8)|ap->len[2];
if(n == 0xFFFFFF)
n = 0;
if(n < 0)
return 0;
if(n > 0 && !validptr(ap, base+n-1))
return 0;
if(ap->check != Noval && checksum(base, n) != ap->check){
print("flash: bad checksum\n");
return 0;
}
*val = (char*)base;
*len = n;
return 1;
}
int
flashinit(void)
{
int len;
char *val;
Flalloc *ap;
void *addr;
long mbytes;
char type[20];
flash.base = 0;
flash.exec = 0;
flash.size = 0;
if(archflashreset(type, &addr, &mbytes) < 0){
print("flash: flash not present or not enabled\n"); /* shouldn't happen */
return 0;
}
flash.size = mbytes;
flash.base = addr;
flash.exec = flash.base + BOOTOFF;
flash.config = nil;
flash.conflen = 0;
for(ap = (Flalloc*)(flash.base+CONFIGLIM)-1; memcmp(ap->sig, flashsig, 4) == 0; ap--){
if(0)
print("conf #%8.8lux: #%x #%6.6lux\n", ap, ap->tag, ap->base);
if(ap->tag == Tconf &&
flashcheck(ap, &val, &len) &&
len >= sizeof(conftag)-1 &&
memcmp(val, conftag, sizeof(conftag)-1) == 0){
flash.config = val;
flash.conflen = len;
if(0)
print("flash: found config %8.8lux(%d):\n%s\n", val, len, val);
}
}
if(flash.config == nil)
print("flash: no config\n");
else
print("flash config %8.8lux(%d):\n%s\n", flash.config, flash.conflen, flash.config);
if(issqueezed(flash.exec) == Q_MAGIC){
print("flash: squeezed powerpc kernel installed\n");
return 1<<0;
}
if(GLLONG(flash.exec) == Q_MAGIC){
print("flash: unsqueezed powerpc kernel installed\n");
return 1<<0;
}
flash.exec = 0;
print("flash: no powerpc kernel in Flash\n");
return 0;
}
char*
flashconfig(int)
{
return flash.config;
}
int
flashbootable(int)
{
return flash.exec != nil && (issqueezed(flash.exec) || GLLONG(flash.exec) == Q_MAGIC);
}
int
flashboot(int)
{
ulong entry, addr;
void (*b)(void);
Exec *ep;
Block in;
long n;
uchar *p;
if(flash.exec == 0)
return -1;
p = flash.exec;
if(GLLONG(p) == Q_MAGIC){
/* unsqueezed: copy data and perhaps text, then jump to it */
ep = (Exec*)p;
entry = PADDR(GLLONG(ep->entry));
p += sizeof(Exec);
addr = entry;
n = GLLONG(ep->text);
if(addr != (ulong)p){
memmove((void*)addr, p, n);
print("text: %8.8lux <- %8.8lux [%ld]\n", addr, p, n);
}
p += n;
if(entry >= FLASHMEM)
addr = 3*BY2PG; /* kernel text is in Flash, data in RAM */
else
addr = PGROUND(addr+n);
n = GLLONG(ep->data);
memmove((void*)addr, p, n);
print("data: %8.8lux <- %8.8lux [%ld]\n", addr, p, n);
}else{
in.data = p;
in.rp = in.data;
in.lim = p+BOOTLEN;
in.wp = in.lim;
n = unsqueezef(&in, &entry);
if(n < 0)
return -1;
}
print("entry=0x%lux\n", entry);
uartwait();
scc2stop();
/*
* Go to new code. It's up to the program to get its PC relocated to
* the right place.
*/
b = (void (*)(void))KADDR(PADDR(entry));
(*b)();
return -1;
}