summaryrefslogtreecommitdiffstats
path: root/arch/sparc/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sparc/kernel')
-rw-r--r--arch/sparc/kernel/Makefile47
-rw-r--r--arch/sparc/kernel/entry.S927
-rw-r--r--arch/sparc/kernel/head.S1045
-rw-r--r--arch/sparc/kernel/idprom.c183
-rw-r--r--arch/sparc/kernel/ioport.c12
-rw-r--r--arch/sparc/kernel/irq.c335
-rw-r--r--arch/sparc/kernel/probe.c432
-rw-r--r--arch/sparc/kernel/process.c112
-rw-r--r--arch/sparc/kernel/promops.c107
-rw-r--r--arch/sparc/kernel/setup.c120
-rw-r--r--arch/sparc/kernel/signal.c71
-rw-r--r--arch/sparc/kernel/traps.c47
12 files changed, 3438 insertions, 0 deletions
diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile
new file mode 100644
index 000000000..b5151d77e
--- /dev/null
+++ b/arch/sparc/kernel/Makefile
@@ -0,0 +1,47 @@
+#
+# Makefile for the linux kernel.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+.c.s:
+ $(CC) $(CFLAGS) -S $<
+.s.o:
+ $(AS) -o $*.o $<
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+.S.s:
+ $(CPP) -D__ASSEMBLY__ -ansi $< -o $*.s
+.S.o:
+ $(CC) -D__ASSEMBLY__ -ansi -c $< -o $*.o
+
+OBJS = entry.o traps.o irq.o process.o promops.o signal.o ioport.o setup.o \
+ idprom.o probe.o
+
+all: kernel.o head.o
+
+head.o: head.s
+
+head.s: head.S $(TOPDIR)/include/asm-sparc/head.h
+ $(CPP) -D__ASSEMBLY__ -ansi -o $*.s $<
+
+kernel.o: $(OBJS)
+ $(LD) -r -o kernel.o $(OBJS)
+ sync
+
+dep:
+ $(CPP) -M *.c > .depend
+
+dummy:
+
+#
+# include a dependency file if one exists
+#
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
+
+
diff --git a/arch/sparc/kernel/entry.S b/arch/sparc/kernel/entry.S
new file mode 100644
index 000000000..21548015e
--- /dev/null
+++ b/arch/sparc/kernel/entry.S
@@ -0,0 +1,927 @@
+/* arch/sparc/kernel/entry.S: Sparc trap low-level entry points.
+ *
+ * Sparc traps are so ugly, this code is going to go through a lot
+ * of changes as I find out more interesting things. See head.S for
+ * the trap table and how it works, this will show you how we get
+ * to these routines.
+ *
+ * Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <asm/head.h>
+#include <asm/asi.h>
+#include <asm/psr.h>
+#include <asm/cprefix.h>
+#include <asm/vaddrs.h>
+
+/* Here are macros for routines we do often, this allows me to inline this
+ * without making the code look real ugly. Well, the macro looks ugly too but
+ * makes the trap entry code easier to understand.
+ */
+
+/* I really don't like synthetic instructions. So I avoid them like the
+ * plague.
+ */
+
+/* Note that when I have to write a window out, and it is a user's window, I
+ * have to check that the pages of memory that I am going to throw the window(s)
+ * onto are valid and are writable by the user (this is %sp to %sp + 64) before
+ * I start dumping stuff there. We always assume that kernels stack is ok.
+ *
+ * If we have to save a kernel window, only one branch is taken. This should
+ * make trap handlers quicker in this scenario.
+ *
+ * Once 'current' is loaded into %g6, it stays there until we leave
+ * this macro.
+ *
+ * XXX must do some checking on the assumption that kernel stack is always ok
+ */
+
+/* I will document how this works real soon. TODO */
+
+#define TRAP_WIN_CLEAN \
+ or %g0, %g5, %l5; /* we need the globals to do our work */ \
+ or %g0, %g6, %l6; /* and %l0 to %l4 are loaded with important */ \
+ or %g0, %g7, %l7; /* information like the psr and pc's to return to */ \
+ sethi %hi( C_LABEL(current) ), %g6; \
+ ld [%g6 + %lo( C_LABEL(current) )], %g6; \
+ ld [%g6 + THREAD_UWINDOWS], %g7; /* how many user wins are active? */ \
+ subcc %g7, 0x0, %g0; \
+ bne 2f; /* If there are any, branch. */ \
+ save %g0, %g0, %g0; /* Save into that window either way. */ \
+ std %l0, [%sp]; /* If above shows only kernel windows */ \
+1: std %l2, [%sp + 0x8]; /* then we get here. */ \
+ std %l4, [%sp + 0x10]; \
+ std %l6, [%sp + 0x18]; \
+ std %i0, [%sp + 0x20]; \
+ std %i2, [%sp + 0x28]; \
+ std %i4, [%sp + 0x30]; \
+ std %i6, [%sp + 0x38]; \
+ or %g0, 0x1, %g5; \
+ rd %psr, %g7; \
+ sll %g5, %g7, %g5; \
+ wr %g5, 0x0, %wim; /* update %wim to 'now' invalid */ \
+ and %g7, 0x1f, %g7; \
+ st %g7, [%g6 + THREAD_WIM]; /* save 'this' threads mask */ \
+ restore %g0, %g0, %g0; \
+ or %g0, %l5, %g5; /* restore the globals we used */ \
+ or %g0, %l6, %g6; \
+ b 8f; /* we are done */ \
+ or %g0, %l7, %g7; \
+2: sub %g7, 0x1, %g7; \
+ st %g7, [%g6 + THREAD_UWINDOWS]; /* There are user windows if we */ \
+ andcc %sp, 0x7, %g0; /* get here. Check for stack alignment. */ \
+ bne 5f; /* Stack is unaligned, yuck. */ \
+ sra %sp, 0x1e, %g7; /* This stuff checks to see if top 3-bits */ \
+ subcc %g7, 0x0, %g0; /* of stack pointer address are ok. */ \
+ be,a 3f; \
+ andn %sp, 0xfff, %g7; \
+ subcc %g7, -1, %g0; \
+ bne 5f; /* bad stack pointer, ugh */ \
+ andn %sp, 0xfff, %g7; \
+3: lda [%g7] ASI_PTE, %g7; /* Ok, user stack is a valid address */ \
+ srl %g7, 0x1d, %g7; \
+ subcc %g7, 0x6, %g0; /* Can the user write to it? */ \
+ bne 5f; \
+ and %sp, 0xfff, %g7; \
+ subcc %g7, 0xfc1, %g0; /* Is our save area on one page? */ \
+ bl,a 1b; \
+ std %l0, [%sp]; \
+ add %sp, 0x38, %g5; /* Nope, have to check both pages */ \
+ sra %g5, 0x1e, %g7; \
+ subcc %g7, 0x0, %g0; \
+ be,a 4f; \
+ andn %g5, 0xfff, %g7; \
+ subcc %g7, -1, %g0; \
+ bne 5f; \
+ andn %g5, 0xfff, %g7; \
+4: lda [%g7] ASI_PTE, %g7; /* Stack space in 2nd page is valid */ \
+ srl %g7, 0x1d, %g7; \
+ subcc %g7, 0x6, %g0; /* Can user write here too? */ \
+ be,a 1b; \
+ std %l0, [%sp]; \
+5: ld [%g6 + THREAD_UWINDOWS], %g7; /* This is due to either bad page perms */ \
+ add %g6, THREAD_REG_WINDOW, %g5; /* for the users stack area, or the stack */ \
+6: std %l0, [%g5]; /* pointer is misaligned. See above. */ \
+ std %l2, [%g5 + 0x8]; \
+ std %l4, [%g5 + 0x10]; \
+ std %l6, [%g5 + 0x18]; \
+ std %i0, [%g5 + 0x20]; \
+ std %i2, [%g5 + 0x28]; \
+ std %i4, [%g5 + 0x30]; \
+ std %i6, [%g5 + 0x38]; \
+ subcc %g7, 0x1, %g7; \
+ bge,a 6b; /* while(uwindows>=0) { write_win(); */ \
+ save %g5, 0x40, %g5; /* uwindows--; } */ \
+ st %sp, [%g6 + THREAD_USP]; \
+ or %g0, 0x1, %g5; \
+ rd %psr, %g7; \
+ sll %g5, %g7, %g5; \
+ wr %g5, 0x0, %wim; \
+ and %g7, 0x1f, %g7; \
+ st %g7, [%g6 + THREAD_WIM]; /* Update thread_struct fields */ \
+ ld [%g6 + THREAD_UWINDOWS], %g7; \
+ add %g7, 0x1, %g5; \
+ st %g5, [%g6 + THREAD_W_SAVED]; \
+ st %g0, [%g6 + THREAD_UWINDOWS]; \
+7: subcc %g7, 0x1, %g7; /* Restore back to where we started. */ \
+ bge 7b; \
+ restore %g0, %g0, %g0; \
+ or %g0, %l5, %g5; /* Restore the globals. */ \
+ or %g0, %l6, %g6; \
+ or %g0, %l7, %g7; \
+8: nop; /* We are done when we get here. */ \
+
+/* As if the last macro wasn't enough, we have to go through a very similar routine
+ * upon entry to most traps and interrupts. This is save away the current window
+ * if it is the trap window, clean it, and adjust the stack for the handler c-code
+ * to work.
+ */
+
+#define ENTER_TRAP \
+ rd %wim, %l4; \
+ or %g0, 0x1, %l5; \
+ sll %l5, %l0, %l5; \
+ andcc %l0, 0x40, %g0; \
+ bz 1f; \
+ andcc %l4, %l5, %g0; \
+ bz,a 3f; \
+ sub %fp, 0xb0, %sp; \
+ TRAP_WIN_CLEAN \
+ b 3f; \
+ sub %fp, 0xb0, %sp; \
+1: sethi %hi( C_LABEL(current) ), %l6; \
+ ld [%l6 + %lo( C_LABEL(current) )], %l6; \
+ ld [%l6 + THREAD_WIM], %l5; \
+ and %l0, 0x1f, %l4; \
+ cmp %l5, %l3; \
+ ble,a 4f; \
+ sethi %hi( C_LABEL(nwindowsm1) ), %l4; \
+ sub %l5, %l3, %l3; \
+ b 5f; \
+ sub %l3, 0x1, %l5; \
+4: ld [%l4 + %lo( C_LABEL(nwindowsm1) )], %l4; \
+ sub %l4, %l3, %l4; \
+ add %l5, %l4, %l5; \
+5: st %l5, [%l6 + THREAD_UWINDOWS]; \
+ bz,a 2f; \
+ sethi %hi(TASK_SIZE-176), %l5; \
+ TRAP_WIN_CLEAN; \
+ sethi %hi( C_LABEL(current) ), %l6; \
+ ld [%l6 + %lo( C_LABEL(current) )], %l6; \
+ sethi %hi(TASK_SIZE-176), %l5; \
+2: or %l5, %lo(TASK_SIZE-176), %l5; \
+ add %l6, %l5, %sp; \
+3: \
+
+#define ENTER_IRQ \
+ rd %wim, %l4; \
+ or %g0, 0x1, %l5; \
+ sll %l5, %l0, %l5; \
+ andcc %l0, 0x40, %g0; \
+ bz 1f; \
+ andcc %l4, %l5, %g0; \
+ sethi %hi( C_LABEL(eintstack) ), %l7; \
+ or %l7, %lo( C_LABEL(eintstack) ), %l7; \
+ bz 0f; \
+ nop; \
+ TRAP_WIN_CLEAN \
+ sethi %hi( C_LABEL(eintstack) ), %l7; \
+ or %l7, %lo( C_LABEL(eintstack) ), %l7; \
+0: subcc %fp, %l7, %g0; \
+ bg,a 3f; \
+ sub %l7, 0xb0, %sp; \
+ b 3f; \
+ sub %fp, 0xb0, %sp; \
+1: sethi %hi( C_LABEL(current) ), %l6; \
+ ld [%l6 + %lo( C_LABEL(current) )], %l6; \
+ ld [%l6 + THREAD_WIM], %l5; \
+ and %l0, 0x1f, %l7; \
+ cmp %l5, %l7; \
+ ble,a 4f; \
+ sethi %hi( C_LABEL(nwindowsm1) ), %l4; \
+ sub %l5, %l7, %l7; \
+ b 5f; \
+ sub %l7, 0x1, %l5; \
+4: ld [%l4 + %lo( C_LABEL(nwindowsm1) )], %l4; \
+ sub %l4, %l7, %l4; \
+ add %l5, %l4, %l5; \
+5: st %l5, [%l6 + THREAD_UWINDOWS]; \
+ bz,a 2f; \
+ sethi %hi( C_LABEL(eintstack) ), %l7; \
+ TRAP_WIN_CLEAN \
+ sethi %hi( C_LABEL(eintstack) ), %l7; \
+2: \
+ sub %l7, 0xb0, %sp; \
+3:
+
+
+ .text
+ .align 4
+
+/* Default trap handler */
+ .globl my_trap_handler
+my_trap_handler:
+#if 1
+ jmp %l1
+ rett %l2
+ nop
+#else
+ rd %wim, %l4
+ or %g0, 0x1, %l5
+ sll %l5, %l0, %l5
+ cmp %l4, %l5 ! are we in the invalid window?
+
+ TRAP_WIN_CLEAN
+
+ nop
+ or %g0, %l3, %o0
+ call C_LABEL(do_hw_interrupt)
+ or %g0, %g0, %o1
+ wr %l0, 0x20, %psr ! re-enable traps and reset the condition codes
+ nop
+ nop
+ nop ! click our heels three times, "no place like home"
+ jmp %l1
+ rett %l2
+#endif /* bogon */
+
+ .align 4
+ .globl sparc_timer
+sparc_timer:
+ sethi %hi(TIMER_VADDR), %l4
+ or %l4, %lo(TIMER_VADDR), %l4 ! read the limit register
+ ld [%l4 + 0xc], %l4 ! to clear the interrupt
+ rd %wim, %l4
+ or %g0, 0x1, %l5
+ sll %l5, %l0, %l5
+ andcc %l0, 0x40, %g0
+ bz st1
+ sethi %hi( C_LABEL(eintstack) ), %l7
+ andcc %l4, %l5, %g0
+ bz st0
+ or %l7, %lo( C_LABEL(eintstack) ), %l7
+ TRAP_WIN_CLEAN
+ sethi %hi( C_LABEL(eintstack) ), %l7
+ or %l7, %lo( C_LABEL(eintstack) ), %l7
+st0: subcc %fp, %l7, %g0
+ bg,a st3
+ sub %l7, 0xb0, %sp
+ b st3
+ sub %fp, 0xb0, %sp
+st1: sethi %hi( C_LABEL(current) ), %l6
+ ld [%l6 + %lo( C_LABEL(current) )], %l6
+ ld [%l6 + THREAD_WIM], %l5
+ and %l0, 0x1f, %l7
+ cmp %l5, %l7
+ ble,a st4
+ sethi %hi( C_LABEL(nwindowsm1) ), %l4
+ sub %l5, %l7, %l7
+ b st5
+ sub %l7, 0x1, %l5
+st4: ld [%l4 + %lo( C_LABEL(nwindowsm1) )], %l4
+ sub %l4, %l7, %l4
+ add %l5, %l4, %l5
+st5: st %l5, [%l6 + THREAD_UWINDOWS]
+ sethi %hi( C_LABEL(eintstack) ), %l7
+ bz,a st2
+ or %l7, %lo( C_LABEL(eintstack) ), %l7
+ TRAP_WIN_CLEAN
+ sethi %hi( C_LABEL(eintstack) ), %l7
+ or %l7, %lo( C_LABEL(eintstack) ), %l7
+st2: sub %l7, 0xb0, %sp
+
+st3: std %g2, [%sp + 96 + 24]
+ or %g0, %g1, %l7
+ rd %y, %l6
+ std %g4, [%sp + 96 + 32]
+ andn %l0, PSR_PIL, %l4
+ sll %l3, 0x8, %l5
+ std %g6, [%sp + 96 + 40]
+ or %l5, %l4, %l4
+
+ wr %l4, 0x0, %psr
+ wr %l4, PSR_ET, %psr
+
+ std %l0, [%sp + 96 + 0]
+ std %l2, [%sp + 96 + 8]
+ st %fp, [%sp + 96 + 16]
+
+ or %g0, 14, %o0
+ or %g0, %g0, %o1
+ call C_LABEL(do_sparc_timer)
+ nop
+
+ or %g0, %l7, %g1
+ wr %l6, 0x0, %y
+ ldd [%sp + 96 + 24], %g2
+ ldd [%sp + 96 + 32], %g4
+ ldd [%sp + 96 + 40], %g6
+ wr %l0, 0x0, %psr
+ nop
+ nop
+ nop
+
+ and %l0, 31, %l5
+ sethi %hi(lnx_winmask), %l6
+ or %l6, %lo(lnx_winmask), %l6
+ ldub [%l6 + %l5], %l5
+ andcc %l0, PSR_PS, %g0
+ bnz 1f
+ rd %wim, %l4
+
+1: andcc %l5, %l4, %g0
+ bnz 2f
+ wr %l0, 0x0, %psr
+ nop
+ nop
+ nop
+
+ jmp %l1
+ rett %l2
+
+2: wr %g0, 0x0, %wim
+ nop
+ nop
+ nop
+
+ restore
+ restore %g0, 0x1, %l1
+ rd %psr, %l0
+ and %l0, 31, %l0
+ sll %l1, %l0, %l1
+ wr %l1, 0x0, %wim
+ sethi %hi( C_LABEL(current) ), %l1
+ ld [%l1 + %lo( C_LABEL(current) ) ], %l1
+ st %l0, [%l1 + THREAD_WIM]
+ save %g0, %g0, %g0
+
+ ldd [%sp], %l0
+ ldd [%sp + 0x8], %l2
+ ldd [%sp + 0x10], %l4
+ ldd [%sp + 0x18], %l6
+ ldd [%sp + 0x20], %i0
+ ldd [%sp + 0x28], %i2
+ ldd [%sp + 0x30], %i4
+ ldd [%sp + 0x38], %i6
+
+ save %g0, %g0, %g0
+
+ jmp %l1
+ rett %l2
+
+
+/* For now all IRQ's not registered get sent here so I can see
+ * what is poking the chip.
+ */
+
+ .align 4
+ .globl stray_irq_entry
+stray_irq_entry:
+ rd %wim, %l4
+ or %g0, 0x1, %l5
+ sll %l5, %l0, %l5
+ andcc %l0, 0x40, %g0
+ bz tt1
+ sethi %hi( C_LABEL(eintstack) ), %l7
+ andcc %l4, %l5, %g0
+ bz tt0
+ or %l7, %lo( C_LABEL(eintstack) ), %l7
+ TRAP_WIN_CLEAN
+ sethi %hi( C_LABEL(eintstack) ), %l7
+ or %l7, %lo( C_LABEL(eintstack) ), %l7
+tt0: subcc %fp, %l7, %g0
+ bg,a tt3
+ sub %l7, 0xb0, %sp
+ b tt3
+ sub %fp, 0xb0, %sp
+tt1: sethi %hi( C_LABEL(current) ), %l6
+ ld [%l6 + %lo( C_LABEL(current) )], %l6
+ ld [%l6 + THREAD_WIM], %l5
+ and %l0, 0x1f, %l7
+ cmp %l5, %l7
+ ble,a tt4
+ sethi %hi( C_LABEL(nwindowsm1) ), %l4
+ sub %l5, %l7, %l7
+ b tt5
+ sub %l7, 0x1, %l5
+tt4: ld [%l4 + %lo( C_LABEL(nwindowsm1) )], %l4
+ sub %l4, %l7, %l4
+ add %l5, %l4, %l5
+tt5: st %l5, [%l6 + THREAD_UWINDOWS]
+ sethi %hi( C_LABEL(eintstack) ), %l7
+ bz,a tt2
+ or %l7, %lo( C_LABEL(eintstack) ), %l7
+ TRAP_WIN_CLEAN
+ sethi %hi( C_LABEL(eintstack) ), %l7
+ or %l7, %lo( C_LABEL(eintstack) ), %l7
+tt2: sub %l7, 0xb0, %sp
+
+tt3: std %g2, [%sp + 96 + 24]
+ or %g0, %g1, %l7
+ rd %y, %l6
+ std %g4, [%sp + 96 + 32]
+ andn %l0, PSR_PIL, %l4
+ sll %l3, 0x8, %l5
+ std %g6, [%sp + 96 + 40]
+ or %l5, %l4, %l4
+
+ wr %l4, 0x0, %psr
+ wr %l4, PSR_ET, %psr
+
+ std %l0, [%sp + 96 + 0]
+ std %l2, [%sp + 96 + 8]
+ st %fp, [%sp + 96 + 16]
+
+ or %g0, %l3, %o0
+ or %g0, %g0, %o1
+ call C_LABEL(unexpected_irq)
+ nop
+
+ or %g0, %l7, %g1
+ wr %l6, 0x0, %y
+ ldd [%sp + 96 + 24], %g2
+ ldd [%sp + 96 + 32], %g4
+ ldd [%sp + 96 + 40], %g6
+ wr %l0, 0x0, %psr
+ nop
+ nop
+ nop
+
+ and %l0, 31, %l5
+ sethi %hi(lnx_winmask), %l6
+ or %l6, %lo(lnx_winmask), %l6
+ ldub [%l6 + %l5], %l5
+ andcc %l0, PSR_PS, %g0
+ bnz 1f
+ rd %wim, %l4
+
+1: andcc %l5, %l4, %g0
+ bnz 2f
+ wr %l0, 0x0, %psr
+ nop
+ nop
+ nop
+
+ jmp %l1
+ rett %l2
+
+2: wr %g0, 0x0, %wim
+ nop
+ nop
+ nop
+
+ restore
+ restore %g0, 0x1, %l1
+ rd %psr, %l0
+ and %l0, 31, %l0
+ sll %l1, %l0, %l1
+ wr %l1, 0x0, %wim
+ sethi %hi( C_LABEL(current) ), %l1
+ ld [%l1 + %lo( C_LABEL(current) ) ], %l1
+ st %l0, [%l1 + THREAD_WIM]
+ save %g0, %g0, %g0
+
+ ldd [%sp], %l0
+ ldd [%sp + 0x8], %l2
+ ldd [%sp + 0x10], %l4
+ ldd [%sp + 0x18], %l6
+ ldd [%sp + 0x20], %i0
+ ldd [%sp + 0x28], %i2
+ ldd [%sp + 0x30], %i4
+ ldd [%sp + 0x38], %i6
+
+ save %g0, %g0, %g0
+
+ jmp %l1
+ rett %l2
+
+
+
+/* This routine is optimized for kernel window fills. User fills take about two
+ * or three extra jumps on the average. We'll see how this works out.
+ */
+
+/* Don't use local labels, or if you do be REAL CAREFUL. TRAP_WIN_CLEAN is
+ * full of them! If you think this routine is hairy, window spills are worse,
+ * see below.
+ */
+
+ .align 4
+ .globl spill_window_entry
+spill_window_entry:
+ andcc %l0, 0x40, %g0 ! see if this is a user window fill
+ bz,a spill_from_user
+ nop
+
+ TRAP_WIN_CLEAN /* danger, danger... */
+ wr %l0, 0x0, %psr
+ nop
+ jmp %l1
+ rett %l2
+
+spill_from_user:
+ sethi %hi( C_LABEL(current) ), %l6
+ ld [%l6 + %lo( C_LABEL(current) )], %l6
+ ld [%l6 + THREAD_WIM], %l5
+ and %l0, 0x1f, %l3
+
+/* I don't know what's worse, the extra comparison here, or an extra load
+ * from a lookup table, we'll see.
+ */
+ cmp %l5, %l3
+ ble,a 1f
+ sethi %hi( C_LABEL(nwindowsm1) ), %l4
+ sub %l5, %l3, %l3
+ b 2f
+ sub %l3, 0x1, %l5
+1: ld [%l4 + %lo( C_LABEL(nwindowsm1) )], %l4
+ sub %l4, %l3, %l4
+ add %l5, %l4, %l5
+2: st %l5, [%l6 + THREAD_UWINDOWS]
+
+ TRAP_WIN_CLEAN /* danger, danger... */
+ sethi %hi( C_LABEL(current) ), %l6
+ ld [%l6 + %lo( C_LABEL(current) )], %l6
+ ld [%l6 + THREAD_KSP], %sp
+ and %l0, 0x1f, %l3
+ sethi %hi(lnx_winmask), %l6
+ or %l6, %lo(lnx_winmask), %l6
+ ldub [%l6 + %l3], %l5
+ rd %wim, %l4
+ jmp %l1
+ rett %l2
+
+/* A window spill has occurred. This presents a weird situation, a restore
+ * was attempted and a trap occurred. Therefore the restore attempt had no
+ * effect on window movement and the trap saved, which means it went in the
+ * other direction. :-( We are in a trap window which is two restores away
+ * from the window we want to un-invalidate so to speak and three away from
+ * the one which will become invalid after this routine. There are probably
+ * bugs already this routine. Bugs suck.
+ */
+
+/* This is a very complicated and hairy routine, don't expect to understand
+ * it the first time. :>
+ */
+
+ .align 4
+ .globl fill_window_entry
+fill_window_entry:
+ wr %g0, 0, %wim ! Can not enter invalid register without this.
+ andcc %l0, 0x40, %g0 ! From user?
+ restore ! restore to where trap occurred
+ bz fill_from_user
+ restore ! enter invalid register, whee...
+ restore %g0, 0x1, %l1 ! enter one-past invalid register
+ rd %psr, %l0 ! this is the window we need to save
+ and %l0, 0x1f, %l0
+ sll %l1, %l0, %l1
+ wr %l1, 0x0, %wim
+ sethi %hi( C_LABEL(current) ), %l1
+ ld [%l1 + %lo( C_LABEL(current) )], %l1
+ st %l0, [%l1 + THREAD_WIM]
+ save %g0, %g0, %g0 ! back to invalid register
+ ldd [%sp], %l0 ! load the window from stack
+ ldd [%sp + 8], %l2
+ ldd [%sp + 16], %l4
+ ldd [%sp + 24], %l6
+ ldd [%sp + 32], %i0
+ ldd [%sp + 40], %i2
+ ldd [%sp + 48], %i4
+ ldd [%sp + 56], %i6
+ save %g0, %g0, %g0 ! to window where trap happened
+ save %g0, %g0, %g0 ! back to trap window, so rett works
+ wr %l0, 0x0, %psr ! load condition codes
+ nop
+ jmp %l1
+ rett %l2 ! are you as confused as I am?
+
+fill_from_user:
+ andcc %sp, 0x7, %g0 ! check for alignment of user stack
+ bne fill_bad_stack
+ sra %sp, 0x1e, %l7
+ cmp %l7, 0x0
+ be,a 1f
+ andn %sp, 0xfff, %l7
+ cmp %l7, -1
+ bne fill_bad_stack
+ andn %sp, 0xfff, %l7
+1: lda [%l7] ASI_PTE, %l7
+ srl %l7, 0x1d, %l7
+ andn %l7, 0x2, %l7
+ cmp %l7, 0x4
+ bne fill_bad_stack
+ and %sp, 0xfff, %l7
+ cmp %l7, 0xfc1
+ bl,a fill_stack_ok
+ restore %g0, 1, %l1
+ add %sp, 0x38, %l5
+ sra %sp, 0x1e, %l7
+ cmp %l7, 0x0
+ be,a 1f
+ andn %sp, 0xfff, %l7
+ cmp %l7, -1
+ bne fill_bad_stack
+ andn %sp, 0xfff, %l7
+1: lda [%l7] ASI_PTE, %l7
+ srl %l7, 0x1d, %l7
+ andn %l7, 0x2, %l7
+ cmp %l7, 0x4
+ be,a fill_stack_ok
+ restore %g0, 0x1, %l1
+
+fill_bad_stack:
+ save %g0, %g0, %g0 ! save to where restore happened
+ save %g0, 0x1, %l4 ! save is an add remember? to trap window
+ sethi %hi( C_LABEL(current) ), %l6
+ ld [%l6 + %lo( C_LABEL(current) )], %l6
+ st %l4, [%l6 + THREAD_UWINDOWS] ! update current->tss values
+ ld [%l6 + THREAD_WIM], %l5
+ sll %l4, %l5, %l4
+ wr %l4, 0x0, %wim
+ ld [%l6 + THREAD_KSP], %sp ! set to kernel stack pointer
+ wr %l0, 0x20, %psr ! turn off traps
+ std %l0, [%sp + C_STACK] ! set up thread_frame on stack
+ rd %y, %l3
+ std %l2, [%sp + C_STACK + 0x8]
+ or %g0, 0x6, %o0 ! so _sparc_trap knows what to do
+ st %g1, [%sp + C_STACK + 0x14] ! no need to save %g0, always zero
+ or %g0, %l0, %o1
+ std %g2, [%sp + C_STACK + 0x18]
+ or %g0, %l1, %o2
+ std %g4, [%sp + C_STACK + 0x20]
+ add %sp, C_STACK, %o3
+ std %g6, [%sp + C_STACK + 0x28]
+ std %i0, [%sp + C_STACK + 0x30]
+ std %i2, [%sp + C_STACK + 0x38]
+ std %i4, [%sp + C_STACK + 0x40]
+ call sparc_trap
+ std %i6, [%sp + C_STACK + 0x48]
+
+ ldd [%sp + C_STACK], %l0
+ ldd [%sp + C_STACK + 0x8], %l2
+ wr %l3, 0, %y
+ ld [%sp + C_STACK + 0x14], %g1
+ ldd [%sp + C_STACK + 0x18], %g2
+ ldd [%sp + C_STACK + 0x20], %g4
+ ldd [%sp + C_STACK + 0x28], %g6
+ ldd [%sp + C_STACK + 0x30], %i0
+ ldd [%sp + C_STACK + 0x38], %i2
+ ldd [%sp + C_STACK + 0x40], %i4
+ wr %l0, 0, %psr ! disable traps again
+ ldd [%sp + C_STACK + 0x48], %i6
+ sethi %hi( C_LABEL(current) ), %l6
+ ld [%l6 + %lo( C_LABEL(current) )], %l6
+ ld [%l6 + THREAD_W_SAVED], %l7
+ cmp %l7, 0x0
+ bl,a 1f
+ wr %g0, 0x0, %wim
+ b,a leave_trap
+
+1: or %g0, %g6, %l3
+ or %g0, %l6, %g6
+ st %g0, [%g6 + THREAD_W_SAVED]
+ restore %g0, %g0, %g0
+ restore %g0, %g0, %g0
+ restore %g0, 0x1, %l1
+ rd %psr, %l0
+ sll %l1, %l0, %l1
+ wr %l1, 0x0, %wim
+ and %l0, 0x1f, %l0
+ st %l0, [%g6 + THREAD_WIM]
+ nop
+ save %g0, %g0, %g0
+ ldd [%sp], %l0 ! load number one
+ ldd [%sp + 0x8], %l2
+ ldd [%sp + 0x10], %l4
+ ldd [%sp + 0x18], %l6
+ ldd [%sp + 0x20], %i0
+ ldd [%sp + 0x28], %i2
+ ldd [%sp + 0x30], %i4
+ ldd [%sp + 0x38], %i6
+ save %g0, %g0, %g0
+ ldd [%sp], %l0 ! load number two
+ ldd [%sp + 0x8], %l2
+ ldd [%sp + 0x10], %l4
+ ldd [%sp + 0x18], %l6
+ ldd [%sp + 0x20], %i0
+ ldd [%sp + 0x28], %i2
+ ldd [%sp + 0x30], %i4
+ ldd [%sp + 0x38], %i6
+ save %g0, %g0, %g0 ! re-enter trap window
+ wr %l0, 0x0, %psr ! restore condition codes
+ or %g0, %l3, %g6 ! restore scratch register
+ jmp %l1
+ rett %l2
+
+fill_stack_ok:
+ rd %psr, %l0
+ sll %l1, %l0, %l1
+ wr %l1, 0x0, %wim
+ sethi %hi( C_LABEL(current) ), %l2
+ ld [%l2 + %lo( C_LABEL(current) )], %l2
+ and %l0, 0x1f, %l0
+ st %l0, [%l2 + THREAD_WIM]
+ save %g0, %g0, %g0
+ ldd [%sp], %l0 ! only one load necessary
+ ldd [%sp + 0x8], %l2
+ ldd [%sp + 0x10], %l4
+ ldd [%sp + 0x18], %l6
+ ldd [%sp + 0x20], %i0
+ ldd [%sp + 0x28], %i2
+ ldd [%sp + 0x30], %i4
+ ldd [%sp + 0x38], %i6
+ save %g0, %g0, %g0
+ save %g0, %g0, %g0 ! save into trap window
+ wr %l0, 0x0, %psr ! local number 0 here has cond codes
+ nop
+ jmp %l1
+ rett %l2
+
+ .align 4
+ .globl trap_entry
+trap_entry:
+ TRAP_WIN_CLEAN
+ jmp %l1
+ rett %l2
+
+ .align 4
+ .globl linux_trap_nmi
+linux_trap_nmi:
+ TRAP_WIN_CLEAN
+ jmp %l1
+ rett %l2
+
+ .align 4
+ .globl sparc_trap
+sparc_trap:
+ TRAP_WIN_CLEAN
+ jmp %l1
+ rett %l2
+
+ .align 4
+ .globl leave_trap
+leave_trap:
+ jmp %l1
+ rett %l2
+
+/* The following two things point to window management tables. The first
+ one is used to quickly look up how many user windows there are from
+ trap-land. The second is used in a trap handler to determine if a rett
+ instruction will land us smack inside the invalid window that possibly
+ the trap was called to fix-up.
+*/
+
+/* For now these are static tables geared for a 7 window sparc. */
+
+ .data
+ .align 4
+lnx_winmask: .byte 2, 4, 8, 16, 32, 64, 128, 1 ! lnx_winmask[0..7]
+
+
+ .align 4
+ .globl C_LABEL(sys_call_table)
+C_LABEL(sys_call_table):
+ .long C_LABEL(sys_setup) /* 0 */
+ .long C_LABEL(sys_exit)
+ .long C_LABEL(sys_fork)
+ .long C_LABEL(sys_read)
+ .long C_LABEL(sys_write)
+ .long C_LABEL(sys_open) /* 5 */
+ .long C_LABEL(sys_close)
+ .long C_LABEL(sys_waitpid)
+ .long C_LABEL(sys_creat)
+ .long C_LABEL(sys_link)
+ .long C_LABEL(sys_unlink) /* 10 */
+ .long C_LABEL(sys_execve)
+ .long C_LABEL(sys_chdir)
+ .long C_LABEL(sys_time)
+ .long C_LABEL(sys_mknod)
+ .long C_LABEL(sys_chmod) /* 15 */
+ .long C_LABEL(sys_chown)
+ .long C_LABEL(sys_break)
+ .long C_LABEL(sys_stat)
+ .long C_LABEL(sys_lseek)
+ .long C_LABEL(sys_getpid) /* 20 */
+ .long C_LABEL(sys_mount)
+ .long C_LABEL(sys_umount)
+ .long C_LABEL(sys_setuid)
+ .long C_LABEL(sys_getuid)
+ .long C_LABEL(sys_stime) /* 25 */
+ .long C_LABEL(sys_ni_syscall) /* this will be sys_ptrace() */
+ .long C_LABEL(sys_alarm)
+ .long C_LABEL(sys_fstat)
+ .long C_LABEL(sys_pause)
+ .long C_LABEL(sys_utime) /* 30 */
+ .long C_LABEL(sys_stty)
+ .long C_LABEL(sys_gtty)
+ .long C_LABEL(sys_access)
+ .long C_LABEL(sys_nice)
+ .long C_LABEL(sys_ftime) /* 35 */
+ .long C_LABEL(sys_sync)
+ .long C_LABEL(sys_kill)
+ .long C_LABEL(sys_rename)
+ .long C_LABEL(sys_mkdir)
+ .long C_LABEL(sys_rmdir) /* 40 */
+ .long C_LABEL(sys_dup)
+ .long C_LABEL(sys_pipe)
+ .long C_LABEL(sys_times)
+ .long C_LABEL(sys_prof)
+ .long C_LABEL(sys_brk) /* 45 */
+ .long C_LABEL(sys_setgid)
+ .long C_LABEL(sys_getgid)
+ .long C_LABEL(sys_signal)
+ .long C_LABEL(sys_geteuid)
+ .long C_LABEL(sys_getegid) /* 50 */
+ .long C_LABEL(sys_acct)
+ .long C_LABEL(sys_phys)
+ .long C_LABEL(sys_lock)
+ .long C_LABEL(sys_ioctl)
+ .long C_LABEL(sys_fcntl) /* 55 */
+ .long C_LABEL(sys_mpx)
+ .long C_LABEL(sys_setpgid)
+ .long C_LABEL(sys_ulimit)
+ .long C_LABEL(sys_olduname)
+ .long C_LABEL(sys_umask) /* 60 */
+ .long C_LABEL(sys_chroot)
+ .long C_LABEL(sys_ustat)
+ .long C_LABEL(sys_dup2)
+ .long C_LABEL(sys_getppid)
+ .long C_LABEL(sys_getpgrp) /* 65 */
+ .long C_LABEL(sys_setsid)
+ .long C_LABEL(sys_sigaction)
+ .long C_LABEL(sys_sgetmask)
+ .long C_LABEL(sys_ssetmask)
+ .long C_LABEL(sys_setreuid) /* 70 */
+ .long C_LABEL(sys_setregid)
+ .long C_LABEL(sys_sigsuspend)
+ .long C_LABEL(sys_sigpending)
+ .long C_LABEL(sys_sethostname)
+ .long C_LABEL(sys_setrlimit) /* 75 */
+ .long C_LABEL(sys_getrlimit)
+ .long C_LABEL(sys_getrusage)
+ .long C_LABEL(sys_gettimeofday)
+ .long C_LABEL(sys_settimeofday)
+ .long C_LABEL(sys_getgroups) /* 80 */
+ .long C_LABEL(sys_setgroups)
+ .long C_LABEL(sys_select)
+ .long C_LABEL(sys_symlink)
+ .long C_LABEL(sys_lstat)
+ .long C_LABEL(sys_readlink) /* 85 */
+ .long C_LABEL(sys_uselib)
+ .long C_LABEL(sys_swapon)
+ .long C_LABEL(sys_reboot)
+ .long C_LABEL(sys_readdir)
+ .long C_LABEL(sys_mmap) /* 90 */
+ .long C_LABEL(sys_munmap)
+ .long C_LABEL(sys_truncate)
+ .long C_LABEL(sys_ftruncate)
+ .long C_LABEL(sys_fchmod)
+ .long C_LABEL(sys_fchown) /* 95 */
+ .long C_LABEL(sys_getpriority)
+ .long C_LABEL(sys_setpriority)
+ .long C_LABEL(sys_profil)
+ .long C_LABEL(sys_statfs)
+ .long C_LABEL(sys_fstatfs) /* 100 */
+ .long C_LABEL(sys_ni_syscall)
+ .long C_LABEL(sys_socketcall)
+ .long C_LABEL(sys_syslog)
+ .long C_LABEL(sys_setitimer)
+ .long C_LABEL(sys_getitimer) /* 105 */
+ .long C_LABEL(sys_newstat)
+ .long C_LABEL(sys_newlstat)
+ .long C_LABEL(sys_newfstat)
+ .long C_LABEL(sys_uname)
+ .long C_LABEL(sys_ni_syscall) /* 110 */
+ .long C_LABEL(sys_vhangup)
+ .long C_LABEL(sys_idle)
+ .long C_LABEL(sys_ni_syscall) /* was vm86, meaningless on Sparc */
+ .long C_LABEL(sys_wait4)
+ .long C_LABEL(sys_swapoff) /* 115 */
+ .long C_LABEL(sys_sysinfo)
+ .long C_LABEL(sys_ipc)
+ .long C_LABEL(sys_fsync)
+ .long C_LABEL(sys_sigreturn)
+ .long C_LABEL(sys_ni_syscall) /* 120 */
+ .long C_LABEL(sys_setdomainname)
+ .long C_LABEL(sys_newuname)
+ .long C_LABEL(sys_ni_syscall)
+ .long C_LABEL(sys_adjtimex)
+ .long C_LABEL(sys_mprotect) /* 125 */
+ .long C_LABEL(sys_sigprocmask)
+ .long C_LABEL(sys_create_module)
+ .long C_LABEL(sys_init_module)
+ .long C_LABEL(sys_delete_module)
+ .long C_LABEL(sys_get_kernel_syms) /* 130 */
+ .long C_LABEL(sys_ni_syscall)
+ .long C_LABEL(sys_getpgid)
+ .long C_LABEL(sys_fchdir)
+ .long C_LABEL(sys_bdflush)
+ .long C_LABEL(sys_sysfs) /* 135 */
+ .long C_LABEL(sys_personality)
+ .long 0 /* for afs_syscall */
+ .long C_LABEL(sys_setfsuid)
+ .long C_LABEL(sys_setfsgid)
+ .long C_LABEL(sys_llseek) /* 140 */
+ .align 4
diff --git a/arch/sparc/kernel/head.S b/arch/sparc/kernel/head.S
new file mode 100644
index 000000000..c3a5453e7
--- /dev/null
+++ b/arch/sparc/kernel/head.S
@@ -0,0 +1,1045 @@
+/* boot.S: The initial boot code for the Sparc port of Linux.
+
+ Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu)
+
+ This file has to serve three purposes.
+
+ 1) determine the prom-version and cpu/architecture
+ 2) print enough useful info before we start to execute
+ c-code that I can possibly begin to debug things
+ 3) Hold the vector of trap entry points
+
+ The Sparc offers many challenges to kernel design. Here I will
+ document those I have come across thus far. Upon bootup the boot
+ prom loads your a.out image into memory. This memory the prom has
+ already mapped for you in two places, however as far as I can tell
+ the virtual address cache is not turned on although the MMU is
+ translating things. You get loaded at 0x4000 exactly and you are
+ aliased to 0xf8004000 with the appropriate mmu entries. So, when
+ you link a boot-loadable object you want to do something like:
+
+ ld -e start -Ttext 4000 -o mykernel myobj1.o myobj2.o ....
+
+ to produce a proper image.
+
+ At boot time you are given (as far as I can tell at this time)
+ one key to figure out what machine you are one and what devices
+ are available. The prom when it loads you leaves a pointer to
+ the 'rom vector' in register %o0 right before it jumps to your
+ starting address. This is a pointer to a struct that is full of
+ pointer to functions (ie. printf, halt, reboot), pointers to
+ linked lists (ie. memory mappings), and pointer to empirical
+ constants (ie. stdin and stdout magic cookies + rom version).
+ Starting with this piece of information you can figure out
+ just about anything you want about the machine you are on.
+
+ Although I don't use it now, if you are on a Multiprocessor and
+ therefore a v3 or above prom, register %o2 at boot contains a
+ function pointer you must call before you proceed to invoke the
+ other cpu's on the machine. I have no idea what kind of magic this
+ is, give me time.
+*/
+
+#include <asm/cprefix.h>
+#include <asm/head.h>
+#include <asm/version.h>
+#include <asm/asi.h>
+#include <asm/contregs.h>
+#include <asm/psr.h>
+#include <asm/page.h>
+
+ .data
+
+/* First thing to go in the data segment is the interrupt stack. */
+
+ .globl C_LABEL(intstack)
+ .globl C_LABEL(eintstack)
+C_LABEL(intstack):
+ .skip 4 * PAGE_SIZE ! 16k = 128 128-byte stack frames
+C_LABEL(eintstack):
+
+
+
+/*
+ The following are used with the prom_vector node-ops to figure out
+ the cpu-type
+*/
+
+ .globl C_LABEL(cputyp)
+
+C_LABEL(cputyp):
+ .word 1
+
+C_LABEL(cputypval):
+ .asciz "sun4c"
+ .ascii " "
+
+ .align 4
+/*
+ * Sun people can't spell worth damn. "compatability" indeed.
+ * At least we *know* we can't spell, and use a spell-checker.
+ */
+
+/* Uh, actually Linus it is I who cannot spell. Too much murky
+ * Sparc assembly will do this to ya.
+ */
+C_LABEL(cputypvar):
+ .asciz "compatability"
+
+C_LABEL(cputypvallen) = C_LABEL(cputypvar) - C_LABEL(cputypval)
+
+/* This hold the prom-interface-version number for either v0 or v2. */
+
+ .align 4
+ .globl C_LABEL(prom_iface_vers)
+
+C_LABEL(prom_iface_vers): .skip 4
+
+/* WARNING: evil messages follow */
+
+ .align 4
+
+sun4_notsup:
+ .asciz "Sparc-Linux: sun4 support not implemented yet\n\n"
+ .align 4
+
+sun4m_notsup:
+ .asciz "Sparc-Linux: sun4m support does not exist\n\n"
+ .align 4
+
+sun4d_notsup:
+ .asciz "Sparc-Linux: sun4d support does not exist\n\n"
+ .align 4
+
+you_lose:
+ .asciz "You lose..... Thanks for playing...\n"
+ .align 4
+
+
+ .globl boot_msg
+
+/* memory descriptor property strings, v2 = yuk yuk yuk */
+/* XXX how to figure out vm mapped by prom? May have to scan magic addresses */
+
+mem_prop_physavail: .asciz "available"
+
+ .align 4
+mem_prop_phystot: .asciz "reg"
+
+/* v2_memory descriptor struct kludged here for assembly, if it ain't broke */
+
+ .align 4
+v2_mem_struct: .skip 0xff
+
+ .align 4
+v2_printf_physavail: .asciz "Physical Memory Available: 0x%x bytes"
+
+ .align 4
+v2_printf_phystot: .asciz "Physical Memory: 0x%x bytes"
+
+/* A place to store property strings returned from the prom 'node' funcs */
+
+ .align 4
+prop_string_buf: .skip 32
+
+ .align 4
+prop_name: .asciz "name"
+
+ .align 4
+current_node: .skip 4
+
+
+/* nice little boot message */
+
+ .align 4
+boot_msg:
+ .ascii "Booting Sparc-Linux V0.00PRE-ALPHA "
+ .ascii WHO_COMPILED_ME
+ .ascii "\r\n"
+ .align 4
+
+ .globl boot_msg2
+
+boot_msg2:
+ .asciz "Booting Sparclinux V0.00 PRE-ALPHA on a (SUN4C)\r\n\n"
+
+ .align 4
+
+pstring1:
+ .asciz "Prom Magic Cookie: 0x%x \n"
+ .align 4
+
+pstring2:
+ .asciz "Interface Version: v%d\n"
+ .align 4
+
+pstring3:
+ .asciz "Prom Revision: V%d\n\n"
+ .align 4
+
+pstring4:
+ .ascii "Total Physical Memory: %d bytes\nVM mapped by Prom: %d bytes\n"
+ .asciz "Available Physical Memory: %d bytes\n"
+ .align 4
+
+
+ .text
+
+ .globl C_LABEL(msgbuf)
+msgbufsize = PAGE_SIZE ! 1 page for msg buffer
+C_LABEL(msgbuf) = PAGE_SIZE
+
+
+IE_reg_addr = C_LABEL(msgbuf) + msgbufsize ! this page not used; points to IEreg
+
+
+/* Ok, things start to get interesting. We get linked such that 'start'
+ is the entry symbol. However, it is real low in kernel address space
+ and as such a nifty place to place the trap table. We achieve this goal
+ by just jumping to 'gokernel' for the first trap's entry as the sparc
+ never receives the zero trap as it is real special (hw reset).
+
+ Each trap entry point is the size of 4 sparc instructions (or 4 bytes
+ * 4 insns = 16 bytes). There are 128 hardware traps (some undefined
+ or unimplemented) and 128 software traps (sys-calls, etc.).
+
+ One of the instructions must be a branch. More often than not this
+ will be to a trap handler entry point because it is completely
+ impossible to handle any trap in 4 insns. I welcome anyone to
+ challenge this theory. :-)
+
+ On entry into this table the hardware has loaded the program counter
+ at which the trap occurred into register %l1 and the next program
+ counter into %l2, this way we can return from the trap with a simple
+
+ jmp %l1; rett %l2 ! poof...
+
+ after properly servicing the trap. It wouldn't be a bad idea to load
+ some more information into the local regs since we have technically
+ 2 or 3 instructions to play with besides the jmp to the 'real' trap
+ handler (one can even go in the delay slot). For now I am going to put
+ the %psr (processor status register) and the trap-type value in %l0
+ and %l3 respectively. Also, for IRQ's I'll put the level in %l4.
+
+*/
+
+ .globl start
+ .globl _start /* warning, solaris hack */
+ .globl C_LABEL(trapbase)
+_start: /* danger danger */
+start:
+C_LABEL(trapbase):
+ b gokernel; nop; nop; nop; ! we never get trap #0 it is special
+
+ TRAP_ENTRY(0x1, my_trap_handler) /* Instruction Access Exception */
+ TRAP_ENTRY(0x2, my_trap_handler) /* Illegal Instruction */
+ TRAP_ENTRY(0x3, my_trap_handler) /* Privileged Instruction */
+ TRAP_ENTRY(0x4, my_trap_handler) /* Floating Point Disabled */
+ TRAP_ENTRY(0x5, spill_window_entry) /* Window Overflow */
+ TRAP_ENTRY(0x6, fill_window_entry) /* Window Underflow */
+ TRAP_ENTRY(0x7, my_trap_handler) /* Memory Address Not Aligned */
+ TRAP_ENTRY(0x8, my_trap_handler) /* Floating Point Exception */
+ TRAP_ENTRY(0x9, my_trap_handler) /* Data Miss Exception */
+ TRAP_ENTRY(0xa, my_trap_handler) /* Tagged Instruction Overflow */
+ TRAP_ENTRY(0xb, my_trap_handler) /* Watchpoint Detected */
+ TRAP_ENTRY(0xc, my_trap_handler) /* Undefined... */
+ TRAP_ENTRY(0xd, my_trap_handler) /* Undefined... */
+ TRAP_ENTRY(0xe, my_trap_handler) /* Undefined... */
+ TRAP_ENTRY(0xf, my_trap_handler) /* Undefined... */
+ TRAP_ENTRY(0x10, my_trap_handler) /* Undefined... */
+
+/* Level'd interrupt entry points, see macro defs above */
+
+ TRAP_ENTRY_INTERRUPT_SOFT(1, 0x101) /* IRQ Software/SBUS Level 1 */
+ TRAP_ENTRY_INTERRUPT(2) /* IRQ SBUS Level 2 */
+ TRAP_ENTRY_INTERRUPT(3) /* IRQ SCSI/DMA/SBUS Level 3 */
+ TRAP_ENTRY_INTERRUPT_SOFT(4, 0x104) /* IRQ Software Level 4 */
+ TRAP_ENTRY_INTERRUPT(5) /* IRQ SBUS/Ethernet Level 5 */
+ TRAP_ENTRY_INTERRUPT_SOFT(6, 0x106) /* IRQ Software Level 6 */
+ TRAP_ENTRY_INTERRUPT(7) /* IRQ Video/SBUS Level 5 */
+ TRAP_ENTRY_INTERRUPT(8) /* IRQ SBUS Level 6 */
+ TRAP_ENTRY_INTERRUPT(9) /* IRQ SBUS Level 7 */
+ TRAP_ENTRY_INTERRUPT(10) /* IRQ Timer #1 */
+ TRAP_ENTRY_INTERRUPT(11) /* IRQ Floppy Intr. */
+ TRAP_ENTRY_INTERRUPT(12) /* IRQ Zilog serial chip */
+ TRAP_ENTRY_INTERRUPT(13) /* IRQ Audio Intr. */
+ TRAP_ENTRY_TIMER /* IRQ Timer #2 (one we use) */
+ TRAP_ENTRY_INTERRUPT_NMI(15, linux_trap_nmi) /* Level 15 (nmi) */
+
+ TRAP_ENTRY(0x20, my_trap_handler) /* General Register Access Error */
+ TRAP_ENTRY(0x21, my_trap_handler) /* Instruction Access Error */
+ TRAP_ENTRY(0x22, my_trap_handler) /* Undefined... */
+ TRAP_ENTRY(0x23, my_trap_handler) /* Undefined... */
+ TRAP_ENTRY(0x24, my_trap_handler) /* Co-Processor Disabled */
+ TRAP_ENTRY(0x25, my_trap_handler) /* Unimplemented FLUSH inst. */
+ TRAP_ENTRY(0x26, my_trap_handler) /* Undefined... */
+ TRAP_ENTRY(0x27, my_trap_handler) /* Undefined... */
+ TRAP_ENTRY(0x28, my_trap_handler) /* Co-Processor Exception */
+ TRAP_ENTRY(0x29, my_trap_handler) /* Data Access Error */
+ TRAP_ENTRY(0x2a, my_trap_handler) /* Division by zero, you lose... */
+ TRAP_ENTRY(0x2b, my_trap_handler) /* Data Store Error */
+ TRAP_ENTRY(0x2c, my_trap_handler) /* Data Access MMU-Miss */
+ TRAP_ENTRY(0x2d, my_trap_handler) /* Undefined... */
+ TRAP_ENTRY(0x2e, my_trap_handler) /* Undefined... */
+ TRAP_ENTRY(0x2f, my_trap_handler) /* Undefined... */
+ TRAP_ENTRY(0x30, my_trap_handler) /* Undefined... */
+ TRAP_ENTRY(0x31, my_trap_handler) /* Undefined... */
+ TRAP_ENTRY(0x32, my_trap_handler) /* Undefined... */
+ TRAP_ENTRY(0x33, my_trap_handler) /* Undefined... */
+ TRAP_ENTRY(0x34, my_trap_handler) /* Undefined... */
+ TRAP_ENTRY(0x35, my_trap_handler) /* Undefined... */
+ TRAP_ENTRY(0x36, my_trap_handler) /* Undefined... */
+ TRAP_ENTRY(0x37, my_trap_handler) /* Undefined... */
+ TRAP_ENTRY(0x38, my_trap_handler) /* Undefined... */
+ TRAP_ENTRY(0x39, my_trap_handler) /* Undefined... */
+ TRAP_ENTRY(0x3a, my_trap_handler) /* Undefined... */
+ TRAP_ENTRY(0x3b, my_trap_handler) /* Undefined... */
+ TRAP_ENTRY(0x3c, my_trap_handler) /* Instruction Access MMU-Miss */
+ TRAP_ENTRY(0x3d, my_trap_handler) /* Undefined... */
+ TRAP_ENTRY(0x3e, my_trap_handler) /* Undefined... */
+ TRAP_ENTRY(0x3f, my_trap_handler) /* Undefined... */
+ TRAP_ENTRY(0x40, my_trap_handler) /* Undefined... */
+ TRAP_ENTRY(0x41, my_trap_handler) /* Undefined... */
+ TRAP_ENTRY(0x42, my_trap_handler) /* Undefined... */
+ TRAP_ENTRY(0x43, my_trap_handler) /* Undefined... */
+ TRAP_ENTRY(0x44, my_trap_handler) /* Undefined... */
+ TRAP_ENTRY(0x45, my_trap_handler) /* Undefined... */
+ TRAP_ENTRY(0x46, my_trap_handler) /* Undefined... */
+ TRAP_ENTRY(0x47, my_trap_handler) /* Undefined... */
+ TRAP_ENTRY(0x48, my_trap_handler) /* Undefined... */
+ TRAP_ENTRY(0x49, my_trap_handler) /* Undefined... */
+ TRAP_ENTRY(0x4a, my_trap_handler) /* Undefined... */
+ TRAP_ENTRY(0x4b, my_trap_handler) /* Undefined... */
+ TRAP_ENTRY(0x4c, my_trap_handler) /* Undefined... */
+ TRAP_ENTRY(0x4d, my_trap_handler) /* Undefined... */
+ TRAP_ENTRY(0x4e, my_trap_handler) /* Undefined... */
+ TRAP_ENTRY(0x4f, my_trap_handler) /* Undefined... */
+ TRAP_ENTRY(0x50, my_trap_handler) /* Undefined... */
+ TRAP_ENTRY(0x51, my_trap_handler) /* Undefined... */
+ TRAP_ENTRY(0x52, my_trap_handler) /* Undefined... */
+ TRAP_ENTRY(0x53, my_trap_handler) /* Undefined... */
+ TRAP_ENTRY(0x54, my_trap_handler) /* Undefined... */
+ TRAP_ENTRY(0x55, my_trap_handler) /* Undefined... */
+ TRAP_ENTRY(0x56, my_trap_handler) /* Undefined... */
+ TRAP_ENTRY(0x57, my_trap_handler) /* Undefined... */
+ TRAP_ENTRY(0x58, my_trap_handler) /* Undefined... */
+ TRAP_ENTRY(0x59, my_trap_handler) /* Undefined... */
+ TRAP_ENTRY(0x5a, my_trap_handler) /* Undefined... */
+ TRAP_ENTRY(0x5b, my_trap_handler) /* Undefined... */
+ TRAP_ENTRY(0x5c, my_trap_handler) /* Undefined... */
+ TRAP_ENTRY(0x5d, my_trap_handler) /* Undefined... */
+ TRAP_ENTRY(0x5e, my_trap_handler) /* Undefined... */
+ TRAP_ENTRY(0x5f, my_trap_handler) /* Undefined... */
+ TRAP_ENTRY(0x60, my_trap_handler) /* Impl-Dep Exception */
+ TRAP_ENTRY(0x61, my_trap_handler) /* Impl-Dep Exception */
+ TRAP_ENTRY(0x62, my_trap_handler) /* Impl-Dep Exception */
+ TRAP_ENTRY(0x63, my_trap_handler) /* Impl-Dep Exception */
+ TRAP_ENTRY(0x64, my_trap_handler) /* Impl-Dep Exception */
+ TRAP_ENTRY(0x65, my_trap_handler) /* Impl-Dep Exception */
+ TRAP_ENTRY(0x66, my_trap_handler) /* Impl-Dep Exception */
+ TRAP_ENTRY(0x67, my_trap_handler) /* Impl-Dep Exception */
+ TRAP_ENTRY(0x68, my_trap_handler) /* Impl-Dep Exception */
+ TRAP_ENTRY(0x69, my_trap_handler) /* Impl-Dep Exception */
+ TRAP_ENTRY(0x6a, my_trap_handler) /* Impl-Dep Exception */
+ TRAP_ENTRY(0x6b, my_trap_handler) /* Impl-Dep Exception */
+ TRAP_ENTRY(0x6c, my_trap_handler) /* Impl-Dep Exception */
+ TRAP_ENTRY(0x6d, my_trap_handler) /* Impl-Dep Exception */
+ TRAP_ENTRY(0x6e, my_trap_handler) /* Impl-Dep Exception */
+ TRAP_ENTRY(0x6f, my_trap_handler) /* Impl-Dep Exception */
+ TRAP_ENTRY(0x70, my_trap_handler) /* Impl-Dep Exception */
+ TRAP_ENTRY(0x71, my_trap_handler) /* Impl-Dep Exception */
+ TRAP_ENTRY(0x72, my_trap_handler) /* Impl-Dep Exception */
+ TRAP_ENTRY(0x73, my_trap_handler) /* Impl-Dep Exception */
+ TRAP_ENTRY(0x74, my_trap_handler) /* Impl-Dep Exception */
+ TRAP_ENTRY(0x75, my_trap_handler) /* Impl-Dep Exception */
+ TRAP_ENTRY(0x76, my_trap_handler) /* Impl-Dep Exception */
+ TRAP_ENTRY(0x77, my_trap_handler) /* Impl-Dep Exception */
+ TRAP_ENTRY(0x78, my_trap_handler) /* Impl-Dep Exception */
+ TRAP_ENTRY(0x79, my_trap_handler) /* Impl-Dep Exception */
+ TRAP_ENTRY(0x7a, my_trap_handler) /* Impl-Dep Exception */
+ TRAP_ENTRY(0x7b, my_trap_handler) /* Impl-Dep Exception */
+ TRAP_ENTRY(0x7c, my_trap_handler) /* Impl-Dep Exception */
+ TRAP_ENTRY(0x7d, my_trap_handler) /* Impl-Dep Exception */
+ TRAP_ENTRY(0x7e, my_trap_handler) /* Impl-Dep Exception */
+ TRAP_ENTRY(0x7f, my_trap_handler) /* Impl-Dep Exception */
+ TRAP_ENTRY(0x80, my_trap_handler) /* SunOS System Call */
+ TRAP_ENTRY(0x81, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0x82, my_trap_handler) /* Divide by zero trap XXX */
+ TRAP_ENTRY(0x83, my_trap_handler) /* Flush Windows Trap XXX */
+ TRAP_ENTRY(0x84, my_trap_handler) /* Clean Windows Trap XXX */
+ TRAP_ENTRY(0x85, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0x86, my_trap_handler) /* Fix Unaligned Access Trap XXX */
+ TRAP_ENTRY(0x87, my_trap_handler) /* Integer Overflow Trap XXX */
+ TRAP_ENTRY(0x88, my_trap_handler) /* Slowaris System Call */
+ TRAP_ENTRY(0x89, my_trap_handler) /* NetBSD System Call */
+ TRAP_ENTRY(0x8a, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0x8b, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0x8c, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0x8d, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0x8e, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0x8f, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0x90, my_trap_handler) /* SparcLinux System Call */
+ TRAP_ENTRY(0x91, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0x92, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0x93, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0x94, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0x95, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0x96, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0x97, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0x98, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0x99, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0x9a, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0x9b, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0x9c, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0x9d, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0x9e, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0x9f, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xa0, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xa1, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xa2, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xa3, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xa4, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xa5, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xa6, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xa7, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xa8, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xa9, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xaa, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xab, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xac, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xad, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xae, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xaf, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xb0, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xb1, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xb2, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xb3, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xb4, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xb5, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xb6, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xb7, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xb8, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xb9, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xba, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xbb, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xbc, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xbd, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xbe, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xbf, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xc0, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xc1, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xc2, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xc3, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xc4, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xc5, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xc6, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xc7, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xc8, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xc9, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xca, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xcb, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xcc, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xcd, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xce, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xcf, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xd0, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xd1, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xd2, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xd3, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xd4, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xd5, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xd6, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xd7, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xd8, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xd9, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xda, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xdb, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xdc, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xdd, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xde, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xdf, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xe0, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xe1, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xe2, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xe3, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xe4, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xe5, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xe6, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xe7, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xe8, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xe9, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xea, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xeb, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xec, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xed, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xee, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xef, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xf0, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xf1, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xf2, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xf3, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xf4, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xf5, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xf6, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xf7, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xf8, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xf9, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xfa, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xfb, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xfc, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xfd, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xfe, my_trap_handler) /* Software Trap */
+ TRAP_ENTRY(0xff, my_trap_handler) /* Software Trap */
+
+ .skip 4096
+
+C_LABEL(msgbufmapped):
+ .word 1
+
+
+
+/* Cool, here we go. Pick up the romvec pointer in %o0 and stash it in
+ %g7 and at _prom_vector_p. And also quickly check whether we are on
+ a v0 or v2 prom.
+*/
+
+gokernel: or %g0, %o0, %g7
+ sethi %hi( C_LABEL(prom_vector_p) ), %g1
+ st %o0, [%g1 + %lo( C_LABEL(prom_vector_p) )] ! we will need it later
+ rd %psr, %l2
+ rd %wim, %l3
+ rd %tbr, %l4
+ or %g0, %o2, %l5 ! could be prom magic value...
+
+#if 0 /* You think I'm nutz? */
+ subcc %l5, 0x0, %g0 ! check for magic SMP pointer
+ bne nosmp
+ nop
+ call %o2 ! call smp prom setup
+ nop
+#endif /* I will be soon... */
+
+/* Acquire boot time privileged register values, this will help debugging.
+ * I figure out and store nwindows later on.
+ */
+
+nosmp: sethi %hi( C_LABEL(boot_psr) ), %l1
+ st %l2, [%l1 + %lo( C_LABEL(boot_psr) )]
+ sethi %hi( C_LABEL(boot_wim) ), %l1
+ st %l3, [%l1 + %lo( C_LABEL(boot_wim) )]
+ sethi %hi( C_LABEL(boot_tbr) ), %l1
+ st %l4, [%l1 + %lo( C_LABEL(boot_tbr) )]
+ sethi %hi( C_LABEL(boot_smp_ptr) ), %l1
+ st %l5, [%l1 + %lo( C_LABEL(boot_smp_ptr) )]
+
+ or %g0, %o0, %g7
+ sethi %hi( C_LABEL(prom_vector_p) ), %g5
+ st %o0, [%g5 + %lo( C_LABEL(prom_vector_p) )] ! we will need it later
+
+ ld [%g7 + 0x4], %o3
+ subcc %o3, 0x2, %g0 ! a v2 prom?
+ be found_v2
+ nop
+
+ /* paul@sfe.com.au */
+ subcc %o3, 0x3, %g0 ! a v3 prom?
+ or %g0, 0x3, %o5
+ sethi %hi(C_LABEL(prom_iface_vers) ), %g1
+ st %o5, [%g1 + %lo( C_LABEL(prom_iface_vers) )]
+ be not_v2
+ nop
+
+
+/* Old sun4's pass our load address into %o0 instead of the prom
+ pointer. On sun4's you have to hard code the romvec pointer into
+ your code. Sun probably still does that because they don't even
+ trust their own "OpenBoot" specifications.
+*/
+
+ sethi %hi(LOAD_ADDR), %g6
+ subcc %o0, %g6, %g0 ! an old sun4?
+ be no_sun4_here
+ nop
+
+ sethi %hi( C_LABEL(prom_iface_vers) ), %g1
+ st %g0, [%g1 + %lo( C_LABEL(prom_iface_vers) )]
+ b not_v2
+ nop
+
+found_v2:
+ or %g0, 0x2, %o5
+ sethi %hi( C_LABEL(prom_iface_vers) ), %g1
+ st %o5, [%g1 + %lo( C_LABEL(prom_iface_vers) )]
+
+not_v2:
+
+/* Get the machine type via the mysterious romvec node operations.
+ * Here we can find out whether we are on a sun4 sun4c, sun4m, or
+ * a sun4m. The "nodes" are set up as a bunch of n-ary trees which
+ * you can traverse to get information about devices and such. The
+ * information acquisition happens via the node-ops which are defined
+ * in the linux_openprom.h header file. Of particular interest is the
+ * 'nextnode(int node)' function as it does the smart thing when
+ * presented with a value of '0', it gives you the first node in the
+ * tree. These node integers probably offset into some internal prom
+ * pointer table the openboot has. It's completely undocumented, so
+ * I'm not about to go sifting through the prom address space, but may
+ * do so if I get suspicious enough. :-)
+ */
+
+ or %g0, %g7, %l1
+ add %l1, 0x1c, %l1
+ ld [%l1], %l0
+ ld [%l0], %l0
+ call %l0
+ or %g0, %g0, %o0 ! next_node(0) = first_node
+
+ sethi %hi( C_LABEL(cputypvar) ), %o1 ! first node has cpu-arch
+ or %o1, %lo( C_LABEL(cputypvar) ), %o1
+ sethi %hi( C_LABEL(cputypval) ), %o2 ! information, the string
+ or %o2, %lo( C_LABEL(cputypval) ), %o2
+ ld [%l1], %l0 ! 'compatibility' tells
+ ld [%l0 + 0xc], %l0 ! that we want 'sun4x' where
+ call %l0 ! x is one of '', 'c', 'm',
+ nop ! 'd' or 'e'. %o2 holds pointer
+ ! to a buf where above string
+ ! will get stored by the prom.
+
+ sethi %hi( C_LABEL(cputypval) ), %o2 ! better safe than sorry
+ or %o2, %lo( C_LABEL(cputypval) ), %o2
+ ldub [%o2 + 0x4], %o0
+ subcc %o0, 'c', %g0 ! we already know we are not
+ be is_sun4c ! on a plain sun4 because of
+ nop ! the check for 0x4000 in %o0
+ subcc %o0, 'm', %g0 ! at start:
+ be is_sun4m
+ nop
+ b no_sun4d_here ! god bless the person who
+ nop ! tried to run this on sun4d
+
+is_sun4m:
+is_sun4c: ! OK, this is a sun4c, yippie
+ or %g0, %g7, %g6 ! load up the promvec offsets
+ sethi %hi(prom_magic), %g5 ! magic mushroom :>
+ st %g6, [%g5 + %lo(prom_magic)]
+ add %g7, 0x4, %g6
+ sethi %hi(prom_rom_vers), %g5
+ st %g6, [%g5 + %lo(prom_rom_vers)]
+ add %g7, 0x8, %g6
+ sethi %hi(prom_pluginvers), %g5
+ st %g6, [%g5 + %lo(prom_pluginvers)]
+ add %g7, 0xc, %g6
+ sethi %hi(prom_revision), %g5
+ st %g6, [%g5 + %lo(prom_revision)]
+ add %g7, 0x10, %g6
+ sethi %hi(prom_v0mem_desc), %g5
+ st %g6, [%g5 + %lo(prom_v0mem_desc)]
+ add %g7, 0x1c, %g6
+ sethi %hi(prom_nodefuncs), %g5
+ st %g6, [%g5 + %lo(prom_nodefuncs)]
+ add %g7, 0x68, %g6
+ sethi %hi(prom_printf), %g5
+ st %g6, [%g5 + %lo(prom_printf)]
+ add %g7, 0x6c, %g6
+ sethi %hi(prom_abort), %g5
+ st %g6, [%g5 + %lo(prom_abort)]
+ add %g7, 0x74, %g6
+ sethi %hi(prom_halt), %g5
+ st %g6, [%g5 + %lo(prom_halt)]
+ add %g7, 0x78, %g6
+ sethi %hi(prom_sync), %g5
+ st %g6, [%g5 + %lo(prom_sync)]
+ add %g7, 0x7c, %g6
+ sethi %hi(prom_eval), %g5
+ st %g6, [%g5 + %lo(prom_eval)]
+ add %g7, 0x80, %g6
+ sethi %hi(prom_v0bootline), %g6
+ st %g6, [%g5 + %lo(prom_v0bootline)]
+
+
+/* That was easy, now lets try to print some message on the screen.
+ * We don't have to worry about bad address translations when the prom
+ * addresses our pointers because our pointers are at 0x0-kern_size
+ * as the prom expects.
+ */
+
+/* paul@sfe.com.au */
+/* V3 doesn't have printf.. And I don't really feel like doing the formatting
+ * myself.. So we miss out on some messages (for now).
+ */
+ ld [%g7 + 0x4], %o0
+ subcc %o3, 0x3, %g0
+ be v3_bootmsg
+ nop
+
+ sethi %hi(boot_msg), %o0
+ or %o0, %lo(boot_msg), %o0
+ sethi %hi(prom_printf), %o1
+ ld [%o1 + %lo(prom_printf)], %o1
+ ld [%o1], %o1
+ call %o1 ! print boot message #1
+ nop
+
+ sethi %hi(pstring1), %o0
+ or %o0, %lo(pstring1), %o0
+ sethi %hi(prom_printf), %o2
+ ld [%o2 + %lo(prom_printf)], %o2
+ ld [%o2], %o2
+ sethi %hi(prom_magic), %o1
+ ld [%o1 + %lo(prom_magic)], %o1
+ ld [%o1], %o1
+ call %o2
+ nop
+
+ sethi %hi(pstring2), %o0
+ or %o0, %lo(pstring2), %o0
+ sethi %hi(prom_printf), %o2
+ ld [%o2 + %lo(prom_printf)], %o2
+ ld [%o2], %o2
+ sethi %hi( C_LABEL(prom_iface_vers) ), %o1
+ ld [%o1 + %lo( C_LABEL(prom_iface_vers) )], %o1
+ ld [%o1], %o1
+ call %o2
+ nop
+
+ b rest_of_boot
+ nop
+
+v3_bootmsg:
+ ld [%g7 + 0x94], %o0
+ ld [%o0], %o0
+ sethi %hi(boot_msg), %o1
+ or %o1, %lo(boot_msg), %o1
+ mov BOOT_MSG_LEN, %o2
+ ld [%g7 + 0xb8], %o4
+ call %o4
+ nop
+
+ ld [%g7 + 0x94], %o0
+ ld [%o0], %o0
+ sethi %hi(boot_msg2), %o1
+ or %o1, %lo(boot_msg2), %o1
+ mov BOOT_MSG2_LEN, %o2
+ ld [%g7 + 0xb8], %o4
+ call %o4
+ nop
+ b rest_of_boot
+ nop
+
+
+no_sun4_here:
+ ld [%g7 + 0x68], %o1
+ set sun4_notsup, %o0
+ call %o1
+ nop
+
+rest_of_boot:
+ or %g0, PAGE_SHIFT, %g5
+
+ sethi %hi(AC_CONTEXT), %g1 ! kernel context, safe now
+ ! the only valid context
+ ! until we call paging_init()
+ stba %g0, [%g1] ASI_CONTROL
+
+
+/* I make the kernel image sit in memory relative to 0x0 with the text
+ * starting at 0x4000. Now it looks like the way memory is set in Linux
+ * on an ix86.
+ */
+
+/* Uh, oh, interrupt time. This crap is real confusing. What I want to do is
+ * clear all interrupts, map the interrupt enable register which in effect
+ * enables non-maskable interrupts (or NMI's). Actually we take no interrupts
+ * until we frob with the %tbr (trap base register) which the prom has set
+ * to all its routines which allows some sanity during bootup.
+ */
+
+ sethi %hi(IE_reg_addr), %l0
+ or %l0, %lo(IE_reg_addr), %l0
+
+ set 0xf4000000, %l3
+ sethi %hi(INT_ENABLE_REG_PHYSADR), %l2
+ or %l2, %lo(INT_ENABLE_REG_PHYSADR), %l2
+ srl %l2, %g5, %l2
+ or %l2, %l3, %l1
+
+#ifndef CONFIG_SRMMU
+ sta %l1, [%l0] ASI_PTE
+#endif
+
+ or %g0, 0x1, %l1
+ stb %l1, [%l0]
+
+
+/* Aieee, now set PC and nPC, enable traps, give ourselves a stack and it's
+ * show-time!
+ */
+
+ sethi %hi(1f), %g1
+ or %g1, %lo(1f), %g1
+ jmp %g1
+ nop
+
+ .align 4
+1: sethi %hi( C_LABEL(cputyp) ), %o0
+ st %g4, [%o0 + %lo( C_LABEL(cputyp) )]
+
+ sethi %hi( C_LABEL(pgshift) ), %o0
+ st %g5, [%o0 + %lo( C_LABEL(pgshift) )]
+
+ mov 1, %o0
+ sll %o0, %g5, %g5
+ sethi %hi( C_LABEL(nbpg) ), %o0
+ st %g5, [%o0 + %lo( C_LABEL(nbpg) )]
+
+ sub %g5, 1, %g5
+ sethi %hi( C_LABEL(pgofset) ), %o0
+ st %g5, [%o0 + %lo( C_LABEL(pgofset) )]
+
+
+ rd %psr, %g3
+ andn %g3, PSR_ET, %g3
+ wr %g3, 0x0, %psr ! make sure traps are off
+ ! before we play around
+ WRITE_PAUSE ! no guarantees until 3 insns
+
+
+ wr %g0, 0x0, %wim ! magical invalid window reg
+ WRITE_PAUSE ! see above
+
+/* I keep the timer interrupt on so that BogoMIPS works and the prom
+ * keeps updating its "jiffies" counter. 100HZ clock on sparcstations.
+ */
+
+/* If gas wasn't so dumb, I could use or'd macros in this next
+ * write. ;-( like this (PSR_PS | PSR_S | PSR_PIL)...
+ */
+
+ sethi %hi(PSR_PS | PSR_S | PSR_PIL | PSR_EF), %g2
+ or %g2, %lo(PSR_PS | PSR_S | PSR_PIL | PSR_EF), %g2
+ wr %g2, 0x0, %psr
+ WRITE_PAUSE
+
+ wr %g0, 0x2, %wim ! window 1 invalid
+ WRITE_PAUSE
+
+ or %g0, 0x1, %g1
+ sethi %hi( C_LABEL(current) + THREAD_WIM), %g2
+ st %g1, [%g2 + %lo( C_LABEL(current) + THREAD_WIM)]
+
+/* I want a kernel stack NOW! */
+
+ set ( C_LABEL(init_user_stack) + 4092 - 96 - 80), %fp
+ set ( C_LABEL(init_user_stack) + 4092), %sp
+
+/* now out stack is set up similarly to the way it is on the i386 */
+
+ rd %psr, %l0
+ wr %l0, PSR_ET, %psr
+ WRITE_PAUSE
+
+/*
+ * Maybe the prom zeroes out our BSS section, maybe it doesn't. I certainly
+ * don't know, do you?
+ */
+
+ set C_LABEL(edata) , %o0
+ set C_LABEL(end) , %o1
+ sub %o1, %o0, %g2
+ sethi %hi( C_LABEL(kernel_bss_len) ), %g3
+ st %g2, [%g3 + %lo( C_LABEL(kernel_bss_len) )]
+ sethi %hi( C_LABEL(trapbase) ), %g3
+ or %g3, %lo( C_LABEL(trapbase) ), %g3
+ sethi %hi( C_LABEL(etext) ), %g4
+ or %g4, %lo( C_LABEL(etext) ), %g4
+ sub %g4, %g3, %g2
+ sethi %hi( C_LABEL(kernel_text_len) ), %g3
+ st %g2, [%g3 + %lo( C_LABEL(kernel_text_len) )]
+ sethi %hi( C_LABEL(etext) ), %g4
+ or %g4, %lo( C_LABEL(etext) ), %g4
+ sethi %hi( C_LABEL(edata) ), %g3
+ or %g3, %lo( C_LABEL(edata) ), %g3
+ sub %g3, %g4, %g2
+ sethi %hi( C_LABEL(kernel_data_len) ), %g3
+ st %g2, [%g3 + %lo( C_LABEL(kernel_data_len) )]
+ or %g0, %g0, %g1
+
+1:
+ st %g0, [%o0]
+ add %o0, 0x4, %o0
+ subcc %o0, %o1, %g0
+ bl 1b
+ nop
+
+/* Compute NWINDOWS and stash it away. Now uses %wim trick explained
+ * in the V8 manual. Ok, this method seems to work, sparc is cool...
+ */
+
+ sethi %hi(0xffffffff), %g1
+ rd %wim, %g2 ! save current value
+ or %g1, %lo(0xffffffff), %g1
+ wr %g1, 0x0, %wim
+ rd %wim, %g1 ! get remaining mask
+ wr %g2, 0x0, %wim ! restore old value
+ WRITE_PAUSE
+
+ or %g0, 0x0, %g3
+
+1: srl %g1, 0x1, %g1 ! shift until highest
+ subcc %g1, 0x0, %g0 ! bit set
+ bne 1b
+ add %g3, 0x1, %g3
+ sethi %hi( C_LABEL(nwindows) ), %g4
+ st %g3, [%g4 + %lo( C_LABEL(nwindows) )] ! store final value
+ sub %g3, 0x1, %g3
+ sethi %hi( C_LABEL(nwindowsm1) ), %g4
+ st %g3, [%g4 + %lo( C_LABEL(nwindowsm1) )]
+
+
+/* Here we go */
+
+#ifndef CONFIG_SUN4M
+ /* paul@sfe.com.au */
+ /* Look into traps later :( */
+ set C_LABEL(trapbase), %g3
+ wr %g3, 0x0, %tbr
+ WRITE_PAUSE
+#endif
+
+
+/* First we call init_prom() to set up romvec, then off to start_kernel() */
+/* XXX put this in arch_init() */
+
+ sethi %hi( C_LABEL(prom_vector_p) ), %g5
+ call C_LABEL(init_prom)
+ ld [%g5 + %lo( C_LABEL(prom_vector_p) )], %o0 /* delay slot */
+
+ call C_LABEL(start_kernel)
+ nop
+
+ call halt_me
+ nop
+
+/* There, happy now adrian? */
+
+no_sun4d_here:
+ ld [%g7 + 0x68], %o1
+ set sun4d_notsup, %o0
+ call %o1
+ nop
+ b halt_me
+ nop
+
+halt_me:
+ ld [%g7 + 0x74], %o0
+ call %o0 ! get us out of here...
+ nop ! apparently solaris is better
+
+ .data
+ .align 4
+
+/*
+ * Fill up the prom vector, note in particular the kind first element,
+ * no joke. I don't need all of them in here as the entire prom vector
+ * gets initialized in c-code so all routines can use it.
+ */
+
+ .globl C_LABEL(prom_vector_p)
+
+C_LABEL(prom_vector_p): .skip 4
+prom_magic: .skip 4 ! magic mushroom, beware...
+prom_rom_vers: .skip 4 ! interface version (v0 or v2)
+prom_pluginvers: .skip 4 ! XXX help help help ???
+prom_revision: .skip 4 ! PROM revision (ie. 1.4)
+prom_halt: .skip 4 ! void halt(void) solaris friend
+prom_eval: .skip 4 ! void eval(int len, char* string)
+prom_v0bootline: .skip 4 ! boot command line
+prom_v0mem_desc: .skip 4 ! V0 memory descriptor list ptr.
+prom_nodefuncs: .skip 4 ! Magical Node functions
+prom_printf: .skip 4 ! minimal printf()
+
+/* The prom_abort pointer MUST be mapped in all contexts, because if you
+ * don't then if a user process is running when you press the abort key
+ * sequence, all sorts of bad things can happen
+ */
+
+prom_abort: .skip 4 ! L1-A magic cookie
+ ! must be mapped in ALL contexts
+
+/* prom_sync is a place where the kernel should place a pointer to a kernel
+ * function that when called will sync all pending information to the drives
+ * and then promptly return. If the kernel gets aborted with 'L1-A' one can
+ * give the 'sync' command to the boot prompt and this magic cookie gets
+ * executed. Nice feature eh?
+ */
+
+prom_sync: .skip 4 ! hook in prom for sync func
+
+ .align 4
+
+/* We calculate the following at boot time, window fills/spills and trap entry
+ * code uses these to keep track of the register windows.
+ */
+
+ .globl C_LABEL(nwindows)
+ .globl C_LABEL(nwindowsm1)
+C_LABEL(nwindows): .skip 4
+C_LABEL(nwindowsm1): .skip 4
+
+ .align 4
+/* Boot time privileged register values, plus magic %o2 value */
+
+ .globl C_LABEL(boot_wim)
+ .globl C_LABEL(boot_psr)
+ .globl C_LABEL(boot_tbr)
+ .globl C_LABEL(boot_smp_ptr)
+C_LABEL(boot_wim): .skip 4
+C_LABEL(boot_psr): .skip 4
+C_LABEL(boot_tbr): .skip 4
+C_LABEL(boot_smp_ptr): .skip 4
+
+
+ .align 4
+/* Miscellaneous pieces of information saved at kernel startup. */
+ .globl C_LABEL(kernel_text_len)
+ .globl C_LABEL(kernel_data_len)
+ .globl C_LABEL(kernel_bss_len)
+C_LABEL(kernel_text_len): .word 0
+C_LABEL(kernel_data_len): .word 0
+C_LABEL(kernel_bss_len): .word 0
+
+/* These are for page alignment/offset information as they change from
+ machine to machine.
+*/
+
+ .globl C_LABEL(pgshift)
+ .globl C_LABEL(nbpg)
+ .globl C_LABEL(pgofset)
+
+ .align 4
+C_LABEL(pgshift):
+ .word 1
+C_LABEL(nbpg):
+ .word 1
+C_LABEL(pgofset):
+ .word 1
+
+/* Just to get the kernel through the compiler for now */
+ .globl C_LABEL(swapper_pg_dir), C_LABEL(pg0)
+ .globl C_LABEL(empty_bad_page)
+ .globl C_LABEL(empty_bad_page_table)
+ .globl C_LABEL(empty_zero_page)
+ .globl C_LABEL(floppy_track_buffer)
+C_LABEL(floppy_track_buffer):
+ .fill 512*2*36,1,0
+
+ .align 4
+C_LABEL(swapper_pg_dir): .skip 0x1000
+C_LABEL(pg0): .skip 0x1000
+C_LABEL(empty_bad_page): .skip 0x1000
+C_LABEL(empty_bad_page_table): .skip 0x1000
+C_LABEL(empty_zero_page): .skip 0x1000
+
+ .align 4
+diagstr: .asciz "DIAG\n"
+ .align 4
diff --git a/arch/sparc/kernel/idprom.c b/arch/sparc/kernel/idprom.c
new file mode 100644
index 000000000..c12f7467b
--- /dev/null
+++ b/arch/sparc/kernel/idprom.c
@@ -0,0 +1,183 @@
+/* idprom.c: Routines to load the idprom into kernel addresses and
+ * interpret the data contained within.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <linux/kernel.h>
+
+#include <asm/types.h>
+#include <asm/openprom.h>
+#include <asm/idprom.h>
+
+struct idp_struct idprom;
+extern int num_segmaps, num_contexts;
+
+void get_idprom(void)
+{
+ char* idp_addr;
+ char* knl_idp_addr;
+ int i;
+
+ idp_addr = (char *)IDPROM_ADDR;
+ knl_idp_addr = (char *) &idprom;
+
+ for(i = 0; i<IDPROM_SIZE; i++)
+ *knl_idp_addr++ = *idp_addr++;
+
+ return;
+}
+
+/* find_vac_size() returns the number of bytes in the VAC (virtual
+ * address cache) on this machine.
+ */
+
+int
+find_vac_size(void)
+{
+ int vac_prop_len;
+ int vacsize = 0;
+ int node_root;
+
+ node_root = (*(romvec->pv_nodeops->no_nextnode))(0);
+
+ vac_prop_len = (*(romvec->pv_nodeops->no_proplen))(node_root, "vac-size");
+
+ if(vac_prop_len != -1)
+ {
+ (*(romvec->pv_nodeops->no_getprop))(node_root, "vac-size", (char *) &vacsize);
+ return vacsize;
+ }
+ else
+ {
+
+ /* The prom node functions can't help, do it via idprom struct */
+ switch(idprom.id_machtype)
+ {
+ case 0x51:
+ case 0x52:
+ case 0x53:
+ case 0x54:
+ case 0x55:
+ case 0x56:
+ case 0x57:
+ return 65536;
+ default:
+ return -1;
+ }
+ };
+}
+
+/* find_vac_linesize() returns the size in bytes of the VAC linesize */
+
+int
+find_vac_linesize(void)
+{
+ int vac_prop_len;
+ int vaclinesize = 0;
+ int node_root;
+
+ node_root = (*(romvec->pv_nodeops->no_nextnode))(0);
+
+ vac_prop_len = (*(romvec->pv_nodeops->no_proplen))(node_root, "vac-linesize");
+
+ if(vac_prop_len != -1)
+ {
+ (*(romvec->pv_nodeops->no_getprop))(node_root, "vac-linesize",
+ (char *) &vaclinesize);
+ return vaclinesize;
+ }
+ else
+ {
+
+ /* The prom node functions can't help, do it via idprom struct */
+ switch(idprom.id_machtype)
+ {
+ case 0x51:
+ case 0x52:
+ case 0x53:
+ case 0x54:
+ return 16;
+ case 0x55:
+ case 0x56:
+ case 0x57:
+ return 32;
+ default:
+ return -1;
+ }
+ };
+}
+
+int
+find_vac_hwflushes(void)
+{
+ register int len, node_root;
+ int tmp1, tmp2;
+
+ node_root = (*(romvec->pv_nodeops->no_nextnode))(0);
+
+ len = (*(romvec->pv_nodeops->no_proplen))(node_root, "vac_hwflush");
+
+#ifdef DEBUG_IDPROM
+ printf("DEBUG: find_vac_hwflushes: proplen vac_hwflush=0x%x\n", len);
+#endif
+
+ /* Sun 4/75 has typo in prom_node, it's a dash instead of an underscore
+ * in the property name. :-(
+ */
+ len |= (*(romvec->pv_nodeops->no_proplen))(node_root, "vac-hwflush");
+
+#ifdef DEBUG_IDPROM
+ printf("DEBUG: find_vac_hwflushes: proplen vac-hwflush=0x%x\n", len);
+#endif
+
+ len = (*(romvec->pv_nodeops->no_getprop))(node_root,"vac_hwflush",
+ (char *) &tmp1);
+ if(len != 4) tmp1=0;
+
+ len = (*(romvec->pv_nodeops->no_getprop))(node_root, "vac-hwflush",
+ (char *) &tmp2);
+ if(len != 4) tmp2=0;
+
+
+ return (tmp1|tmp2);
+}
+
+void
+find_mmu_num_segmaps(void)
+{
+ register int root_node, len;
+
+ root_node = (*(romvec->pv_nodeops->no_nextnode))(0);
+
+ len = (*(romvec->pv_nodeops->no_getprop))(root_node, "mmu-npmg",
+ (char *) &num_segmaps);
+
+#ifdef DEBUG_MMU
+ printf("find_mmu_num_segmaps: property length = %d\n", len);
+#endif
+
+ if(len != 4) num_segmaps = 128;
+
+ return;
+}
+
+void
+find_mmu_num_contexts(void)
+{
+ register int root_node, len;
+
+ root_node = (*(romvec->pv_nodeops->no_nextnode))(0);
+
+ len = (*(romvec->pv_nodeops->no_getprop))(root_node, "mmu-nctx",
+ (char *) &num_contexts);
+
+#ifdef DEBUG_MMU
+ printf("find_mmu_num_contexts: property length = %d\n", len);
+#endif
+
+ if(len != 4) num_contexts = 8;
+
+ return;
+}
+
diff --git a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c
new file mode 100644
index 000000000..effa6c25e
--- /dev/null
+++ b/arch/sparc/kernel/ioport.c
@@ -0,0 +1,12 @@
+/* ioport.c: I/O access on the Sparc. Work in progress.. Most of the things
+ * in this file are for the sole purpose of getting the kernel
+ * through the compiler. :-)
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/ioport.h>
diff --git a/arch/sparc/kernel/irq.c b/arch/sparc/kernel/irq.c
new file mode 100644
index 000000000..5dcaf1971
--- /dev/null
+++ b/arch/sparc/kernel/irq.c
@@ -0,0 +1,335 @@
+/* arch/sparc/kernel/irq.c: Interrupt request handling routines. On the
+ * Sparc the IRQ's are basically 'cast in stone'
+ * and you are supposed to probe the prom's device
+ * node trees to find out who's got which IRQ.
+ *
+ * Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu)
+ *
+ */
+
+/*
+ * IRQ's are in fact implemented a bit like signal handlers for the kernel.
+ * The same sigaction struct is used, and with similar semantics (ie there
+ * is a SA_INTERRUPT flag etc). Naturally it's not a 1:1 relation, but there
+ * are similarities.
+ *
+ * sa_handler(int irq_NR) is the default function called (0 if no).
+ * sa_mask is horribly ugly (I won't even mention it)
+ * sa_flags contains various info: SA_INTERRUPT etc
+ * sa_restorer is the unused
+ */
+
+#include <linux/config.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/linkage.h>
+#include <linux/kernel_stat.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <asm/ptrace.h>
+#include <asm/system.h>
+#include <asm/psr.h>
+#include <asm/vaddrs.h>
+#include <asm/clock.h>
+#include <asm/openprom.h>
+
+#define DEBUG_IRQ
+
+void disable_irq(unsigned int irq_nr)
+{
+ unsigned long flags;
+ unsigned char *int_reg;
+
+ save_flags(flags);
+ cli();
+
+ /* We have mapped the irq enable register in head.S and all we
+ * have to do here is frob the bits.
+ */
+
+ int_reg = (unsigned char *) IRQ_ENA_ADR;
+
+ switch(irq_nr)
+ {
+ case 1:
+ *int_reg = ((*int_reg) & (~(0x02)));
+ break;
+ case 4:
+ *int_reg = ((*int_reg) & (~(0x04)));
+ break;
+ case 6:
+ *int_reg = ((*int_reg) & (~(0x08)));
+ break;
+ case 8:
+ *int_reg = ((*int_reg) & (~(0x10)));
+ break;
+ case 10:
+ *int_reg = ((*int_reg) & (~(0x20)));
+ break;
+ case 14:
+ *int_reg = ((*int_reg) & (~(0x80)));
+ break;
+ default:
+ printk("AIEEE, Illegal interrupt disable requested irq=%d\n",
+ (int) irq_nr);
+ break;
+ };
+
+ restore_flags(flags);
+ return;
+}
+
+void enable_irq(unsigned int irq_nr)
+{
+ unsigned long flags;
+ unsigned char *int_reg;
+
+ save_flags(flags);
+ cli();
+
+ /* We have mapped the irq enable register in head.S and all we
+ * have to do here is frob the bits.
+ */
+
+ int_reg = (unsigned char *) IRQ_ENA_ADR;
+
+#ifdef DEBUG_IRQ
+ printk(" --- Enabling IRQ level %d ---\n", irq_nr);
+#endif
+
+ switch(irq_nr)
+ {
+ case 1:
+ *int_reg = ((*int_reg) | 0x02);
+ break;
+ case 4:
+ *int_reg = ((*int_reg) | 0x04);
+ break;
+ case 6:
+ *int_reg = ((*int_reg) | 0x08);
+ break;
+ case 8:
+ *int_reg = ((*int_reg) | 0x10);
+ break;
+ case 10:
+ *int_reg = ((*int_reg) | 0x20);
+ break;
+ case 14:
+ *int_reg = ((*int_reg) | 0x80);
+ break;
+ default:
+ printk("AIEEE, Illegal interrupt enable requested irq=%d\n",
+ (int) irq_nr);
+ break;
+ };
+
+ restore_flags(flags);
+
+ return;
+}
+
+/*
+ * Initial irq handlers.
+ */
+struct irqaction {
+ void (*handler)(int, struct pt_regs *);
+ unsigned long flags;
+ unsigned long mask;
+ const char *name;
+};
+
+static struct irqaction irq_action[16] = {
+ { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
+ { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
+ { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
+ { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
+ { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
+ { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
+ { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
+ { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL }
+};
+
+
+int get_irq_list(char *buf)
+{
+ int i, len = 0;
+ struct irqaction * action = irq_action;
+
+ for (i = 0 ; i < 16 ; i++, action++) {
+ if (!action->handler)
+ continue;
+ len += sprintf(buf+len, "%2d: %8d %c %s\n",
+ i, kstat.interrupts[i],
+ (action->flags & SA_INTERRUPT) ? '+' : ' ',
+ action->name);
+ }
+ return len;
+}
+
+void free_irq(unsigned int irq)
+{
+ struct irqaction * action = irq + irq_action;
+ unsigned long flags;
+
+ if (irq > 14) { /* 14 irq levels on the sparc */
+ printk("Trying to free IRQ %d\n", irq);
+ return;
+ }
+ if (!action->handler) {
+ printk("Trying to free free IRQ%d\n", irq);
+ return;
+ }
+ save_flags(flags);
+ cli();
+ disable_irq(irq);
+ action->handler = NULL;
+ action->flags = 0;
+ action->mask = 0;
+ action->name = NULL;
+ restore_flags(flags);
+}
+
+#if 0
+static void handle_nmi(struct pt_regs * regs)
+{
+ printk("NMI, probably due to bus-parity error.\n");
+ printk("PC=%08lx, SP=%08lx\n", regs->pc, regs->sp);
+}
+#endif
+
+void unexpected_irq(int irq, struct pt_regs * regs)
+{
+ int i;
+
+ printk("IO device interrupt, irq = %d\n", irq);
+ printk("PC = %08lx NPC = %08lx SP=%08lx\n", regs->pc,
+ regs->npc, regs->sp);
+ printk("Expecting: ");
+ for (i = 0; i < 16; i++)
+ if (irq_action[i].handler)
+ printk("[%s:%d] ", irq_action[i].name, i);
+ printk("AIEEE\n");
+}
+
+static inline void handler_irq(int irq, struct pt_regs * regs)
+{
+ struct irqaction * action = irq + irq_action;
+
+ if (!action->handler) {
+ unexpected_irq(irq, regs);
+ return;
+ }
+ action->handler(irq, regs);
+}
+
+/*
+ * do_IRQ handles IRQ's that have been installed without the
+ * SA_INTERRUPT flag: it uses the full signal-handling return
+ * and runs with other interrupts enabled. All relatively slow
+ * IRQ's should use this format: notably the keyboard/timer
+ * routines.
+ */
+asmlinkage void do_IRQ(int irq, struct pt_regs * regs)
+{
+ struct irqaction *action = irq + irq_action;
+
+ kstat.interrupts[irq]++;
+ action->handler(irq, regs);
+ return;
+}
+
+/*
+ * Since we need to special things to clear up the clock chip around
+ * the do_timer() call we have a special version of do_IRQ for the
+ * level 14 interrupt which does these things.
+ */
+
+asmlinkage void do_sparc_timer(int irq, struct pt_regs * regs)
+{
+ struct irqaction *action = irq + irq_action;
+ register volatile int clear;
+
+ kstat.interrupts[irq]++;
+
+ /* I do the following already in the entry code, better safe than
+ * sorry for now. Reading the limit register clears the interrupt.
+ */
+ clear = TIMER_STRUCT->timer_limit14;
+
+ action->handler(irq, regs);
+ return;
+}
+
+/*
+ * do_fast_IRQ handles IRQ's that don't need the fancy interrupt return
+ * stuff - the handler is also running with interrupts disabled unless
+ * it explicitly enables them later.
+ */
+asmlinkage void do_fast_IRQ(int irq)
+{
+ kstat.interrupts[irq]++;
+ printk("Got FAST_IRQ number %04lx\n", (long unsigned int) irq);
+ return;
+}
+
+extern int first_descent;
+extern void probe_clock(int);
+
+int request_irq(unsigned int irq, void (*handler)(int, struct pt_regs *),
+ unsigned long irqflags, const char * devname)
+{
+ struct irqaction *action;
+ unsigned long flags;
+
+ if(irq > 14) /* Only levels 1-14 are valid on the Sparc. */
+ return -EINVAL;
+
+ if(irq == 0) /* sched_init() requesting the timer IRQ */
+ {
+ irq = 14;
+ probe_clock(first_descent);
+ }
+
+ action = irq + irq_action;
+
+ if(action->handler)
+ return -EBUSY;
+
+ if(!handler)
+ return -EINVAL;
+
+ save_flags(flags);
+
+ cli();
+
+ action->handler = handler;
+ action->flags = irqflags;
+ action->mask = 0;
+ action->name = devname;
+
+ enable_irq(irq);
+
+ restore_flags(flags);
+
+ return 0;
+}
+
+unsigned int probe_irq_on (void)
+{
+ unsigned int irqs = 0;
+
+ return irqs;
+}
+
+int probe_irq_off (unsigned int irqs)
+{
+ unsigned int i = 0;
+
+ return i;
+}
+
+void init_IRQ(void)
+{
+ return;
+}
diff --git a/arch/sparc/kernel/probe.c b/arch/sparc/kernel/probe.c
new file mode 100644
index 000000000..462556164
--- /dev/null
+++ b/arch/sparc/kernel/probe.c
@@ -0,0 +1,432 @@
+/* probe.c: Preliminary device tree probing routines...
+
+ Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+*/
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <asm/vac-ops.h>
+#include <asm/io.h>
+#include <asm/vaddrs.h>
+#include <asm/param.h>
+#include <asm/clock.h>
+#include <asm/system.h>
+
+/* #define DEBUG_PROBING */
+
+char promstr_buf[64]; /* overkill */
+unsigned int promint_buf[1];
+
+extern int prom_node_root;
+extern int num_segmaps, num_contexts;
+
+extern int node_get_sibling(int node);
+extern int node_get_child(int node);
+extern char* get_str_from_prom(int node, char* name, char* value);
+extern unsigned int* get_int_from_prom(int node, char* name, unsigned int *value);
+
+int first_descent;
+
+/* Cpu-type information and manufacturer strings */
+
+
+struct cpu_iu_info {
+ int psr_impl;
+ int psr_vers;
+ char* cpu_name; /* should be enough I hope... */
+};
+
+struct cpu_fp_info {
+ int psr_impl;
+ int fp_vers;
+ char* fp_name;
+};
+
+struct cpu_fp_info linux_sparc_fpu[] = {
+ { 0, 0, "Fujitsu MB86910 or Weitek WTL1164/5"},
+ { 0, 1, "Fujitsu MB86911 or Weitek WTL1164/5"},
+ { 0, 2, "LSI Logic L64802 or Texas Instruments ACT8847"},
+ { 0, 3, "Weitek WTL3170/2"},
+ { 0, 4, "Lsi Logic/Meiko L64804"},
+ { 0, 5, "reserved"},
+ { 0, 6, "reserved"},
+ { 0, 7, "No FPU"},
+ { 1, 0, "Lsi Logic L64812 or Texas Instruments ACT8847"},
+ { 1, 1, "Lsi Logic L64814"},
+ { 1, 2, "Texas Instruments TMS390-C602A"},
+ { 1, 3, "Weitek WTL3171"},
+ { 1, 4, "reserved"},
+ { 1, 5, "reserved"},
+ { 1, 6, "reserved"},
+ { 1, 7, "No FPU"},
+ { 2, 0, "BIT B5010 or B5110/20 or B5210"},
+ { 2, 1, "reserved"},
+ { 2, 2, "reserved"},
+ { 2, 3, "reserved"},
+ { 2, 4, "reserved"},
+ { 2, 5, "reserved"},
+ { 2, 6, "reserved"},
+ { 2, 7, "No FPU"},
+ { 5, 0, "Matsushita MN10501"},
+ { 5, 1, "reserved"},
+ { 5, 2, "reserved"},
+ { 5, 3, "reserved"},
+ { 5, 4, "reserved"},
+ { 5, 5, "reserved"},
+ { 5, 6, "reserved"},
+ { 5, 7, "No FPU"},
+};
+
+struct cpu_iu_info linux_sparc_chips[] = {
+ { 0, 0, "Fujitsu Microelectronics, Inc. - MB86900/1A"},
+ { 1, 0, "Cypress CY7C601"},
+ { 1, 1, "LSI Logic Corporation - L64811"},
+ { 1, 3, "Cypress CY7C611"},
+ { 2, 0, "Bipolar Integrated Technology - B5010"},
+ { 3, 0, "LSI Logic Corporation - unknown-type"},
+ { 4, 0, "Texas Instruments, Inc. - unknown"},
+ { 4, 1, "Texas Instruments, Inc. - Sparc Classic"},
+ { 4, 2, "Texas Instruments, Inc. - unknown"},
+ { 4, 3, "Texas Instruments, Inc. - unknown"},
+ { 4, 4, "Texas Instruments, Inc. - unknown"},
+ { 4, 5, "Texas Instruments, Inc. - unknown"},
+ { 5, 0, "Matsushita - MN10501"},
+ { 6, 0, "Philips Corporation - unknown"},
+ { 7, 0, "Harvest VLSI Design Center, Inc. - unknown"},
+ { 8, 0, "Systems and Processes Engineering Corporation (SPEC)"},
+ { 9, 0, "UNKNOWN CPU-VENDOR/TYPE"},
+ { 0xa, 0, "UNKNOWN CPU-VENDOR/TYPE"},
+ { 0xb, 0, "UNKNOWN CPU-VENDOR/TYPE"},
+ { 0xc, 0, "UNKNOWN CPU-VENDOR/TYPE"},
+ { 0xd, 0, "UNKNOWN CPU-VENDOR/TYPE"},
+ { 0xe, 0, "UNKNOWN CPU-VENDOR/TYPE"},
+ { 0xf, 0, "UNKNOWN CPU-VENDOR/TYPE"},
+};
+
+char *sparc_cpu_type = "cpu-oops";
+char *sparc_fpu_type = "fpu-oops";
+
+/* various Virtual Address Cache parameters we find at boot time... */
+
+extern int vac_size, vac_linesize, vac_do_hw_vac_flushes;
+extern int vac_entries_per_context, vac_entries_per_segment;
+extern int vac_entries_per_page;
+
+extern int find_vac_size(void);
+extern int find_vac_linesize(void);
+extern int find_vac_hwflushes(void);
+extern void find_mmu_num_segmaps(void);
+extern void find_mmu_num_contexts(void);
+
+void
+probe_cpu(void)
+{
+ register int psr_impl=0;
+ register int psr_vers = 0;
+ register int fpu_vers = 0;
+ register int i = 0;
+ unsigned int tmp_fsr;
+
+ &tmp_fsr; /* GCC grrr... */
+
+ __asm__("rd %%psr, %0\n\t"
+ "mov %0, %1\n\t"
+ "srl %0, 28, %0\n\t"
+ "srl %1, 24, %1\n\t"
+ "and %0, 0xf, %0\n\t"
+ "and %1, 0xf, %1\n\t" :
+ "=r" (psr_impl),
+ "=r" (psr_vers) :
+ "0" (psr_impl),
+ "1" (psr_vers));
+
+
+ __asm__("st %%fsr, %1\n\t"
+ "ld %1, %0\n\t"
+ "srl %0, 17, %0\n\t"
+ "and %0, 0x7, %0\n\t" :
+ "=r" (fpu_vers),
+ "=m" (tmp_fsr) :
+ "0" (fpu_vers),
+ "1" (tmp_fsr));
+
+ printk("fpu_vers: %d ", fpu_vers);
+ printk("psr_impl: %d ", psr_impl);
+ printk("psr_vers: %d \n\n", psr_vers);
+
+ for(i = 0; i<23; i++)
+ {
+ if(linux_sparc_chips[i].psr_impl == psr_impl)
+ if(linux_sparc_chips[i].psr_vers == psr_vers)
+ {
+ sparc_cpu_type = linux_sparc_chips[i].cpu_name;
+ break;
+ }
+ }
+
+ if(i==23)
+ {
+ printk("No CPU type! You lose\n");
+ printk("DEBUG: psr.impl = 0x%x psr.vers = 0x%x\n", psr_impl,
+ psr_vers);
+ return;
+ }
+
+ for(i = 0; i<32; i++)
+ {
+ if(linux_sparc_fpu[i].psr_impl == psr_impl)
+ if(linux_sparc_fpu[i].fp_vers == fpu_vers)
+ {
+ sparc_fpu_type = linux_sparc_fpu[i].fp_name;
+ break;
+ }
+ }
+
+ if(i == 32)
+ {
+ printk("No FPU type! You don't completely lose though...\n");
+ printk("DEBUG: psr.impl = 0x%x fsr.vers = 0x%x\n", psr_impl, fpu_vers);
+ sparc_fpu_type = linux_sparc_fpu[31].fp_name;
+ }
+
+ printk("CPU: %s \n", sparc_cpu_type);
+ printk("FPU: %s \n", sparc_fpu_type);
+
+ return;
+}
+
+void
+probe_vac(void)
+{
+ register unsigned int x,y;
+
+#ifndef CONFIG_SRMMU
+ vac_size = find_vac_size();
+ vac_linesize = find_vac_linesize();
+ vac_do_hw_vac_flushes = find_vac_hwflushes();
+
+ /* Calculate various constants that make the cache-flushing code
+ * mode speedy.
+ */
+
+ vac_entries_per_segment = vac_entries_per_context = vac_size >> 12;
+
+ for(x=0,y=vac_linesize; ((1<<x)<y); x++);
+ if((1<<x) != vac_linesize) printk("Warning BOGUS VAC linesize 0x%x",
+ vac_size);
+
+ vac_entries_per_page = x;
+
+ printk("Sparc VAC cache: Size=%d bytes Line-Size=%d bytes ... ", vac_size,
+ vac_linesize);
+
+ /* Here we want to 'invalidate' all the software VAC "tags"
+ * just in case there is garbage in there. Then we enable it.
+ */
+
+ for(x=0x80000000, y=(x+vac_size); x<y; x+=vac_linesize)
+ __asm__("sta %0, [%1] %2" : : "r" (0), "r" (x), "n" (0x2));
+
+ x=enable_vac();
+ printk("ENABLED\n");
+#endif
+
+ return;
+}
+
+void
+probe_mmu(void)
+{
+ find_mmu_num_segmaps();
+ find_mmu_num_contexts();
+
+ printk("MMU segmaps: %d MMU contexts: %d\n", num_segmaps,
+ num_contexts);
+
+ return;
+}
+
+void
+probe_clock(int fchild)
+{
+ register int node, type;
+ register char *node_str;
+
+ /* This will basically traverse the node-tree of the prom to see
+ * which timer chip is on this machine.
+ */
+
+ printk("Probing timer chip... ");
+
+ type = 0;
+ for(node = fchild ; ; )
+ {
+ node_str = get_str_from_prom(node, "model", promstr_buf);
+ if(strcmp(node_str, "mk48t02") == 0)
+ {
+ type = 2;
+ break;
+ }
+
+ if(strcmp(node_str, "mk48t08") == 0)
+ {
+ type = 8;
+ break;
+ }
+
+ node = node_get_sibling(node);
+ if(node == fchild)
+ {
+ printk("Aieee, could not find timer chip type\n");
+ return;
+ }
+ }
+
+ printk("Mostek %s\n", node_str);
+ printk("At OBIO address: 0x%x Virtual address: 0x%x\n",
+ (unsigned int) TIMER_PHYSADDR, (unsigned int) TIMER_STRUCT);
+
+ mapioaddr((unsigned long) TIMER_PHYSADDR,
+ (unsigned long) TIMER_STRUCT);
+
+ TIMER_STRUCT->timer_limit14=(((1000000/HZ) << 10) | 0x80000000);
+
+ return;
+}
+
+
+void
+probe_esp(register int esp_node)
+{
+ register int nd;
+ register char* lbuf;
+
+ nd = node_get_child(esp_node);
+
+ printk("\nProbing ESP:\n");
+ lbuf = get_str_from_prom(nd, "name", promstr_buf);
+
+ if(*get_int_from_prom(nd, "name", promint_buf) != 0)
+ printk("Node: 0x%x Name: %s\n", nd, lbuf);
+
+ while((nd = node_get_sibling(nd)) != 0) {
+ lbuf = get_str_from_prom(nd, "name", promstr_buf);
+ printk("Node: 0x%x Name: %s\n", nd, lbuf);
+ }
+
+ printk("\n");
+
+ return;
+}
+
+void
+probe_sbus(register int cpu_child_node)
+{
+ register int nd, savend;
+ register char* lbuf;
+
+ nd = cpu_child_node;
+
+ lbuf = (char *) 0;
+
+ while((nd = node_get_sibling(nd)) != 0) {
+ lbuf = get_str_from_prom(nd, "name", promstr_buf);
+ if(strcmp(lbuf, "sbus") == 0)
+ break;
+ };
+
+ nd = node_get_child(nd);
+
+ printk("Node: 0x%x Name: %s\n", nd,
+ get_str_from_prom(nd, "name", promstr_buf));
+
+ if(strcmp(lbuf, "esp") == 0) {
+ probe_esp(nd);
+ };
+
+ while((nd = node_get_sibling(nd)) != 0) {
+ printk("Node: 0x%x Name: %s\n", nd,
+ lbuf = get_str_from_prom(nd, "name", promstr_buf));
+
+ if(strcmp(lbuf, "esp") == 0) {
+ savend = nd;
+ probe_esp(nd);
+ nd = savend;
+ };
+ };
+
+ printk("\n");
+ return;
+}
+
+extern unsigned long probe_memory(void);
+extern struct sparc_phys_banks sp_banks[14];
+unsigned int phys_bytes_of_ram, end_of_phys_memory;
+
+void
+probe_devices(void)
+{
+ register int nd, i;
+ register char* str;
+
+ nd = prom_node_root;
+
+ printk("PROBING DEVICES:\n");
+
+ str = get_str_from_prom(nd, "device_type", promstr_buf);
+ if(strcmp(str, "cpu") == 0) {
+ printk("Found CPU root prom device tree node.\n");
+ } else {
+ printk("Root node in device tree was not 'cpu' cannot continue.\n");
+ halt();
+ };
+
+#ifdef DEBUG_PROBING
+ printk("String address for d_type: 0x%x\n", (unsigned int) str);
+ printk("str[0] = %c str[1] = %c str[2] = %c \n", str[0], str[1], str[2]);
+#endif
+
+ str = get_str_from_prom(nd, "name", promstr_buf);
+
+#ifdef DEBUG_PROBING
+ printk("String address for name: 0x%x\n", (unsigned int) str);
+ printk("str[0] = %c str[1] = %c str[2] = %c \n", str[0], str[1], str[2]);
+#endif
+
+ printk("Name: %s \n", str);
+
+ first_descent = nd = node_get_child(nd);
+
+
+/* Ok, here will go a call to each specific device probe. We can
+ * call these now that we have the 'root' node and the child of
+ * this node to send to the routines. ORDER IS IMPORTANT!
+ */
+
+ probe_cpu();
+ probe_vac();
+ probe_mmu();
+ phys_bytes_of_ram = probe_memory();
+
+ printk("Physical Memory: %d bytes\n", (int) phys_bytes_of_ram);
+ for(i=0; sp_banks[i].num_bytes != 0; i++) {
+ printk("Bank %d: base 0x%x bytes %d\n", i,
+ (unsigned int) sp_banks[i].base_addr,
+ (int) sp_banks[i].num_bytes);
+ end_of_phys_memory = sp_banks[i].base_addr + sp_banks[i].num_bytes;
+ }
+
+ printk("PROM Root Child Node: 0x%x Name: %s \n", nd,
+ get_str_from_prom(nd, "name", promstr_buf));
+
+ while((nd = node_get_sibling(nd)) != 0) {
+ printk("Node: 0x%x Name: %s", nd,
+ get_str_from_prom(nd, "name", promstr_buf));
+ printk("\n");
+ };
+
+ printk("\nProbing SBUS:\n");
+ probe_sbus(first_descent);
+
+ return;
+}
diff --git a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c
new file mode 100644
index 000000000..679863ba3
--- /dev/null
+++ b/arch/sparc/kernel/process.c
@@ -0,0 +1,112 @@
+/*
+ * linux/arch/i386/kernel/process.c
+ *
+ * Copyright (C) 1995 Linus Torvalds
+ */
+
+/*
+ * This file handles the architecture-dependent parts of process handling..
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/ldt.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+
+#include <asm/segment.h>
+#include <asm/system.h>
+
+void ret_from_sys_call(void) { __asm__("nop"); }
+
+/*
+ * The idle loop on a i386..
+ */
+asmlinkage int sys_idle(void)
+{
+ if (current->pid != 0)
+ return -EPERM;
+
+ /* Map out the low memory: it's no longer needed */
+ /* Sparc version RSN */
+
+ /* endless idle loop with no priority at all */
+ current->counter = -100;
+ for (;;) {
+ schedule();
+ }
+}
+
+void hard_reset_now(void)
+{
+ halt();
+}
+
+void show_regs(struct pt_regs * regs)
+{
+ printk("\nSP: %08lx PC: %08lx NPC: %08lx\n", regs->sp, regs->pc,
+ regs->npc);
+}
+
+/*
+ * Do necessary setup to start up a newly executed thread.
+ */
+void start_thread(struct pt_regs * regs, unsigned long sp, unsigned long fp)
+{
+ regs->sp = sp;
+ regs->fp = fp;
+}
+
+/*
+ * Free current thread data structures etc..
+ */
+void exit_thread(void)
+{
+ halt();
+}
+
+void flush_thread(void)
+{
+ halt();
+}
+
+void copy_thread(int nr, unsigned long clone_flags, unsigned long sp, struct task_struct * p, struct pt_regs * regs)
+{
+ struct pt_regs * childregs;
+
+ childregs = ((struct pt_regs *) (p->kernel_stack_page + PAGE_SIZE)) - 1;
+ p->tss.usp = (unsigned long) childregs;
+ *childregs = *regs;
+ childregs->sp = sp;
+ p->tss.psr = regs->psr; /* for condition codes */
+ return;
+}
+
+/*
+ * fill in the user structure for a core dump..
+ */
+void dump_thread(struct pt_regs * regs, struct user * dump)
+{
+ return; /* solaris does this enough */
+}
+
+asmlinkage int sys_fork(struct pt_regs regs)
+{
+ return do_fork(COPYVM | SIGCHLD, regs.sp, &regs);
+}
+
+/*
+ * sys_execve() executes a new program.
+ */
+asmlinkage int sys_execve(struct pt_regs regs)
+{
+ halt();
+ return 0;
+}
+
diff --git a/arch/sparc/kernel/promops.c b/arch/sparc/kernel/promops.c
new file mode 100644
index 000000000..b5c897b0d
--- /dev/null
+++ b/arch/sparc/kernel/promops.c
@@ -0,0 +1,107 @@
+/* promops.c: Prom node tree operations and Prom Vector initialization
+ * initialization routines.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <linux/kernel.h>
+
+#include <asm/openprom.h>
+
+/* #define DEBUG_PROMOPS */
+#define MAX_PR_LEN 64 /* exotic hardware probably overshoots this */
+
+int prom_node_root; /* initialized in init_prom */
+
+extern struct linux_romvec *romvec;
+
+/* These two functions return and siblings and direct child descendents
+ * in the prom device tree respectively.
+ */
+
+int
+node_get_sibling(int node)
+{
+ return (*(romvec->pv_nodeops->no_nextnode))(node);
+}
+
+int
+node_get_child(int node)
+{
+ return (*(romvec->pv_nodeops->no_child))(node);
+}
+
+/* The following routine is used during device probing to determine
+ * an integer value property about a (perhaps virtual) device. This
+ * could be anything, like the size of the mmu cache lines, etc.
+ * the default return value is -1 is the prom has nothing interesting.
+ */
+
+unsigned int prom_int_null;
+
+unsigned int *
+get_int_from_prom(int node, char *nd_prop, unsigned int *value)
+{
+ unsigned int pr_len;
+
+ *value = &prom_int_null; /* duh, I was returning -1 as an unsigned int, prom_panic() */
+
+ pr_len = romvec->pv_nodeops->no_proplen(node, nd_prop);
+ if(pr_len > MAX_PR_LEN)
+ {
+#ifdef DEBUG_PROMOPS
+ printk("Bad pr_len in promops -- node: %d nd_prop: %s pr_len: %d",
+ node, nd_prop, (int) pr_len);
+#endif
+ return value; /* XXX */
+ }
+
+ romvec->pv_nodeops->no_getprop(node, nd_prop, (char *) value);
+
+ return value;
+}
+
+
+/* This routine returns what is termed a property string as opposed
+ * to a property integer as above. This can be used to extract the
+ * 'type' of device from the prom. An example could be the clock timer
+ * chip type. By default you get returned a null string if garbage
+ * is returned from the prom.
+ */
+
+char *
+get_str_from_prom(int node, char *nd_prop, char *value)
+{
+ unsigned int pr_len;
+
+ *value='\n';
+
+ pr_len = romvec->pv_nodeops->no_proplen(node, nd_prop);
+ if(pr_len > MAX_PR_LEN)
+ {
+#ifdef DEBUG_PROMOPS
+ printk("Bad pr_len in promops -- node: %d nd_prop: %s pr_len: %d",
+ node, nd_prop, pr_len);
+#endif
+ return value; /* XXX */
+ }
+
+ romvec->pv_nodeops->no_getprop(node, nd_prop, value);
+ value[pr_len] = 0;
+
+ return value;
+}
+
+/* This gets called from head.S upon bootup to initialize the
+ * prom vector pointer for the rest of the kernel.
+ */
+
+void
+init_prom(struct linux_romvec *r_ptr)
+{
+ romvec = r_ptr;
+ prom_node_root = romvec->pv_nodeops->no_nextnode(0);
+ prom_int_null = 0;
+
+ return;
+}
diff --git a/arch/sparc/kernel/setup.c b/arch/sparc/kernel/setup.c
new file mode 100644
index 000000000..5ec5b56ba
--- /dev/null
+++ b/arch/sparc/kernel/setup.c
@@ -0,0 +1,120 @@
+/*
+ * linux/arch/alpha/kernel/setup.c
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+/*
+ * bootup setup stuff..
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/ldt.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/tty.h>
+
+#include <asm/segment.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/openprom.h> /* for console registration + cheese */
+
+extern void get_idprom(void);
+extern void probe_devices(void);
+
+/*
+ * Gcc is hard to keep happy ;-)
+ */
+struct screen_info screen_info = {
+ 0, 0, /* orig-x, orig-y */
+ { 0, 0, }, /* unused */
+ 0, /* orig-video-page */
+ 0, /* orig-video-mode */
+ 80, /* orig-video-cols */
+ 0,0,0, /* ega_ax, ega_bx, ega_cx */
+ 25 /* orig-video-lines */
+};
+
+/* At least I hide the sneaky floppy_track_buffer in my dirty assembly
+ * code. ;-)
+ */
+
+unsigned long bios32_init(unsigned long memory_start, unsigned long memory_end)
+{
+ return memory_start;
+}
+
+/* Lame prom console routines, gets registered below. Thanks for the
+ * tip Linus. First comes the V0 prom routine, then the V3 version
+ * written by Paul Hatchman (paul@sfe.com.au).
+ */
+
+void sparc_console_print(const char * p)
+{
+ unsigned char c;
+
+ while ((c = *(p++)) != 0)
+ {
+ if (c == '\n') romvec->pv_putchar('\r');
+ (*(romvec->pv_putchar))(c);
+ }
+
+ return;
+
+}
+
+/* paul@sfe.com.au */
+/* V3 prom console printing routines */
+void sparc_console_print_v3 (const char *p)
+{
+ unsigned char c;
+
+ while ((c = *(p++)) != 0)
+ {
+ if (c == '\n') romvec->pv_v2devops.v2_dev_write
+ ((*romvec->pv_v2bootargs.fd_stdout), "\r", 1);
+ romvec->pv_v2devops.v2_dev_write
+ ((*romvec->pv_v2bootargs.fd_stdout), &c, 1);
+ }
+
+ return;
+}
+
+
+/* This routine will in the future do all the nasty prom stuff
+ * to probe for the mmu type and its parameters, etc. This will
+ * also be where SMP things happen plus the Sparc specific memory
+ * physical memory probe as on the alpha.
+ */
+
+extern void register_console(void (*proc)(const char *));
+extern unsigned int prom_iface_vers, end_of_phys_memory;
+
+void setup_arch(char **cmdline_p,
+ unsigned long * memory_start_p, unsigned long * memory_end_p)
+{
+ if(romvec->pv_romvers == 0) {
+ register_console(sparc_console_print);
+ } else {
+ register_console(sparc_console_print_v3);
+ };
+
+ printk("Sparc PROM-Console registered...\n");
+ get_idprom(); /* probe_devices expects this to be done */
+ probe_devices(); /* cpu/fpu, mmu probes */
+
+ *memory_start_p = (((unsigned long) &end));
+ *memory_end_p = (((unsigned long) end_of_phys_memory));
+}
+
+asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on)
+{
+ return -EIO;
+}
diff --git a/arch/sparc/kernel/signal.c b/arch/sparc/kernel/signal.c
new file mode 100644
index 000000000..cd949e4ed
--- /dev/null
+++ b/arch/sparc/kernel/signal.c
@@ -0,0 +1,71 @@
+/*
+ * linux/arch/sparc/kernel/signal.c
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/wait.h>
+#include <linux/ptrace.h>
+#include <linux/unistd.h>
+
+#include <asm/segment.h>
+
+#define _S(nr) (1<<((nr)-1))
+
+#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
+
+asmlinkage int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options);
+
+/*
+ * atomically swap in the new signal mask, and wait for a signal.
+ */
+asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, unsigned long set)
+{
+ unsigned long mask;
+ struct pt_regs * regs = (struct pt_regs *) &restart;
+
+ mask = current->blocked;
+ current->blocked = set & _BLOCKABLE;
+
+ while (1) {
+ current->state = TASK_INTERRUPTIBLE;
+ schedule();
+ if (do_signal(mask,regs))
+ return -EINTR;
+ }
+}
+
+asmlinkage int sys_sigreturn(unsigned long __unused)
+{
+ halt();
+ return 0;
+}
+
+/*
+ * Set up a signal frame... Make the stack look the way iBCS2 expects
+ * it to look.
+ */
+void setup_frame(struct sigaction * sa, unsigned long ** fp, unsigned long eip,
+ struct pt_regs * regs, int signr, unsigned long oldmask)
+{
+ halt();
+}
+
+/*
+ * Note that 'init' is a special process: it doesn't get signals it doesn't
+ * want to handle. Thus you cannot kill init even with a SIGKILL even by
+ * mistake.
+ *
+ * Note that we go through the signals twice: once to check the signals that
+ * the kernel can handle, and then we build all the user-level signal handling
+ * stack-frames in one go after that.
+ */
+asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
+{
+ halt();
+ return 1;
+}
diff --git a/arch/sparc/kernel/traps.c b/arch/sparc/kernel/traps.c
new file mode 100644
index 000000000..9302191c7
--- /dev/null
+++ b/arch/sparc/kernel/traps.c
@@ -0,0 +1,47 @@
+/*
+ * arch/sparc/kernel/traps.c
+ *
+ * Copyright 1994 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+/*
+ * I hate traps on the sparc, grrr...
+ */
+
+#include <linux/sched.h> /* for jiffies */
+#include <linux/kernel.h>
+
+void do_hw_interrupt(unsigned long type, unsigned long vector)
+{
+ if (vector == 14) {
+ jiffies++;
+ return;
+ }
+
+ /* Just print garbage for everything else for now. */
+
+ printk("Unimplemented Sparc TRAP, vector = %lx type = %lx\n", vector, type);
+
+ return;
+}
+
+extern unsigned long *trapbase;
+
+void trap_init(void)
+{
+
+ /* load up the trap table */
+
+#if 0 /* not yet */
+ __asm__("wr %0, 0x0, %%tbr\n\t"
+ "nop; nop; nop\n\t" : :
+ "r" (trapbase));
+#endif
+
+ return;
+}
+
+void die_if_kernel(char * str, struct pt_regs * regs, long err)
+{
+ return;
+}