From 7b4ca7013c58a67f1ec41478b1bfc250b3485d28 Mon Sep 17 00:00:00 2001 From: Florian Lohoff Date: Sat, 29 Nov 2008 12:16:56 +0000 Subject: Add basic SNIRM support Add basic SNIRM support - Currently has a hardcoded boot location but you get the idea. --- snilib/sniprom.c | 181 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 181 insertions(+) create mode 100644 snilib/sniprom.c (limited to 'snilib/sniprom.c') diff --git a/snilib/sniprom.c b/snilib/sniprom.c new file mode 100644 index 0000000..fa5acc1 --- /dev/null +++ b/snilib/sniprom.c @@ -0,0 +1,181 @@ + +#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