summaryrefslogtreecommitdiffstats
path: root/arch/alpha/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/alpha/kernel')
-rw-r--r--arch/alpha/kernel/Makefile47
-rw-r--r--arch/alpha/kernel/bios32.c478
-rw-r--r--arch/alpha/kernel/entry.S554
-rw-r--r--arch/alpha/kernel/head.S97
-rw-r--r--arch/alpha/kernel/irq.c414
-rw-r--r--arch/alpha/kernel/lca.c304
-rw-r--r--arch/alpha/kernel/osf_sys.c494
-rw-r--r--arch/alpha/kernel/process.c186
-rw-r--r--arch/alpha/kernel/setup.c172
-rw-r--r--arch/alpha/kernel/signal.c319
-rw-r--r--arch/alpha/kernel/traps.c159
11 files changed, 3224 insertions, 0 deletions
diff --git a/arch/alpha/kernel/Makefile b/arch/alpha/kernel/Makefile
new file mode 100644
index 000000000..2843d4481
--- /dev/null
+++ b/arch/alpha/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__ -traditional $< -o $*.s
+.S.o:
+ $(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o
+
+OBJS = entry.o traps.o process.o osf_sys.o irq.o signal.o setup.o \
+ lca.o bios32.o
+
+all: kernel.o head.o
+
+head.o: head.s
+
+head.s: head.S $(TOPDIR)/include/asm-alpha/system.h
+ $(CPP) -traditional -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/alpha/kernel/bios32.c b/arch/alpha/kernel/bios32.c
new file mode 100644
index 000000000..37c566fb1
--- /dev/null
+++ b/arch/alpha/kernel/bios32.c
@@ -0,0 +1,478 @@
+#define DEBUG
+/*
+ * bios32.c - PCI BIOS functions for Alpha systems not using BIOS
+ * emulation code.
+ *
+ * Written by Dave Rusling (david.rusling@reo.mts.dec.com)
+ *
+ * Adapted to 64-bit kernel and then rewritten by David Mosberger
+ * (davidm@cs.arizona.edu)
+ *
+ * For more information, please consult
+ *
+ * PCI BIOS Specification Revision
+ * PCI Local Bus Specification
+ * PCI System Design Guide
+ *
+ * PCI Special Interest Group
+ * M/S HF3-15A
+ * 5200 N.E. Elam Young Parkway
+ * Hillsboro, Oregon 97124-6497
+ * +1 (503) 696-2000
+ * +1 (800) 433-5177
+ *
+ * Manuals are $25 each or $50 for all three, plus $7 shipping
+ * within the United States, $35 abroad.
+ */
+#include <linux/config.h>
+
+#ifndef CONFIG_PCI
+
+int pcibios_present(void)
+{
+ return 0;
+}
+
+#else /* CONFIG_PCI */
+
+#include <linux/kernel.h>
+#include <linux/bios32.h>
+#include <linux/pci.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+
+#include <asm/hwrpb.h>
+#include <asm/io.h>
+
+
+#define KB 1024
+#define MB (1024*KB)
+#define GB (1024*MB)
+
+#define MAJOR_REV 0
+#define MINOR_REV 2
+
+/*
+ * Align VAL to ALIGN, which must be a power of two.
+ */
+#define ALIGN(val,align) (((val) + ((align) - 1)) & ~((align) - 1))
+
+
+/*
+ * Temporary internal macro. If this 0, then do not write to any of
+ * the PCI registers, merely read them (i.e., use configuration as
+ * determined by SRM). The SRM seem do be doing a less than perfect
+ * job in configuring PCI devices, so for now we do it ourselves.
+ * Reconfiguring PCI devices breaks console (RPB) callbacks, but
+ * those don't work properly with 64 bit addresses anyways.
+ *
+ * The accepted convention seems to be that the console (POST
+ * software) should fully configure boot devices and configure the
+ * interrupt routing of *all* devices. In particular, the base
+ * addresses of non-boot devices need not be initialized. For
+ * example, on the AXPpci33 board, the base address a #9 GXE PCI
+ * graphics card reads as zero (this may, however, be due to a bug in
+ * the graphics card---there have been some rumor that the #9 BIOS
+ * incorrectly resets that address to 0...).
+ */
+#define PCI_MODIFY 1
+
+
+extern struct hwrpb_struct *hwrpb;
+
+
+#if PCI_MODIFY
+
+static unsigned int io_base = 64*KB; /* <64KB are (E)ISA ports */
+static unsigned int mem_base = 16*MB; /* <16MB is ISA memory */
+
+
+/*
+ * Layout memory and I/O for a device:
+ */
+static void layout_dev(struct pci_dev *dev)
+{
+ struct pci_bus *bus;
+ unsigned short cmd;
+ unsigned int base, mask, size, reg;
+
+ bus = dev->bus;
+ pcibios_read_config_word(bus->number, dev->devfn, PCI_COMMAND, &cmd);
+
+ for (reg = PCI_BASE_ADDRESS_0; reg <= PCI_BASE_ADDRESS_5; reg += 4) {
+ /*
+ * Figure out how much space and of what type this
+ * device wants.
+ */
+ pcibios_write_config_dword(bus->number, dev->devfn, reg,
+ 0xffffffff);
+ pcibios_read_config_dword(bus->number, dev->devfn, reg, &base);
+ if (!base) {
+ break; /* done with this device */
+ }
+ /*
+ * We've read the base address register back after
+ * writing all ones and so now we must decode it.
+ */
+ if (base & PCI_BASE_ADDRESS_SPACE_IO) {
+ /*
+ * I/O space base address register.
+ */
+ cmd |= PCI_COMMAND_IO;
+
+ base &= PCI_BASE_ADDRESS_IO_MASK;
+ mask = (~base << 1) | 0x1;
+ size = (mask & base) & 0xffffffff;
+ base = ALIGN(io_base, size);
+ io_base = base + size;
+ pcibios_write_config_dword(bus->number, dev->devfn,
+ reg, base | 0x1);
+ } else {
+ unsigned int type;
+ /*
+ * Memory space base address register.
+ */
+ cmd |= PCI_COMMAND_MEMORY;
+
+ type = base & PCI_BASE_ADDRESS_MEM_TYPE_MASK;
+ base &= PCI_BASE_ADDRESS_MEM_MASK;
+ mask = (~base << 1) | 0x1;
+ size = (mask & base) & 0xffffffff;
+ switch (type) {
+ case PCI_BASE_ADDRESS_MEM_TYPE_32:
+ break;
+
+ case PCI_BASE_ADDRESS_MEM_TYPE_64:
+ printk("bios32 WARNING: "
+ "ignoring 64-bit device in "
+ "slot %d, function %d: \n",
+ PCI_SLOT(dev->devfn),
+ PCI_FUNC(dev->devfn));
+ reg += 4; /* skip extra 4 bytes */
+ continue;
+
+ case PCI_BASE_ADDRESS_MEM_TYPE_1M:
+ /*
+ * Allocating memory below 1MB is *very*
+ * tricky, as there may be all kinds of
+ * ISA devices lurking that we don't know
+ * about. For now, we just cross fingers
+ * and hope nobody tries to do this on an
+ * Alpha (or that the console has set it
+ * up properly).
+ */
+ printk("bios32 WARNING: slot %d, function %d "
+ "requests memory below 1MB---don't "
+ "know how to do that.\n",
+ PCI_SLOT(dev->devfn),
+ PCI_FUNC(dev->devfn));
+ continue;
+ }
+ /*
+ * The following holds at least for the Low Cost
+ * Alpha implementation of the PCI interface:
+ *
+ * In sparse memory address space, the first
+ * octant (16MB) of every 128MB segment is
+ * aliased to the the very first 16MB of the
+ * address space (i.e., it aliases the ISA
+ * memory address space). Thus, we try to
+ * avoid allocating PCI devices in that range.
+ * Can be allocated in 2nd-7th octant only.
+ * Devices that need more than 112MB of
+ * address space must be accessed through
+ * dense memory space only!
+ */
+ base = ALIGN(mem_base, size);
+ if (size > 7 * 16*MB) {
+ printk("bios32 WARNING: slot %d, function %d "
+ "requests %dB of contiguous address "
+ " space---don't use sparse memory "
+ " accesses on this device!!\n",
+ PCI_SLOT(dev->devfn),
+ PCI_FUNC(dev->devfn), size);
+ } else {
+ if (((base / 16*MB) & 0x7) == 0) {
+ base &= ~(128*MB - 1);
+ base += 16*MB;
+ base = ALIGN(base, size);
+ }
+ if (base / 128*MB != (base + size) / 128*MB) {
+ base &= ~(128*MB - 1);
+ base += (128 + 16)*MB;
+ base = ALIGN(base, size);
+ }
+ }
+ mem_base = base + size;
+ pcibios_write_config_dword(bus->number, dev->devfn,
+ reg, base);
+ }
+ }
+ /* enable device: */
+ pcibios_write_config_word(bus->number, dev->devfn, PCI_COMMAND,
+ cmd | PCI_COMMAND_MASTER);
+}
+
+
+static void layout_bus(struct pci_bus *bus)
+{
+ unsigned int l, tio, bio, tmem, bmem;
+ struct pci_bus *child;
+ struct pci_dev *dev;
+
+ if (!bus->devices && !bus->children)
+ return;
+
+ /*
+ * Align the current bases on appropriate boundaries (4K for
+ * IO and 1MB for memory).
+ */
+ bio = io_base = ALIGN(io_base, 4*KB);
+ bmem = mem_base = ALIGN(mem_base, 1*MB);
+
+ /*
+ * Allocate space to each device:
+ */
+ for (dev = bus->devices; dev; dev = dev->sibling) {
+ if (dev->class >> 16 != PCI_BASE_CLASS_BRIDGE) {
+ layout_dev(dev);
+ }
+ }
+ /*
+ * Recursively allocate space for all of the sub-buses:
+ */
+ for (child = bus->children; child; child = child->next) {
+ layout_bus(child);
+ }
+ /*
+ * Align the current bases on 4K and 1MB boundaries:
+ */
+ tio = io_base = ALIGN(io_base, 4*KB);
+ tmem = mem_base = ALIGN(mem_base, 1*MB);
+
+ if (bus->self) {
+ struct pci_dev *bridge = bus->self;
+ /*
+ * Set up the top and bottom of the I/O memory segment
+ * for this bus.
+ */
+ pcibios_read_config_dword(bridge->bus->number, bridge->devfn,
+ 0x1c, &l);
+ l = l | (bio >> 8) | ((tio - 1) & 0xf000);
+ pcibios_write_config_dword(bridge->bus->number, bridge->devfn,
+ 0x1c, l);
+
+ l = ((bmem & 0xfff00000) >> 16) | ((tmem - 1) & 0xfff00000);
+ pcibios_write_config_dword(bridge->bus->number, bridge->devfn,
+ 0x20, l);
+ /*
+ * Turn off downstream PF memory address range:
+ */
+ pcibios_write_config_dword(bridge->bus->number, bridge->devfn,
+ 0x24, 0x0000ffff);
+ /*
+ * Tell bridge that there is an ISA bus in the system:
+ */
+ pcibios_write_config_dword(bridge->bus->number, bridge->devfn,
+ 0x3c, 0x00040000);
+ /*
+ * Clear status bits, enable I/O (for downstream I/O),
+ * turn on master enable (for upstream I/O), turn on
+ * memory enable (for downstream memory), turn on
+ * master enable (for upstream memory and I/O).
+ */
+ pcibios_write_config_dword(bridge->bus->number, bridge->devfn,
+ 0x4, 0xffff0007);
+ }
+}
+
+#endif /* !PCI_MODIFY */
+
+
+/*
+ * Given the vendor and device ids, find the n'th instance of that device
+ * in the system.
+ */
+int pcibios_find_device (unsigned short vendor, unsigned short device_id,
+ unsigned short index, unsigned char *bus,
+ unsigned char *devfn)
+{
+ unsigned int current = 0;
+ struct pci_dev *dev;
+
+ for (dev = pci_devices; dev; dev = dev->next) {
+ if (dev->vendor == vendor && dev->device == device_id) {
+ if (current == index) {
+ *devfn = dev->devfn;
+ *bus = dev->bus->number;
+ return PCIBIOS_SUCCESSFUL;
+ }
+ ++current;
+ }
+ }
+ return PCIBIOS_DEVICE_NOT_FOUND;
+}
+
+
+/*
+ * Given the class, find the n'th instance of that device
+ * in the system.
+ */
+int pcibios_find_class (unsigned int class_code, unsigned short index,
+ unsigned char *bus, unsigned char *devfn)
+{
+ unsigned int current = 0;
+ struct pci_dev *dev;
+
+ for (dev = pci_devices; dev; dev = dev->next) {
+ if (dev->class == class_code) {
+ if (current == index) {
+ *devfn = dev->devfn;
+ *bus = dev->bus->number;
+ return PCIBIOS_SUCCESSFUL;
+ }
+ ++current;
+ }
+ }
+ return PCIBIOS_DEVICE_NOT_FOUND;
+}
+
+
+int pcibios_present(void)
+{
+ return 1;
+}
+
+
+unsigned long pcibios_init(unsigned long mem_start,
+ unsigned long mem_end)
+{
+ printk("Alpha PCI BIOS32 revision %x.%02x\n", MAJOR_REV, MINOR_REV);
+
+#if !PCI_MODIFY
+ printk("...NOT modifying existing (SRM) PCI configuration\n");
+#endif
+ return mem_start;
+}
+
+
+/*
+ * Fixup configuration for Noname boards (AXPpci33).
+ */
+static void noname_fixup(void)
+{
+ struct pci_dev *dev;
+
+ /*
+ * The Noname board has 5 PCI slots with each of the 4
+ * interrupt pins routed to different pins on the PCI/ISA
+ * bridge (PIRQ0-PIRQ3). I don't have any information yet as
+ * to how INTB, INTC, and INTD get routed (4/12/95,
+ * davidm@cs.arizona.edu).
+ */
+ static const char pirq_tab[5][4] = {
+ { 3, -1, -1, -1}, /* slot 6 (53c810) */
+ {-1, -1, -1, -1}, /* slot 7 (PCI/ISA bridge) */
+ { 2, -1, -1, -1}, /* slot 8 (slot closest to ISA) */
+ { 1, -1, -1, -1}, /* slot 9 (middle slot) */
+ { 0, -1, -1, -1}, /* slot 10 (slot furthest from ISA) */
+ };
+ /*
+ * route_tab selects irq routing in PCI/ISA bridge so that:
+ * PIRQ0 -> irq 15
+ * PIRQ1 -> irq 9
+ * PIRQ2 -> irq 10
+ * PIRQ3 -> irq 11
+ */
+ const unsigned int route_tab = 0x0b0a090f;
+ unsigned char pin;
+ int pirq;
+
+ pcibios_write_config_dword(0, PCI_DEVFN(7, 0), 0x60, route_tab);
+
+ /* ensure irq 9, 10, 11, and 15 are level sensitive: */
+ outb((1<<(9-8)) | (1<<(10-8)) | (1<<(11-8)) | (1<<(15-8)), 0x4d1);
+
+ /*
+ * Go through all devices, fixing up irqs as we see fit:
+ */
+ for (dev = pci_devices; dev; dev = dev->next) {
+ dev->irq = 0;
+ if (dev->bus->number != 0 ||
+ PCI_SLOT(dev->devfn) < 6 || PCI_SLOT(dev->devfn) > 10)
+ {
+ printk("noname_set_irq: no dev on bus %d, slot %d!!\n",
+ dev->bus->number, PCI_SLOT(dev->devfn));
+ continue;
+ }
+
+ pcibios_read_config_byte(dev->bus->number, dev->devfn,
+ PCI_INTERRUPT_PIN, &pin);
+ if (!pin) {
+ if (dev->vendor == PCI_VENDOR_ID_S3 &&
+ (dev->device == PCI_DEVICE_ID_S3_864_1 ||
+ dev->device == PCI_DEVICE_ID_S3_864_2))
+ {
+ pin = 1;
+ } else {
+ continue; /* no interrupt line */
+ }
+ }
+ pirq = pirq_tab[PCI_SLOT(dev->devfn) - 6][pin - 1];
+ if (pirq < 0) {
+ continue;
+ }
+ dev->irq = (route_tab >> (8 * pirq)) & 0xff;
+#if PCI_MODIFY
+ /* tell the device: */
+ pcibios_write_config_byte(dev->bus->number, dev->devfn,
+ PCI_INTERRUPT_LINE, dev->irq);
+#endif
+ }
+
+#if PCI_MODIFY
+ {
+ unsigned char hostid;
+ /*
+ * SRM console version X3.9 seems to reset the SCSI
+ * host-id to 0 no matter what console environment
+ * variable pka0_host_id is set to. Thus, if the
+ * host-id reads out as a zero, we set it to 7. The
+ * SCSI controller is on the motherboard on bus 0,
+ * slot 6
+ */
+ if (pcibios_read_config_byte(0, PCI_DEVFN(6, 0), 0x84, &hostid)
+ == PCIBIOS_SUCCESSFUL && (hostid == 0))
+ {
+ pcibios_write_config_byte(0, PCI_DEVFN(6, 0),
+ 0x84, 7);
+ }
+ }
+#endif /* !PCI_MODIFY */
+}
+
+
+unsigned long pcibios_fixup(unsigned long mem_start, unsigned long mem_end)
+{
+#if PCI_MODIFY
+ /*
+ * Scan the tree, allocating PCI memory and I/O space.
+ */
+ layout_bus(&pci_root);
+#endif
+
+ /*
+ * Now is the time to do all those dirty little deeds...
+ */
+ switch (hwrpb->sys_type) {
+ case ST_DEC_AXPPCI_33: noname_fixup(); break;
+
+ default:
+ printk("pcibios_fixup: don't know how to fixup sys type %ld\n",
+ hwrpb->sys_type);
+ break;
+ }
+ return mem_start;
+}
+
+#endif /* CONFIG_PCI */
diff --git a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S
new file mode 100644
index 000000000..b54ea220b
--- /dev/null
+++ b/arch/alpha/kernel/entry.S
@@ -0,0 +1,554 @@
+/*
+ * alpha/entry.S
+ *
+ * kernel entry-points
+ */
+
+#include <asm/system.h>
+
+#define halt .long PAL_halt
+#define rti .long PAL_rti
+
+#define NR_SYSCALLS 310
+#define osf_vfork sys_fork
+
+/*
+ * These offsets must match with "struct hae" in io.h:
+ */
+#define HAE_CACHE 0
+#define HAE_REG 8
+
+/*
+ * stack offsets
+ */
+#define SP_OFF 160
+
+#define SWITCH_STACK_SIZE 320
+
+/*
+ * task structure offsets
+ */
+#define TASK_STATE 0
+#define TASK_COUNTER 8
+#define TASK_PRIORITY 16
+#define TASK_SIGNAL 24
+#define TASK_BLOCKED 32
+#define TASK_FLAGS 40
+
+/*
+ * This defines the normal kernel pt-regs layout.
+ *
+ * regs 9-15 preserved by C code
+ * regs 16-18 saved by PAL-code
+ * regs 29-30 saved and set up by PAL-code
+ */
+#define SAVE_ALL \
+ subq $30,160,$30; \
+ stq $0,0($30); \
+ stq $1,8($30); \
+ stq $2,16($30); \
+ stq $3,24($30); \
+ stq $4,32($30); \
+ stq $5,40($30); \
+ stq $6,48($30); \
+ stq $7,56($30); \
+ stq $8,64($30); \
+ stq $19,72($30); \
+ stq $20,80($30); \
+ stq $21,88($30); \
+ stq $22,96($30); \
+ stq $23,104($30); \
+ stq $24,112($30); \
+ stq $25,120($30); \
+ stq $26,128($30); \
+ stq $27,136($30); \
+ stq $28,144($30); \
+ lda $2,hae; \
+ ldq $2,HAE_CACHE($2); \
+ stq $2,152($30)
+
+#define RESTORE_ALL \
+ lda $8,hae; \
+ ldq $7,HAE_CACHE($8); \
+ ldq $6,152($30); \
+ subq $7,$6,$5; \
+ beq $5,99f; \
+ ldq $7,HAE_REG($8); \
+ addq $31,7,$16; \
+ call_pal PAL_swpipl; \
+ stq $6,HAE_CACHE($8); \
+ stq $6,0($7); \
+ mb; \
+ bis $0,$0,$16; \
+ call_pal PAL_swpipl; \
+99:; \
+ ldq $0,0($30); \
+ ldq $1,8($30); \
+ ldq $2,16($30); \
+ ldq $3,24($30); \
+ ldq $4,32($30); \
+ ldq $5,40($30); \
+ ldq $6,48($30); \
+ ldq $7,56($30); \
+ ldq $8,64($30); \
+ ldq $19,72($30); \
+ ldq $20,80($30); \
+ ldq $21,88($30); \
+ ldq $22,96($30); \
+ ldq $23,104($30); \
+ ldq $24,112($30); \
+ ldq $25,120($30); \
+ ldq $26,128($30); \
+ ldq $27,136($30); \
+ ldq $28,144($30); \
+ addq $30,160,$30
+
+.text
+.set noat
+
+.align 3
+.globl entInt
+.ent entInt
+entInt:
+ SAVE_ALL
+/* start atomic operation with respect to software interrupts */
+ lda $0,intr_count
+ ldq $1,0($0)
+ addq $1,1,$1
+ stq $1,0($0)
+/* set up the arguments to the C interrupt handler */
+ lda $27,do_entInt
+ jsr $26,($27),do_entInt
+/* ok, check if we need to do software interrupts */
+1: lda $0,intr_count
+ ldq $1,0($0)
+ subq $1,1,$1
+ bne $1,2f /* interrupt within interrupt: return now */
+ lda $2,bh_active
+ ldq $3,0($2)
+ lda $2,bh_mask
+ ldq $2,0($2)
+ and $2,$3,$2
+ bne $2,3f
+ stq $1,0($0)
+ br $31,ret_from_sys_call
+.align 3
+2: stq $1,0($0)
+ br $31,restore_all
+.align 3
+3: lda $27,do_bottom_half
+ jsr $26,($27),do_bottom_half
+ br $31,1b
+.end entInt
+
+.align 3
+.globl entMM
+.ent entMM
+entMM:
+ SAVE_ALL
+ lda $27,do_page_fault
+ lda $26,ret_from_sys_call
+ jsr $31,($27),do_page_fault
+.end entMM
+
+.align 3
+.globl entArith
+.ent entArith
+entArith:
+ SAVE_ALL
+ lda $27,do_entArith
+ lda $26,ret_from_sys_call
+ jsr $31,($27),do_entArith
+.end entArith
+
+.align 3
+.globl entIF
+.ent entIF
+entIF:
+ SAVE_ALL
+ lda $27,do_entIF
+ lda $26,ret_from_sys_call
+ jsr $31,($27),do_entIF
+.end entIF
+
+/*
+ * Fork() is one of the special system calls: it needs to
+ * save the callee-saved regs so that the regs can be found
+ * for the new process.. We save them in the "context switch"
+ * stack format (see arch/alpha/kernel/process.c).
+ *
+ * Also, for the kernel fork, we need to fake the system call
+ * stack buildup, as we can't do system calls from kernel space.
+ */
+.align 3
+.globl kernel_fork
+.ent kernel_fork
+kernel_fork:
+ subq $30,6*8,$30
+ stq $31,0($30)
+ stq $26,8($30)
+ stq $29,16($30)
+ stq $16,24($30)
+ stq $17,32($30)
+ stq $18,40($30)
+ SAVE_ALL
+ lda $27,sys_fork
+ jsr $26,($27),sys_fork
+ br ret_from_sys_call
+.end kernel_fork
+
+.align 3
+.ent do_switch_stack
+do_switch_stack:
+ lda $30,-SWITCH_STACK_SIZE($30)
+ stq $9,0($30)
+ stq $10,8($30)
+ stq $11,16($30)
+ stq $12,24($30)
+ stq $13,32($30)
+ stq $14,40($30)
+ stq $15,48($30)
+ stq $26,56($30)
+ stt $f0,64($30)
+ stt $f1,72($30)
+ stt $f2,80($30)
+ stt $f3,88($30)
+ stt $f4,96($30)
+ stt $f5,104($30)
+ stt $f6,112($30)
+ stt $f7,120($30)
+ stt $f8,128($30)
+ stt $f9,136($30)
+ stt $f10,144($30)
+ stt $f11,152($30)
+ stt $f12,160($30)
+ stt $f13,168($30)
+ stt $f14,176($30)
+ stt $f15,184($30)
+ stt $f16,192($30)
+ stt $f17,200($30)
+ stt $f18,208($30)
+ stt $f19,216($30)
+ stt $f20,224($30)
+ stt $f21,232($30)
+ stt $f22,240($30)
+ stt $f23,248($30)
+ stt $f24,256($30)
+ stt $f25,264($30)
+ stt $f26,272($30)
+ stt $f27,280($30)
+ stt $f28,288($30)
+ stt $f29,296($30)
+ stt $f30,304($30)
+ ret $31,($0),1
+.end do_switch_stack
+
+.align 3
+.ent undo_switch_stack
+undo_switch_stack:
+ ldq $9,0($30)
+ ldq $10,8($30)
+ ldq $11,16($30)
+ ldq $12,24($30)
+ ldq $13,32($30)
+ ldq $14,40($30)
+ ldq $15,48($30)
+ ldq $26,56($30)
+ ldt $f0,64($30)
+ ldt $f1,72($30)
+ ldt $f2,80($30)
+ ldt $f3,88($30)
+ ldt $f4,96($30)
+ ldt $f5,104($30)
+ ldt $f6,112($30)
+ ldt $f7,120($30)
+ ldt $f8,128($30)
+ ldt $f9,136($30)
+ ldt $f10,144($30)
+ ldt $f11,152($30)
+ ldt $f12,160($30)
+ ldt $f13,168($30)
+ ldt $f14,176($30)
+ ldt $f15,184($30)
+ ldt $f16,192($30)
+ ldt $f17,200($30)
+ ldt $f18,208($30)
+ ldt $f19,216($30)
+ ldt $f20,224($30)
+ ldt $f21,232($30)
+ ldt $f22,240($30)
+ ldt $f23,248($30)
+ ldt $f24,256($30)
+ ldt $f25,264($30)
+ ldt $f26,272($30)
+ ldt $f27,280($30)
+ ldt $f28,288($30)
+ ldt $f29,296($30)
+ ldt $f30,304($30)
+ lda $30,SWITCH_STACK_SIZE($30)
+ ret $31,($0),1
+.end undo_switch_stack
+
+.align 3
+.globl entUna
+.ent entUna
+entUna:
+ lda $30,-256($30)
+ stq $0,0($30)
+ stq $1,8($30)
+ stq $2,16($30)
+ stq $3,24($30)
+ stq $4,32($30)
+ stq $5,40($30)
+ stq $6,48($30)
+ stq $7,56($30)
+ stq $8,64($30)
+ stq $9,72($30)
+ stq $10,80($30)
+ stq $11,88($30)
+ stq $12,96($30)
+ stq $13,104($30)
+ stq $14,112($30)
+ stq $15,120($30)
+ /* 16-18 PAL-saved */
+ stq $19,152($30)
+ stq $20,160($30)
+ stq $21,168($30)
+ stq $22,176($30)
+ stq $23,184($30)
+ stq $24,192($30)
+ stq $25,200($30)
+ stq $26,208($30)
+ stq $27,216($30)
+ stq $28,224($30)
+ stq $29,232($30)
+ stq $30,240($30)
+ stq $31,248($30)
+ lda $27,do_entUna
+ jsr $26,($27),do_entUna
+ ldq $0,0($30)
+ ldq $1,8($30)
+ ldq $2,16($30)
+ ldq $3,24($30)
+ ldq $4,32($30)
+ ldq $5,40($30)
+ ldq $6,48($30)
+ ldq $7,56($30)
+ ldq $8,64($30)
+ ldq $9,72($30)
+ ldq $10,80($30)
+ ldq $11,88($30)
+ ldq $12,96($30)
+ ldq $13,104($30)
+ ldq $14,112($30)
+ ldq $15,120($30)
+ /* 16-18 PAL-saved */
+ ldq $19,152($30)
+ ldq $20,160($30)
+ ldq $21,168($30)
+ ldq $22,176($30)
+ ldq $23,184($30)
+ ldq $24,192($30)
+ ldq $25,200($30)
+ ldq $26,208($30)
+ ldq $27,216($30)
+ ldq $28,224($30)
+ ldq $29,232($30)
+ ldq $30,240($30)
+ lda $30,256($30)
+ rti
+.end entUna
+
+.align 3
+.globl sys_fork
+.ent sys_fork
+sys_fork:
+ br $0,do_switch_stack
+ bis $30,$30,$16
+ lda $27,alpha_fork
+ jsr $26,($27),alpha_fork
+ br $0,undo_switch_stack
+ ldq $0,0($30)
+ ret $31,($26),1
+.end sys_fork
+
+.align 3
+.globl alpha_switch_to
+.ent alpha_switch_to
+alpha_switch_to:
+ br $0,do_switch_stack
+ call_pal PAL_swpctx
+ br $0,undo_switch_stack
+ ret $31,($26),1
+.end alpha_switch_to
+
+/*
+ * Oh, well.. Disassembling OSF/1 binaries to find out how the
+ * system calls work isn't much fun.
+ *
+ * entSys is special in that the PAL-code doesn't save a0-a2, so
+ * we start off by doing that by hand.
+ */
+.align 3
+.globl entSys
+.globl ret_from_sys_call
+.ent entSys
+entSys:
+ stq $16,24($30)
+ stq $17,32($30)
+ stq $18,40($30)
+ SAVE_ALL
+ lda $1,NR_SYSCALLS($31)
+ lda $2,sys_call_table
+ lda $27,do_entSys
+ cmpult $0,$1,$1
+ s8addq $0,$2,$2
+ beq $1,1f
+ ldq $27,0($2)
+1: jsr $26,($27),do_entSys
+ bis $31,$31,$1
+ bge $0,2f
+ bis $31,$31,$26 /* tell "ret_from_sys_call" that we can restart */
+ ldq $19,0($30) /* .. with this syscall nr */
+ ldq $20,72($30) /* .. and this a3 */
+ addq $31,1,$1 /* set a3 for errno return */
+ subq $31,$0,$0 /* with error in v0 */
+2: stq $0,0($30)
+ stq $1,72($30) /* a3 for return */
+.align 3
+ret_from_sys_call:
+ ldq $0,SP_OFF($30)
+ cmovne $26,0,$19
+ and $0,8,$0
+ beq $0,restore_all
+ret_from_reschedule:
+ lda $0,need_resched
+ lda $1,current
+ ldl $2,0($0)
+ lda $4,init_task
+ ldq $3,0($1)
+ bne $2,reschedule
+ subq $4,$3,$4
+ beq $4,restore_all
+ ldq $4,TASK_SIGNAL($3)
+ ldq $16,TASK_BLOCKED($3)
+ bic $4,$16,$4
+ bne $4,signal_return
+restore_all:
+ RESTORE_ALL
+ rti
+.align 3
+signal_return:
+ bis $30,$30,$17
+ br $0,do_switch_stack
+ bis $30,$30,$18
+ lda $27,do_signal
+ jsr $26,($27),do_signal
+ lda $30,SWITCH_STACK_SIZE($30)
+ br $31,restore_all
+.end entSys
+
+.align 3
+.ent reschedule
+reschedule:
+ subq $30,16,$30
+ stq $19,0($30)
+ stq $20,8($30)
+ lda $27,schedule
+ jsr $26,($27),schedule
+ ldq $19,0($30)
+ ldq $20,8($30)
+ addq $30,16,$30
+ br $31,ret_from_reschedule
+.end reschedule
+
+.align 3
+.ent sys_sigreturn
+sys_sigreturn:
+ bis $30,$30,$17
+ lda $30,-SWITCH_STACK_SIZE($30)
+ bis $30,$30,$18
+ lda $27,do_sigreturn
+ jsr $26,($27),do_sigreturn
+ br $0,undo_switch_stack
+ br $31,ret_from_sys_call
+.end sys_sigreturn
+
+.align 3
+.ent sys_sigsuspend
+sys_sigsuspend:
+ bis $30,$30,$17
+ br $0,do_switch_stack
+ bis $30,$30,$18
+ lda $27,do_sigsuspend
+ jsr $26,($27),do_sigsuspend
+ lda $30,SWITCH_STACK_SIZE($30)
+ br $31,ret_from_sys_call
+.end sys_sigreturn
+
+ .align 3
+ .globl sys_call_table
+sys_call_table:
+/*0*/ .quad do_entSys, sys_exit, sys_fork, sys_read, sys_write
+ .quad do_entSys, sys_close, sys_wait4, do_entSys, sys_link
+ .quad sys_unlink, do_entSys, sys_chdir, sys_fchdir, sys_mknod
+ .quad sys_chmod, sys_chown, sys_brk, do_entSys, sys_lseek
+ .quad sys_getxpid, osf_mount, osf_umount, sys_setuid, sys_getxuid
+ .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
+ .quad do_entSys, do_entSys, do_entSys, sys_access, do_entSys
+ .quad do_entSys, sys_sync, sys_kill, do_entSys, sys_setpgid
+ .quad do_entSys, sys_dup, sys_pipe, do_entSys, do_entSys
+ .quad sys_open, do_entSys, sys_getxgid, osf_sigprocmask, do_entSys
+/*50*/ .quad do_entSys, do_entSys, do_entSys, do_entSys, sys_ioctl
+ .quad do_entSys, do_entSys, sys_symlink, sys_readlink, sys_execve
+ .quad sys_umask, do_entSys, do_entSys, sys_getpgrp, sys_getpagesize
+ .quad do_entSys, osf_vfork, sys_newstat, sys_newlstat, do_entSys
+ .quad do_entSys, osf_mmap, do_entSys, sys_munmap, sys_mprotect
+ .quad sys_madvise, do_entSys, do_entSys, do_entSys, sys_getgroups
+ .quad do_entSys, do_entSys, do_entSys, sys_setitimer, do_entSys
+ .quad do_entSys, sys_getitimer, sys_gethostname, do_entSys, sys_getdtablesize
+ .quad sys_dup2, sys_newfstat, sys_fcntl, sys_select, do_entSys
+ .quad sys_fsync, do_entSys, sys_socket, do_entSys, do_entSys
+/*100*/ .quad do_entSys, do_entSys, do_entSys, sys_sigreturn, sys_bind
+ .quad do_entSys, sys_listen, do_entSys, do_entSys, do_entSys
+ .quad do_entSys, sys_sigsuspend, do_entSys, do_entSys, do_entSys
+ .quad do_entSys, sys_gettimeofday, sys_getrusage, do_entSys, do_entSys
+ .quad do_entSys, do_entSys, sys_settimeofday, sys_fchown, sys_fchmod
+ .quad do_entSys, sys_setreuid, sys_setregid, sys_rename, sys_truncate
+ .quad sys_ftruncate, do_entSys, sys_setgid, do_entSys, do_entSys
+ .quad do_entSys, sys_mkdir, sys_rmdir, sys_utimes, do_entSys
+ .quad do_entSys, do_entSys, do_entSys, do_entSys, sys_getrlimit
+ .quad sys_setrlimit, do_entSys, sys_setsid, do_entSys, do_entSys
+/*150*/ .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
+ .quad do_entSys, sys_sigaction, do_entSys, do_entSys, osf_getdirentries
+ .quad osf_statfs, osf_fstatfs, do_entSys, do_entSys, do_entSys
+ .quad osf_getdomainname, do_entSys, do_entSys, do_entSys, do_entSys
+ .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
+ .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
+ .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
+ .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
+ .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
+ .quad do_entSys, do_entSys, do_entSys, do_entSys, osf_swapon
+/*200*/ .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
+ .quad do_entSys, do_entSys, osf_utsname, do_entSys, do_entSys
+ .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
+ .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
+ .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
+ .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
+ .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
+ .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
+ .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
+ .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
+/*250*/ .quad do_entSys, osf_usleep_thread, do_entSys, do_entSys, do_entSys
+ .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
+ .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
+ .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
+ .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
+ .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
+ .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
+ .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
+ .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
+ .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
+/* linux-specific system calls start at 300 */
+/*300*/ .quad sys_bdflush, sys_sethae, do_entSys, do_entSys, do_entSys
+ .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
diff --git a/arch/alpha/kernel/head.S b/arch/alpha/kernel/head.S
new file mode 100644
index 000000000..2cff1159a
--- /dev/null
+++ b/arch/alpha/kernel/head.S
@@ -0,0 +1,97 @@
+/*
+ * alpha/boot/head.S
+ *
+ * initial boot stuff.. At this point, the bootloader has already
+ * switched into OSF/1 PAL-code, and loaded us at the correct address
+ * (START_ADDR). So there isn't much left for us to do: just set up
+ * the kernel global pointer and jump to the kernel entry-point.
+ */
+
+#define __ASSEMBLY__
+#include <asm/system.h>
+#include <linux/fd.h>
+
+#define halt .long PAL_halt
+
+.globl swapper_pg_dir
+swapper_pg_dir=SWAPPER_PGD
+
+ .set noreorder
+ .globl __start
+ .ent __start
+__start:
+ br $27,1f
+1: ldgp $29,0($27)
+ lda $27,start_kernel
+ jsr $26,($27),start_kernel
+ halt
+ .end __start
+
+ .align 3
+ .globl wrent
+ .ent wrent
+wrent:
+ .long PAL_wrent
+ ret ($26)
+ .end wrent
+
+ .align 3
+ .globl wrkgp
+ .ent wrkgp
+wrkgp:
+ .long PAL_wrkgp
+ ret ($26)
+ .end wrkgp
+
+ .align 3
+ .globl wrusp
+ .ent wrusp
+wrusp:
+ .long PAL_wrusp
+ ret ($26)
+ .end wrusp
+
+ .align 3
+ .globl rdusp
+ .ent rdusp
+rdusp:
+ .long PAL_rdusp
+ ret ($26)
+ .end rdusp
+
+ .align 3
+ .globl tbi
+ .ent tbi
+tbi:
+ .long PAL_tbi
+ ret ($26)
+ .end tbi
+
+ .align 3
+ .globl imb
+ .ent imb
+imb:
+ .long PAL_imb
+ ret ($26)
+ .end imb
+
+ .align 3
+ .globl rdmces
+ .ent rdmces
+rdmces:
+ call_pal PAL_rdmces
+ ret ($26)
+ .end rdmces
+
+ .align 3
+ .globl wrmces
+ .ent wrmces
+wrmces:
+ call_pal PAL_wrmces
+ ret ($26)
+ .end wrmces
+
+.align 9
+.globl floppy_track_buffer
+floppy_track_buffer:
+ .space 512*2*MAX_BUFFER_SECTORS,1
diff --git a/arch/alpha/kernel/irq.c b/arch/alpha/kernel/irq.c
new file mode 100644
index 000000000..a59077539
--- /dev/null
+++ b/arch/alpha/kernel/irq.c
@@ -0,0 +1,414 @@
+/*
+ * linux/arch/alpha/kernel/irq.c
+ *
+ * Copyright (C) 1995 Linus Torvalds
+ *
+ * This file contains the code used by various IRQ handling routines:
+ * asking for different IRQ's should be done through these routines
+ * instead of just grabbing them. Thus setups with different IRQ numbers
+ * shouldn't result in any weird surprises, and installing new handlers
+ * should be easier.
+ */
+
+#include <linux/config.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/kernel_stat.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/bitops.h>
+#include <asm/dma.h>
+
+static unsigned char cache_21 = 0xff;
+static unsigned char cache_A1 = 0xff;
+
+void disable_irq(unsigned int irq_nr)
+{
+ unsigned long flags;
+ unsigned char mask;
+
+ mask = 1 << (irq_nr & 7);
+ save_flags(flags);
+ if (irq_nr < 8) {
+ cli();
+ cache_21 |= mask;
+ outb(cache_21,0x21);
+ restore_flags(flags);
+ return;
+ }
+ cli();
+ cache_A1 |= mask;
+ outb(cache_A1,0xA1);
+ restore_flags(flags);
+}
+
+void enable_irq(unsigned int irq_nr)
+{
+ unsigned long flags;
+ unsigned char mask;
+
+ mask = ~(1 << (irq_nr & 7));
+ save_flags(flags);
+ if (irq_nr < 8) {
+ cli();
+ cache_21 &= mask;
+ outb(cache_21,0x21);
+ restore_flags(flags);
+ return;
+ }
+ cli();
+ cache_A1 &= mask;
+ outb(cache_A1,0xA1);
+ restore_flags(flags);
+}
+
+/*
+ * 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;
+}
+
+static inline void ack_irq(int irq)
+{
+ /* ACK the interrupt making it the lowest priority */
+ /* First the slave .. */
+ if (irq > 7) {
+ outb(0xE0 | (irq - 8), 0xa0);
+ irq = 2;
+ }
+ /* .. then the master */
+ outb(0xE0 | irq, 0x20);
+}
+
+static inline void mask_irq(int irq)
+{
+ if (irq < 8) {
+ cache_21 |= 1 << irq;
+ outb(cache_21, 0x21);
+ } else {
+ cache_A1 |= 1 << (irq - 8);
+ outb(cache_A1, 0xA1);
+ }
+}
+
+static inline void unmask_irq(unsigned long irq)
+{
+ if (irq < 8) {
+ cache_21 &= ~(1 << irq);
+ outb(cache_21, 0x21);
+ } else {
+ cache_A1 &= ~(1 << (irq - 8));
+ outb(cache_A1, 0xA1);
+ }
+}
+
+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 > 15)
+ return -EINVAL;
+ 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;
+ if (irq < 8) {
+ if (irq) {
+ cache_21 &= ~(1<<irq);
+ outb(cache_21,0x21);
+ }
+ } else {
+ cache_21 &= ~(1<<2);
+ cache_A1 &= ~(1<<(irq-8));
+ outb(cache_21,0x21);
+ outb(cache_A1,0xA1);
+ }
+ restore_flags(flags);
+ return 0;
+}
+
+void free_irq(unsigned int irq)
+{
+ struct irqaction * action = irq + irq_action;
+ unsigned long flags;
+
+ if (irq > 15) {
+ 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();
+ mask_irq(irq);
+ action->handler = NULL;
+ action->flags = 0;
+ action->mask = 0;
+ action->name = NULL;
+ restore_flags(flags);
+}
+
+static void handle_nmi(struct pt_regs * regs)
+{
+ printk("Whee.. NMI received. Probable hardware error\n");
+ printk("61=%02x, 461=%02x\n", inb(0x61), inb(0x461));
+}
+
+static void unexpected_irq(int irq, struct pt_regs * regs)
+{
+ int i;
+
+ printk("IO device interrupt, irq = %d\n", irq);
+ printk("PC = %016lx PS=%04lx\n", regs->pc, regs->ps);
+ printk("Expecting: ");
+ for (i = 0; i < 16; i++)
+ if (irq_action[i].handler)
+ printk("[%s:%d] ", irq_action[i].name, i);
+ printk("\n");
+ printk("64=%02x, 60=%02x, 3fa=%02x 2fa=%02x\n",
+ inb(0x64), inb(0x60), inb(0x3fa), inb(0x2fa));
+ outb(0x0c, 0x3fc);
+ outb(0x0c, 0x2fc);
+ outb(0,0x61);
+ outb(0,0x461);
+}
+
+static inline void handle_irq(int irq, struct pt_regs * regs)
+{
+ struct irqaction * action = irq + irq_action;
+
+ kstat.interrupts[irq]++;
+ if (!action->handler) {
+ unexpected_irq(irq, regs);
+ return;
+ }
+ action->handler(irq, regs);
+}
+
+static void local_device_interrupt(unsigned long vector, struct pt_regs * regs)
+{
+ switch (vector) {
+ /* com1: map to irq 4 */
+ case 0x900:
+ handle_irq(4, regs);
+ return;
+
+ /* com2: map to irq 3 */
+ case 0x920:
+ handle_irq(3, regs);
+ return;
+
+ /* keyboard: map to irq 1 */
+ case 0x980:
+ handle_irq(1, regs);
+ return;
+
+ /* mouse: map to irq 9 */
+ case 0x990:
+ handle_irq(9, regs);
+ return;
+ default:
+ printk("Unknown local interrupt %lx\n", vector);
+ }
+}
+
+/*
+ * The vector is 0x8X0 for EISA interrupt X, and 0x9X0 for the local
+ * motherboard interrupts.. This is for the Jensen.
+ *
+ * 0x660 - NMI
+ *
+ * 0x800 - IRQ0 interval timer (not used, as we use the RTC timer)
+ * 0x810 - IRQ1 line printer (duh..)
+ * 0x860 - IRQ6 floppy disk
+ * 0x8E0 - IRQ14 SCSI controller
+ *
+ * 0x900 - COM1
+ * 0x920 - COM2
+ * 0x980 - keyboard
+ * 0x990 - mouse
+ *
+ * The PCI version is more sane: it doesn't have the local interrupts at
+ * all, and has only normal PCI interrupts from devices. Happily it's easy
+ * enough to do a sane mapping from the Jensen.. Note that this means
+ * that we may have to do a hardware "ack" to a different interrupt than
+ * we report to the rest of the world..
+ */
+static void device_interrupt(unsigned long vector, struct pt_regs * regs)
+{
+ int irq, ack;
+ struct irqaction * action;
+
+ if (vector == 0x660) {
+ handle_nmi(regs);
+ return;
+ }
+
+ ack = irq = (vector - 0x800) >> 4;
+#ifndef CONFIG_PCI
+ if (vector >= 0x900) {
+ local_device_interrupt(vector, regs);
+ return;
+ }
+ /* irq1 is supposed to be the keyboard, silly Jensen */
+ if (irq == 1)
+ irq = 7;
+#endif
+ kstat.interrupts[irq]++;
+ action = irq_action + irq;
+ /* quick interrupts get executed with no extra overhead */
+ if (action->flags & SA_INTERRUPT) {
+ action->handler(irq, regs);
+ ack_irq(ack);
+ return;
+ }
+ /*
+ * For normal interrupts, we mask it out, and then ACK it.
+ * This way another (more timing-critical) interrupt can
+ * come through while we're doing this one.
+ *
+ * Note! A irq without a handler gets masked and acked, but
+ * never unmasked. The autoirq stuff depends on this (it looks
+ * at the masks before and after doing the probing).
+ */
+ mask_irq(ack);
+ ack_irq(ack);
+ if (!action->handler)
+ return;
+ action->handler(irq, regs);
+ unmask_irq(ack);
+}
+
+/*
+ * Start listening for interrupts..
+ */
+unsigned int probe_irq_on(void)
+{
+ unsigned int i, irqs = 0, irqmask;
+ unsigned long delay;
+
+ for (i = 15; i > 0; i--) {
+ if (!irq_action[i].handler) {
+ enable_irq(i);
+ irqs |= (1 << i);
+ }
+ }
+
+ /* wait for spurious interrupts to mask themselves out again */
+ for (delay = jiffies + HZ/10; delay > jiffies; )
+ /* about 100 ms delay */;
+
+ /* now filter out any obviously spurious interrupts */
+ irqmask = (((unsigned int)cache_A1)<<8) | (unsigned int) cache_21;
+ irqs &= ~irqmask;
+ return irqs;
+}
+
+/*
+ * Get the result of the IRQ probe.. A negative result means that
+ * we have several candidates (but we return the lowest-numbered
+ * one).
+ */
+int probe_irq_off(unsigned int irqs)
+{
+ unsigned int i, irqmask;
+
+ irqmask = (((unsigned int)cache_A1)<<8) | (unsigned int)cache_21;
+ irqs &= irqmask;
+ if (!irqs)
+ return 0;
+ i = ffz(~irqs);
+ if (irqs != (1 << i))
+ i = -i;
+ return i;
+}
+
+static void machine_check(unsigned long vector, unsigned long la_ptr, struct pt_regs * regs)
+{
+ printk("Machine check\n");
+}
+
+asmlinkage void do_entInt(unsigned long type, unsigned long vector, unsigned long la_ptr,
+ unsigned long a3, unsigned long a4, unsigned long a5,
+ struct pt_regs regs)
+{
+ switch (type) {
+ case 0:
+ printk("Interprocessor interrupt? You must be kidding\n");
+ break;
+ case 1:
+ /* timer interrupt.. */
+ handle_irq(0, &regs);
+ return;
+ case 2:
+ machine_check(vector, la_ptr, &regs);
+ break;
+ case 3:
+ device_interrupt(vector, &regs);
+ return;
+ case 4:
+ printk("Performance counter interrupt\n");
+ break;;
+ default:
+ printk("Hardware intr %ld %lx? Huh?\n", type, vector);
+ }
+ printk("PC = %016lx PS=%04lx\n", regs.pc, regs.ps);
+}
+
+extern asmlinkage void entInt(void);
+
+void init_IRQ(void)
+{
+ wrent(entInt, 0);
+ dma_outb(0, DMA1_RESET_REG);
+ dma_outb(0, DMA2_RESET_REG);
+ dma_outb(0, DMA1_CLR_MASK_REG);
+ dma_outb(0, DMA2_CLR_MASK_REG);
+}
diff --git a/arch/alpha/kernel/lca.c b/arch/alpha/kernel/lca.c
new file mode 100644
index 000000000..c32c308fb
--- /dev/null
+++ b/arch/alpha/kernel/lca.c
@@ -0,0 +1,304 @@
+/*
+ * Code common to all LCA chips.
+ *
+ * Written by David Mosberger (davidm@cs.arizona.edu) with some code
+ * taken from Dave Rusling's (david.rusling@reo.mts.dec.com) 32-bit
+ * bios code.
+ */
+#include <linux/kernel.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/bios32.h>
+#include <linux/pci.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+
+/*
+ * BIOS32-style PCI interface:
+ */
+
+#ifdef CONFIG_PCI
+
+#define vulp volatile unsigned long *
+
+/*
+ * Given a bus, device, and function number, compute resulting
+ * configuration space address and setup the LCA_IOC_CONF register
+ * accordingly. It is therefore not safe to have concurrent
+ * invocations to configuration space access routines, but there
+ * really shouldn't be any need for this.
+ *
+ * Type 0:
+ *
+ * 3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1
+ * 3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | | | | | | | | | | | | | | | | | | | | | | | |F|F|F|R|R|R|R|R|R|0|0|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * 31:11 Device select bit.
+ * 10:8 Function number
+ * 7:2 Register number
+ *
+ * Type 1:
+ *
+ * 3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1
+ * 3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | | | | | | | | | | |B|B|B|B|B|B|B|B|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|1|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * 31:24 reserved
+ * 23:16 bus number (8 bits = 128 possible buses)
+ * 15:11 Device number (5 bits)
+ * 10:8 function number
+ * 7:2 register number
+ *
+ * Notes:
+ * The function number selects which function of a multi-function device
+ * (e.g., scsi and ethernet).
+ *
+ * The register selects a DWORD (32 bit) register offset. Hence it
+ * doesn't get shifted by 2 bits as we want to "drop" the bottom two
+ * bits.
+ */
+static int mk_conf_addr(unsigned char bus, unsigned char device_fn,
+ unsigned char where, unsigned long *pci_addr)
+{
+ unsigned long addr;
+
+ if (bus == 0) {
+ int device = device_fn >> 3;
+ int func = device_fn & 0x7;
+
+ /* type 0 configuration cycle: */
+
+ if (device > 12) {
+ return -1;
+ } /* if */
+
+ *((volatile unsigned long*) LCA_IOC_CONF) = 0;
+ addr = (1 << (11 + device)) | (func << 8) | where;
+ } else {
+ /* type 1 configuration cycle: */
+ *((volatile unsigned long*) LCA_IOC_CONF) = 1;
+ addr = (bus << 16) | (device_fn << 8) | where;
+ } /* if */
+ *pci_addr = addr;
+
+ return 0;
+}
+
+
+static unsigned int conf_read(unsigned long addr)
+{
+ unsigned long old_ipl, code, stat0;
+ unsigned int value;
+
+ old_ipl = swpipl(7); /* avoid getting hit by machine check */
+
+ /* reset status register to avoid loosing errors: */
+ stat0 = *((volatile unsigned long*)LCA_IOC_STAT0);
+ *((volatile unsigned long*)LCA_IOC_STAT0) = stat0;
+ mb();
+
+ /* access configuration space: */
+
+ value = *((volatile unsigned int*)addr);
+ draina();
+
+ stat0 = *((unsigned long*)LCA_IOC_STAT0);
+ if (stat0 & LCA_IOC_STAT0_ERR) {
+ code = ((stat0 >> LCA_IOC_STAT0_CODE_SHIFT)
+ & LCA_IOC_STAT0_CODE_MASK);
+ if (code != 1) {
+ printk("lca.c:conf_read: got stat0=%lx\n", stat0);
+ }
+
+ /* reset error status: */
+ *((volatile unsigned long*)LCA_IOC_STAT0) = stat0;
+ mb();
+ wrmces(0x7); /* reset machine check */
+
+ value = 0xffffffff;
+ }
+ swpipl(old_ipl);
+
+ return value;
+}
+
+
+static void conf_write(unsigned long addr, unsigned int value)
+{
+ unsigned long old_ipl, code, stat0;
+
+ old_ipl = swpipl(7); /* avoid getting hit by machine check */
+
+ /* reset status register to avoid loosing errors: */
+ stat0 = *((volatile unsigned long*)LCA_IOC_STAT0);
+ *((volatile unsigned long*)LCA_IOC_STAT0) = stat0;
+ mb();
+
+ /* access configuration space: */
+
+ *((volatile unsigned int*)addr) = value;
+ draina();
+
+ stat0 = *((unsigned long*)LCA_IOC_STAT0);
+ if (stat0 & LCA_IOC_STAT0_ERR) {
+ code = ((stat0 >> LCA_IOC_STAT0_CODE_SHIFT)
+ & LCA_IOC_STAT0_CODE_MASK);
+ if (code != 1) {
+ printk("lca.c:conf_write: got stat0=%lx\n", stat0);
+ }
+
+ /* reset error status: */
+ *((volatile unsigned long*)LCA_IOC_STAT0) = stat0;
+ mb();
+ wrmces(0x7); /* reset machine check */
+ }
+ swpipl(old_ipl);
+}
+
+
+int pcibios_read_config_byte (unsigned char bus, unsigned char device_fn,
+ unsigned char where, unsigned char *value)
+{
+ unsigned long addr = LCA_CONF;
+ unsigned long pci_addr;
+
+ *value = 0xff;
+
+ if (mk_conf_addr(bus, device_fn, where, &pci_addr) < 0) {
+ return PCIBIOS_SUCCESSFUL;
+ } /* if */
+
+ addr |= (pci_addr << 5) + 0x00;
+
+ *value = conf_read(addr) >> ((where & 3) * 8);
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+
+int pcibios_read_config_word (unsigned char bus, unsigned char device_fn,
+ unsigned char where, unsigned short *value)
+{
+ unsigned long addr = LCA_CONF;
+ unsigned long pci_addr;
+
+ *value = 0xffff;
+
+ if (where & 0x1) {
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+ } /* if */
+
+ if (mk_conf_addr(bus, device_fn, where, &pci_addr)) {
+ return PCIBIOS_SUCCESSFUL;
+ } /* if */
+
+ addr |= (pci_addr << 5) + 0x08;
+
+ *value = conf_read(addr) >> ((where & 3) * 8);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+
+int pcibios_read_config_dword (unsigned char bus, unsigned char device_fn,
+ unsigned char where, unsigned int *value)
+{
+ unsigned long addr = LCA_CONF;
+ unsigned long pci_addr;
+
+ *value = 0xffffffff;
+
+ if (where & 0x3) {
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+ } /* if */
+
+ if (mk_conf_addr(bus, device_fn, where, &pci_addr)) {
+ return PCIBIOS_SUCCESSFUL;
+ } /* if */
+
+ addr |= (pci_addr << 5) + 0x18;
+
+ *value = conf_read(addr);
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+
+int pcibios_write_config_byte (unsigned char bus, unsigned char device_fn,
+ unsigned char where, unsigned char value)
+{
+ unsigned long addr = LCA_CONF;
+ unsigned long pci_addr;
+
+ if (mk_conf_addr(bus, device_fn, where, &pci_addr) < 0) {
+ return PCIBIOS_SUCCESSFUL;
+ } /* if */
+
+ addr |= (pci_addr << 5) + 0x00;
+
+ conf_write(addr, value << ((where & 3) * 8));
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+
+int pcibios_write_config_word (unsigned char bus, unsigned char device_fn,
+ unsigned char where, unsigned short value)
+{
+ unsigned long addr = LCA_CONF;
+ unsigned long pci_addr;
+
+ if (mk_conf_addr(bus, device_fn, where, &pci_addr) < 0) {
+ return PCIBIOS_SUCCESSFUL;
+ } /* if */
+
+ addr |= (pci_addr << 5) + 0x08;
+
+ conf_write(addr, value << ((where & 3) * 8));
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+
+int pcibios_write_config_dword (unsigned char bus, unsigned char device_fn,
+ unsigned char where, unsigned int value)
+{
+ unsigned long addr = LCA_CONF;
+ unsigned long pci_addr;
+
+ if (mk_conf_addr(bus, device_fn, where, &pci_addr) < 0) {
+ return PCIBIOS_SUCCESSFUL;
+ } /* if */
+
+ addr |= (pci_addr << 5) + 0x18;
+
+ conf_write(addr, value << ((where & 3) * 8));
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+
+unsigned long lca_init(unsigned long mem_start, unsigned long mem_end)
+{
+ /*
+ * Set up the PCI->physical memory translation windows.
+ * For now, window 1 is disabled. In the future, we may
+ * want to use it to do scatter/gather DMA. Window 0
+ * goes at 1 GB and is 1 GB large.
+ */
+ *(vulp)LCA_IOC_W_BASE1 = 0UL<<33;
+ *(vulp)LCA_IOC_W_BASE0 = 1UL<<33 | LCA_DMA_WIN_BASE;
+ *(vulp)LCA_IOC_W_MASK0 = LCA_DMA_WIN_SIZE - 1;
+ *(vulp)LCA_IOC_T_BASE0 = 0;
+
+ return mem_start;
+}
+
+#endif /* CONFIG_PCI */
+
+ /*** end of lca.c ***/
diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c
new file mode 100644
index 000000000..ddf090283
--- /dev/null
+++ b/arch/alpha/kernel/osf_sys.c
@@ -0,0 +1,494 @@
+/*
+ * linux/arch/alpha/kernel/osf_sys.c
+ *
+ * Copyright (C) 1995 Linus Torvalds
+ */
+
+/*
+ * This file handles some of the stranger OSF/1 system call interfaces.
+ * Some of the system calls expect a non-C calling standard, others have
+ * special parameter blocks..
+ */
+
+#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/utsname.h>
+#include <linux/time.h>
+#include <linux/major.h>
+#include <linux/stat.h>
+#include <linux/mman.h>
+
+#include <asm/segment.h>
+#include <asm/system.h>
+#include <asm/io.h>
+
+extern int do_mount(dev_t, const char *, char *, int, void *);
+extern int do_pipe(int *);
+
+extern struct file_operations * get_blkfops(unsigned int);
+extern struct file_operations * get_chrfops(unsigned int);
+
+extern dev_t get_unnamed_dev(void);
+extern void put_unnamed_dev(dev_t);
+
+extern asmlinkage int sys_umount(char *);
+extern asmlinkage int sys_swapon(const char *specialfile);
+
+/*
+ * OSF/1 directory handling functions...
+ *
+ * The "getdents()" interface is much more sane: the "basep" stuff is
+ * braindamage (it can't really handle filesystems where the directory
+ * offset differences aren't the same as "d_reclen").
+ */
+#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
+#define ROUND_UP(x) (((x)+7) & ~7)
+
+struct osf_dirent {
+ unsigned int d_ino;
+ unsigned short d_reclen;
+ unsigned short d_namlen;
+ char d_name[1];
+};
+
+struct osf_dirent_callback {
+ struct osf_dirent * dirent;
+ long *basep;
+ int count;
+ int error;
+};
+
+static int osf_filldir(void * __buf, char * name, int namlen, off_t offset, ino_t ino)
+{
+ struct osf_dirent * dirent;
+ struct osf_dirent_callback * buf = (struct osf_dirent_callback *) __buf;
+ int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1);
+
+ buf->error = -EINVAL; /* unly used if we fail */
+ if (reclen > buf->count)
+ return -EINVAL;
+ if (buf->basep) {
+ put_user(offset, buf->basep);
+ buf->basep = NULL;
+ }
+ dirent = buf->dirent;
+ put_user(ino, &dirent->d_ino);
+ put_user(namlen, &dirent->d_namlen);
+ put_user(reclen, &dirent->d_reclen);
+ memcpy_tofs(dirent->d_name, name, namlen);
+ put_fs_byte(0, dirent->d_name + namlen);
+ ((char *) dirent) += reclen;
+ buf->dirent = dirent;
+ buf->count -= reclen;
+ return 0;
+}
+
+asmlinkage int osf_getdirentries(unsigned int fd, struct osf_dirent * dirent,
+ unsigned int count, long *basep)
+{
+ int error;
+ struct file * file;
+ struct osf_dirent_callback buf;
+
+ if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
+ return -EBADF;
+ if (!file->f_op || !file->f_op->readdir)
+ return -ENOTDIR;
+ error = verify_area(VERIFY_WRITE, dirent, count);
+ if (error)
+ return error;
+ if (basep) {
+ error = verify_area(VERIFY_WRITE, basep, sizeof(long));
+ if (error)
+ return error;
+ }
+ buf.dirent = dirent;
+ buf.basep = basep;
+ buf.count = count;
+ buf.error = 0;
+ error = file->f_op->readdir(file->f_inode, file, dirent, osf_filldir);
+ if (error < 0)
+ return error;
+ if (count == buf.count)
+ return buf.error;
+ return count - buf.count;
+}
+
+/*
+ * Heh. As documented by DEC..
+ */
+asmlinkage unsigned long sys_madvise(void)
+{
+ return 0;
+}
+
+asmlinkage unsigned long sys_getxuid(int a0, int a1, int a2, int a3, int a4, int a5,
+ struct pt_regs regs)
+{
+ (&regs)->r20 = current->euid;
+ return current->uid;
+}
+
+asmlinkage unsigned long sys_getxgid(int a0, int a1, int a2, int a3, int a4, int a5,
+ struct pt_regs regs)
+{
+ (&regs)->r20 = current->egid;
+ return current->gid;
+}
+
+asmlinkage unsigned long sys_getxpid(int a0, int a1, int a2, int a3, int a4, int a5,
+ struct pt_regs regs)
+{
+ (&regs)->r20 = current->p_opptr->pid;
+ return current->pid;
+}
+
+#define OSF_MAP_ANONYMOUS 0x0010
+#define OSF_MAP_FIXED 0x0100
+#define OSF_MAP_HASSEMAPHORE 0x0200
+#define OSF_MAP_INHERIT 0x0400
+#define OSF_MAP_UNALIGNED 0x0800
+
+asmlinkage unsigned long osf_mmap(unsigned long addr, unsigned long len,
+ unsigned long prot, unsigned long osf_flags, unsigned long fd,
+ unsigned long off)
+{
+ struct file * file = NULL;
+ unsigned long flags = osf_flags & 0x0f;
+
+ if (osf_flags & (OSF_MAP_HASSEMAPHORE | OSF_MAP_INHERIT | OSF_MAP_UNALIGNED))
+ printk("%s: unimplemented OSF mmap flags %04lx\n", current->comm, osf_flags);
+ if (osf_flags & OSF_MAP_FIXED)
+ flags |= MAP_FIXED;
+ if (osf_flags & OSF_MAP_ANONYMOUS)
+ flags |= MAP_ANONYMOUS;
+ else {
+ if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
+ return -EBADF;
+ }
+ return do_mmap(file, addr, len, prot, flags, off);
+}
+
+asmlinkage int osf_statfs(char * path, struct statfs * buffer, unsigned long bufsiz)
+{
+ struct inode * inode;
+ int retval;
+
+ if (bufsiz > sizeof(struct statfs))
+ bufsiz = sizeof(struct statfs);
+ retval = verify_area(VERIFY_WRITE, buffer, bufsiz);
+ if (retval)
+ return retval;
+ retval = namei(path, &inode);
+ if (retval)
+ return retval;
+ if (!inode->i_sb->s_op->statfs) {
+ iput(inode);
+ return -ENOSYS;
+ }
+ inode->i_sb->s_op->statfs(inode->i_sb, buffer, bufsiz);
+ iput(inode);
+ return 0;
+}
+
+asmlinkage int osf_fstatfs(unsigned long fd, struct statfs * buffer, unsigned long bufsiz)
+{
+ struct file * file;
+ struct inode * inode;
+ int retval;
+
+ retval = verify_area(VERIFY_WRITE, buffer, bufsiz);
+ if (retval)
+ return retval;
+ if (bufsiz > sizeof(struct statfs))
+ bufsiz = sizeof(struct statfs);
+ if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
+ return -EBADF;
+ if (!(inode = file->f_inode))
+ return -ENOENT;
+ if (!inode->i_sb->s_op->statfs)
+ return -ENOSYS;
+ inode->i_sb->s_op->statfs(inode->i_sb, buffer, bufsiz);
+ return 0;
+}
+
+/*
+ * Uhh.. OSF/1 mount parameters aren't exactly obvious..
+ *
+ * Although to be frank, neither are the native Linux/i386 ones..
+ */
+struct ufs_args {
+ char * devname;
+ int flags;
+ uid_t exroot;
+};
+
+struct cdfs_args {
+ char * devname;
+ int flags;
+ uid_t exroot;
+/*
+ * this has lots more here, which linux handles with the option block
+ * but I'm too lazy to do the translation into ascii..
+ */
+};
+
+struct procfs_args {
+ char * devname;
+ int flags;
+ uid_t exroot;
+};
+
+static int getdev(const char * name, int rdonly, struct inode ** ino)
+{
+ dev_t dev;
+ struct inode * inode;
+ struct file_operations * fops;
+ int retval;
+
+ retval = namei(name, &inode);
+ if (retval)
+ return retval;
+ if (!S_ISBLK(inode->i_mode)) {
+ iput(inode);
+ return -ENOTBLK;
+ }
+ if (IS_NODEV(inode)) {
+ iput(inode);
+ return -EACCES;
+ }
+ dev = inode->i_rdev;
+ if (MAJOR(dev) >= MAX_BLKDEV) {
+ iput(inode);
+ return -ENXIO;
+ }
+ fops = get_blkfops(MAJOR(dev));
+ if (!fops) {
+ iput(inode);
+ return -ENODEV;
+ }
+ if (fops->open) {
+ struct file dummy;
+ memset(&dummy, 0, sizeof(dummy));
+ dummy.f_inode = inode;
+ dummy.f_mode = rdonly ? 1 : 3;
+ retval = fops->open(inode, &dummy);
+ if (retval) {
+ iput(inode);
+ return retval;
+ }
+ }
+ *ino = inode;
+ return 0;
+}
+
+static void putdev(struct inode * inode)
+{
+ struct file_operations * fops;
+
+ fops = get_blkfops(MAJOR(inode->i_rdev));
+ if (fops->release)
+ fops->release(inode, NULL);
+}
+
+/*
+ * We can't actually handle ufs yet, so we translate UFS mounts to
+ * ext2fs mounts... I wouldn't mind a USF filesystem, but the UFS
+ * layout is so braindead it's a major headache doing it..
+ */
+static int osf_ufs_mount(char * dirname, struct ufs_args * args, int flags)
+{
+ int retval;
+ struct inode * inode;
+ struct cdfs_args tmp;
+
+ retval = verify_area(VERIFY_READ, args, sizeof(*args));
+ if (retval)
+ return retval;
+ memcpy_fromfs(&tmp, args, sizeof(tmp));
+ retval = getdev(tmp.devname, 0, &inode);
+ if (retval)
+ return retval;
+ retval = do_mount(inode->i_rdev, dirname, "ext2", flags, NULL);
+ if (retval)
+ putdev(inode);
+ iput(inode);
+ return retval;
+}
+
+static int osf_cdfs_mount(char * dirname, struct cdfs_args * args, int flags)
+{
+ int retval;
+ struct inode * inode;
+ struct cdfs_args tmp;
+
+ retval = verify_area(VERIFY_READ, args, sizeof(*args));
+ if (retval)
+ return retval;
+ memcpy_fromfs(&tmp, args, sizeof(tmp));
+ retval = getdev(tmp.devname, 1, &inode);
+ if (retval)
+ return retval;
+ retval = do_mount(inode->i_rdev, dirname, "iso9660", flags, NULL);
+ if (retval)
+ putdev(inode);
+ iput(inode);
+ return retval;
+}
+
+static int osf_procfs_mount(char * dirname, struct procfs_args * args, int flags)
+{
+ dev_t dev;
+ int retval;
+ struct procfs_args tmp;
+
+ retval = verify_area(VERIFY_READ, args, sizeof(*args));
+ if (retval)
+ return retval;
+ memcpy_fromfs(&tmp, args, sizeof(tmp));
+ dev = get_unnamed_dev();
+ if (!dev)
+ return -ENODEV;
+ retval = do_mount(dev, dirname, "proc", flags, NULL);
+ if (retval)
+ put_unnamed_dev(dev);
+ return retval;
+}
+
+asmlinkage int osf_mount(unsigned long typenr, char * path, int flag, void * data)
+{
+ int retval;
+
+ retval = -EINVAL;
+ switch (typenr) {
+ case 1:
+ retval = osf_ufs_mount(path, (struct ufs_args *) data, flag);
+ break;
+ case 6:
+ retval = osf_cdfs_mount(path, (struct cdfs_args *) data, flag);
+ break;
+ case 9:
+ retval = osf_procfs_mount(path, (struct procfs_args *) data, flag);
+ break;
+ default:
+ printk("osf_mount(%ld, %x)\n", typenr, flag);
+ }
+ return retval;
+}
+
+asmlinkage int osf_umount(char * path, int flag)
+{
+ return sys_umount(path);
+}
+
+/*
+ * I don't know what the parameters are: the first one
+ * seems to be a timeval pointer, and I suspect the second
+ * one is the time remaining.. Ho humm.. No documentation.
+ */
+asmlinkage int osf_usleep_thread(struct timeval * sleep, struct timeval * remain)
+{
+ struct timeval tmp;
+ unsigned long ticks;
+ int retval;
+
+ retval = verify_area(VERIFY_READ, sleep, sizeof(*sleep));
+ if (retval)
+ return retval;
+ if (remain && (retval = verify_area(VERIFY_WRITE, remain, sizeof(*remain))))
+ return retval;
+ memcpy_fromfs(&tmp, sleep, sizeof(*sleep));
+ ticks = tmp.tv_usec;
+ ticks = (ticks + (1000000 / HZ) - 1) / (1000000 / HZ);
+ ticks += tmp.tv_sec * HZ;
+ current->timeout = ticks + jiffies;
+ current->state = TASK_INTERRUPTIBLE;
+ schedule();
+ if (!remain)
+ return 0;
+ ticks = jiffies;
+ if (ticks < current->timeout)
+ ticks = current->timeout - ticks;
+ else
+ ticks = 0;
+ current->timeout = 0;
+ tmp.tv_sec = ticks / HZ;
+ tmp.tv_usec = ticks % HZ;
+ memcpy_tofs(remain, &tmp, sizeof(*remain));
+ return 0;
+}
+
+asmlinkage int osf_utsname(char * name)
+{
+ int error = verify_area(VERIFY_WRITE, name, 5*32);
+ if (error)
+ return error;
+ memcpy_tofs(name + 0, system_utsname.sysname, 32);
+ memcpy_tofs(name + 32, system_utsname.nodename, 32);
+ memcpy_tofs(name + 64, system_utsname.release, 32);
+ memcpy_tofs(name + 96, system_utsname.version, 32);
+ memcpy_tofs(name + 128, system_utsname.machine, 32);
+ return 0;
+}
+
+asmlinkage int osf_swapon(const char * path, int flags, int lowat, int hiwat)
+{
+ /* for now, simply ignore flags, lowat and hiwat... */
+ return sys_swapon(path);
+}
+
+asmlinkage unsigned long sys_getpagesize(void)
+{
+ return PAGE_SIZE;
+}
+
+asmlinkage unsigned long sys_getdtablesize(void)
+{
+ return NR_OPEN;
+}
+
+asmlinkage int sys_pipe(int a0, int a1, int a2, int a3, int a4, int a5,
+ struct pt_regs regs)
+{
+ int fd[2];
+ int error;
+
+ error = do_pipe(fd);
+ if (error)
+ return error;
+ (&regs)->r20 = fd[1];
+ return fd[0];
+}
+
+/*
+ * For compatibility with OSF/1 only. Use utsname(2) instead.
+ */
+asmlinkage int osf_getdomainname(char *name, int namelen)
+{
+ unsigned len;
+ int i, error;
+
+ error = verify_area(VERIFY_WRITE, name, namelen);
+ if (error)
+ return error;
+
+ len = namelen;
+ if (namelen > 32)
+ len = 32;
+
+ for (i = 0; i < len; ++i) {
+ put_user(system_utsname.domainname[i], name + i);
+ if (system_utsname.domainname[i] == '\0')
+ break;
+ }
+ return 0;
+}
diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c
new file mode 100644
index 000000000..257f431a5
--- /dev/null
+++ b/arch/alpha/kernel/process.c
@@ -0,0 +1,186 @@
+/*
+ * linux/arch/alpha/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 <linux/utsname.h>
+#include <linux/time.h>
+#include <linux/major.h>
+#include <linux/stat.h>
+#include <linux/mman.h>
+
+#include <asm/segment.h>
+#include <asm/system.h>
+#include <asm/io.h>
+
+asmlinkage int sys_sethae(unsigned long hae, unsigned long a1, unsigned long a2,
+ unsigned long a3, unsigned long a4, unsigned long a5,
+ struct pt_regs regs)
+{
+ (&regs)->hae = hae;
+ return 0;
+}
+
+asmlinkage int sys_idle(void)
+{
+ if (current->pid != 0)
+ return -EPERM;
+
+ /* 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("\nps: %04lx pc: %016lx\n", regs->ps, regs->pc);
+ printk("rp: %016lx sp: %p\n", regs->r26, regs+1);
+ printk(" r0: %016lx r1: %016lx r2: %016lx r3: %016lx\n",
+ regs->r0, regs->r1, regs->r2, regs->r3);
+ printk(" r4: %016lx r5: %016lx r6: %016lx r7: %016lx\n",
+ regs->r4, regs->r5, regs->r6, regs->r7);
+ printk(" r8: %016lx r16: %016lx r17: %016lx r18: %016lx\n",
+ regs->r8, regs->r16, regs->r17, regs->r18);
+ printk("r19: %016lx r20: %016lx r21: %016lx r22: %016lx\n",
+ regs->r19, regs->r20, regs->r21, regs->r22);
+ printk("r23: %016lx r24: %016lx r25: %016lx r26: %016lx\n",
+ regs->r23, regs->r24, regs->r25, regs->r26);
+ printk("r27: %016lx r28: %016lx r29: %016lx hae: %016lx\n",
+ regs->r27, regs->r28, regs->gp, regs->hae);
+}
+
+/*
+ * Free current thread data structures etc..
+ */
+void exit_thread(void)
+{
+}
+
+void flush_thread(void)
+{
+}
+
+/*
+ * "alpha_fork()".. By the time we get here, the
+ * non-volatile registers have also been saved on the
+ * stack. We do some ugly pointer stuff here.. (see
+ * also copy_thread)
+ */
+int alpha_fork(struct switch_stack * swstack)
+{
+ return do_fork(COPYVM | SIGCHLD,
+ rdusp(),
+ (struct pt_regs *) (swstack+1));
+}
+
+extern void ret_from_sys_call(void);
+/*
+ * Copy an alpha thread..
+ *
+ * Note the "stack_offset" stuff: when returning to kernel mode, we need
+ * to have some extra stack-space for the kernel stack that still exists
+ * after the "ret_from_sys_call". When returning to user mode, we only
+ * want the space needed by the syscall stack frame (ie "struct pt_regs").
+ * Use the passed "regs" pointer to determine how much space we need
+ * for a kernel fork().
+ */
+void copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
+ struct task_struct * p, struct pt_regs * regs)
+{
+ struct pt_regs * childregs;
+ struct switch_stack * childstack, *stack;
+ unsigned long stack_offset;
+
+ stack_offset = PAGE_SIZE - sizeof(struct pt_regs);
+ if (!(regs->ps & 8))
+ stack_offset = (PAGE_SIZE-1) & (unsigned long) regs;
+ childregs = (struct pt_regs *) (p->kernel_stack_page + stack_offset);
+
+ *childregs = *regs;
+ childregs->r0 = 0;
+ childregs->r19 = 0;
+ childregs->r20 = 1; /* OSF/1 has some strange fork() semantics.. */
+ regs->r0 = p->pid;
+ regs->r20 = 0;
+ stack = ((struct switch_stack *) regs) - 1;
+ childstack = ((struct switch_stack *) childregs) - 1;
+ *childstack = *stack;
+ childstack->r26 = (unsigned long) ret_from_sys_call;
+ p->tss.usp = usp;
+ p->tss.ksp = (unsigned long) childstack;
+ p->tss.flags = 1;
+}
+
+/*
+ * fill in the user structure for a core dump..
+ */
+void dump_thread(struct pt_regs * regs, struct user * dump)
+{
+}
+
+/*
+ * sys_execve() executes a new program.
+ *
+ * This works due to the alpha calling sequence: the first 6 args
+ * are gotten from registers, while the rest is on the stack, so
+ * we get a0-a5 for free, and then magically find "struct pt_regs"
+ * on the stack for us..
+ *
+ * Don't do this at home.
+ */
+asmlinkage int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2,
+ unsigned long a3, unsigned long a4, unsigned long a5,
+ struct pt_regs regs)
+{
+ int error;
+ char * filename;
+
+ error = getname((char *) a0, &filename);
+ if (error)
+ return error;
+ error = do_execve(filename, (char **) a1, (char **) a2, &regs);
+ putname(filename);
+ return error;
+}
+
+/*
+ * This doesn't actually work correctly like this: we need to do the
+ * same stack setups that fork() does first.
+ */
+asmlinkage int sys_clone(unsigned long a0, unsigned long a1, unsigned long a2,
+ unsigned long a3, unsigned long a4, unsigned long a5,
+ struct pt_regs regs)
+{
+ unsigned long clone_flags = a0;
+ unsigned long newsp;
+
+ newsp = rdusp();
+ if (newsp == a1 || !a1)
+ clone_flags |= COPYVM;
+ else
+ newsp = a1;
+ return do_fork(clone_flags, newsp, &regs);
+}
diff --git a/arch/alpha/kernel/setup.c b/arch/alpha/kernel/setup.c
new file mode 100644
index 000000000..23a2efd65
--- /dev/null
+++ b/arch/alpha/kernel/setup.c
@@ -0,0 +1,172 @@
+/*
+ * linux/arch/alpha/kernel/setup.c
+ *
+ * Copyright (C) 1995 Linus Torvalds
+ */
+
+/*
+ * 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 <linux/delay.h>
+
+#include <asm/segment.h>
+#include <asm/system.h>
+#include <asm/hwrpb.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+
+struct hae hae = {
+ 0,
+ (unsigned long*) HAE_ADDRESS
+};
+
+struct hwrpb_struct *hwrpb;
+
+unsigned char aux_device_present;
+
+/*
+ * This is setup by the secondary bootstrap loader. Because
+ * the zero page is zeroed out as soon as the vm system is
+ * initialized, we need to copy things out into a more permanent
+ * place.
+ */
+#define PARAM ZERO_PGE
+#define COMMAND_LINE ((char*)(PARAM + 0x0000))
+#define COMMAND_LINE_SIZE 256
+
+static char command_line[COMMAND_LINE_SIZE] = { 0, };
+
+/*
+ * The format of "screen_info" is strange, and due to early
+ * i386-setup code. This is just enough to make the console
+ * code think we're on a EGA+ colour display.
+ */
+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 */
+};
+
+static unsigned long find_end_memory(void)
+{
+ int i;
+ unsigned long high = 0;
+ struct memclust_struct * cluster;
+ struct memdesc_struct * memdesc;
+
+ memdesc = (struct memdesc_struct *) (INIT_HWRPB->mddt_offset + (unsigned long) INIT_HWRPB);
+ cluster = memdesc->cluster;
+ for (i = memdesc->numclusters ; i > 0; i--, cluster++) {
+ unsigned long tmp;
+ tmp = (cluster->start_pfn + cluster->numpages) << PAGE_SHIFT;
+ if (tmp > high)
+ high = tmp;
+ }
+ /* round it up to an even number of pages.. */
+ high = (high + PAGE_SIZE) & (PAGE_MASK*2);
+ return PAGE_OFFSET + high;
+}
+
+void setup_arch(char **cmdline_p,
+ unsigned long * memory_start_p, unsigned long * memory_end_p)
+{
+ extern int _end;
+
+ hwrpb = (struct hwrpb_struct*)(IDENT_ADDR + INIT_HWRPB->phys_addr);
+
+ set_hae(hae.cache); /* sync HAE register w/hae_cache */
+
+ ROOT_DEV = 0x0802; /* sda2 */
+#ifndef CONFIG_PCI
+ aux_device_present = 0xaa;
+#else
+ aux_device_present = 0x00;
+#endif
+ command_line[COMMAND_LINE_SIZE - 1] = '\0';
+ strcpy(command_line, COMMAND_LINE);
+
+ *cmdline_p = command_line;
+ *memory_start_p = (unsigned long) &_end;
+ *memory_end_p = find_end_memory();
+
+#ifdef CONFIG_PCI
+ *memory_start_p = lca_init(*memory_start_p, *memory_end_p);
+#endif
+}
+
+asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on)
+{
+ return -EIO;
+}
+
+
+/*
+ * BUFFER is PAGE_SIZE bytes long.
+ */
+int get_cpuinfo(char *buffer)
+{
+ const char *cpu_name[] = {
+ "EV3", "EV4", "Unknown 1", "LCA4", "EV5", "EV45"
+ };
+ const char *systype_name[] = {
+ "ADU", "Cobra", "Ruby", "Flamingo", "Unknown 1", "Jensen",
+ "Pelican", "Unknown 2", "Sable", "AXPvme", "Noname",
+ "Turbolaser", "Avanti", "Mustang", "Alcor", "Unknown 3",
+ "Mikasa", "Unknown3", "EB66", "EB64+"
+ };
+ struct percpu_struct *cpu;
+ unsigned int cpu_index, system_index;
+# define N(a) (sizeof(a)/sizeof(a[0]))
+
+ cpu = (struct percpu_struct*)((char*)hwrpb + hwrpb->processor_offset);
+ cpu_index = (unsigned) (cpu->type - 1);
+ system_index = (unsigned) (hwrpb->sys_type - 1);
+
+ return sprintf(buffer,
+ "cpu\t\t\t: Alpha\n"
+ "cpu model\t\t: %s\n"
+ "cpu variation\t\t: %ld\n"
+ "cpu revision\t\t: %ld\n"
+ "cpu serial number\t: %s\n"
+ "system type\t\t: %s\n"
+ "system variation\t: %ld\n"
+ "system revision\t\t: %ld\n"
+ "system serial number\t: %s\n"
+ "cycle frequency [Hz]\t: %lu\n"
+ "timer frequency [Hz]\t: %lu.%02lu\n"
+ "page size [bytes]\t: %ld\n"
+ "phys. address bits\t: %ld\n"
+ "max. addr. space #\t: %ld\n"
+ "BogoMIPS\t\t: %lu.%02lu\n",
+
+ (cpu_index < N(cpu_name) ? cpu_name[cpu_index] : "Unknown"),
+ cpu->variation, cpu->revision, (char*)cpu->serial_no,
+ (system_index < N(systype_name) ? systype_name[system_index] : "Unknown"),
+ hwrpb->sys_variation, hwrpb->sys_revision,
+ (char*)hwrpb->ssn,
+ hwrpb->cycle_freq,
+ hwrpb->intr_freq / 4096,
+ (100 * hwrpb->intr_freq / 4096) % 100,
+ hwrpb->pagesize,
+ hwrpb->pa_bits,
+ hwrpb->max_asn,
+ loops_per_sec / 500000, (loops_per_sec / 5000) % 100);
+# undef N
+}
diff --git a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c
new file mode 100644
index 000000000..cc7069728
--- /dev/null
+++ b/arch/alpha/kernel/signal.c
@@ -0,0 +1,319 @@
+/*
+ * linux/arch/alpha/kernel/signal.c
+ *
+ * Copyright (C) 1995 Linus Torvalds
+ */
+
+#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 <linux/mm.h>
+
+#include <asm/bitops.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);
+asmlinkage void ret_from_sys_call(void);
+asmlinkage int do_signal(unsigned long, struct pt_regs *, struct switch_stack *,
+ unsigned long, unsigned long);
+asmlinkage void imb(void);
+
+/*
+ * The OSF/1 sigprocmask calling sequence is different from the
+ * C sigprocmask() sequence..
+ */
+asmlinkage unsigned long osf_sigprocmask(int how, unsigned long newmask)
+{
+ unsigned long oldmask = current->blocked;
+
+ newmask &= _BLOCKABLE;
+ switch (how) {
+ case SIG_BLOCK:
+ current->blocked |= newmask;
+ return oldmask;
+ case SIG_UNBLOCK:
+ current->blocked &= ~newmask;
+ return oldmask;
+ case SIG_SETMASK:
+ current->blocked = newmask;
+ return oldmask;
+ }
+ return -EINVAL;
+}
+
+/*
+ * atomically swap in the new signal mask, and wait for a signal.
+ */
+asmlinkage int do_sigsuspend(unsigned long mask, struct pt_regs * regs, struct switch_stack * sw)
+{
+ unsigned long oldmask = current->blocked;
+ current->blocked = mask & _BLOCKABLE;
+ while (1) {
+ current->state = TASK_INTERRUPTIBLE;
+ schedule();
+ if (do_signal(oldmask,regs, sw, 0, 0))
+ return -EINTR;
+ }
+}
+
+/*
+ * Do a signal return; undo the signal stack.
+ */
+asmlinkage void do_sigreturn(struct sigcontext_struct * sc,
+ struct pt_regs * regs, struct switch_stack * sw)
+{
+ unsigned long mask;
+ int i;
+
+ /* verify that it's a good sigcontext before using it */
+ if (verify_area(VERIFY_READ, sc, sizeof(*sc)))
+ do_exit(SIGSEGV);
+ if (get_fs_quad(&sc->sc_ps) != 8)
+ do_exit(SIGSEGV);
+ mask = get_fs_quad(&sc->sc_mask);
+ if (mask & ~_BLOCKABLE)
+ do_exit(SIGSEGV);
+
+ /* ok, looks fine, start restoring */
+ wrusp(get_fs_quad(sc->sc_regs+30));
+ regs->pc = get_fs_quad(&sc->sc_pc);
+ sw->r26 = (unsigned long) ret_from_sys_call;
+ current->blocked = mask;
+
+ regs->r0 = get_fs_quad(sc->sc_regs+0);
+ regs->r1 = get_fs_quad(sc->sc_regs+1);
+ regs->r2 = get_fs_quad(sc->sc_regs+2);
+ regs->r3 = get_fs_quad(sc->sc_regs+3);
+ regs->r4 = get_fs_quad(sc->sc_regs+4);
+ regs->r5 = get_fs_quad(sc->sc_regs+5);
+ regs->r6 = get_fs_quad(sc->sc_regs+6);
+ regs->r7 = get_fs_quad(sc->sc_regs+7);
+ regs->r8 = get_fs_quad(sc->sc_regs+8);
+ sw->r9 = get_fs_quad(sc->sc_regs+9);
+ sw->r10 = get_fs_quad(sc->sc_regs+10);
+ sw->r11 = get_fs_quad(sc->sc_regs+11);
+ sw->r12 = get_fs_quad(sc->sc_regs+12);
+ sw->r13 = get_fs_quad(sc->sc_regs+13);
+ sw->r14 = get_fs_quad(sc->sc_regs+14);
+ sw->r15 = get_fs_quad(sc->sc_regs+15);
+ regs->r16 = get_fs_quad(sc->sc_regs+16);
+ regs->r17 = get_fs_quad(sc->sc_regs+17);
+ regs->r18 = get_fs_quad(sc->sc_regs+18);
+ regs->r19 = get_fs_quad(sc->sc_regs+19);
+ regs->r20 = get_fs_quad(sc->sc_regs+20);
+ regs->r21 = get_fs_quad(sc->sc_regs+21);
+ regs->r22 = get_fs_quad(sc->sc_regs+22);
+ regs->r23 = get_fs_quad(sc->sc_regs+23);
+ regs->r24 = get_fs_quad(sc->sc_regs+24);
+ regs->r25 = get_fs_quad(sc->sc_regs+25);
+ regs->r26 = get_fs_quad(sc->sc_regs+26);
+ regs->r27 = get_fs_quad(sc->sc_regs+27);
+ regs->r28 = get_fs_quad(sc->sc_regs+28);
+ regs->gp = get_fs_quad(sc->sc_regs+29);
+ for (i = 0; i < 31; i++)
+ sw->fp[i] = get_fs_quad(sc->sc_fpregs+i);
+}
+
+/*
+ * Set up a signal frame...
+ */
+static void setup_frame(struct sigaction * sa, struct sigcontext_struct ** fp, unsigned long pc,
+ struct pt_regs * regs, struct switch_stack * sw, int signr, unsigned long oldmask)
+{
+ int i;
+ struct sigcontext_struct * sc;
+
+ sc = *fp;
+ /* check here if we would need to switch stacks.. */
+ sc--;
+ if (verify_area(VERIFY_WRITE, sc, sizeof(*sc)))
+ do_exit(SIGSEGV);
+
+ put_fs_quad(oldmask, &sc->sc_mask);
+ put_fs_quad(8, &sc->sc_ps);
+ put_fs_quad(pc, &sc->sc_pc);
+ put_fs_quad((unsigned long)*fp, sc->sc_regs+30);
+
+ put_fs_quad(regs->r0 , sc->sc_regs+0);
+ put_fs_quad(regs->r1 , sc->sc_regs+1);
+ put_fs_quad(regs->r2 , sc->sc_regs+2);
+ put_fs_quad(regs->r3 , sc->sc_regs+3);
+ put_fs_quad(regs->r4 , sc->sc_regs+4);
+ put_fs_quad(regs->r5 , sc->sc_regs+5);
+ put_fs_quad(regs->r6 , sc->sc_regs+6);
+ put_fs_quad(regs->r7 , sc->sc_regs+7);
+ put_fs_quad(regs->r8 , sc->sc_regs+8);
+ put_fs_quad(sw->r9 , sc->sc_regs+9);
+ put_fs_quad(sw->r10 , sc->sc_regs+10);
+ put_fs_quad(sw->r11 , sc->sc_regs+11);
+ put_fs_quad(sw->r12 , sc->sc_regs+12);
+ put_fs_quad(sw->r13 , sc->sc_regs+13);
+ put_fs_quad(sw->r14 , sc->sc_regs+14);
+ put_fs_quad(sw->r15 , sc->sc_regs+15);
+ put_fs_quad(regs->r16, sc->sc_regs+16);
+ put_fs_quad(regs->r17, sc->sc_regs+17);
+ put_fs_quad(regs->r18, sc->sc_regs+18);
+ put_fs_quad(regs->r19, sc->sc_regs+19);
+ put_fs_quad(regs->r20, sc->sc_regs+20);
+ put_fs_quad(regs->r21, sc->sc_regs+21);
+ put_fs_quad(regs->r22, sc->sc_regs+22);
+ put_fs_quad(regs->r23, sc->sc_regs+23);
+ put_fs_quad(regs->r24, sc->sc_regs+24);
+ put_fs_quad(regs->r25, sc->sc_regs+25);
+ put_fs_quad(regs->r26, sc->sc_regs+26);
+ put_fs_quad(regs->r27, sc->sc_regs+27);
+ put_fs_quad(regs->r28, sc->sc_regs+28);
+ put_fs_quad(regs->gp , sc->sc_regs+29);
+ for (i = 0; i < 31; i++)
+ put_fs_quad(sw->fp[i], sc->sc_fpregs+i);
+
+ /*
+ * The following is:
+ *
+ * bis $30,$30,$16
+ * addq $31,0x67,$0
+ * call_pal callsys
+ *
+ * ie, "sigreturn(stack-pointer)"
+ */
+ put_fs_quad(0x43ecf40047de0410, sc->sc_retcode+0);
+ put_fs_quad(0x0000000000000083, sc->sc_retcode+1);
+ regs->r26 = (unsigned long) sc->sc_retcode;
+ regs->r16 = signr;
+ *fp = sc;
+}
+
+/*
+ * 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.
+ *
+ * "r0" and "r19" are the registers we need to restore for system call
+ * restart. "r0" is also used as an indicator whether we can restart at
+ * all (if we get here from anything but a syscall return, it will be 0)
+ */
+asmlinkage int do_signal(unsigned long oldmask,
+ struct pt_regs * regs,
+ struct switch_stack * sw,
+ unsigned long r0, unsigned long r19)
+{
+ unsigned long mask = ~current->blocked;
+ unsigned long handler_signal = 0;
+ struct sigcontext_struct *frame = NULL;
+ unsigned long pc = 0;
+ unsigned long signr;
+ struct sigaction * sa;
+
+ while ((signr = current->signal & mask) != 0) {
+ signr = ffz(~signr);
+ clear_bit(signr, &current->signal);
+ sa = current->sigaction + signr;
+ signr++;
+ if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
+ current->exit_code = signr;
+ current->state = TASK_STOPPED;
+ notify_parent(current);
+ schedule();
+ if (!(signr = current->exit_code))
+ continue;
+ current->exit_code = 0;
+ if (signr == SIGSTOP)
+ continue;
+ if (_S(signr) & current->blocked) {
+ current->signal |= _S(signr);
+ continue;
+ }
+ sa = current->sigaction + signr - 1;
+ }
+ if (sa->sa_handler == SIG_IGN) {
+ if (signr != SIGCHLD)
+ continue;
+ /* check for SIGCHLD: it's special */
+ while (sys_waitpid(-1,NULL,WNOHANG) > 0)
+ /* nothing */;
+ continue;
+ }
+ if (sa->sa_handler == SIG_DFL) {
+ if (current->pid == 1)
+ continue;
+ switch (signr) {
+ case SIGCONT: case SIGCHLD: case SIGWINCH:
+ continue;
+
+ case SIGSTOP: case SIGTSTP: case SIGTTIN: case SIGTTOU:
+ if (current->flags & PF_PTRACED)
+ continue;
+ current->state = TASK_STOPPED;
+ current->exit_code = signr;
+ if (!(current->p_pptr->sigaction[SIGCHLD-1].sa_flags &
+ SA_NOCLDSTOP))
+ notify_parent(current);
+ schedule();
+ continue;
+
+ case SIGQUIT: case SIGILL: case SIGTRAP:
+ case SIGABRT: case SIGFPE: case SIGSEGV:
+ if (current->binfmt && current->binfmt->core_dump) {
+ if (current->binfmt->core_dump(signr, regs))
+ signr |= 0x80;
+ }
+ /* fall through */
+ default:
+ current->signal |= _S(signr & 0x7f);
+ do_exit(signr);
+ }
+ }
+ /*
+ * OK, we're invoking a handler
+ */
+ if (r0) {
+ if (regs->r0 == ERESTARTNOHAND ||
+ (regs->r0 == ERESTARTSYS && !(sa->sa_flags & SA_RESTART)))
+ regs->r0 = EINTR;
+ }
+ handler_signal |= 1 << (signr-1);
+ mask &= ~sa->sa_mask;
+ }
+ if (r0 &&
+ (regs->r0 == ERESTARTNOHAND ||
+ regs->r0 == ERESTARTSYS ||
+ regs->r0 == ERESTARTNOINTR)) {
+ regs->r0 = r0;
+ regs->r19 = r19;
+ regs->pc -= 4;
+ }
+ if (!handler_signal) /* no handler will be called - return 0 */
+ return 0;
+ pc = regs->pc;
+ frame = (struct sigcontext_struct *) rdusp();
+ signr = 1;
+ sa = current->sigaction;
+ for (mask = 1 ; mask ; sa++,signr++,mask += mask) {
+ if (mask > handler_signal)
+ break;
+ if (!(mask & handler_signal))
+ continue;
+ setup_frame(sa,&frame,pc,regs,sw,signr,oldmask);
+ pc = (unsigned long) sa->sa_handler;
+ regs->r27 = pc;
+ if (sa->sa_flags & SA_ONESHOT)
+ sa->sa_handler = NULL;
+ current->blocked |= sa->sa_mask;
+ oldmask |= sa->sa_mask;
+ }
+ imb();
+ wrusp((unsigned long) frame);
+ regs->pc = pc; /* "return" to the first handler */
+ return 1;
+}
diff --git a/arch/alpha/kernel/traps.c b/arch/alpha/kernel/traps.c
new file mode 100644
index 000000000..4e3512ddd
--- /dev/null
+++ b/arch/alpha/kernel/traps.c
@@ -0,0 +1,159 @@
+/*
+ * kernel/traps.c
+ *
+ * (C) Copyright 1994 Linus Torvalds
+ */
+
+/*
+ * This file initializes the trap entry points
+ */
+
+#include <linux/sched.h>
+#include <linux/tty.h>
+
+#include <asm/unaligned.h>
+
+void die_if_kernel(char * str, struct pt_regs * regs, long err)
+{
+ long i;
+ unsigned long sp;
+ unsigned int * pc;
+
+ printk("%s(%d): %s %ld\n", current->comm, current->pid, str, err);
+ sp = (unsigned long) (regs+1);
+ if (regs->ps & 8)
+ sp = rdusp();
+ printk("pc = %lx ps = %04lx\n", regs->pc, regs->ps);
+ printk("rp = %lx sp = %lx\n", regs->r26, sp);
+ printk("r0=%lx r1=%lx r2=%lx r3=%lx\n",
+ regs->r0, regs->r1, regs->r2, regs->r3);
+ printk("r8=%lx\n", regs->r8);
+ printk("r16=%lx r17=%lx r18=%lx r19=%lx\n",
+ regs->r16, regs->r17, regs->r18, regs->r19);
+ printk("r20=%lx r21=%lx r22=%lx r23=%lx\n",
+ regs->r20, regs->r21, regs->r22, regs->r23);
+ printk("r24=%lx r25=%lx r26=%lx r27=%lx\n",
+ regs->r24, regs->r25, regs->r26, regs->r27);
+ printk("r28=%lx r29=%lx r30=%lx\n",
+ regs->r28, regs->gp, sp);
+ if (regs->ps & 8)
+ return;
+ printk("Code:");
+ pc = (unsigned int *) regs->pc;
+ for (i = -3; i < 6; i++)
+ printk("%c%08x%c",i?' ':'<',pc[i],i?' ':'>');
+ printk("\n");
+ for (i = 0 ; i < 5000000000 ; i++)
+ /* pause */;
+ halt();
+}
+
+asmlinkage void do_entArith(unsigned long summary, unsigned long write_mask,
+ unsigned long a2, unsigned long a3, unsigned long a4, unsigned long a5,
+ struct pt_regs regs)
+{
+ printk("Arithmetic trap: %02lx %016lx\n", summary, write_mask);
+ die_if_kernel("Arithmetic fault", &regs, 0);
+}
+
+asmlinkage void do_entIF(unsigned long type, unsigned long a1, unsigned long a2,
+ unsigned long a3, unsigned long a4, unsigned long a5,
+ struct pt_regs regs)
+{
+ die_if_kernel("Instruction fault", &regs, type);
+}
+
+/*
+ * entUna has a different register layout to be reasonably simple. It
+ * needs access to all the integer registers (the kernel doesn't use
+ * fp-regs), and it needs to have them in order for simpler access.
+ *
+ * Due to the non-standard register layout (and because we don't want
+ * to handle floating-point regs), we disallow user-mode unaligned
+ * accesses (we'd need to do "verify_area()" checking, as well as
+ * do a full "ret_from_sys_call" return).
+ *
+ * Oh, btw, we don't handle the "gp" register correctly, but if we fault
+ * on a gp-register unaligned load/store, something is _very_ wrong
+ * in the kernel anyway..
+ */
+struct allregs {
+ unsigned long regs[32];
+ unsigned long ps, pc, gp, a0, a1, a2;
+};
+
+asmlinkage void do_entUna(void * va, unsigned long opcode, unsigned long reg,
+ unsigned long a3, unsigned long a4, unsigned long a5,
+ struct allregs regs)
+{
+ static int cnt = 0;
+
+ if (regs.ps & 8)
+ do_exit(SIGSEGV);
+ if (++cnt < 5)
+ printk("Unaligned trap at %016lx: %p %lx %ld\n",
+ regs.pc, va, opcode, reg);
+ /* $16-$18 are PAL-saved, and are offset by 19 entries */
+ if (reg >= 16 && reg <= 18)
+ reg += 19;
+ switch (opcode) {
+ case 0x28: /* ldl */
+ *(reg+regs.regs) = (int) ldl_u(va);
+ return;
+ case 0x29: /* ldq */
+ *(reg+regs.regs) = ldq_u(va);
+ return;
+ case 0x2c: /* stl */
+ stl_u(*(reg+regs.regs), va);
+ return;
+ case 0x2d: /* stq */
+ stq_u(*(reg+regs.regs), va);
+ return;
+ }
+ printk("Bad unaligned kernel access at %016lx: %p %lx %ld\n",
+ regs.pc, va, opcode, reg);
+ do_exit(SIGSEGV);
+}
+
+/*
+ * DEC means people to use the "retsys" instruction for return from
+ * a system call, but they are clearly misguided about this. We use
+ * "rti" in all cases, and fill in the stack with the return values.
+ * That should make signal handling etc much cleaner.
+ *
+ * Even more horribly, DEC doesn't allow system calls from kernel mode.
+ * "Security" features letting the user do something the kernel can't
+ * are a thinko. DEC palcode is strange. The PAL-code designers probably
+ * got terminally tainted by VMS at some point.
+ */
+asmlinkage long do_entSys(unsigned long a0, unsigned long a1, unsigned long a2,
+ unsigned long a3, unsigned long a4, unsigned long a5, struct pt_regs regs)
+{
+ printk("<sc %ld(%lx,%lx,%lx)>", regs.r0, a0, a1, a2);
+ return -1;
+}
+
+extern asmlinkage void entMM(void);
+extern asmlinkage void entIF(void);
+extern asmlinkage void entArith(void);
+extern asmlinkage void entUna(void);
+extern asmlinkage void entSys(void);
+
+void trap_init(void)
+{
+ unsigned long gptr;
+
+ /*
+ * Tell PAL-code what global pointer we want in the kernel..
+ */
+ __asm__("br %0,___tmp\n"
+ "___tmp:\tldgp %0,0(%0)"
+ : "=r" (gptr));
+ wrkgp(gptr);
+
+ wrent(entArith, 1);
+ wrent(entMM, 2);
+ wrent(entIF, 3);
+ wrent(entUna, 4);
+ wrent(entSys, 5);
+}