summaryrefslogtreecommitdiffstats
path: root/arch/sparc
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1995-11-14 08:00:00 +0000
committer <ralf@linux-mips.org>1995-11-14 08:00:00 +0000
commite7c2a72e2680827d6a733931273a93461c0d8d1b (patch)
treec9abeda78ef7504062bb2e816bcf3e3c9d680112 /arch/sparc
parentec6044459060a8c9ce7f64405c465d141898548c (diff)
Import of Linux/MIPS 1.3.0
Diffstat (limited to 'arch/sparc')
-rw-r--r--arch/sparc/Makefile33
-rw-r--r--arch/sparc/config.in246
-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
-rw-r--r--arch/sparc/lib/COPYING.LIB481
-rw-r--r--arch/sparc/lib/Makefile48
-rw-r--r--arch/sparc/lib/ashrdi3.S28
-rw-r--r--arch/sparc/lib/mul.S127
-rw-r--r--arch/sparc/lib/rem.S359
-rw-r--r--arch/sparc/lib/sdiv.S363
-rw-r--r--arch/sparc/lib/udiv.S346
-rw-r--r--arch/sparc/lib/umul.S158
-rw-r--r--arch/sparc/lib/urem.S344
-rw-r--r--arch/sparc/mm/Makefile32
-rw-r--r--arch/sparc/mm/fault.c173
-rw-r--r--arch/sparc/mm/init.c364
-rw-r--r--arch/sparc/mm/vac-flush.c94
27 files changed, 6634 insertions, 0 deletions
diff --git a/arch/sparc/Makefile b/arch/sparc/Makefile
new file mode 100644
index 000000000..88bcd6578
--- /dev/null
+++ b/arch/sparc/Makefile
@@ -0,0 +1,33 @@
+#
+# sparc/Makefile
+#
+# Makefile for the architecture dependent flags and dependencies on the
+# Sparc.
+#
+# Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu)
+#
+
+
+# If the solaris /bin/sh wasn't so broken, I wouldn't need the following
+# line...
+SHELL =/bin/bash
+
+#
+# How to link, we send the linker the address at which the text section
+# is to start. The prom loads us at 0x0-kernel_size. There is also an
+# alias of this address space at 0xf8000000-(0xf8000000+kernel_size) but
+# I ignore it and eliminate those mappings during vm initialization and
+# just leave the low mapping.
+#
+LINKFLAGS = -N -Ttext 0x00004000
+CFLAGS := $(CFLAGS) -pipe
+
+HEAD := arch/sparc/kernel/head.o
+
+SUBDIRS := $(SUBDIRS) arch/sparc/kernel arch/sparc/lib arch/sparc/mm
+ARCHIVES := arch/sparc/kernel/kernel.o arch/sparc/mm/mm.o $(ARCHIVES)
+LIBS := $(TOPDIR)/lib/lib.a $(LIBS) $(TOPDIR)/arch/sparc/lib/lib.a
+
+archclean:
+
+archdep:
diff --git a/arch/sparc/config.in b/arch/sparc/config.in
new file mode 100644
index 000000000..be9336eed
--- /dev/null
+++ b/arch/sparc/config.in
@@ -0,0 +1,246 @@
+#
+# arch/sparc/config.in
+#
+# Bare minimum configuration file for the Sparc.
+#
+# Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu)
+#
+# For a description of the syntax of this configuration file,
+# see the Configure script.
+#
+
+comment 'Sparc Kernel setup'
+
+bool 'Sparc V8 kernel' CONFIG_SPARC_V8 y
+bool 'Sparc SMP support' CONFIG_LINUX_SMP n
+bool 'Sparc SUN4M support' CONFIG_SUN4M n
+bool 'Sparc Reference MMU' CONFIG_SRMMU n
+bool 'Networking support' CONFIG_NET n
+bool 'Limit memory to low 16MB' CONFIG_MAX_16M n
+bool 'System V IPC' CONFIG_SYSVIPC y
+bool 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF y
+
+if [ "$CONFIG_NET" = "y" ]; then
+comment 'Networking options'
+bool 'TCP/IP networking' CONFIG_INET y
+if [ "$CONFIG_INET" "=" "y" ]; then
+bool 'IP forwarding/gatewaying' CONFIG_IP_FORWARD n
+bool 'IP multicasting (ALPHA)' CONFIG_IP_MULTICAST n
+bool 'IP firewalling' CONFIG_IP_FIREWALL n
+bool 'IP accounting' CONFIG_IP_ACCT n
+comment '(it is safe to leave these untouched)'
+bool 'PC/TCP compatibility mode' CONFIG_INET_PCTCP n
+bool 'Reverse ARP' CONFIG_INET_RARP n
+bool 'Assume subnets are local' CONFIG_INET_SNARL y
+bool 'Disable NAGLE algorithm (normally enabled)' CONFIG_TCP_NAGLE_OFF n
+fi
+bool 'The IPX protocol' CONFIG_IPX n
+#bool 'Amateur Radio AX.25 Level 2' CONFIG_AX25 n
+fi
+
+comment 'SCSI support'
+
+bool 'SCSI support?' CONFIG_SCSI n
+
+if [ "$CONFIG_SCSI" = "n" ]; then
+
+comment 'Skipping SCSI configuration options...'
+
+else
+
+comment 'SCSI support type (disk, tape, CDrom)'
+
+bool 'SCSI disk support' CONFIG_BLK_DEV_SD y
+bool 'SCSI tape support' CONFIG_CHR_DEV_ST n
+bool 'SCSI CDROM support' CONFIG_BLK_DEV_SR n
+bool 'SCSI generic support' CONFIG_CHR_DEV_SG n
+
+comment 'SCSI low-level drivers'
+
+bool 'Adaptec AHA152X support' CONFIG_SCSI_AHA152X n
+bool 'Adaptec AHA1542 support' CONFIG_SCSI_AHA1542 y
+bool 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 n
+bool 'Adaptec AHA274X/284X support' CONFIG_SCSI_AHA274X n
+bool 'BusLogic SCSI support' CONFIG_SCSI_BUSLOGIC n
+bool 'UltraStor 14F/34F support' CONFIG_SCSI_U14_34F n
+bool 'Future Domain 16xx SCSI support' CONFIG_SCSI_FUTURE_DOMAIN n
+bool 'Generic NCR5380 SCSI support' CONFIG_SCSI_GENERIC_NCR5380 n
+if [ "$CONFIG_PCI" = "y" ]; then
+ bool 'NCR53c7,8xx SCSI support' CONFIG_SCSI_NCR53C7xx n
+fi
+bool 'Always IN2000 SCSI support (test release)' CONFIG_SCSI_IN2000 n
+bool 'PAS16 SCSI support' CONFIG_SCSI_PAS16 n
+bool 'QLOGIC SCSI support' CONFIG_SCSI_QLOGIC n
+bool 'Seagate ST-02 and Future Domain TMC-8xx SCSI support' CONFIG_SCSI_SEAGATE n
+bool 'Trantor T128/T128F/T228 SCSI support' CONFIG_SCSI_T128 n
+bool 'UltraStor SCSI support' CONFIG_SCSI_ULTRASTOR n
+bool '7000FASST SCSI support' CONFIG_SCSI_7000FASST n
+bool 'EATA ISA/EISA (DPT PM2011/021/012/022/122/322) support' CONFIG_SCSI_EATA n
+#bool 'SCSI debugging host adapter' CONFIG_SCSI_DEBUG n
+fi
+
+
+if [ "$CONFIG_NET" = "y" ]; then
+
+comment 'Network device support'
+
+bool 'Network device support?' CONFIG_NETDEVICES y
+if [ "$CONFIG_NETDEVICES" = "n" ]; then
+
+comment 'Skipping network driver configuration options...'
+
+else
+bool 'Dummy net driver support' CONFIG_DUMMY n
+bool 'SLIP (serial line) support' CONFIG_SLIP n
+if [ "$CONFIG_SLIP" = "y" ]; then
+ bool ' CSLIP compressed headers' SL_COMPRESSED y
+ bool ' 16 channels instead of 4' SL_SLIP_LOTS n
+# bool ' SLIP debugging on' SL_DUMP y
+fi
+bool 'PPP (point-to-point) support' CONFIG_PPP n
+bool 'PLIP (parallel port) support' CONFIG_PLIP n
+bool 'Load balancing support (experimental)' CONFIG_SLAVE_BALANCING n
+bool 'Do you want to be offered ALPHA test drivers' CONFIG_NET_ALPHA n
+bool 'Western Digital/SMC cards' CONFIG_NET_VENDOR_SMC n
+if [ "$CONFIG_NET_VENDOR_SMC" = "y" ]; then
+ bool 'WD80*3 support' CONFIG_WD80x3 n
+ bool 'SMC Ultra support' CONFIG_ULTRA n
+fi
+bool 'AMD LANCE and PCnet (AT1500 and NE2100) support' CONFIG_LANCE n
+bool '3COM cards' CONFIG_NET_VENDOR_3COM y
+if [ "$CONFIG_NET_VENDOR_3COM" = "y" ]; then
+ bool '3c501 support' CONFIG_EL1 n
+ bool '3c503 support' CONFIG_EL2 n
+ if [ "$CONFIG_NET_ALPHA" = "y" ]; then
+ bool '3c505 support' CONFIG_ELPLUS n
+ bool '3c507 support' CONFIG_EL16 n
+ fi
+ bool '3c509/3c579 support' CONFIG_EL3 y
+fi
+bool 'Other ISA cards' CONFIG_NET_ISA n
+if [ "$CONFIG_NET_ISA" = "y" ]; then
+ bool 'Cabletron E21xx support' CONFIG_E2100 n
+ bool 'DEPCA support' CONFIG_DEPCA n
+ bool 'EtherWorks 3 support' CONFIG_EWRK3 n
+ if [ "$CONFIG_NET_ALPHA" = "y" ]; then
+# bool 'Arcnet support' CONFIG_ARCNET n
+ bool 'AT1700 support' CONFIG_AT1700 n
+# bool 'EtherExpressPro support' CONFIG_EEXPRESS_PRO n
+ bool 'EtherExpress support' CONFIG_EEXPRESS n
+ bool 'NI5210 support' CONFIG_NI52 n
+ bool 'NI6510 support' CONFIG_NI65 n
+ fi
+ bool 'HP PCLAN+ (27247B and 27252A) support' CONFIG_HPLAN_PLUS n
+ bool 'HP PCLAN (27245 and other 27xxx series) support' CONFIG_HPLAN n
+ bool 'NE2000/NE1000 support' CONFIG_NE2000 y
+ bool 'SK_G16 support' CONFIG_SK_G16 n
+fi
+bool 'EISA, VLB, PCI and on board controllers' CONFIG_NET_EISA n
+if [ "$CONFIG_NET_EISA" = "y" ]; then
+ if [ "$CONFIG_NET_ALPHA" = "y" ]; then
+ bool 'Ansel Communications EISA 3200 support' CONFIG_AC3200 n
+ fi
+ bool 'Apricot Xen-II on board ethernet' CONFIG_APRICOT n
+# bool 'DEC 21040 PCI support' CONFIG_DEC_ELCP n
+# bool 'LPL T100V 100Mbs support' CONFIG_LPL_T100 n
+# bool 'PCnet32 (32 bit VLB and PCI LANCE) support' CONFIG_PCNET32 n
+ bool 'Zenith Z-Note support' CONFIG_ZNET y
+fi
+bool 'Pocket and portable adaptors' CONFIG_NET_POCKET n
+if [ "$CONFIG_NET_POCKET" = "y" ]; then
+ bool 'AT-LAN-TEC/RealTek pocket adaptor support' CONFIG_ATP n
+ bool 'D-Link DE600 pocket adaptor support' CONFIG_DE600 n
+ bool 'D-Link DE620 pocket adaptor support' CONFIG_DE620 n
+# bool 'Silicom pocket adaptor support' CONFIG_SILICOM_PEA n
+# bool 'WaveLAN PCMCIA support' CONFIG_WaveLAN n
+# bool '3 Com 3c589 PCMCIA support' CONFIG_3C589 n
+fi
+fi
+fi
+
+comment 'CD-ROM drivers (not for SCSI or IDE/ATAPI drives)'
+
+bool 'Sony CDU31A/CDU33A CDROM driver support' CONFIG_CDU31A n
+bool 'Mitsumi (not IDE/ATAPI) CDROM driver support' CONFIG_MCD n
+bool 'Matsushita/Panasonic CDROM driver support' CONFIG_SBPCD n
+if [ "$CONFIG_SBPCD" = "y" ]; then
+ bool 'Matsushita/Panasonic second CDROM controller support' CONFIG_SBPCD2 n
+ if [ "$CONFIG_SBPCD2" = "y" ]; then
+ bool 'Matsushita/Panasonic third CDROM controller support' CONFIG_SBPCD3 n
+ if [ "$CONFIG_SBPCD3" = "y" ]; then
+ bool 'Matsushita/Panasonic fourth CDROM controller support' CONFIG_SBPCD4 n
+ fi
+ fi
+fi
+bool 'Aztech/Orchid/Okano/Wearnes (non IDE) CDROM support' CONFIG_AZTCD n
+
+comment 'Filesystems'
+
+bool 'Standard (minix) fs support' CONFIG_MINIX_FS y
+bool 'Extended fs support' CONFIG_EXT_FS y
+bool 'Second extended fs support' CONFIG_EXT2_FS y
+bool 'xiafs filesystem support' CONFIG_XIA_FS y
+bool 'msdos fs support' CONFIG_MSDOS_FS y
+if [ "$CONFIG_MSDOS_FS" = "y" ]; then
+bool 'umsdos: Unix like fs on top of std MSDOS FAT fs' CONFIG_UMSDOS_FS n
+fi
+bool '/proc filesystem support' CONFIG_PROC_FS n
+if [ "$CONFIG_INET" = "y" ]; then
+bool 'NFS filesystem support' CONFIG_NFS_FS n
+fi
+if [ "$CONFIG_BLK_DEV_SR" = "y" -o "$CONFIG_CDU31A" = "y" -o "$CONFIG_MCD" = "y" -o "$CONFIG_SBPCD" = "y" -o "$CONFIG_BLK_DEV_IDECD" = "y" ]; then
+ bool 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS y
+else
+ bool 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS n
+fi
+bool 'OS/2 HPFS filesystem support (read only)' CONFIG_HPFS_FS n
+bool 'System V and Coherent filesystem support' CONFIG_SYSV_FS y
+
+
+comment 'character devices'
+
+bool 'Cyclades async mux support' CONFIG_CYCLADES n
+bool 'Parallel printer support' CONFIG_PRINTER n
+bool 'Logitech busmouse support' CONFIG_BUSMOUSE n
+bool 'PS/2 mouse (aka "auxiliary device") support' CONFIG_PSMOUSE n
+if [ "$CONFIG_PSMOUSE" = "y" ]; then
+bool 'C&T 82C710 mouse port support (as on TI Travelmate)' CONFIG_82C710_MOUSE y
+fi
+bool 'Microsoft busmouse support' CONFIG_MS_BUSMOUSE n
+bool 'ATIXL busmouse support' CONFIG_ATIXL_BUSMOUSE n
+
+
+bool 'QIC-02 tape support' CONFIG_QIC02_TAPE n
+if [ "$CONFIG_QIC02_TAPE" = "y" ]; then
+bool 'Do you want runtime configuration for QIC-02' CONFIG_QIC02_DYNCONF y
+if [ "$CONFIG_QIC02_DYNCONF" != "y" ]; then
+
+comment '>>> Edit configuration parameters in ./include/linux/tpqic02.h!'
+
+else
+
+comment '>>> Setting runtime QIC-02 configuration is done with qic02conf'
+comment '>>> Which is available from ftp://ftp.funet.fi/pub/OS/Linux/BETA/QIC-02/'
+
+fi
+fi
+
+bool 'QIC-117 tape support' CONFIG_FTAPE n
+if [ "$CONFIG_FTAPE" = "y" ]; then
+int ' number of ftape buffers' NR_FTAPE_BUFFERS 3
+fi
+
+comment 'Sound'
+
+bool 'Sound card support' CONFIG_SOUND n
+
+comment 'Kernel hacking'
+
+#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC n
+bool 'Kernel profiling support' CONFIG_PROFILE n
+if [ "$CONFIG_PROFILE" = "y" ]; then
+ int ' Profile shift count' CONFIG_PROFILE_SHIFT 2
+fi
+if [ "$CONFIG_SCSI" = "y" ]; then
+bool 'Verbose SCSI error reporting (kernel size +=12K)' CONFIG_SCSI_CONSTANTS y
+fi
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;
+}
diff --git a/arch/sparc/lib/COPYING.LIB b/arch/sparc/lib/COPYING.LIB
new file mode 100644
index 000000000..eb685a5ec
--- /dev/null
+++ b/arch/sparc/lib/COPYING.LIB
@@ -0,0 +1,481 @@
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL. It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it. You can use it for
+your libraries, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library. If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software. To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+ Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs. This
+license, the GNU Library General Public License, applies to certain
+designated libraries. This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+ The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it. Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program. However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+ Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries. We
+concluded that weaker conditions might promote sharing better.
+
+ However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves. This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them. (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.) The hope is that this
+will lead to faster development of free libraries.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+ Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License"). Each licensee is
+addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ c) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ d) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/arch/sparc/lib/Makefile b/arch/sparc/lib/Makefile
new file mode 100644
index 000000000..1f2ce0e1c
--- /dev/null
+++ b/arch/sparc/lib/Makefile
@@ -0,0 +1,48 @@
+#
+# Makefile for Sparc library files..
+#
+
+CFLAGS := $(CFLAGS) -ansi
+
+.c.s:
+ $(CC) $(CFLAGS) -S $<
+.s.o:
+ $(AS) -c -o $*.o $<
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+
+OBJS = mul.o rem.o sdiv.o udiv.o umul.o urem.o ashrdi3.o
+
+lib.a: $(OBJS)
+ $(AR) rcs lib.a $(OBJS)
+ sync
+
+mul.o: mul.S
+ $(CC) -c -o mul.o mul.S
+
+rem.o: rem.S
+ $(CC) -DST_DIV0=0x2 -c -o rem.o rem.S
+
+sdiv.o: sdiv.S
+ $(CC) -DST_DIV0=0x2 -c -o sdiv.o sdiv.S
+
+udiv.o: udiv.S
+ $(CC) -DST_DIV0=0x2 -c -o udiv.o udiv.S
+
+umul.o: umul.S
+ $(CC) -c -o umul.o umul.S
+
+urem.o: urem.S
+ $(CC) -DST_DIV0=0x2 -c -o urem.o urem.S
+
+ashrdi3.o: ashrdi3.S
+ $(CC) -c -o ashrdi3.o ashrdi3.S
+
+dep:
+
+#
+# include a dependency file if one exists
+#
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
diff --git a/arch/sparc/lib/ashrdi3.S b/arch/sparc/lib/ashrdi3.S
new file mode 100644
index 000000000..c672d2c9f
--- /dev/null
+++ b/arch/sparc/lib/ashrdi3.S
@@ -0,0 +1,28 @@
+/* ashrdi3.S: The filesystem code creates all kinds of references to
+ * this little routine on the sparc with gcc.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <asm/cprefix.h>
+
+ .globl C_LABEL(__ashrdi3)
+C_LABEL(__ashrdi3):
+ tst %o2
+ be 3f
+ or %g0, 32, %g2
+ sub %g2, %o2, %g2
+ tst %g2
+ bg 1f
+ sra %o0, %o2, %o4
+ sra %o0, 31, %o4
+ sub %g0, %g2, %g2
+ ba 2f
+ sra %o0, %g2, %o5
+1: sll %o0, %g2, %g3
+ srl %o1, %o2, %g2
+ or %g2, %g3, %o5
+2: or %g0, %o4, %o0
+ or %g0, %o5, %o1
+3: jmpl %o7 + 8, %g0
+ nop
diff --git a/arch/sparc/lib/mul.S b/arch/sparc/lib/mul.S
new file mode 100644
index 000000000..e6d78f85f
--- /dev/null
+++ b/arch/sparc/lib/mul.S
@@ -0,0 +1,127 @@
+/* mul.S: This routine was taken from glibc-1.09 and is covered
+ * by the GNU Library General Public License Version 2.
+ */
+
+/*
+ * Signed multiply, from Appendix E of the Sparc Version 8
+ * Architecture Manual.
+ */
+
+/*
+ * Returns %o0 * %o1 in %o1%o0 (i.e., %o1 holds the upper 32 bits of
+ * the 64-bit product).
+ *
+ * This code optimizes short (less than 13-bit) multiplies.
+ */
+
+ .globl .mul
+.mul:
+ mov %o0, %y ! multiplier -> Y
+ andncc %o0, 0xfff, %g0 ! test bits 12..31
+ be Lmul_shortway ! if zero, can do it the short way
+ andcc %g0, %g0, %o4 ! zero the partial product and clear N and V
+
+ /*
+ * Long multiply. 32 steps, followed by a final shift step.
+ */
+ mulscc %o4, %o1, %o4 ! 1
+ mulscc %o4, %o1, %o4 ! 2
+ mulscc %o4, %o1, %o4 ! 3
+ mulscc %o4, %o1, %o4 ! 4
+ mulscc %o4, %o1, %o4 ! 5
+ mulscc %o4, %o1, %o4 ! 6
+ mulscc %o4, %o1, %o4 ! 7
+ mulscc %o4, %o1, %o4 ! 8
+ mulscc %o4, %o1, %o4 ! 9
+ mulscc %o4, %o1, %o4 ! 10
+ mulscc %o4, %o1, %o4 ! 11
+ mulscc %o4, %o1, %o4 ! 12
+ mulscc %o4, %o1, %o4 ! 13
+ mulscc %o4, %o1, %o4 ! 14
+ mulscc %o4, %o1, %o4 ! 15
+ mulscc %o4, %o1, %o4 ! 16
+ mulscc %o4, %o1, %o4 ! 17
+ mulscc %o4, %o1, %o4 ! 18
+ mulscc %o4, %o1, %o4 ! 19
+ mulscc %o4, %o1, %o4 ! 20
+ mulscc %o4, %o1, %o4 ! 21
+ mulscc %o4, %o1, %o4 ! 22
+ mulscc %o4, %o1, %o4 ! 23
+ mulscc %o4, %o1, %o4 ! 24
+ mulscc %o4, %o1, %o4 ! 25
+ mulscc %o4, %o1, %o4 ! 26
+ mulscc %o4, %o1, %o4 ! 27
+ mulscc %o4, %o1, %o4 ! 28
+ mulscc %o4, %o1, %o4 ! 29
+ mulscc %o4, %o1, %o4 ! 30
+ mulscc %o4, %o1, %o4 ! 31
+ mulscc %o4, %o1, %o4 ! 32
+ mulscc %o4, %g0, %o4 ! final shift
+
+ ! If %o0 was negative, the result is
+ ! (%o0 * %o1) + (%o1 << 32))
+ ! We fix that here.
+
+#if 0
+ tst %o0
+ bge 1f
+ rd %y, %o0
+
+ ! %o0 was indeed negative; fix upper 32 bits of result by subtracting
+ ! %o1 (i.e., return %o4 - %o1 in %o1).
+ retl
+ sub %o4, %o1, %o1
+
+1:
+ retl
+ mov %o4, %o1
+#else
+ /* Faster code adapted from tege@sics.se's code for umul.S. */
+ sra %o0, 31, %o2 ! make mask from sign bit
+ and %o1, %o2, %o2 ! %o2 = 0 or %o1, depending on sign of %o0
+ rd %y, %o0 ! get lower half of product
+ retl
+ sub %o4, %o2, %o1 ! subtract compensation
+ ! and put upper half in place
+#endif
+
+Lmul_shortway:
+ /*
+ * Short multiply. 12 steps, followed by a final shift step.
+ * The resulting bits are off by 12 and (32-12) = 20 bit positions,
+ * but there is no problem with %o0 being negative (unlike above).
+ */
+ mulscc %o4, %o1, %o4 ! 1
+ mulscc %o4, %o1, %o4 ! 2
+ mulscc %o4, %o1, %o4 ! 3
+ mulscc %o4, %o1, %o4 ! 4
+ mulscc %o4, %o1, %o4 ! 5
+ mulscc %o4, %o1, %o4 ! 6
+ mulscc %o4, %o1, %o4 ! 7
+ mulscc %o4, %o1, %o4 ! 8
+ mulscc %o4, %o1, %o4 ! 9
+ mulscc %o4, %o1, %o4 ! 10
+ mulscc %o4, %o1, %o4 ! 11
+ mulscc %o4, %o1, %o4 ! 12
+ mulscc %o4, %g0, %o4 ! final shift
+
+ /*
+ * %o4 has 20 of the bits that should be in the low part of the
+ * result; %y has the bottom 12 (as %y's top 12). That is:
+ *
+ * %o4 %y
+ * +----------------+----------------+
+ * | -12- | -20- | -12- | -20- |
+ * +------(---------+------)---------+
+ * --hi-- ----low-part----
+ *
+ * The upper 12 bits of %o4 should be sign-extended to form the
+ * high part of the product (i.e., highpart = %o4 >> 20).
+ */
+
+ rd %y, %o5
+ sll %o4, 12, %o0 ! shift middle bits left 12
+ srl %o5, 20, %o5 ! shift low bits right 20, zero fill at left
+ or %o5, %o0, %o0 ! construct low part of result
+ retl
+ sra %o4, 20, %o1 ! ... and extract high part of result
diff --git a/arch/sparc/lib/rem.S b/arch/sparc/lib/rem.S
new file mode 100644
index 000000000..3c0cc579b
--- /dev/null
+++ b/arch/sparc/lib/rem.S
@@ -0,0 +1,359 @@
+/* rem.S: This routine was taken from glibc-1.09 and is covered
+ * by the GNU Library General Public License Version 2.
+ */
+
+
+/* This file is generated from divrem.m4; DO NOT EDIT! */
+/*
+ * Division and remainder, from Appendix E of the Sparc Version 8
+ * Architecture Manual, with fixes from Gordon Irlam.
+ */
+
+/*
+ * Input: dividend and divisor in %o0 and %o1 respectively.
+ *
+ * m4 parameters:
+ * .rem name of function to generate
+ * rem rem=div => %o0 / %o1; rem=rem => %o0 % %o1
+ * true true=true => signed; true=false => unsigned
+ *
+ * Algorithm parameters:
+ * N how many bits per iteration we try to get (4)
+ * WORDSIZE total number of bits (32)
+ *
+ * Derived constants:
+ * TOPBITS number of bits in the top decade of a number
+ *
+ * Important variables:
+ * Q the partial quotient under development (initially 0)
+ * R the remainder so far, initially the dividend
+ * ITER number of main division loop iterations required;
+ * equal to ceil(log2(quotient) / N). Note that this
+ * is the log base (2^N) of the quotient.
+ * V the current comparand, initially divisor*2^(ITER*N-1)
+ *
+ * Cost:
+ * Current estimate for non-large dividend is
+ * ceil(log2(quotient) / N) * (10 + 7N/2) + C
+ * A large dividend is one greater than 2^(31-TOPBITS) and takes a
+ * different path, as the upper bits of the quotient must be developed
+ * one bit at a time.
+ */
+
+
+ .globl .rem
+.rem:
+ ! compute sign of result; if neither is negative, no problem
+ orcc %o1, %o0, %g0 ! either negative?
+ bge 2f ! no, go do the divide
+ xor %o1, %o0, %g6 ! compute sign in any case
+ tst %o1
+ bge 1f
+ tst %o0
+ ! %o1 is definitely negative; %o0 might also be negative
+ bge 2f ! if %o0 not negative...
+ sub %g0, %o1, %o1 ! in any case, make %o1 nonneg
+1: ! %o0 is negative, %o1 is nonnegative
+ sub %g0, %o0, %o0 ! make %o0 nonnegative
+2:
+
+ ! Ready to divide. Compute size of quotient; scale comparand.
+ orcc %o1, %g0, %o5
+ bne 1f
+ mov %o0, %o3
+
+ ! Divide by zero trap. If it returns, return 0 (about as
+ ! wrong as possible, but that is what SunOS does...).
+ ta ST_DIV0
+ retl
+ clr %o0
+
+1:
+ cmp %o3, %o5 ! if %o1 exceeds %o0, done
+ blu Lgot_result ! (and algorithm fails otherwise)
+ clr %o2
+ sethi %hi(1 << (32 - 4 - 1)), %g1
+ cmp %o3, %g1
+ blu Lnot_really_big
+ clr %o4
+
+ ! Here the dividend is >= 2**(31-N) or so. We must be careful here,
+ ! as our usual N-at-a-shot divide step will cause overflow and havoc.
+ ! The number of bits in the result here is N*ITER+SC, where SC <= N.
+ ! Compute ITER in an unorthodox manner: know we need to shift V into
+ ! the top decade: so do not even bother to compare to R.
+ 1:
+ cmp %o5, %g1
+ bgeu 3f
+ mov 1, %g7
+ sll %o5, 4, %o5
+ b 1b
+ add %o4, 1, %o4
+
+ ! Now compute %g7.
+ 2: addcc %o5, %o5, %o5
+ bcc Lnot_too_big
+ add %g7, 1, %g7
+
+ ! We get here if the %o1 overflowed while shifting.
+ ! This means that %o3 has the high-order bit set.
+ ! Restore %o5 and subtract from %o3.
+ sll %g1, 4, %g1 ! high order bit
+ srl %o5, 1, %o5 ! rest of %o5
+ add %o5, %g1, %o5
+ b Ldo_single_div
+ sub %g7, 1, %g7
+
+ Lnot_too_big:
+ 3: cmp %o5, %o3
+ blu 2b
+ nop
+ be Ldo_single_div
+ nop
+ /* NB: these are commented out in the V8-Sparc manual as well */
+ /* (I do not understand this) */
+ ! %o5 > %o3: went too far: back up 1 step
+ ! srl %o5, 1, %o5
+ ! dec %g7
+ ! do single-bit divide steps
+ !
+ ! We have to be careful here. We know that %o3 >= %o5, so we can do the
+ ! first divide step without thinking. BUT, the others are conditional,
+ ! and are only done if %o3 >= 0. Because both %o3 and %o5 may have the high-
+ ! order bit set in the first step, just falling into the regular
+ ! division loop will mess up the first time around.
+ ! So we unroll slightly...
+ Ldo_single_div:
+ subcc %g7, 1, %g7
+ bl Lend_regular_divide
+ nop
+ sub %o3, %o5, %o3
+ mov 1, %o2
+ b Lend_single_divloop
+ nop
+ Lsingle_divloop:
+ sll %o2, 1, %o2
+ bl 1f
+ srl %o5, 1, %o5
+ ! %o3 >= 0
+ sub %o3, %o5, %o3
+ b 2f
+ add %o2, 1, %o2
+ 1: ! %o3 < 0
+ add %o3, %o5, %o3
+ sub %o2, 1, %o2
+ 2:
+ Lend_single_divloop:
+ subcc %g7, 1, %g7
+ bge Lsingle_divloop
+ tst %o3
+ b,a Lend_regular_divide
+
+Lnot_really_big:
+1:
+ sll %o5, 4, %o5
+ cmp %o5, %o3
+ bleu 1b
+ addcc %o4, 1, %o4
+ be Lgot_result
+ sub %o4, 1, %o4
+
+ tst %o3 ! set up for initial iteration
+Ldivloop:
+ sll %o2, 4, %o2
+ ! depth 1, accumulated bits 0
+ bl L.1.16
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ ! depth 2, accumulated bits 1
+ bl L.2.17
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ ! depth 3, accumulated bits 3
+ bl L.3.19
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ ! depth 4, accumulated bits 7
+ bl L.4.23
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (7*2+1), %o2
+
+L.4.23:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (7*2-1), %o2
+
+
+L.3.19:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ ! depth 4, accumulated bits 5
+ bl L.4.21
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (5*2+1), %o2
+
+L.4.21:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (5*2-1), %o2
+
+
+
+L.2.17:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ ! depth 3, accumulated bits 1
+ bl L.3.17
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ ! depth 4, accumulated bits 3
+ bl L.4.19
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (3*2+1), %o2
+
+L.4.19:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (3*2-1), %o2
+
+
+L.3.17:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ ! depth 4, accumulated bits 1
+ bl L.4.17
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (1*2+1), %o2
+
+L.4.17:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (1*2-1), %o2
+
+
+
+
+L.1.16:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ ! depth 2, accumulated bits -1
+ bl L.2.15
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ ! depth 3, accumulated bits -1
+ bl L.3.15
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ ! depth 4, accumulated bits -1
+ bl L.4.15
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-1*2+1), %o2
+
+L.4.15:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-1*2-1), %o2
+
+
+L.3.15:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ ! depth 4, accumulated bits -3
+ bl L.4.13
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-3*2+1), %o2
+
+L.4.13:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-3*2-1), %o2
+
+
+
+L.2.15:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ ! depth 3, accumulated bits -3
+ bl L.3.13
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ ! depth 4, accumulated bits -5
+ bl L.4.11
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-5*2+1), %o2
+
+L.4.11:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-5*2-1), %o2
+
+
+L.3.13:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ ! depth 4, accumulated bits -7
+ bl L.4.9
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-7*2+1), %o2
+
+L.4.9:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-7*2-1), %o2
+
+
+
+
+ 9:
+Lend_regular_divide:
+ subcc %o4, 1, %o4
+ bge Ldivloop
+ tst %o3
+ bl,a Lgot_result
+ ! non-restoring fixup here (one instruction only!)
+ add %o3, %o1, %o3
+
+
+Lgot_result:
+
+ retl
+ mov %o3, %o0
diff --git a/arch/sparc/lib/sdiv.S b/arch/sparc/lib/sdiv.S
new file mode 100644
index 000000000..2fa7a9794
--- /dev/null
+++ b/arch/sparc/lib/sdiv.S
@@ -0,0 +1,363 @@
+/* sdiv.S: This routine was taken from glibc-1.09 and is covered
+ * by the GNU Library General Public License Version 2.
+ */
+
+
+/* This file is generated from divrem.m4; DO NOT EDIT! */
+/*
+ * Division and remainder, from Appendix E of the Sparc Version 8
+ * Architecture Manual, with fixes from Gordon Irlam.
+ */
+
+/*
+ * Input: dividend and divisor in %o0 and %o1 respectively.
+ *
+ * m4 parameters:
+ * .div name of function to generate
+ * div div=div => %o0 / %o1; div=rem => %o0 % %o1
+ * true true=true => signed; true=false => unsigned
+ *
+ * Algorithm parameters:
+ * N how many bits per iteration we try to get (4)
+ * WORDSIZE total number of bits (32)
+ *
+ * Derived constants:
+ * TOPBITS number of bits in the top decade of a number
+ *
+ * Important variables:
+ * Q the partial quotient under development (initially 0)
+ * R the remainder so far, initially the dividend
+ * ITER number of main division loop iterations required;
+ * equal to ceil(log2(quotient) / N). Note that this
+ * is the log base (2^N) of the quotient.
+ * V the current comparand, initially divisor*2^(ITER*N-1)
+ *
+ * Cost:
+ * Current estimate for non-large dividend is
+ * ceil(log2(quotient) / N) * (10 + 7N/2) + C
+ * A large dividend is one greater than 2^(31-TOPBITS) and takes a
+ * different path, as the upper bits of the quotient must be developed
+ * one bit at a time.
+ */
+
+
+ .globl .div
+.div:
+ ! compute sign of result; if neither is negative, no problem
+ orcc %o1, %o0, %g0 ! either negative?
+ bge 2f ! no, go do the divide
+ xor %o1, %o0, %g6 ! compute sign in any case
+ tst %o1
+ bge 1f
+ tst %o0
+ ! %o1 is definitely negative; %o0 might also be negative
+ bge 2f ! if %o0 not negative...
+ sub %g0, %o1, %o1 ! in any case, make %o1 nonneg
+1: ! %o0 is negative, %o1 is nonnegative
+ sub %g0, %o0, %o0 ! make %o0 nonnegative
+2:
+
+ ! Ready to divide. Compute size of quotient; scale comparand.
+ orcc %o1, %g0, %o5
+ bne 1f
+ mov %o0, %o3
+
+ ! Divide by zero trap. If it returns, return 0 (about as
+ ! wrong as possible, but that is what SunOS does...).
+ ta ST_DIV0
+ retl
+ clr %o0
+
+1:
+ cmp %o3, %o5 ! if %o1 exceeds %o0, done
+ blu Lgot_result ! (and algorithm fails otherwise)
+ clr %o2
+ sethi %hi(1 << (32 - 4 - 1)), %g1
+ cmp %o3, %g1
+ blu Lnot_really_big
+ clr %o4
+
+ ! Here the dividend is >= 2**(31-N) or so. We must be careful here,
+ ! as our usual N-at-a-shot divide step will cause overflow and havoc.
+ ! The number of bits in the result here is N*ITER+SC, where SC <= N.
+ ! Compute ITER in an unorthodox manner: know we need to shift V into
+ ! the top decade: so do not even bother to compare to R.
+ 1:
+ cmp %o5, %g1
+ bgeu 3f
+ mov 1, %g7
+ sll %o5, 4, %o5
+ b 1b
+ add %o4, 1, %o4
+
+ ! Now compute %g7.
+ 2: addcc %o5, %o5, %o5
+ bcc Lnot_too_big
+ add %g7, 1, %g7
+
+ ! We get here if the %o1 overflowed while shifting.
+ ! This means that %o3 has the high-order bit set.
+ ! Restore %o5 and subtract from %o3.
+ sll %g1, 4, %g1 ! high order bit
+ srl %o5, 1, %o5 ! rest of %o5
+ add %o5, %g1, %o5
+ b Ldo_single_div
+ sub %g7, 1, %g7
+
+ Lnot_too_big:
+ 3: cmp %o5, %o3
+ blu 2b
+ nop
+ be Ldo_single_div
+ nop
+ /* NB: these are commented out in the V8-Sparc manual as well */
+ /* (I do not understand this) */
+ ! %o5 > %o3: went too far: back up 1 step
+ ! srl %o5, 1, %o5
+ ! dec %g7
+ ! do single-bit divide steps
+ !
+ ! We have to be careful here. We know that %o3 >= %o5, so we can do the
+ ! first divide step without thinking. BUT, the others are conditional,
+ ! and are only done if %o3 >= 0. Because both %o3 and %o5 may have the high-
+ ! order bit set in the first step, just falling into the regular
+ ! division loop will mess up the first time around.
+ ! So we unroll slightly...
+ Ldo_single_div:
+ subcc %g7, 1, %g7
+ bl Lend_regular_divide
+ nop
+ sub %o3, %o5, %o3
+ mov 1, %o2
+ b Lend_single_divloop
+ nop
+ Lsingle_divloop:
+ sll %o2, 1, %o2
+ bl 1f
+ srl %o5, 1, %o5
+ ! %o3 >= 0
+ sub %o3, %o5, %o3
+ b 2f
+ add %o2, 1, %o2
+ 1: ! %o3 < 0
+ add %o3, %o5, %o3
+ sub %o2, 1, %o2
+ 2:
+ Lend_single_divloop:
+ subcc %g7, 1, %g7
+ bge Lsingle_divloop
+ tst %o3
+ b,a Lend_regular_divide
+
+Lnot_really_big:
+1:
+ sll %o5, 4, %o5
+ cmp %o5, %o3
+ bleu 1b
+ addcc %o4, 1, %o4
+ be Lgot_result
+ sub %o4, 1, %o4
+
+ tst %o3 ! set up for initial iteration
+Ldivloop:
+ sll %o2, 4, %o2
+ ! depth 1, accumulated bits 0
+ bl L.1.16
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ ! depth 2, accumulated bits 1
+ bl L.2.17
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ ! depth 3, accumulated bits 3
+ bl L.3.19
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ ! depth 4, accumulated bits 7
+ bl L.4.23
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (7*2+1), %o2
+
+L.4.23:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (7*2-1), %o2
+
+
+L.3.19:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ ! depth 4, accumulated bits 5
+ bl L.4.21
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (5*2+1), %o2
+
+L.4.21:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (5*2-1), %o2
+
+
+
+L.2.17:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ ! depth 3, accumulated bits 1
+ bl L.3.17
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ ! depth 4, accumulated bits 3
+ bl L.4.19
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (3*2+1), %o2
+
+L.4.19:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (3*2-1), %o2
+
+
+L.3.17:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ ! depth 4, accumulated bits 1
+ bl L.4.17
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (1*2+1), %o2
+
+L.4.17:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (1*2-1), %o2
+
+
+
+
+L.1.16:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ ! depth 2, accumulated bits -1
+ bl L.2.15
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ ! depth 3, accumulated bits -1
+ bl L.3.15
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ ! depth 4, accumulated bits -1
+ bl L.4.15
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-1*2+1), %o2
+
+L.4.15:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-1*2-1), %o2
+
+
+L.3.15:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ ! depth 4, accumulated bits -3
+ bl L.4.13
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-3*2+1), %o2
+
+L.4.13:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-3*2-1), %o2
+
+
+
+L.2.15:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ ! depth 3, accumulated bits -3
+ bl L.3.13
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ ! depth 4, accumulated bits -5
+ bl L.4.11
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-5*2+1), %o2
+
+L.4.11:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-5*2-1), %o2
+
+
+L.3.13:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ ! depth 4, accumulated bits -7
+ bl L.4.9
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-7*2+1), %o2
+
+L.4.9:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-7*2-1), %o2
+
+
+
+
+ 9:
+Lend_regular_divide:
+ subcc %o4, 1, %o4
+ bge Ldivloop
+ tst %o3
+ bl,a Lgot_result
+ ! non-restoring fixup here (one instruction only!)
+ sub %o2, 1, %o2
+
+
+Lgot_result:
+ ! check to see if answer should be < 0
+ tst %g6
+ bl,a 1f
+ sub %g0, %o2, %o2
+1:
+ retl
+ mov %o2, %o0
diff --git a/arch/sparc/lib/udiv.S b/arch/sparc/lib/udiv.S
new file mode 100644
index 000000000..53cfeac90
--- /dev/null
+++ b/arch/sparc/lib/udiv.S
@@ -0,0 +1,346 @@
+/* udiv.S: This routine was taken from glibc-1.09 and is covered
+ * by the GNU Library General Public License Version 2.
+ */
+
+
+/* This file is generated from divrem.m4; DO NOT EDIT! */
+/*
+ * Division and remainder, from Appendix E of the Sparc Version 8
+ * Architecture Manual, with fixes from Gordon Irlam.
+ */
+
+/*
+ * Input: dividend and divisor in %o0 and %o1 respectively.
+ *
+ * m4 parameters:
+ * .udiv name of function to generate
+ * div div=div => %o0 / %o1; div=rem => %o0 % %o1
+ * false false=true => signed; false=false => unsigned
+ *
+ * Algorithm parameters:
+ * N how many bits per iteration we try to get (4)
+ * WORDSIZE total number of bits (32)
+ *
+ * Derived constants:
+ * TOPBITS number of bits in the top decade of a number
+ *
+ * Important variables:
+ * Q the partial quotient under development (initially 0)
+ * R the remainder so far, initially the dividend
+ * ITER number of main division loop iterations required;
+ * equal to ceil(log2(quotient) / N). Note that this
+ * is the log base (2^N) of the quotient.
+ * V the current comparand, initially divisor*2^(ITER*N-1)
+ *
+ * Cost:
+ * Current estimate for non-large dividend is
+ * ceil(log2(quotient) / N) * (10 + 7N/2) + C
+ * A large dividend is one greater than 2^(31-TOPBITS) and takes a
+ * different path, as the upper bits of the quotient must be developed
+ * one bit at a time.
+ */
+
+
+ .globl .udiv
+.udiv:
+
+ ! Ready to divide. Compute size of quotient; scale comparand.
+ orcc %o1, %g0, %o5
+ bne 1f
+ mov %o0, %o3
+
+ ! Divide by zero trap. If it returns, return 0 (about as
+ ! wrong as possible, but that is what SunOS does...).
+ ta ST_DIV0
+ retl
+ clr %o0
+
+1:
+ cmp %o3, %o5 ! if %o1 exceeds %o0, done
+ blu Lgot_result ! (and algorithm fails otherwise)
+ clr %o2
+ sethi %hi(1 << (32 - 4 - 1)), %g1
+ cmp %o3, %g1
+ blu Lnot_really_big
+ clr %o4
+
+ ! Here the dividend is >= 2**(31-N) or so. We must be careful here,
+ ! as our usual N-at-a-shot divide step will cause overflow and havoc.
+ ! The number of bits in the result here is N*ITER+SC, where SC <= N.
+ ! Compute ITER in an unorthodox manner: know we need to shift V into
+ ! the top decade: so do not even bother to compare to R.
+ 1:
+ cmp %o5, %g1
+ bgeu 3f
+ mov 1, %g7
+ sll %o5, 4, %o5
+ b 1b
+ add %o4, 1, %o4
+
+ ! Now compute %g7.
+ 2: addcc %o5, %o5, %o5
+ bcc Lnot_too_big
+ add %g7, 1, %g7
+
+ ! We get here if the %o1 overflowed while shifting.
+ ! This means that %o3 has the high-order bit set.
+ ! Restore %o5 and subtract from %o3.
+ sll %g1, 4, %g1 ! high order bit
+ srl %o5, 1, %o5 ! rest of %o5
+ add %o5, %g1, %o5
+ b Ldo_single_div
+ sub %g7, 1, %g7
+
+ Lnot_too_big:
+ 3: cmp %o5, %o3
+ blu 2b
+ nop
+ be Ldo_single_div
+ nop
+ /* NB: these are commented out in the V8-Sparc manual as well */
+ /* (I do not understand this) */
+ ! %o5 > %o3: went too far: back up 1 step
+ ! srl %o5, 1, %o5
+ ! dec %g7
+ ! do single-bit divide steps
+ !
+ ! We have to be careful here. We know that %o3 >= %o5, so we can do the
+ ! first divide step without thinking. BUT, the others are conditional,
+ ! and are only done if %o3 >= 0. Because both %o3 and %o5 may have the high-
+ ! order bit set in the first step, just falling into the regular
+ ! division loop will mess up the first time around.
+ ! So we unroll slightly...
+ Ldo_single_div:
+ subcc %g7, 1, %g7
+ bl Lend_regular_divide
+ nop
+ sub %o3, %o5, %o3
+ mov 1, %o2
+ b Lend_single_divloop
+ nop
+ Lsingle_divloop:
+ sll %o2, 1, %o2
+ bl 1f
+ srl %o5, 1, %o5
+ ! %o3 >= 0
+ sub %o3, %o5, %o3
+ b 2f
+ add %o2, 1, %o2
+ 1: ! %o3 < 0
+ add %o3, %o5, %o3
+ sub %o2, 1, %o2
+ 2:
+ Lend_single_divloop:
+ subcc %g7, 1, %g7
+ bge Lsingle_divloop
+ tst %o3
+ b,a Lend_regular_divide
+
+Lnot_really_big:
+1:
+ sll %o5, 4, %o5
+ cmp %o5, %o3
+ bleu 1b
+ addcc %o4, 1, %o4
+ be Lgot_result
+ sub %o4, 1, %o4
+
+ tst %o3 ! set up for initial iteration
+Ldivloop:
+ sll %o2, 4, %o2
+ ! depth 1, accumulated bits 0
+ bl L.1.16
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ ! depth 2, accumulated bits 1
+ bl L.2.17
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ ! depth 3, accumulated bits 3
+ bl L.3.19
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ ! depth 4, accumulated bits 7
+ bl L.4.23
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (7*2+1), %o2
+
+L.4.23:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (7*2-1), %o2
+
+
+L.3.19:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ ! depth 4, accumulated bits 5
+ bl L.4.21
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (5*2+1), %o2
+
+L.4.21:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (5*2-1), %o2
+
+
+
+L.2.17:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ ! depth 3, accumulated bits 1
+ bl L.3.17
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ ! depth 4, accumulated bits 3
+ bl L.4.19
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (3*2+1), %o2
+
+L.4.19:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (3*2-1), %o2
+
+
+L.3.17:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ ! depth 4, accumulated bits 1
+ bl L.4.17
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (1*2+1), %o2
+
+L.4.17:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (1*2-1), %o2
+
+
+
+
+L.1.16:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ ! depth 2, accumulated bits -1
+ bl L.2.15
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ ! depth 3, accumulated bits -1
+ bl L.3.15
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ ! depth 4, accumulated bits -1
+ bl L.4.15
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-1*2+1), %o2
+
+L.4.15:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-1*2-1), %o2
+
+
+L.3.15:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ ! depth 4, accumulated bits -3
+ bl L.4.13
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-3*2+1), %o2
+
+L.4.13:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-3*2-1), %o2
+
+
+
+L.2.15:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ ! depth 3, accumulated bits -3
+ bl L.3.13
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ ! depth 4, accumulated bits -5
+ bl L.4.11
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-5*2+1), %o2
+
+L.4.11:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-5*2-1), %o2
+
+
+L.3.13:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ ! depth 4, accumulated bits -7
+ bl L.4.9
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-7*2+1), %o2
+
+L.4.9:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-7*2-1), %o2
+
+
+
+
+ 9:
+Lend_regular_divide:
+ subcc %o4, 1, %o4
+ bge Ldivloop
+ tst %o3
+ bl,a Lgot_result
+ ! non-restoring fixup here (one instruction only!)
+ sub %o2, 1, %o2
+
+
+Lgot_result:
+
+ retl
+ mov %o2, %o0
diff --git a/arch/sparc/lib/umul.S b/arch/sparc/lib/umul.S
new file mode 100644
index 000000000..24f7c3cda
--- /dev/null
+++ b/arch/sparc/lib/umul.S
@@ -0,0 +1,158 @@
+/* umul.S: This routine was taken from glibc-1.09 and is covered
+ * by the GNU Library General Public License Version 2.
+ */
+
+
+/*
+ * Unsigned multiply. Returns %o0 * %o1 in %o1%o0 (i.e., %o1 holds the
+ * upper 32 bits of the 64-bit product).
+ *
+ * This code optimizes short (less than 13-bit) multiplies. Short
+ * multiplies require 25 instruction cycles, and long ones require
+ * 45 instruction cycles.
+ *
+ * On return, overflow has occurred (%o1 is not zero) if and only if
+ * the Z condition code is clear, allowing, e.g., the following:
+ *
+ * call .umul
+ * nop
+ * bnz overflow (or tnz)
+ */
+
+ .globl .umul
+.umul:
+ or %o0, %o1, %o4
+ mov %o0, %y ! multiplier -> Y
+ andncc %o4, 0xfff, %g0 ! test bits 12..31 of *both* args
+ be Lmul_shortway ! if zero, can do it the short way
+ andcc %g0, %g0, %o4 ! zero the partial product and clear N and V
+
+ /*
+ * Long multiply. 32 steps, followed by a final shift step.
+ */
+ mulscc %o4, %o1, %o4 ! 1
+ mulscc %o4, %o1, %o4 ! 2
+ mulscc %o4, %o1, %o4 ! 3
+ mulscc %o4, %o1, %o4 ! 4
+ mulscc %o4, %o1, %o4 ! 5
+ mulscc %o4, %o1, %o4 ! 6
+ mulscc %o4, %o1, %o4 ! 7
+ mulscc %o4, %o1, %o4 ! 8
+ mulscc %o4, %o1, %o4 ! 9
+ mulscc %o4, %o1, %o4 ! 10
+ mulscc %o4, %o1, %o4 ! 11
+ mulscc %o4, %o1, %o4 ! 12
+ mulscc %o4, %o1, %o4 ! 13
+ mulscc %o4, %o1, %o4 ! 14
+ mulscc %o4, %o1, %o4 ! 15
+ mulscc %o4, %o1, %o4 ! 16
+ mulscc %o4, %o1, %o4 ! 17
+ mulscc %o4, %o1, %o4 ! 18
+ mulscc %o4, %o1, %o4 ! 19
+ mulscc %o4, %o1, %o4 ! 20
+ mulscc %o4, %o1, %o4 ! 21
+ mulscc %o4, %o1, %o4 ! 22
+ mulscc %o4, %o1, %o4 ! 23
+ mulscc %o4, %o1, %o4 ! 24
+ mulscc %o4, %o1, %o4 ! 25
+ mulscc %o4, %o1, %o4 ! 26
+ mulscc %o4, %o1, %o4 ! 27
+ mulscc %o4, %o1, %o4 ! 28
+ mulscc %o4, %o1, %o4 ! 29
+ mulscc %o4, %o1, %o4 ! 30
+ mulscc %o4, %o1, %o4 ! 31
+ mulscc %o4, %o1, %o4 ! 32
+ mulscc %o4, %g0, %o4 ! final shift
+
+
+ /*
+ * Normally, with the shift-and-add approach, if both numbers are
+ * positive you get the correct result. With 32-bit two's-complement
+ * numbers, -x is represented as
+ *
+ * x 32
+ * ( 2 - ------ ) mod 2 * 2
+ * 32
+ * 2
+ *
+ * (the `mod 2' subtracts 1 from 1.bbbb). To avoid lots of 2^32s,
+ * we can treat this as if the radix point were just to the left
+ * of the sign bit (multiply by 2^32), and get
+ *
+ * -x = (2 - x) mod 2
+ *
+ * Then, ignoring the `mod 2's for convenience:
+ *
+ * x * y = xy
+ * -x * y = 2y - xy
+ * x * -y = 2x - xy
+ * -x * -y = 4 - 2x - 2y + xy
+ *
+ * For signed multiplies, we subtract (x << 32) from the partial
+ * product to fix this problem for negative multipliers (see mul.s).
+ * Because of the way the shift into the partial product is calculated
+ * (N xor V), this term is automatically removed for the multiplicand,
+ * so we don't have to adjust.
+ *
+ * But for unsigned multiplies, the high order bit wasn't a sign bit,
+ * and the correction is wrong. So for unsigned multiplies where the
+ * high order bit is one, we end up with xy - (y << 32). To fix it
+ * we add y << 32.
+ */
+#if 0
+ tst %o1
+ bl,a 1f ! if %o1 < 0 (high order bit = 1),
+ add %o4, %o0, %o4 ! %o4 += %o0 (add y to upper half)
+1: rd %y, %o0 ! get lower half of product
+ retl
+ addcc %o4, %g0, %o1 ! put upper half in place and set Z for %o1==0
+#else
+ /* Faster code from tege@sics.se. */
+ sra %o1, 31, %o2 ! make mask from sign bit
+ and %o0, %o2, %o2 ! %o2 = 0 or %o0, depending on sign of %o1
+ rd %y, %o0 ! get lower half of product
+ retl
+ addcc %o4, %o2, %o1 ! add compensation and put upper half in place
+#endif
+
+Lmul_shortway:
+ /*
+ * Short multiply. 12 steps, followed by a final shift step.
+ * The resulting bits are off by 12 and (32-12) = 20 bit positions,
+ * but there is no problem with %o0 being negative (unlike above),
+ * and overflow is impossible (the answer is at most 24 bits long).
+ */
+ mulscc %o4, %o1, %o4 ! 1
+ mulscc %o4, %o1, %o4 ! 2
+ mulscc %o4, %o1, %o4 ! 3
+ mulscc %o4, %o1, %o4 ! 4
+ mulscc %o4, %o1, %o4 ! 5
+ mulscc %o4, %o1, %o4 ! 6
+ mulscc %o4, %o1, %o4 ! 7
+ mulscc %o4, %o1, %o4 ! 8
+ mulscc %o4, %o1, %o4 ! 9
+ mulscc %o4, %o1, %o4 ! 10
+ mulscc %o4, %o1, %o4 ! 11
+ mulscc %o4, %o1, %o4 ! 12
+ mulscc %o4, %g0, %o4 ! final shift
+
+ /*
+ * %o4 has 20 of the bits that should be in the result; %y has
+ * the bottom 12 (as %y's top 12). That is:
+ *
+ * %o4 %y
+ * +----------------+----------------+
+ * | -12- | -20- | -12- | -20- |
+ * +------(---------+------)---------+
+ * -----result-----
+ *
+ * The 12 bits of %o4 left of the `result' area are all zero;
+ * in fact, all top 20 bits of %o4 are zero.
+ */
+
+ rd %y, %o5
+ sll %o4, 12, %o0 ! shift middle bits left 12
+ srl %o5, 20, %o5 ! shift low bits right 20
+ or %o5, %o0, %o0
+ retl
+ addcc %g0, %g0, %o1 ! %o1 = zero, and set Z
diff --git a/arch/sparc/lib/urem.S b/arch/sparc/lib/urem.S
new file mode 100644
index 000000000..c84aa81e5
--- /dev/null
+++ b/arch/sparc/lib/urem.S
@@ -0,0 +1,344 @@
+/* urem.S: This routine was taken from glibc-1.09 and is covered
+ * by the GNU Library General Public License Version 2.
+ */
+
+/* This file is generated from divrem.m4; DO NOT EDIT! */
+/*
+ * Division and remainder, from Appendix E of the Sparc Version 8
+ * Architecture Manual, with fixes from Gordon Irlam.
+ */
+
+/*
+ * Input: dividend and divisor in %o0 and %o1 respectively.
+ *
+ * m4 parameters:
+ * .urem name of function to generate
+ * rem rem=div => %o0 / %o1; rem=rem => %o0 % %o1
+ * false false=true => signed; false=false => unsigned
+ *
+ * Algorithm parameters:
+ * N how many bits per iteration we try to get (4)
+ * WORDSIZE total number of bits (32)
+ *
+ * Derived constants:
+ * TOPBITS number of bits in the top decade of a number
+ *
+ * Important variables:
+ * Q the partial quotient under development (initially 0)
+ * R the remainder so far, initially the dividend
+ * ITER number of main division loop iterations required;
+ * equal to ceil(log2(quotient) / N). Note that this
+ * is the log base (2^N) of the quotient.
+ * V the current comparand, initially divisor*2^(ITER*N-1)
+ *
+ * Cost:
+ * Current estimate for non-large dividend is
+ * ceil(log2(quotient) / N) * (10 + 7N/2) + C
+ * A large dividend is one greater than 2^(31-TOPBITS) and takes a
+ * different path, as the upper bits of the quotient must be developed
+ * one bit at a time.
+ */
+
+ .globl .urem
+.urem:
+
+ ! Ready to divide. Compute size of quotient; scale comparand.
+ orcc %o1, %g0, %o5
+ bne 1f
+ mov %o0, %o3
+
+ ! Divide by zero trap. If it returns, return 0 (about as
+ ! wrong as possible, but that is what SunOS does...).
+ ta ST_DIV0
+ retl
+ clr %o0
+
+1:
+ cmp %o3, %o5 ! if %o1 exceeds %o0, done
+ blu Lgot_result ! (and algorithm fails otherwise)
+ clr %o2
+ sethi %hi(1 << (32 - 4 - 1)), %g1
+ cmp %o3, %g1
+ blu Lnot_really_big
+ clr %o4
+
+ ! Here the dividend is >= 2**(31-N) or so. We must be careful here,
+ ! as our usual N-at-a-shot divide step will cause overflow and havoc.
+ ! The number of bits in the result here is N*ITER+SC, where SC <= N.
+ ! Compute ITER in an unorthodox manner: know we need to shift V into
+ ! the top decade: so do not even bother to compare to R.
+ 1:
+ cmp %o5, %g1
+ bgeu 3f
+ mov 1, %g7
+ sll %o5, 4, %o5
+ b 1b
+ add %o4, 1, %o4
+
+ ! Now compute %g7.
+ 2: addcc %o5, %o5, %o5
+ bcc Lnot_too_big
+ add %g7, 1, %g7
+
+ ! We get here if the %o1 overflowed while shifting.
+ ! This means that %o3 has the high-order bit set.
+ ! Restore %o5 and subtract from %o3.
+ sll %g1, 4, %g1 ! high order bit
+ srl %o5, 1, %o5 ! rest of %o5
+ add %o5, %g1, %o5
+ b Ldo_single_div
+ sub %g7, 1, %g7
+
+ Lnot_too_big:
+ 3: cmp %o5, %o3
+ blu 2b
+ nop
+ be Ldo_single_div
+ nop
+ /* NB: these are commented out in the V8-Sparc manual as well */
+ /* (I do not understand this) */
+ ! %o5 > %o3: went too far: back up 1 step
+ ! srl %o5, 1, %o5
+ ! dec %g7
+ ! do single-bit divide steps
+ !
+ ! We have to be careful here. We know that %o3 >= %o5, so we can do the
+ ! first divide step without thinking. BUT, the others are conditional,
+ ! and are only done if %o3 >= 0. Because both %o3 and %o5 may have the high-
+ ! order bit set in the first step, just falling into the regular
+ ! division loop will mess up the first time around.
+ ! So we unroll slightly...
+ Ldo_single_div:
+ subcc %g7, 1, %g7
+ bl Lend_regular_divide
+ nop
+ sub %o3, %o5, %o3
+ mov 1, %o2
+ b Lend_single_divloop
+ nop
+ Lsingle_divloop:
+ sll %o2, 1, %o2
+ bl 1f
+ srl %o5, 1, %o5
+ ! %o3 >= 0
+ sub %o3, %o5, %o3
+ b 2f
+ add %o2, 1, %o2
+ 1: ! %o3 < 0
+ add %o3, %o5, %o3
+ sub %o2, 1, %o2
+ 2:
+ Lend_single_divloop:
+ subcc %g7, 1, %g7
+ bge Lsingle_divloop
+ tst %o3
+ b,a Lend_regular_divide
+
+Lnot_really_big:
+1:
+ sll %o5, 4, %o5
+ cmp %o5, %o3
+ bleu 1b
+ addcc %o4, 1, %o4
+ be Lgot_result
+ sub %o4, 1, %o4
+
+ tst %o3 ! set up for initial iteration
+Ldivloop:
+ sll %o2, 4, %o2
+ ! depth 1, accumulated bits 0
+ bl L.1.16
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ ! depth 2, accumulated bits 1
+ bl L.2.17
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ ! depth 3, accumulated bits 3
+ bl L.3.19
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ ! depth 4, accumulated bits 7
+ bl L.4.23
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (7*2+1), %o2
+
+L.4.23:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (7*2-1), %o2
+
+
+L.3.19:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ ! depth 4, accumulated bits 5
+ bl L.4.21
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (5*2+1), %o2
+
+L.4.21:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (5*2-1), %o2
+
+
+
+L.2.17:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ ! depth 3, accumulated bits 1
+ bl L.3.17
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ ! depth 4, accumulated bits 3
+ bl L.4.19
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (3*2+1), %o2
+
+L.4.19:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (3*2-1), %o2
+
+
+L.3.17:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ ! depth 4, accumulated bits 1
+ bl L.4.17
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (1*2+1), %o2
+
+L.4.17:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (1*2-1), %o2
+
+
+
+
+L.1.16:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ ! depth 2, accumulated bits -1
+ bl L.2.15
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ ! depth 3, accumulated bits -1
+ bl L.3.15
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ ! depth 4, accumulated bits -1
+ bl L.4.15
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-1*2+1), %o2
+
+L.4.15:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-1*2-1), %o2
+
+
+L.3.15:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ ! depth 4, accumulated bits -3
+ bl L.4.13
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-3*2+1), %o2
+
+L.4.13:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-3*2-1), %o2
+
+
+
+L.2.15:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ ! depth 3, accumulated bits -3
+ bl L.3.13
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ ! depth 4, accumulated bits -5
+ bl L.4.11
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-5*2+1), %o2
+
+L.4.11:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-5*2-1), %o2
+
+
+L.3.13:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ ! depth 4, accumulated bits -7
+ bl L.4.9
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-7*2+1), %o2
+
+L.4.9:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-7*2-1), %o2
+
+
+
+
+ 9:
+Lend_regular_divide:
+ subcc %o4, 1, %o4
+ bge Ldivloop
+ tst %o3
+ bl,a Lgot_result
+ ! non-restoring fixup here (one instruction only!)
+ add %o3, %o1, %o3
+
+
+Lgot_result:
+
+ retl
+ mov %o3, %o0
diff --git a/arch/sparc/mm/Makefile b/arch/sparc/mm/Makefile
new file mode 100644
index 000000000..a4148d013
--- /dev/null
+++ b/arch/sparc/mm/Makefile
@@ -0,0 +1,32 @@
+#
+# Makefile for the linux Sparc-specific parts of the memory manager.
+#
+# 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 definition is now in the main makefile...
+
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+.s.o:
+ $(AS) -o $*.o $<
+.c.s:
+ $(CC) $(CFLAGS) -S $<
+
+OBJS = fault.o vac-flush.o init.o
+
+mm.o: $(OBJS)
+ $(LD) -r -o mm.o $(OBJS)
+
+modules:
+
+dep:
+ $(CPP) -M *.c > .depend
+
+#
+# include a dependency file if one exists
+#
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
diff --git a/arch/sparc/mm/fault.c b/arch/sparc/mm/fault.c
new file mode 100644
index 000000000..4c5fd0bc3
--- /dev/null
+++ b/arch/sparc/mm/fault.c
@@ -0,0 +1,173 @@
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/ptrace.h>
+#include <linux/mman.h>
+#include <linux/signal.h>
+#include <linux/mm.h>
+
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <asm/openprom.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+
+extern unsigned long pg0[1024]; /* page table for 0-4MB for everybody */
+extern struct sparc_phys_banks sp_banks[14];
+
+extern void die_if_kernel(char *,struct pt_regs *,long);
+
+struct linux_romvec *romvec;
+
+/* foo */
+
+int tbase_needs_unmapping;
+
+/* At boot time we determine these two values necessary for setting
+ * up the segment maps and page table entries (pte's).
+ */
+
+int num_segmaps, num_contexts;
+int invalid_segment;
+
+/* various Virtual Address Cache parameters we find at boot time... */
+
+int vac_size, vac_linesize, vac_do_hw_vac_flushes;
+int vac_entries_per_context, vac_entries_per_segment;
+int vac_entries_per_page;
+
+/*
+ * Define this if things work differently on a i386 and a i486:
+ * it will (on a i486) warn about kernel memory accesses that are
+ * done without a 'verify_area(VERIFY_WRITE,..)'
+ */
+#undef CONFIG_TEST_VERIFY_AREA
+
+/* Traverse the memory lists in the prom to see how much physical we
+ * have.
+ */
+
+unsigned long
+probe_memory(void)
+{
+ register struct linux_romvec *lprom;
+ register struct linux_mlist_v0 *mlist;
+ register unsigned long bytes, base_paddr, tally;
+ register int i;
+
+ bytes = tally = 0;
+ base_paddr = 0;
+ i=0;
+ lprom = romvec;
+ switch(lprom->pv_romvers)
+ {
+ case 0:
+ mlist=(*(lprom->pv_v0mem.v0_totphys));
+ bytes = tally = mlist->num_bytes;
+ base_paddr = (unsigned long) mlist->start_adr;
+
+ sp_banks[0].base_addr = base_paddr;
+ sp_banks[0].num_bytes = bytes;
+
+ if(mlist->theres_more != (void *)0) {
+ i++;
+ mlist=mlist->theres_more;
+ bytes=mlist->num_bytes;
+ tally += bytes;
+ sp_banks[i].base_addr = (unsigned long) mlist->start_adr;
+ sp_banks[i].num_bytes = mlist->num_bytes;
+ }
+ break;
+ case 2:
+ printk("no v2 memory probe support yet.\n");
+ (*(lprom->pv_halt))();
+ break;
+ }
+
+ i++;
+ sp_banks[i].base_addr = 0xdeadbeef;
+ sp_banks[i].num_bytes = 0;
+
+ return tally;
+}
+
+/* Sparc routine to reserve the mapping of the open boot prom */
+
+/* uncomment this for FAME and FORTUNE! */
+/* #define DEBUG_MAP_PROM */
+
+int
+map_the_prom(int curr_num_segs)
+{
+ register unsigned long prom_va_begin;
+ register unsigned long prom_va_end;
+ register int segmap_entry, i;
+
+ prom_va_begin = LINUX_OPPROM_BEGVM;
+ prom_va_end = LINUX_OPPROM_ENDVM;
+
+#ifdef DEBUG_MAP_PROM
+ printk("\ncurr_num_segs = 0x%x\n", curr_num_segs);
+#endif
+
+ while( prom_va_begin < prom_va_end)
+ {
+ segmap_entry=get_segmap(prom_va_begin);
+
+ curr_num_segs = ((segmap_entry<curr_num_segs)
+ ? segmap_entry : curr_num_segs);
+
+ for(i = num_contexts; --i > 0;)
+ (*romvec->pv_setctxt)(i, (char *) prom_va_begin,
+ segmap_entry);
+
+ if(segmap_entry == invalid_segment)
+ {
+
+#ifdef DEBUG_MAP_PROM
+ printk("invalid_segments, virt_addr 0x%x\n", prom_va_begin);
+#endif
+
+ prom_va_begin += 0x40000; /* num bytes per segment entry */
+ continue;
+ }
+
+ /* DUH, prom maps itself so that users can access it. This is
+ * broken.
+ */
+
+#ifdef DEBUG_MAP_PROM
+ printk("making segmap for prom privileged, va = 0x%x\n",
+ prom_va_begin);
+#endif
+
+ for(i = 0x40; --i >= 0; prom_va_begin+=4096)
+ {
+ put_pte(prom_va_begin, get_pte(prom_va_begin) | 0x20000000);
+ }
+
+ }
+
+ printk("Mapped the PROM in all contexts...\n");
+
+#ifdef DEBUG_MAP_PROM
+ printk("curr_num_segs = 0x%x\n", curr_num_segs);
+#endif
+
+ return curr_num_segs;
+
+}
+
+/*
+ * This routine handles page faults. It determines the address,
+ * and the problem, and then passes it off to one of the appropriate
+ * routines.
+ */
+asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
+{
+ die_if_kernel("Oops", regs, error_code);
+ do_exit(SIGKILL);
+}
+
+
+
+
diff --git a/arch/sparc/mm/init.c b/arch/sparc/mm/init.c
new file mode 100644
index 000000000..a65e9e094
--- /dev/null
+++ b/arch/sparc/mm/init.c
@@ -0,0 +1,364 @@
+/*
+ * linux/arch/sparc/mm/init.c
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <linux/config.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/head.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/ptrace.h>
+#include <linux/mman.h>
+#include <linux/mm.h>
+
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <asm/vac-ops.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+
+extern void scsi_mem_init(unsigned long);
+extern void sound_mem_init(void);
+extern void die_if_kernel(char *,struct pt_regs *,long);
+extern void show_net_buffers(void);
+
+extern int map_the_prom(int);
+
+struct sparc_phys_banks sp_banks[14];
+unsigned long *sun4c_mmu_table;
+extern int invalid_segment, num_segmaps, num_contexts;
+
+/*
+ * BAD_PAGE is the page that is used for page faults when linux
+ * is out-of-memory. Older versions of linux just did a
+ * do_exit(), but using this instead means there is less risk
+ * for a process dying in kernel mode, possibly leaving a inode
+ * unused etc..
+ *
+ * BAD_PAGETABLE is the accompanying page-table: it is initialized
+ * to point to BAD_PAGE entries.
+ *
+ * ZERO_PAGE is a special page that is used for zero-initialized
+ * data and COW.
+ */
+pte_t *__bad_pagetable(void)
+{
+ memset((void *) EMPTY_PGT, 0, PAGE_SIZE);
+ return (pte_t *) EMPTY_PGT;
+}
+
+pte_t __bad_page(void)
+{
+ memset((void *) EMPTY_PGE, 0, PAGE_SIZE);
+ return pte_mkdirty(mk_pte((unsigned long) EMPTY_PGE, PAGE_SHARED));
+}
+
+unsigned long __zero_page(void)
+{
+ memset((void *) ZERO_PGE, 0, PAGE_SIZE);
+ return ZERO_PGE;
+}
+
+void show_mem(void)
+{
+ int i,free = 0,total = 0,reserved = 0;
+ int shared = 0;
+
+ printk("Mem-info:\n");
+ show_free_areas();
+ printk("Free swap: %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10));
+ i = high_memory >> PAGE_SHIFT;
+ while (i-- > 0) {
+ total++;
+ if (mem_map[i] & MAP_PAGE_RESERVED)
+ reserved++;
+ else if (!mem_map[i])
+ free++;
+ else
+ shared += mem_map[i]-1;
+ }
+ printk("%d pages of RAM\n",total);
+ printk("%d free pages\n",free);
+ printk("%d reserved pages\n",reserved);
+ printk("%d pages shared\n",shared);
+ show_buffers();
+#ifdef CONFIG_NET
+ show_net_buffers();
+#endif
+}
+
+extern unsigned long free_area_init(unsigned long, unsigned long);
+
+/*
+ * paging_init() sets up the page tables: in the alpha version this actually
+ * unmaps the bootup page table (as we're now in KSEG, so we don't need it).
+ *
+ * The bootup sequence put the virtual page table into high memory: that
+ * means that we can change the L1 page table by just using VL1p below.
+ */
+
+unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)
+{
+ unsigned long i, a, b, mask=0;
+ unsigned long curseg, curpte, num_inval;
+ unsigned long address;
+ pte_t *pg_table;
+
+ register int num_segs, num_ctx;
+ register char * c;
+
+ num_segs = num_segmaps;
+ num_ctx = num_contexts;
+
+ num_segs -= 1;
+ invalid_segment = num_segs;
+
+ start_mem = free_area_init(start_mem, end_mem);
+
+/* On the sparc we first need to allocate the segmaps for the
+ * PROM's virtual space, and make those segmaps unusable. We
+ * map the PROM in ALL contexts therefore the break key and the
+ * sync command work no matter what state you took the machine
+ * out of
+ */
+
+ printk("mapping the prom...\n");
+ num_segs = map_the_prom(num_segs);
+
+ start_mem = PAGE_ALIGN(start_mem);
+
+ /* Set up static page tables in kernel space, this will be used
+ * so that the low-level page fault handler can fill in missing
+ * TLB entries since all mmu entries cannot be loaded at once
+ * on the sun4c.
+ */
+
+#if 0
+ /* ugly debugging code */
+ for(i=0; i<40960; i+=PAGE_SIZE)
+ printk("address=0x%x vseg=%d pte=0x%x\n", (unsigned int) i,
+ (int) get_segmap(i), (unsigned int) get_pte(i));
+#endif
+
+ printk("Setting up kernel static mmu table... bounce bounce\n");
+
+ address = 0; /* ((unsigned long) &end) + 524288; */
+ sun4c_mmu_table = (unsigned long *) start_mem;
+ pg_table = (pte_t *) start_mem;
+ curseg = curpte = num_inval = 0;
+ while(address < end_mem) {
+ if(curpte == 0)
+ put_segmap((address&PGDIR_MASK), curseg);
+ for(i=0; sp_banks[i].num_bytes != 0; i++)
+ if((address >= sp_banks[i].base_addr) &&
+ (address <= (sp_banks[i].base_addr + sp_banks[i].num_bytes)))
+ goto good_address;
+ /* No physical memory here, so set the virtual segment to
+ * the invalid one, and put an invalid pte in the static
+ * kernel table.
+ */
+ *pg_table = mk_pte((address >> PAGE_SHIFT), PAGE_INVALID);
+ pg_table++; curpte++; num_inval++;
+ if(curpte > 63) {
+ if(curpte == num_inval) {
+ put_segmap((address&PGDIR_MASK), invalid_segment);
+ } else {
+ put_segmap((address&PGDIR_MASK), curseg);
+ curseg++;
+ }
+ curpte = num_inval = 0;
+ }
+ address += PAGE_SIZE;
+ continue;
+
+ good_address:
+ /* create pte entry */
+ if(address < (((unsigned long) &end) + 524288)) {
+ pte_val(*pg_table) = get_pte(address);
+ } else {
+ *pg_table = mk_pte((address >> PAGE_SHIFT), PAGE_KERNEL);
+ put_pte(address, pte_val(*pg_table));
+ }
+
+ pg_table++; curpte++;
+ if(curpte > 63) {
+ put_segmap((address&PGDIR_MASK), curseg);
+ curpte = num_inval = 0;
+ curseg++;
+ }
+ address += PAGE_SIZE;
+ }
+
+ start_mem = (unsigned long) pg_table;
+ /* ok, allocate the kernel pages, map them in all contexts
+ * (with help from the prom), and lock them. Isn't the sparc
+ * fun kiddies? TODO
+ */
+
+#if 0
+ /* ugly debugging code */
+ for(i=0x1a3000; i<(0x1a3000+40960); i+=PAGE_SIZE)
+ printk("address=0x%x vseg=%d pte=0x%x\n", (unsigned int) i,
+ (int) get_segmap(i), (unsigned int) get_pte(i));
+ halt();
+#endif
+
+ b=PGDIR_ALIGN(start_mem)>>18;
+ c= (char *)0x0;
+
+ printk("mapping kernel in all contexts...\n");
+
+ for(a=0; a<b; a++)
+ {
+ for(i=0; i<num_contexts; i++)
+ {
+ /* map the kernel virt_addrs */
+ (*(romvec->pv_setctxt))(i, (char *) c, a);
+ }
+ c += 0x40000;
+ }
+
+ /* Ok, since now mapped in all contexts, we can free up
+ * context zero to be used amongst user processes.
+ */
+
+ /* free context 0 here TODO */
+
+ /* invalidate all user pages and initialize the pte struct
+ * for userland. TODO
+ */
+
+ /* Make the kernel text unwritable and cacheable, the prom
+ * loaded our text as writable, only sneaky sunos kernels need
+ * self-modifying code.
+ */
+
+ a= (unsigned long) &etext;
+ mask=~(PTE_NC|PTE_W); /* make cacheable + not writable */
+
+ /* must do for every segment since kernel uses all contexts
+ * and unlike some sun kernels I know of, we can't hard wire
+ * context 0 just for the kernel, that is unnecessary.
+ */
+
+ for(i=0; i<8; i++)
+ {
+ b=PAGE_ALIGN((unsigned long) &trapbase);
+
+ switch_to_context(i);
+
+ for(;b<a; b+=4096)
+ {
+ put_pte(b, (get_pte(b) & mask));
+ }
+ }
+
+ invalidate(); /* flush the virtual address cache */
+
+ printk("\nCurrently in context - ");
+ for(i=0; i<num_contexts; i++)
+ {
+ switch_to_context(i);
+ printk("%d ", (int) i);
+ }
+ printk("\n");
+
+ switch_to_context(0);
+
+ invalidate();
+ return start_mem;
+}
+
+void mem_init(unsigned long start_mem, unsigned long end_mem)
+{
+ unsigned long start_low_mem = PAGE_SIZE;
+ int codepages = 0;
+ int reservedpages = 0;
+ int datapages = 0;
+ int i = 0;
+ unsigned long tmp, limit, tmp2, addr;
+ extern char etext;
+
+ end_mem &= PAGE_MASK;
+ high_memory = end_mem;
+
+ start_low_mem = PAGE_ALIGN(start_low_mem);
+ start_mem = PAGE_ALIGN(start_mem);
+
+ for(i = 0; sp_banks[i].num_bytes != 0; i++) {
+ tmp = sp_banks[i].base_addr;
+ limit = (sp_banks[i].base_addr + sp_banks[i].num_bytes);
+ if(tmp<start_mem) {
+ if(limit>start_mem)
+ tmp = start_mem;
+ else continue;
+ }
+
+ while(tmp<limit) {
+ mem_map[MAP_NR(tmp)] = 0;
+ tmp += PAGE_SIZE;
+ }
+ if(sp_banks[i+1].num_bytes != 0)
+ while(tmp < sp_banks[i+1].base_addr) {
+ mem_map[MAP_NR(tmp)] = MAP_PAGE_RESERVED;
+ tmp += PAGE_SIZE;
+ }
+ }
+
+#ifdef CONFIG_SCSI
+ scsi_mem_init(high_memory);
+#endif
+
+ for (addr = 0; addr < high_memory; addr += PAGE_SIZE) {
+ if(mem_map[MAP_NR(addr)]) {
+ if (addr < (unsigned long) &etext)
+ codepages++;
+ else if(addr < start_mem)
+ datapages++;
+ else
+ reservedpages++;
+ continue;
+ }
+ mem_map[MAP_NR(addr)] = 1;
+ free_page(addr);
+ }
+
+ tmp2 = nr_free_pages << PAGE_SHIFT;
+
+ printk("Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data)\n",
+ tmp2 >> 10,
+ high_memory >> 10,
+ codepages << (PAGE_SHIFT-10),
+ reservedpages << (PAGE_SHIFT-10),
+ datapages << (PAGE_SHIFT-10));
+
+ invalidate();
+ return;
+}
+
+void si_meminfo(struct sysinfo *val)
+{
+ int i;
+
+ i = high_memory >> PAGE_SHIFT;
+ val->totalram = 0;
+ val->sharedram = 0;
+ val->freeram = nr_free_pages << PAGE_SHIFT;
+ val->bufferram = buffermem;
+ while (i-- > 0) {
+ if (mem_map[i] & MAP_PAGE_RESERVED)
+ continue;
+ val->totalram++;
+ if (!mem_map[i])
+ continue;
+ val->sharedram += mem_map[i]-1;
+ }
+ val->totalram <<= PAGE_SHIFT;
+ val->sharedram <<= PAGE_SHIFT;
+ return;
+}
diff --git a/arch/sparc/mm/vac-flush.c b/arch/sparc/mm/vac-flush.c
new file mode 100644
index 000000000..796366b53
--- /dev/null
+++ b/arch/sparc/mm/vac-flush.c
@@ -0,0 +1,94 @@
+/* vac.c: Routines for flushing various amount of the Sparc VAC
+ (virtual address cache).
+
+ Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu)
+*/
+
+#include <asm/vac-ops.h>
+#include <asm/page.h>
+
+/* Flush all VAC entries for the current context */
+
+extern int vac_do_hw_vac_flushes, vac_size, vac_linesize;
+extern int vac_entries_per_context, vac_entries_per_segment;
+extern int vac_entries_per_page;
+
+void
+flush_vac_context()
+{
+ register int entries_left, offset;
+ register char* address;
+
+ entries_left = vac_entries_per_context;
+ address = (char *) 0;
+
+ if(vac_do_hw_vac_flushes)
+ {
+ while(entries_left-- >=0)
+ {
+ hw_flush_vac_context_entry(address);
+ address += PAGE_SIZE;
+ }
+ }
+ else
+ {
+ offset = vac_linesize;
+ while(entries_left-- >=0)
+ {
+ sw_flush_vac_context_entry(address);
+ address += offset;
+ }
+ }
+}
+
+void
+flush_vac_segment(register unsigned int segment)
+{
+ register int entries_left, offset;
+ register char* address = (char *) 0;
+
+ entries_left = vac_entries_per_segment;
+ __asm__ __volatile__("sll %0, 18, %1\n\t"
+ "sra %1, 0x2, %1\n\t"
+ : "=r" (segment) : "0" (address));
+
+ if(vac_do_hw_vac_flushes)
+ {
+ while(entries_left-- >=0)
+ {
+ hw_flush_vac_segment_entry(address);
+ address += PAGE_SIZE;
+ }
+ }
+ else
+ {
+ offset = vac_linesize;
+ while(entries_left-- >=0)
+ {
+ sw_flush_vac_segment_entry(address);
+ address += offset;
+ }
+ }
+}
+
+void
+flush_vac_page(register unsigned int addr)
+{
+ register int entries_left, offset;
+
+ if(vac_do_hw_vac_flushes)
+ {
+ hw_flush_vac_page_entry((unsigned long *) addr);
+ }
+ else
+ {
+ entries_left = vac_entries_per_page;
+ offset = vac_linesize;
+ while(entries_left-- >=0)
+ {
+ sw_flush_vac_page_entry((unsigned long *) addr);
+ addr += offset;
+ }
+ }
+}
+