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/Makefile | 20 ++++++ snilib/sniprom.c | 181 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ snilib/sniprom.h | 59 ++++++++++++++++++ 3 files changed, 260 insertions(+) create mode 100644 snilib/Makefile create mode 100644 snilib/sniprom.c create mode 100644 snilib/sniprom.h (limited to 'snilib') diff --git a/snilib/Makefile b/snilib/Makefile new file mode 100644 index 0000000..4e6ec18 --- /dev/null +++ b/snilib/Makefile @@ -0,0 +1,20 @@ +# +# Copyright 1999 Silicon Graphics, Inc. +# +CFLAGS += -O2 -I../common -mno-abicalls -G 0 -fno-pic -ffreestanding -DDEBUG + +TARGETS = libsni.a +OBJECTS = sniprom.o + +all: $(TARGETS) + +$(TARGETS): $(OBJECTS) + rm -f $@ + $(AR) -crs $@ $(OBJECTS) + +install: $(TARGETS) + install -d ${PREFIX}/${LIBDIR} + install -m 644 $< ${PREFIX}/${LIBDIR} + +clean: + rm -f libsni.a $(OBJECTS) *~ tags 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 + +#define PROM_VEC KSEG1ADDR(0x1fc00000) +#define PROM_ENTRY(x) (PROM_VEC + (x*8)) + +#define PROM_RESET 0 +#define PROM_OPEN 6 +#define PROM_READ 7 +#define PROM_WRITE 8 +//#define PROM_SEEK 8 +#define PROM_PUTCHAR 12 +#define PROM_FLUSHCACHE 28 +#define PROM_CLEARCACHE 29 +#define PROM_GETENV 33 +#define PROM_GET_MEMCONF 58 + + +typedef struct { + unsigned int size; + unsigned int base; + unsigned int size2; + unsigned int pad1; + unsigned int pad2; +} MEMBANK; + +typedef struct { + MEMBANK bank[8]; +} MEMCONF; + +static inline int __prom_get_memconf(MEMCONF *mc) { + return ((int (*)(MEMCONF *))PROM_ENTRY(PROM_GET_MEMCONF))(mc); +} + +static inline int __prom_putchar(char a) { + return ((int (*)(int))PROM_ENTRY(PROM_PUTCHAR))(a); +} + +static inline int __prom_open(char *filename, int mode) { + return ((int (*)(char *, int))PROM_ENTRY(PROM_OPEN))(filename, mode); +} + +static inline int __prom_write(FILE stream, char *buf, unsigned long len) { + return ((int (*)(FILE, char *, unsigned long))PROM_ENTRY(PROM_WRITE)) + (stream, buf, len); +} + +static inline int __prom_read(FILE stream, char *buf, unsigned long len) { + return ((int (*)(FILE, char *, unsigned long))PROM_ENTRY(PROM_READ)) + (stream, buf, len); +} + +static inline void __prom_reset(void ) { + ((void (*)(void ))PROM_ENTRY(PROM_RESET))(); +} + +static inline void __prom_flushcache(void) { + ((void (*)(void ))PROM_ENTRY(PROM_FLUSHCACHE))(); +} -- cgit v1.2.3