#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 ulongchecksum(uchar* p, int n){ ulong s; for(s=0; --n >= 0;) s += *p++; return s;} static intvalidptr(Flalloc *ap, uchar *p){ return p > (uchar*)&end && p < (uchar*)ap;} static intflashcheck(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;} intflashinit(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;} intflashbootable(int){ return flash.exec != nil && (issqueezed(flash.exec) || GLLONG(flash.exec) == Q_MAGIC);} intflashboot(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;}
#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;
}