aboutsummaryrefslogtreecommitdiff
path: root/snilib
diff options
context:
space:
mode:
authorFlorian Lohoff <flo@rfc822.org>2008-11-29 12:16:56 +0000
committerGuido Günther <agx@sigxcpu.org>2009-04-26 15:26:27 +0200
commit7b4ca7013c58a67f1ec41478b1bfc250b3485d28 (patch)
treef759f75d5ac13dda6c581c3f6357d976b6cb593a /snilib
parent4ce5705be57a10598775d14cc1b8a6296df9c653 (diff)
Add basic SNIRM support
Add basic SNIRM support - Currently has a hardcoded boot location but you get the idea.
Diffstat (limited to 'snilib')
-rw-r--r--snilib/Makefile20
-rw-r--r--snilib/sniprom.c181
-rw-r--r--snilib/sniprom.h59
3 files changed, 260 insertions, 0 deletions
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 <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+#include <subarch.h>
+#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 <spacebar> 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<argc;i++ )
+ prom_add_arg(argv[i]);
+ return iargc;
+}
+
+char *prom_get_label(void ) {
+ return (label) ? label : "linux";
+}
+
+char *prom_get_partition(void ) {
+ return "dkncr(0,0,1)";
+}
+
+char *prom_get_options(void ) {
+ return NULL;
+}
+
+void prom_get_karg(int *argc, char ***argv) {
+ *argc=iargc;
+ *argv=iargv;
+}
diff --git a/snilib/sniprom.h b/snilib/sniprom.h
new file mode 100644
index 0000000..db079ad
--- /dev/null
+++ b/snilib/sniprom.h
@@ -0,0 +1,59 @@
+
+#include <subarch.h>
+
+#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))();
+}