#include #include #include #include #include "sniprom.h" #define MAX_ARG 64 static char *iargv[MAX_ARG]; static int iargc=0; static char *label=NULL; extern unsigned long _end; void prom_wait(const char *prompt) { printf("%s: called\n\r", __FUNCTION__); } void prom_fatal(const char *message, ...) { va_list ap; if (message != NULL) { printf("FATAL ERROR: "); va_start(ap, message); vprintf(message, ap); va_end(ap); } prom_wait("\n\r--- Press to enter ARC interactive mode ---"); __prom_reset(); } int (*__prom_lseek)(FILE, int, int) = NULL; /* * The SNI Prom does not contain an official entry point for "prom_seek" which is * a pain and basically is a showstopper for bootloaders. There is a seek function * though which seems to be inbetween prom_open and prom_read. We try to find * it by looking for the function prolog e.g. the $sp setup. We then know the * address of the seek. flo@rfc822.org 2007-08-13 */ void prom_init(void ) { unsigned int jump; unsigned int *readaddr, *openaddr, *saddr; jump = *((unsigned int *)PROM_ENTRY(PROM_READ)); readaddr=(unsigned int *) (((jump & 0x03ffffff)<<2)|0xb0000000); jump = *((unsigned int *)PROM_ENTRY(PROM_OPEN)); openaddr= (unsigned int *) (((jump & 0x03ffffff)<<2)|0xb0000000); for(saddr=readaddr-1;saddr>openaddr;saddr--) { /* Search for addiu $sp, negative */ if ((*saddr & 0xffff8000) == 0x27bd8000) { __prom_lseek=(void *) saddr; break; } } if (__prom_lseek == NULL) prom_fatal("Didnt find prom_seek prolog between open and read\n\r"); } /* Give 1MByte of memory behind the arcboot to the allocator */ void prom_init_malloc(unsigned long loadaddr, unsigned long size) { malloc_area_add((unsigned long) &_end, 0x100000); } int prom_seek(FILE stream, long long position, int whence) { int pos32=position, res; res=__prom_lseek(stream, pos32, whence); if (res != position) prom_fatal("Seek failed\n\r"); return 0; } void prom_restart(void ) { printf("%s: called\n\r", __FUNCTION__); } void prom_flush_cache_all(void ) { __prom_flushcache(); } void prom_return_interactive(void ) { printf("%s: called\n\r", __FUNCTION__); } int prom_write(FILE stream, char *buf, unsigned long len, unsigned long *rlen) { int res; /* SNI returns no status but standard conform length */ res=__prom_write(stream, buf, len); *rlen=res; return res<0; } /* * We have seen larger reads to fail on RM200C Prom Version 5 * and RM400 Prom Version 4. It seems this is secondary cache related. As we * would like to use the read-ahead and cache we simply split the reads into * smaller chunks here. * */ int prom_read(FILE stream, char *buf, unsigned long len, unsigned long *rlen) { int res=0,i; int read=0, thisread; while(read < len) { int left=len-read; if (left > 4096) thisread=4096; else thisread=left; res=__prom_read(stream, buf+read, thisread); read+=thisread; if (res < thisread) break; } *rlen=read; return (len > read); } int prom_open(char *name, int mode, FILE *stream) { int res; res=__prom_open(name, mode); *stream=res; return 0; } int prom_close(FILE stream) { return 0; } void prom_add_arg(char *arg) { iargv[iargc++]=strdup(arg); } /* * dkncr(0,0,10) label cmd line arg * Kernel drops argv[0] so we need to add dkncr... and drop the label * */ int prom_parse_args(int argc, char **argv) { int i; prom_add_arg(argv[0]); if (argc > 1) label=strdup(argv[1]); for(i=2;i