summaryrefslogtreecommitdiffstats
path: root/arch/m68k/kernel
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1998-03-17 22:05:47 +0000
committerRalf Baechle <ralf@linux-mips.org>1998-03-17 22:05:47 +0000
commit27cfca1ec98e91261b1a5355d10a8996464b63af (patch)
tree8e895a53e372fa682b4c0a585b9377d67ed70d0e /arch/m68k/kernel
parent6a76fb7214c477ccf6582bd79c5b4ccc4f9c41b1 (diff)
Look Ma' what I found on my harddisk ...
o New faster syscalls for 2.1.x, too o Upgrade to 2.1.89. Don't try to run this. It's flaky as hell. But feel free to debug ...
Diffstat (limited to 'arch/m68k/kernel')
-rw-r--r--arch/m68k/kernel/Makefile17
-rw-r--r--arch/m68k/kernel/bios32.c580
-rw-r--r--arch/m68k/kernel/console.c2748
-rw-r--r--arch/m68k/kernel/entry.S86
-rw-r--r--arch/m68k/kernel/head.S150
-rw-r--r--arch/m68k/kernel/ints.c6
-rw-r--r--arch/m68k/kernel/m68k_defs.c23
-rw-r--r--arch/m68k/kernel/m68k_ksyms.c7
-rw-r--r--arch/m68k/kernel/process.c26
-rw-r--r--arch/m68k/kernel/ptrace.c68
-rw-r--r--arch/m68k/kernel/setup.c90
-rw-r--r--arch/m68k/kernel/signal.c971
-rw-r--r--arch/m68k/kernel/sys_m68k.c26
-rw-r--r--arch/m68k/kernel/time.c27
-rw-r--r--arch/m68k/kernel/traps.c155
15 files changed, 1783 insertions, 3197 deletions
diff --git a/arch/m68k/kernel/Makefile b/arch/m68k/kernel/Makefile
index a4fc10ab0..977120c1e 100644
--- a/arch/m68k/kernel/Makefile
+++ b/arch/m68k/kernel/Makefile
@@ -10,19 +10,26 @@
.S.o:
$(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o
-all: kernel.o head.o
+all: head.o kernel.o
O_TARGET := kernel.o
O_OBJS := entry.o process.o traps.o ints.o signal.o ptrace.o \
setup.o sys_m68k.o time.o
-ifdef CONFIG_VT
-O_OBJS += console.o
-endif
OX_OBJS := m68k_ksyms.o
ifdef CONFIG_KGDB
O_OBJS += kgdb.o
endif
-head.o: head.S
+ifdef CONFIG_PCI
+O_OBJS += bios32.o
+endif
+
+head.o: head.S m68k_defs.h
+
+m68k_defs.h: m68k_defs.c m68k_defs.head $(TOPDIR)/include/linux/sched.h
+ $(CC) ${CFLAGS} -S m68k_defs.c
+ cp m68k_defs.head m68k_defs.h
+ sed -n < m68k_defs.s >> m68k_defs.h '/^#define/s/ #/ /p'
+ rm m68k_defs.s
include $(TOPDIR)/Rules.make
diff --git a/arch/m68k/kernel/bios32.c b/arch/m68k/kernel/bios32.c
new file mode 100644
index 000000000..a1dc77f33
--- /dev/null
+++ b/arch/m68k/kernel/bios32.c
@@ -0,0 +1,580 @@
+/*
+ * bios32.c - PCI BIOS functions for Alpha systems not using BIOS
+ * emulation code.
+ *
+ * Written by Wout Klaren.
+ *
+ * Based on the DEC Alpha bios32.c by Dave Rusling and David Mosberger.
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+
+#if 0
+# define DBG_DEVS(args) printk args
+#else
+# define DBG_DEVS(args)
+#endif
+
+#ifdef CONFIG_PCI
+
+/*
+ * PCI support for Linux/m68k. Currently only the Hades is supported.
+ *
+ * Notes:
+ *
+ * 1. The PCI memory area starts at address 0x80000000 and the
+ * I/O area starts at 0xB0000000. Therefore these offsets
+ * are added to the base addresses when they are read and
+ * substracted when they are written.
+ *
+ * 2. The support for PCI bridges in the DEC Alpha version has
+ * been removed in this version.
+ */
+
+#include <linux/bios32.h>
+#include <linux/pci.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+
+#include <asm/atarihw.h>
+#include <asm/atariints.h>
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+#define KB 1024
+#define MB (1024*KB)
+#define GB (1024*MB)
+
+#define MAJOR_REV 0
+#define MINOR_REV 0
+
+/*
+ * Base addresses of the PCI memory and I/O areas on the Hades.
+ */
+
+static unsigned long pci_mem_base = 0;
+static unsigned long pci_io_base = 0;
+
+/*
+ * Align VAL to ALIGN, which must be a power of two.
+ */
+
+#define ALIGN(val,align) (((val) + ((align) - 1)) & ~((align) - 1))
+
+/*
+ * Calculate the address of the PCI configuration area of the given
+ * device.
+ *
+ * BUG: boards with multiple functions are probably not correctly
+ * supported.
+ */
+
+static int mk_conf_addr(unsigned char bus, unsigned char device_fn,
+ unsigned char where, unsigned long *pci_addr)
+{
+ static const unsigned long pci_conf_base[] = { 0xA0080000, 0xA0040000,
+ 0xA0020000, 0xA0010000 };
+ int device = device_fn >> 3;
+
+ DBG_DEVS(("mk_conf_addr(bus=%d ,device_fn=0x%x, where=0x%x, pci_addr=0x%p)\n",
+ bus, device_fn, where, pci_addr));
+
+ if (device > 3) {
+ DBG_DEVS(("mk_conf_addr: device (%d) > 3, returning -1\n", device));
+ return -1;
+ }
+
+ *pci_addr = pci_conf_base[device] | (where);
+ DBG_DEVS(("mk_conf_addr: returning pci_addr 0x%lx\n", *pci_addr));
+ return 0;
+}
+
+int pcibios_read_config_byte(unsigned char bus, unsigned char device_fn,
+ unsigned char where, unsigned char *value)
+{
+ unsigned long pci_addr;
+
+ *value = 0xff;
+
+ if (mk_conf_addr(bus, device_fn, where, &pci_addr) < 0)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ *value = *((unsigned char *)pci_addr);
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int pcibios_read_config_word(unsigned char bus, unsigned char device_fn,
+ unsigned char where, unsigned short *value)
+{
+ unsigned long pci_addr;
+
+ *value = 0xffff;
+
+ if (where & 0x1)
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ if (mk_conf_addr(bus, device_fn, where, &pci_addr))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ *value = le16_to_cpu(*((unsigned short *)pci_addr));
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int pcibios_read_config_dword(unsigned char bus, unsigned char device_fn,
+ unsigned char where, unsigned int *value)
+{
+ unsigned long pci_addr;
+
+ *value = 0xffffffff;
+
+ if (where & 0x3)
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ if (mk_conf_addr(bus, device_fn, where, &pci_addr))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ *value = le32_to_cpu(*((unsigned int *)pci_addr));
+
+ if ((where >= PCI_BASE_ADDRESS_0) && (where <= PCI_BASE_ADDRESS_5))
+ {
+ if ((*value & PCI_BASE_ADDRESS_SPACE) ==
+ PCI_BASE_ADDRESS_SPACE_IO)
+ *value += pci_io_base;
+ else
+ {
+ if (*value == 0)
+ {
+ /*
+ * Base address is 0. Test if this base
+ * address register is used.
+ */
+
+ *((unsigned long *)pci_addr) = 0xffffffff;
+ if (*((unsigned long *)pci_addr) != 0)
+ *value += pci_mem_base;
+ }
+ else
+ *value += pci_mem_base;
+ }
+ }
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int pcibios_write_config_byte(unsigned char bus, unsigned char device_fn,
+ unsigned char where, unsigned char value)
+{
+ unsigned long pci_addr;
+
+ if (mk_conf_addr(bus, device_fn, where, &pci_addr) < 0)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ *((unsigned char *)pci_addr) = value;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int pcibios_write_config_word(unsigned char bus, unsigned char device_fn,
+ unsigned char where, unsigned short value)
+{
+ unsigned long pci_addr;
+
+ if (mk_conf_addr(bus, device_fn, where, &pci_addr) < 0)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ *((unsigned short *)pci_addr) = cpu_to_le16(value);
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int pcibios_write_config_dword(unsigned char bus, unsigned char device_fn,
+ unsigned char where, unsigned int value)
+{
+ unsigned long pci_addr;
+
+ if (mk_conf_addr(bus, device_fn, where, &pci_addr) < 0)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ if ((where >= PCI_BASE_ADDRESS_0) && (where <= PCI_BASE_ADDRESS_5))
+ {
+ if ((value & PCI_BASE_ADDRESS_SPACE) ==
+ PCI_BASE_ADDRESS_SPACE_IO)
+ value -= pci_io_base;
+ else
+ value -= pci_mem_base;
+ }
+
+ *((unsigned int *)pci_addr) = cpu_to_le32(value);
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+/*
+ * Macro to enable programming of the PCI devices. On the Hades this
+ * define should be true, because the Hades has no PCI BIOS.
+ */
+
+#define PCI_MODIFY 1
+
+#if PCI_MODIFY
+
+/*
+ * Leave some room for a VGA card. We assume that the VGA card is
+ * always in the first 32M of PCI memory. For the time being we do
+ * not program the VGA card, because to make this work we also
+ * need to change the frame buffer device.
+ */
+
+#define FIRST_IO_ADDR 0x10000
+#define FIRST_MEM_ADDR 0x02000000
+
+static unsigned int io_base = FIRST_IO_ADDR; /* Skip first 64K. */
+static unsigned int mem_base = FIRST_MEM_ADDR; /* Skip first 32M. */
+
+/*
+ * Disable PCI device DEV so that it does not respond to I/O or memory
+ * accesses.
+ */
+
+__initfunc(static void disable_dev(struct pci_dev *dev))
+{
+ struct pci_bus *bus;
+ unsigned short cmd;
+
+ if (dev->class >> 8 == PCI_CLASS_NOT_DEFINED_VGA ||
+ dev->class >> 8 == PCI_CLASS_DISPLAY_VGA ||
+ dev->class >> 8 == PCI_CLASS_DISPLAY_XGA)
+ return;
+
+ bus = dev->bus;
+ pcibios_read_config_word(bus->number, dev->devfn, PCI_COMMAND, &cmd);
+
+ cmd &= (~PCI_COMMAND_IO & ~PCI_COMMAND_MEMORY & ~PCI_COMMAND_MASTER);
+ pcibios_write_config_word(bus->number, dev->devfn, PCI_COMMAND, cmd);
+}
+
+/*
+ * Layout memory and I/O for a device:
+ */
+
+#define MAX(val1, val2) ( ((val1) > (val2)) ? val1 : val2)
+
+__initfunc(static void layout_dev(struct pci_dev *dev))
+{
+ struct pci_bus *bus;
+ unsigned short cmd;
+ unsigned int base, mask, size, reg;
+ unsigned int alignto;
+
+ /*
+ * Skip video cards for the time being.
+ */
+
+ if (dev->class >> 8 == PCI_CLASS_NOT_DEFINED_VGA ||
+ dev->class >> 8 == PCI_CLASS_DISPLAY_VGA ||
+ dev->class >> 8 == PCI_CLASS_DISPLAY_XGA)
+ return;
+
+ 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)
+ {
+ /* this base-address register is unused */
+ continue;
+ }
+
+ /*
+ * 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;
+ /* align to multiple of size of minimum base */
+ alignto = MAX(0x400, size) ;
+ base = ALIGN(io_base, alignto);
+ io_base = base + size;
+ pcibios_write_config_dword(bus->number, dev->devfn,
+ reg, base | 0x1);
+ DBG_DEVS(("layout_dev: IO address: %lX\n", base));
+ }
+ 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:
+ 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;
+ }
+
+ /*
+ * Align to multiple of size of minimum base
+ */
+
+ alignto = MAX(0x1000, size) ;
+ base = ALIGN(mem_base, alignto);
+ mem_base = base + size;
+ pcibios_write_config_dword(bus->number, dev->devfn,
+ reg, base);
+ }
+ }
+
+ /*
+ * Enable device:
+ */
+
+ if (dev->class >> 8 == PCI_CLASS_NOT_DEFINED ||
+ dev->class >> 8 == PCI_CLASS_NOT_DEFINED_VGA ||
+ dev->class >> 8 == PCI_CLASS_DISPLAY_VGA ||
+ dev->class >> 8 == PCI_CLASS_DISPLAY_XGA)
+ {
+ /*
+ * All of these (may) have I/O scattered all around
+ * and may not use i/o-base address registers at all.
+ * So we just have to always enable I/O to these
+ * devices.
+ */
+ cmd |= PCI_COMMAND_IO;
+ }
+
+ pcibios_write_config_word(bus->number, dev->devfn, PCI_COMMAND,
+ cmd | PCI_COMMAND_MASTER);
+ DBG_DEVS(("layout_dev: bus %d slot 0x%x VID 0x%x DID 0x%x class 0x%x\n",
+ bus->number, PCI_SLOT(dev->devfn), dev->vendor, dev->device, dev->class));
+}
+
+__initfunc(static void layout_bus(struct pci_bus *bus))
+{
+ struct pci_dev *dev;
+
+ DBG_DEVS(("layout_bus: starting bus %d\n", bus->number));
+
+ if (!bus->devices && !bus->children)
+ return;
+
+ /*
+ * Align the current bases on appropriate boundaries (4K for
+ * IO and 1MB for memory).
+ */
+
+ io_base = ALIGN(io_base, 4*KB);
+ mem_base = ALIGN(mem_base, 1*MB);
+
+ /*
+ * PCI devices might have been setup by a PCI BIOS emulation
+ * running under TOS. In these cases there is a
+ * window during which two devices may have an overlapping
+ * address range. To avoid this causing trouble, we first
+ * turn off the I/O and memory address decoders for all PCI
+ * devices. They'll be re-enabled only once all address
+ * decoders are programmed consistently.
+ */
+
+ for (dev = bus->devices; dev; dev = dev->sibling)
+ {
+ if (dev->class >> 16 != PCI_BASE_CLASS_BRIDGE)
+ disable_dev(dev);
+ }
+
+ /*
+ * Allocate space to each device:
+ */
+
+ DBG_DEVS(("layout_bus: starting bus %d devices\n", bus->number));
+
+ for (dev = bus->devices; dev; dev = dev->sibling)
+ {
+ if (dev->class >> 16 != PCI_BASE_CLASS_BRIDGE)
+ layout_dev(dev);
+ }
+}
+
+#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 curr = 0;
+ struct pci_dev *dev;
+
+ for (dev = pci_devices; dev; dev = dev->next)
+ {
+ if (dev->vendor == vendor && dev->device == device_id)
+ {
+ if (curr == index)
+ {
+ *devfn = dev->devfn;
+ *bus = dev->bus->number;
+ return PCIBIOS_SUCCESSFUL;
+ }
+ ++curr;
+ }
+ }
+ 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 curr = 0;
+ struct pci_dev *dev;
+
+ for (dev = pci_devices; dev; dev = dev->next)
+ {
+ if (dev->class == class_code)
+ {
+ if (curr == index)
+ {
+ *devfn = dev->devfn;
+ *bus = dev->bus->number;
+ return PCIBIOS_SUCCESSFUL;
+ }
+ ++curr;
+ }
+ }
+ return PCIBIOS_DEVICE_NOT_FOUND;
+}
+
+int pcibios_present(void)
+{
+ if (MACH_IS_HADES)
+ return 1;
+ else
+ return 0;
+}
+
+__initfunc(unsigned long pcibios_init(unsigned long mem_start,
+ unsigned long mem_end))
+{
+ printk("Linux/m68k PCI BIOS32 revision %x.%02x\n", MAJOR_REV, MINOR_REV);
+
+#if !PCI_MODIFY
+ printk("...NOT modifying existing PCI configuration\n");
+#endif
+
+ return mem_start;
+}
+
+/*
+ * static inline void hades_fixup(void)
+ *
+ * Assign IRQ numbers as used by Linux to the interrupt pins
+ * of the PCI cards.
+ */
+
+__initfunc(static inline void hades_fixup(void))
+{
+ char irq_tab[4] = {
+ IRQ_TT_MFP_IO0, /* Slot 0. */
+ IRQ_TT_MFP_IO1, /* Slot 1. */
+ IRQ_TT_MFP_SCC, /* Slot 2. */
+ IRQ_TT_MFP_SCSIDMA /* Slot 3. */
+ };
+ struct pci_dev *dev;
+ unsigned char slot;
+
+ /*
+ * Go through all devices, fixing up irqs as we see fit:
+ */
+
+ for (dev = pci_devices; dev; dev = dev->next)
+ {
+ if (dev->class >> 16 != PCI_BASE_CLASS_BRIDGE)
+ {
+ slot = PCI_SLOT(dev->devfn); /* Determine slot number. */
+ dev->irq = irq_tab[slot];
+#if PCI_MODIFY
+ pcibios_write_config_byte(dev->bus->number, dev->devfn,
+ PCI_INTERRUPT_LINE, dev->irq);
+#endif
+ }
+ }
+}
+
+__initfunc(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
+
+ pci_mem_base = 0x80000000;
+ pci_io_base = 0xB0000000;
+
+ /*
+ * Now is the time to do all those dirty little deeds...
+ */
+
+ hades_fixup();
+
+ return mem_start;
+}
+#endif /* CONFIG_PCI */
diff --git a/arch/m68k/kernel/console.c b/arch/m68k/kernel/console.c
deleted file mode 100644
index 5e7b29717..000000000
--- a/arch/m68k/kernel/console.c
+++ /dev/null
@@ -1,2748 +0,0 @@
-/*
- * linux/drivers/char/console.c
- *
- * Copyright (C) 1991, 1992 Linus Torvalds
- */
-/*
- * console.c
- *
- * This module exports the console io functions:
- *
- * 'void do_keyboard_interrupt(void)'
- *
- * 'int vc_allocate(unsigned int console)'
- * 'int vc_cons_allocated(unsigned int console)'
- * 'int vc_resize(unsigned long lines, unsigned long cols)'
- * 'int vc_resize_con(unsigned long lines, unsigned long cols,
- * unsigned int currcons)'
- * 'void vc_disallocate(unsigned int currcons)'
- *
- * 'unsigned long con_init(unsigned long)'
- * 'int con_open(struct tty_struct *tty, struct file * filp)'
- * 'void con_write(struct tty_struct * tty)'
- * 'void vt_console_print(const char * b)'
- * 'void update_screen(int new_console)'
- *
- * 'void do_blank_screen(int)'
- * 'void do_unblank_screen(void)'
- * 'void poke_blanked_console(void)'
- *
- * 'unsigned short *screen_pos(int currcons, int w_offset, int viewed)'
- * 'void complement_pos(int currcons, int offset)'
- * 'void invert_screen(int currcons, int offset, int count, int shift)'
- *
- * 'void scrollback(int lines)'
- * 'void scrollfront(int lines)'
- *
- * 'int con_get_font(char *)'
- * 'int con_set_font(char *)'
- *
- * 'void mouse_report(struct tty_struct * tty, int butt, int mrx, int mry)'
- * 'int mouse_reporting(void)'
- *
- * 'unsigned long get_video_num_lines(unsigned int console)'
- * 'unsigned long get_video_num_columns(unsigned int console)'
- * 'unsigned long get_video_size_row(unsigned int console)'
- *
- * Hopefully this will be a rather complete VT102 implementation.
- *
- * Beeping thanks to John T Kohl.
- *
- * Virtual Consoles, Screen Blanking, Screen Dumping, Color, Graphics
- * Chars, and VT100 enhancements by Peter MacDonald.
- *
- * Copy and paste function by Andrew Haylett,
- * some enhancements by Alessandro Rubini.
- *
- * User definable mapping table and font loading by Eugene G. Crosser,
- * <crosser@pccross.msk.su>
- *
- * Code to check for different video-cards mostly by Galen Hunt,
- * <g-hunt@ee.utah.edu>
- *
- * Rudimentary ISO 10646/Unicode/UTF-8 character set support by
- * Markus Kuhn, <mskuhn@immd4.informatik.uni-erlangen.de>.
- *
- * Dynamic allocation of consoles, aeb@cwi.nl, May 1994
- * Resizing of consoles, aeb, 940926
- *
- * Code for xterm like mouse click reporting by Peter Orbaek 20-Jul-94
- * <poe@daimi.aau.dk>
- *
- * 680x0 LINUX support by Arno Griffioen (arno@usn.nl)
- *
- * 9-Apr-94: Arno Griffioen: fixed scrolling and delete-char bug.
- * Scrolling code moved to amicon.c
- *
- * 18-Apr-94: David Carter [carter@cs.bris.ac.uk]. 680x0 LINUX modified
- * Integrated support for new low level driver `amicon_ocs.c'
- *
- */
-
-#define BLANK 0x0020
-#define CAN_LOAD_EGA_FONTS /* undefine if the user must not do this */
-
-/* A bitmap for codes <32. A bit of 1 indicates that the code
- * corresponding to that bit number invokes some special action
- * (such as cursor movement) and should not be displayed as a
- * glyph unless the disp_ctrl mode is explicitly enabled.
- */
-#define CTRL_ACTION 0x0d00ff81
-#define CTRL_ALWAYS 0x0800f501 /* Cannot be overridden by disp_ctrl */
-
-/*
- * Here is the default bell parameters: 750HZ, 1/8th of a second
- */
-#define DEFAULT_BELL_PITCH 750
-#define DEFAULT_BELL_DURATION (HZ/8)
-
-/*
- * NOTE!!! We sometimes disable and enable interrupts for a short while
- * (to put a word in video IO), but this will work even for keyboard
- * interrupts. We know interrupts aren't enabled when getting a keyboard
- * interrupt, as we use trap-gates. Hopefully all is well.
- */
-
-#include <linux/config.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/console.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/console.h>
-#include <linux/kd.h>
-#include <linux/malloc.h>
-#include <linux/major.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <asm/bitops.h>
-
-#include <linux/kbd_kern.h>
-#include <linux/vt_kern.h>
-#include <linux/consolemap.h>
-#include <linux/selection.h>
-#include <linux/console_struct.h>
-
-
-#ifndef MIN
-#define MIN(a,b) ((a) < (b) ? (a) : (b))
-#endif
-
-struct tty_driver console_driver;
-static int console_refcount;
-static struct tty_struct *console_table[MAX_NR_CONSOLES];
-static struct termios *console_termios[MAX_NR_CONSOLES];
-static struct termios *console_termios_locked[MAX_NR_CONSOLES];
-
-static void vc_init(unsigned int console, int do_clear);
-
-static void update_attr(int currcons);
-static void gotoxy(int currcons, int new_x, int new_y);
-static void save_cur(int currcons);
-static void blank_screen(void);
-static void unblank_screen(void);
-static int con_open(struct tty_struct *, struct file *);
-extern void change_console(unsigned int);
-static inline void set_cursor(int currcons);
-static void reset_terminal(int currcons, int do_clear);
-extern void reset_vc(unsigned int new_console);
-extern void vt_init(void);
-static void set_vesa_blanking(unsigned long arg);
-extern void vesa_blank(void);
-extern void vesa_unblank(void);
-extern void compute_shiftstate(void);
-extern void reset_palette(int currcons);
-extern void set_palette(void);
-void poke_blanked_console(void);
-void do_blank_screen(int);
-
-#if 0
-/* Make sure there are no references left to this variables. */
-unsigned long video_num_lines;
-unsigned long video_num_columns;
-unsigned long video_size_row;
-#endif
-
-static int printable = 0; /* Is console ready for printing? */
-unsigned long video_font_height; /* Height of current screen font */
-unsigned long video_scan_lines; /* Number of scan lines on screen */
-unsigned long default_font_height; /* Height of default screen font */
-int video_mode_512ch = 0; /* 512-character mode */
-static unsigned short console_charmask = 0x0ff;
-
-static unsigned short *vc_scrbuf[MAX_NR_CONSOLES];
-struct vc vc_cons [MAX_NR_CONSOLES];
-
-/* used by kbd_bh - set by keyboard_interrupt */
- int do_poke_blanked_console = 0;
- int console_blanked = 0;
-static int blankinterval = 10*60*HZ;
-static int vesa_off_interval = 0;
-static int vesa_blank_mode = 0; /* 0:none 1:suspendV 2:suspendH 3:powerdown */
-
-/*
- * fg_console is the current virtual console,
- * last_console is the last used one,
- * want_console is the console we want to switch to,
- * kmsg_redirect is the console for kernel messages,
- */
-int fg_console = 0;
-int last_console = 0;
-int want_console = -1;
-int kmsg_redirect = 0;
-
-struct consw *conswitchp;
-
-#define cols (vc_cons[currcons].d->vc_cols)
-#define rows (vc_cons[currcons].d->vc_rows)
-#define size_row (vc_cons[currcons].d->vc_size_row)
-#define screenbuf_size (vc_cons[currcons].d->vc_screenbuf_size)
-#define cons_num (vc_cons[currcons].d->vc_num)
-#define origin (vc_cons[currcons].d->vc_origin)
-#define scr_end (vc_cons[currcons].d->vc_scr_end)
-#define pos (vc_cons[currcons].d->vc_pos)
-#define top (vc_cons[currcons].d->vc_top)
-#define bottom (vc_cons[currcons].d->vc_bottom)
-#define x (vc_cons[currcons].d->vc_x)
-#define y (vc_cons[currcons].d->vc_y)
-#define vc_state (vc_cons[currcons].d->vc_state)
-#define npar (vc_cons[currcons].d->vc_npar)
-#define par (vc_cons[currcons].d->vc_par)
-#define ques (vc_cons[currcons].d->vc_ques)
-#define attr (vc_cons[currcons].d->vc_attr)
-#define saved_x (vc_cons[currcons].d->vc_saved_x)
-#define saved_y (vc_cons[currcons].d->vc_saved_y)
-#define translate (vc_cons[currcons].d->vc_translate)
-#define G0_charset (vc_cons[currcons].d->vc_G0_charset)
-#define G1_charset (vc_cons[currcons].d->vc_G1_charset)
-#define saved_G0 (vc_cons[currcons].d->vc_saved_G0)
-#define saved_G1 (vc_cons[currcons].d->vc_saved_G1)
-#define utf (vc_cons[currcons].d->vc_utf)
-#define utf_count (vc_cons[currcons].d->vc_utf_count)
-#define utf_char (vc_cons[currcons].d->vc_utf_char)
-#define video_mem_start (vc_cons[currcons].d->vc_video_mem_start)
-#define video_mem_end (vc_cons[currcons].d->vc_video_mem_end)
-#define video_erase_char (vc_cons[currcons].d->vc_video_erase_char)
-#define disp_ctrl (vc_cons[currcons].d->vc_disp_ctrl)
-#define toggle_meta (vc_cons[currcons].d->vc_toggle_meta)
-#define decscnm (vc_cons[currcons].d->vc_decscnm)
-#define decom (vc_cons[currcons].d->vc_decom)
-#define decawm (vc_cons[currcons].d->vc_decawm)
-#define deccm (vc_cons[currcons].d->vc_deccm)
-#define decim (vc_cons[currcons].d->vc_decim)
-#define deccolm (vc_cons[currcons].d->vc_deccolm)
-#define need_wrap (vc_cons[currcons].d->vc_need_wrap)
-#define has_scrolled (vc_cons[currcons].d->vc_has_scrolled)
-#define kmalloced (vc_cons[currcons].d->vc_kmalloced)
-#define report_mouse (vc_cons[currcons].d->vc_report_mouse)
-#define can_do_color (vc_cons[currcons].d->vc_can_do_color)
-#define color (vc_cons[currcons].d->vc_color)
-#define s_color (vc_cons[currcons].d->vc_s_color)
-#define def_color (vc_cons[currcons].d->vc_def_color)
-#define foreground (color & 0x0f)
-#define background (color & 0xf0)
-#define charset (vc_cons[currcons].d->vc_charset)
-#define s_charset (vc_cons[currcons].d->vc_s_charset)
-#define intensity (vc_cons[currcons].d->vc_intensity)
-#define underline (vc_cons[currcons].d->vc_underline)
-#define blink (vc_cons[currcons].d->vc_blink)
-#define reverse (vc_cons[currcons].d->vc_reverse)
-#define s_intensity (vc_cons[currcons].d->vc_s_intensity)
-#define s_underline (vc_cons[currcons].d->vc_s_underline)
-#define s_blink (vc_cons[currcons].d->vc_s_blink)
-#define s_reverse (vc_cons[currcons].d->vc_s_reverse)
-#define ulcolor (vc_cons[currcons].d->vc_ulcolor)
-#define halfcolor (vc_cons[currcons].d->vc_halfcolor)
-#define tab_stop (vc_cons[currcons].d->vc_tab_stop)
-#define palette (vc_cons[currcons].d->vc_palette)
-#define bell_pitch (vc_cons[currcons].d->vc_bell_pitch)
-#define bell_duration (vc_cons[currcons].d->vc_bell_duration)
-#define sw (vc_cons[currcons].d->vc_sw)
-
-#define vcmode (vt_cons[currcons]->vc_mode)
-#if 0 /* XXX */
-#define vtmode (vt_cons[currcons]->vt_mode)
-#define vtpid (vt_cons[currcons]->vt_pid)
-#define vtnewvt (vt_cons[currcons]->vt_newvt)
-#endif
-
-int vc_cons_allocated(unsigned int i)
-{
- return (i < MAX_NR_CONSOLES && vc_cons[i].d);
-}
-
-int vc_allocate(unsigned int currcons) /* return 0 on success */
-{
- if (currcons >= MAX_NR_CONSOLES)
- return -ENODEV;
- if (!vc_cons[currcons].d) {
- long p, q;
-
- /* prevent users from taking too much memory */
- if (currcons >= MAX_NR_USER_CONSOLES && !suser())
- return -EPERM;
-
- /* due to the granularity of kmalloc, we waste some memory here */
- /* the alloc is done in two steps, to optimize the common situation
- of a 25x80 console (structsize=216, screenbuf_size=4000) */
- p = (long) kmalloc(structsize, GFP_KERNEL);
- if (!p)
- return -ENOMEM;
- vc_cons[currcons].d = (struct vc_data *) p;
- vt_cons[currcons] = (struct vt_struct *)(p+sizeof(struct vc_data));
-
- /* ++Geert: sw->con_init determines console size */
- sw = conswitchp;
- cons_num = currcons;
- sw->con_init (vc_cons[currcons].d);
- size_row = cols<<1;
- screenbuf_size = rows*size_row;
-
- q = (long) kmalloc(screenbuf_size, GFP_KERNEL);
- if (!q) {
- kfree_s((char *) p, structsize);
- vc_cons[currcons].d = NULL;
- return -ENOMEM;
- }
- vc_scrbuf[currcons] = (unsigned short *) q;
- kmalloced = 1;
- vc_init (currcons, 1);
- }
- return 0;
-}
-
-/*
- * Change # of rows and columns (0 means the size of fg_console)
- * [this is to be used together with some user program
- * like resize that changes the hardware videomode]
- */
-int vc_resize(unsigned long lines, unsigned long columns)
-{
- unsigned long cc, ll, ss, sr;
- unsigned long occ, oll, oss, osr;
- unsigned short *p;
- unsigned int currcons = fg_console, i;
- unsigned short *newscreens[MAX_NR_CONSOLES];
- long ol, nl, rlth, rrem;
-
- cc = (columns ? columns : cols);
- ll = (lines ? lines : rows);
- sr = cc << 1;
- ss = sr * ll;
-
- /*
- * Some earlier version had all consoles of potentially
- * different sizes, but that was really messy.
- * So now we only change if there is room for all consoles
- * of the same size.
- */
- for (currcons = 0; currcons < MAX_NR_CONSOLES; currcons++) {
- if (!vc_cons_allocated(currcons))
- newscreens[currcons] = 0;
- else {
- p = (unsigned short *) kmalloc(ss, GFP_USER);
- if (!p) {
- for (i = 0; i< currcons; i++)
- if (newscreens[i])
- kfree_s(newscreens[i], ss);
- return -ENOMEM;
- }
- newscreens[currcons] = p;
- }
- }
-
-#if 0 /* XXX */
- get_scrmem(fg_console);
-#endif
-
- for (currcons = 0; currcons < MAX_NR_CONSOLES; currcons++) {
- if (!vc_cons_allocated(currcons))
- continue;
-
- oll = rows;
- occ = cols;
- osr = size_row;
- oss = screenbuf_size;
-
- rows = ll;
- cols = cc;
- size_row = sr;
- screenbuf_size = ss;
-
- rlth = MIN(osr, sr);
- rrem = sr - rlth;
- ol = origin;
- nl = (long) newscreens[currcons];
- if (ll < oll)
- ol += (oll - ll) * osr;
-
- update_attr(currcons);
- while (ol < scr_end) {
- /* ++Geert: TODO: Because the attributes have different meanings
- on monochrome and color, they should really be converted if
- can_do_color changes... */
- memcpyw((unsigned short *) nl, (unsigned short *) ol, rlth);
- if (rrem)
- memsetw((void *)(nl + rlth), video_erase_char, rrem);
- ol += osr;
- nl += sr;
- }
-
- if (kmalloced)
- kfree_s(vc_scrbuf[currcons], oss);
- vc_scrbuf[currcons] = newscreens[currcons];
- kmalloced = 1;
- screenbuf_size = ss;
-
- origin = (long) video_mem_start = vc_scrbuf[currcons];
- scr_end = video_mem_end = ((long) video_mem_start) + ss;
-
- if (scr_end > nl)
- memsetw((void *) nl, video_erase_char, scr_end - nl);
-
- /* do part of a reset_terminal() */
- top = 0;
- bottom = rows;
- gotoxy(currcons, x, y);
- save_cur(currcons);
- }
-
-#if 0 /* XXX */
- set_scrmem(fg_console, 0);
- set_origin(fg_console);
-#endif /* XXX */
- /* don't update in graphics mode */
- if (currcons == fg_console && vt_cons[fg_console]->vc_mode == KD_TEXT)
- update_screen(fg_console);
-
- set_cursor(fg_console);
-
- return 0;
-}
-
-/*
- * ++Geert: Change # of rows and columns for one specific console.
- * Of course it's not messy to have all consoles of potentially different sizes,
- * except on PCish hardware :-)
- *
- * This is called by the low level console driver (arch/m68k/console/fbcon.c or
- * arch/m68k/console/txtcon.c)
- */
-void vc_resize_con(unsigned long lines, unsigned long columns,
- unsigned int currcons)
-{
- unsigned long cc, ll, ss, sr;
- unsigned long occ, oll, oss, osr;
- unsigned short *newscreen;
- long ol, nl, rlth, rrem;
- struct winsize ws;
-
- if (!columns || !lines || currcons >= MAX_NR_CONSOLES)
- return;
-
- cc = columns;
- ll = lines;
- sr = cc << 1;
- ss = sr * ll;
-
- if (!vc_cons_allocated(currcons))
- newscreen = 0;
- else if (!(newscreen = (unsigned short *) kmalloc(ss, GFP_USER)))
- return;
-
- if (vc_cons_allocated(currcons)) {
- oll = rows;
- occ = cols;
- osr = size_row;
- oss = screenbuf_size;
-
- rows = ll;
- cols = cc;
- size_row = sr;
- screenbuf_size = ss;
-
- rlth = MIN(osr, sr);
- rrem = sr - rlth;
- ol = origin;
- nl = (long) newscreen;
- if (ll < oll)
- ol += (oll - ll) * osr;
-
- update_attr(currcons);
- while (ol < scr_end) {
- /* ++Geert: TODO: Because the attributes have different meanings
- on monochrome and color, they should really be converted if
- can_do_color changes... */
- memcpyw((unsigned short *) nl, (unsigned short *) ol, rlth);
- if (rrem)
- memsetw((void *)(nl + rlth), video_erase_char, rrem);
- ol += osr;
- nl += sr;
- }
-
- if (kmalloced)
- kfree_s(vc_scrbuf[currcons], oss);
- vc_scrbuf[currcons] = newscreen;
- kmalloced = 1;
- screenbuf_size = ss;
-
- origin = (long) video_mem_start = vc_scrbuf[currcons];
- scr_end = video_mem_end = ((long)video_mem_start) + ss;
-
- if (scr_end > nl)
- memsetw((void *) nl, video_erase_char, scr_end - nl);
-
- /* do part of a reset_terminal() */
- top = 0;
- bottom = rows;
- gotoxy(currcons, x, y);
- save_cur(currcons);
-
- ws.ws_row = rows;
- ws.ws_col = cols;
- if (memcmp(&ws, &console_table[currcons]->winsize, sizeof (struct winsize)) &&
- console_table[currcons]->pgrp > 0)
- kill_pg(console_table[currcons]->pgrp, SIGWINCH, 1);
- console_table[currcons]->winsize = ws;
- }
-
- /* don't update in graphics mode */
- if (currcons == fg_console && vt_cons[fg_console]->vc_mode == KD_TEXT)
- update_screen(fg_console);
-}
-
-void vc_disallocate(unsigned int currcons)
-{
- if (vc_cons_allocated(currcons)) {
- if (kmalloced)
- kfree_s(vc_scrbuf[currcons], screenbuf_size);
- if (currcons >= MIN_NR_CONSOLES)
- kfree_s(vc_cons[currcons].d, structsize);
- vc_cons[currcons].d = 0;
- }
-}
-
-
-#define set_kbd(x) set_vc_kbd_mode(kbd_table+currcons,x)
-#define clr_kbd(x) clr_vc_kbd_mode(kbd_table+currcons,x)
-#define is_kbd(x) vc_kbd_mode(kbd_table+currcons,x)
-
-#define decarm VC_REPEAT
-#define decckm VC_CKMODE
-#define kbdapplic VC_APPLIC
-#define lnm VC_CRLF
-
-/*
- * this is what the terminal answers to a ESC-Z or csi0c query.
- */
-#define VT100ID "\033[?1;2c"
-#define VT102ID "\033[?6c"
-
-static unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7,
- 8,12,10,14, 9,13,11,15 };
-
-/* the default colour table, for VGA+ colour systems */
-int default_red[] = {0x00,0xaa,0x00,0xaa,0x00,0xaa,0x00,0xaa,
- 0x55,0xff,0x55,0xff,0x55,0xff,0x55,0xff};
-int default_grn[] = {0x00,0x00,0xaa,0x55,0x00,0x00,0xaa,0xaa,
- 0x55,0x55,0xff,0xff,0x55,0x55,0xff,0xff};
-int default_blu[] = {0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa,
- 0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff};
-
-/*
- * gotoxy() must verify all boundaries, because the arguments
- * might also be negative. If the given position is out of
- * bounds, the cursor is placed at the nearest margin.
- */
-static void gotoxy(int currcons, int new_x, int new_y)
-{
- int min_y, max_y;
-
- if (new_x < 0)
- x = 0;
- else
- if (new_x >= cols)
- x = cols - 1;
- else
- x = new_x;
- if (decom) {
- min_y = top;
- max_y = bottom;
- } else {
- min_y = 0;
- max_y = rows;
- }
- if (new_y < min_y)
- y = min_y;
- else if (new_y >= max_y)
- y = max_y - 1;
- else
- y = new_y;
- pos = video_mem_start + y * cols + x;
- need_wrap = 0;
-}
-
-/* for absolute user moves, when decom is set */
-static void gotoxay(int currcons, int new_x, int new_y)
-{
- gotoxy(currcons, new_x, decom ? (top+new_y) : new_y);
-}
-
-static void hide_cursor(int currcons)
-{
- sw->con_cursor(vc_cons[currcons].d,CM_ERASE);
- return;
-}
-
-static void set_cursor(int currcons)
-{
- if (currcons != fg_console || console_blanked || vcmode == KD_GRAPHICS)
- return;
- if (deccm)
- sw->con_cursor(vc_cons[currcons].d,CM_DRAW);
- else
- hide_cursor(currcons);
- return;
-}
-
-void no_scroll(char *str, int *ints)
-{
- /*
- * no_scroll currently does nothing on the m68k.
- */
-}
-
-/*
- * Arno:
- * Why do we need these? The keyboard code doesn't seem to do anything
- * with them either...
- */
-void scrollfront(int l)
-{
- return;
-}
-
-void scrollback(int l)
-{
- return;
-}
-
-static void scrup(int currcons, unsigned int t, unsigned int b, int nr)
-{
- unsigned short *p;
- int i;
-
- if (b > rows || t >= b)
- return;
-
- memmove (video_mem_start + t * cols,
- video_mem_start + (t + nr) * cols,
- (b - t - nr) * cols * 2);
-
- p = video_mem_start + (b - nr) * cols;
- for (i = nr * cols; i > 0; i--)
- *p++ = video_erase_char;
-
- if (currcons != fg_console)
- return;
-/*
- * Arno:
- * Scrolling has now been moved to amicon.c where it should have
- * been all along.
- */
- sw->con_scroll(vc_cons[currcons].d, t, b, SM_UP, nr);
-
- return;
-
-}
-
-static void scrdown(int currcons, unsigned int t, unsigned int b,
- int nr)
-{
- unsigned short *p;
- int i;
-
- if (b > rows || t >= b)
- return;
-
- memmove (video_mem_start + (t + nr) * cols,
- video_mem_start + t * cols,
- (b - t - nr) * cols * 2);
-
- p = video_mem_start + t * cols;
- for (i = nr * cols; i > 0; i--)
- *p++ = video_erase_char;
-
- if (currcons != fg_console)
- return;
-/*
- * Arno:
- * Scrolling has now been moved to amicon.c where it should have
- * been all along.
- */
- sw->con_scroll(vc_cons[currcons].d, t, b, SM_DOWN, nr);
-
- return;
-}
-
-static void lf(int currcons)
-{
- /* don't scroll if above bottom of scrolling region, or
- * if below scrolling region
- */
- if (y+1 == bottom)
- scrup(currcons,top,bottom, 1);
- else if (y < rows-1) {
- y++;
- pos += cols;
- }
- need_wrap = 0;
-}
-
-static void ri(int currcons)
-{
- /* don't scroll if below top of scrolling region, or
- * if above scrolling region
- */
- if (y == top)
- scrdown(currcons,top,bottom, 1);
- else if (y > 0) {
- y--;
- pos -= cols;
- }
- need_wrap = 0;
-}
-
-static inline void cr(int currcons)
-{
- pos -= x;
- need_wrap = x = 0;
-}
-
-static inline void bs(int currcons)
-{
- if (x) {
- pos--;
- x--;
- need_wrap = 0;
- }
-}
-
-static inline void del(int currcons)
-{
- /* ignored */
-}
-
-static void csi_J(int currcons, int vpar)
-{
- unsigned long count;
- unsigned short *start;
-
- switch (vpar) {
- case 0: /* erase from cursor to end of display */
- count = (video_mem_start
- + cols * rows
- - pos);
- start = pos;
- if (currcons != fg_console)
- break;
- /* 680x0 do in two stages */
- sw->con_clear(vc_cons[currcons].d,y,x,1,cols-x);
- sw->con_clear(vc_cons[currcons].d,y+1,0,rows-y-1, cols);
- break;
- case 1: /* erase from start to cursor */
- count = pos - video_mem_start + 1;
- start = video_mem_start;
- if (currcons != fg_console)
- break;
- /* 680x0 do in two stages */
- sw->con_clear(vc_cons[currcons].d,0,0,y, cols);
- sw->con_clear(vc_cons[currcons].d,y,0,1,x + 1);
- break;
- case 2: /* erase whole display */
- count = cols * rows;
- start = video_mem_start;
- if (currcons != fg_console)
- break;
- sw->con_clear(vc_cons[currcons].d,0,0,rows, cols);
- break;
- default:
- return;
- }
- while (count-- > 0)
- *start++ = video_erase_char;
- need_wrap = 0;
-}
-
-static void csi_K(int currcons, int vpar)
-{
- unsigned long count;
- unsigned short *start;
-
- switch (vpar) {
- case 0: /* erase from cursor to end of line */
- count = cols - x;
- start = pos;
- if (currcons != fg_console)
- break;
- sw->con_clear(vc_cons[currcons].d,y,x,1,cols-x);
- break;
- case 1: /* erase from start of line to cursor */
- start = pos - x;
- count = x + 1;
- if (currcons != fg_console)
- break;
- sw->con_clear(vc_cons[currcons].d,y,0,1,x + 1);
- break;
- case 2: /* erase whole line */
- start = pos - x;
- count = cols;
- if (currcons != fg_console)
- break;
- sw->con_clear(vc_cons[currcons].d,y,0,1,cols);
- break;
- default:
- return;
- }
- while (count-- > 0)
- *start++ = video_erase_char;
- need_wrap = 0;
-}
-
-static void csi_X(int currcons, int vpar) /* erase the following vpar positions */
-{ /* not vt100? */
- unsigned long count;
- unsigned short * start;
-
- if (!vpar)
- vpar++;
-
- start = pos;
- count = (vpar > cols-x) ? (cols-x) : vpar;
-
- if (currcons == fg_console)
- sw->con_clear(vc_cons[currcons].d,y,x,1,count);
-
- while (count-- > 0)
- *start++ = video_erase_char;
- need_wrap = 0;
-}
-
-/*
- * Arno:
- * On 680x0 attributes are currently not used. This piece of code
- * seems hardware independent, but uses the EGA/VGA way of representing
- * attributes.
- * TODO: modify for 680x0 and add attribute processing to putc code.
- *
- * ++roman: I completely changed the attribute format for monochrome
- * mode (!can_do_color). The formerly used MDA (monochrome display
- * adapter) format didn't allow the combination of certain effects.
- * Now the attribute is just a bit vector:
- * Bit 0..1: intensity (0..2)
- * Bit 2 : underline
- * Bit 3 : reverse
- * Bit 7 : blink
- */
-static void update_attr(int currcons)
-{
- if (!can_do_color) {
- /* Special treatment for monochrome */
- attr = intensity |
- (underline ? 4 : 0) |
- ((reverse ^ decscnm) ? 8 : 0) |
- (blink ? 0x80 : 0);
- video_erase_char = ' ' | ((reverse ^ decscnm) ? 0x800 : 0);
- return;
- }
-
- attr = color;
- if (underline)
- attr = (attr & 0xf0) | ulcolor;
- else if (intensity == 0)
- attr = (attr & 0xf0) | halfcolor;
- if (reverse ^ decscnm)
- attr = reverse_video_char(attr);
- if (blink)
- attr ^= 0x80;
- if (intensity == 2)
- attr ^= 0x08;
- if (decscnm)
- video_erase_char = (reverse_video_char(color) << 8) | ' ';
- else
- video_erase_char = (color << 8) | ' ';
-}
-
-static void default_attr(int currcons)
-{
- intensity = 1;
- underline = 0;
- reverse = 0;
- blink = 0;
- color = def_color;
-}
-
-static void csi_m(int currcons)
-{
- int i;
-
- for (i=0;i<=npar;i++)
- switch (par[i]) {
- case 0: /* all attributes off */
- default_attr(currcons);
- break;
- case 1:
- intensity = 2;
- break;
- case 2:
- intensity = 0;
- break;
- case 4:
- underline = 1;
- break;
- case 5:
- blink = 1;
- break;
- case 7:
- reverse = 1;
- break;
- case 10: /* ANSI X3.64-1979 (SCO-ish?)
- * Select primary font, don't display
- * control chars if defined, don't set
- * bit 8 on output.
- */
- translate = set_translate(charset == 0
- ? G0_charset
- : G1_charset);
- disp_ctrl = 0;
- toggle_meta = 0;
- break;
- case 11: /* ANSI X3.64-1979 (SCO-ish?)
- * Select first alternate font, let's
- * chars < 32 be displayed as ROM chars.
- */
- translate = set_translate(IBMPC_MAP);
- disp_ctrl = 1;
- toggle_meta = 0;
- break;
- case 12: /* ANSI X3.64-1979 (SCO-ish?)
- * Select second alternate font, toggle
- * high bit before displaying as ROM char.
- */
- translate = set_translate(IBMPC_MAP);
- disp_ctrl = 1;
- toggle_meta = 1;
- break;
- case 21:
- case 22:
- intensity = 1;
- break;
- case 24:
- underline = 0;
- break;
- case 25:
- blink = 0;
- break;
- case 27:
- reverse = 0;
- break;
- case 38: /* ANSI X3.64-1979 (SCO-ish?)
- * Enables underscore, white foreground
- * with white underscore (Linux - use
- * default foreground).
- */
- color = (def_color & 0x0f) | background;
- underline = 1;
- break;
- case 39: /* ANSI X3.64-1979 (SCO-ish?)
- * Disable underline option.
- * Reset colour to default? It did this
- * before...
- */
- color = (def_color & 0x0f) | background;
- underline = 0;
- break;
- case 49:
- color = (def_color & 0xf0) | foreground;
- break;
- default:
- if (par[i] >= 30 && par[i] <= 37)
- color = color_table[par[i]-30]
- | background;
- else if (par[i] >= 40 && par[i] <= 47)
- color = (color_table[par[i]-40]<<4)
- | foreground;
- break;
- }
- update_attr(currcons);
-}
-
-static void respond_string(const char * p, struct tty_struct * tty)
-{
- while (*p) {
- tty_insert_flip_char(tty, *p, 0);
- p++;
- }
- tty_schedule_flip(tty);
-}
-
-static inline void cursor_report(int currcons, struct tty_struct * tty)
-{
- char buf[40];
-
- sprintf(buf, "\033[%ld;%ldR", y + (decom ? top+1 : 1), x+1);
- respond_string(buf, tty);
-}
-
-static inline void status_report(struct tty_struct * tty)
-{
- respond_string("\033[0n", tty); /* Terminal ok */
-}
-
-static inline void respond_ID(struct tty_struct * tty)
-{
- respond_string(VT102ID, tty);
-}
-
-void mouse_report(struct tty_struct * tty, int butt, int mrx, int mry)
-{
- char buf[8];
-
- sprintf(buf, "\033[M%c%c%c", (char)(' ' + butt), (char)('!' + mrx),
- (char)('!' + mry));
- respond_string(buf, tty);
-}
-
-/* invoked via ioctl(TIOCLINUX) and through set_selection */
-int mouse_reporting(void)
-{
- int currcons = fg_console;
-
- return report_mouse;
-}
-
-int tioclinux(struct tty_struct *tty, unsigned long arg)
-{
- char type, data;
-
- if (tty->driver.type != TTY_DRIVER_TYPE_CONSOLE)
- return -EINVAL;
- if (current->tty != tty && !suser())
- return -EPERM;
- if (get_user(type, (char *)arg))
- return -EFAULT;
- switch (type)
- {
- case 2:
- return set_selection(arg, tty, 1);
- case 3:
- return paste_selection(tty);
- case 4:
- do_unblank_screen();
- return 0;
- case 5:
- return sel_loadlut(arg);
- case 6:
-
- /*
- * Make it possible to react to Shift+Mousebutton.
- * Note that 'shift_state' is an undocumented
- * kernel-internal variable; programs not closely
- * related to the kernel should not use this.
- */
- data = shift_state;
- return put_user(data, (char *) arg);
- case 7:
- data = mouse_reporting();
- return put_user(data, (char *) arg);
- case 10:
- set_vesa_blanking(arg);
- return 0;
- case 11: /* set kmsg redirect */
- if (!suser())
- return -EPERM;
- if (get_user(data, (char *)arg+1))
- return -EFAULT;
- kmsg_redirect = data;
- return 0;
- case 12: /* get fg_console */
- return fg_console;
- }
- return -EINVAL;
-}
-
-static inline unsigned short *screenpos(int currcons, int offset, int viewed)
-{
- unsigned short *p = (unsigned short *)(origin + offset);
-#if 0
- if (viewed && currcons == fg_console)
- p -= (__real_origin - __origin);
-#endif
- return p;
-}
-
-/* Note: inverting the screen twice should revert to the original state */
-void invert_screen(int currcons, int offset, int count, int viewed)
-{
- unsigned short *p;
- unsigned short xx, yy, oldattr;
-
- count /= 2;
- p = screenpos(currcons, offset, viewed);
- xx = (offset >> 1) % cols;
- yy = (offset >> 1) / cols;
- oldattr = attr;
- if (can_do_color)
- while (count--) {
- unsigned short old = scr_readw(p);
- unsigned short new = reverse_video_short(old);
- scr_writew(new, p);
- p++;
- if (currcons != fg_console)
- continue;
- attr = new >> 8;
- sw->con_putc(vc_cons[currcons].d, new & 0xff, yy, xx);
- if (++xx == cols)
- xx = 0, ++yy;
- }
- else
- while (count--) {
- unsigned short old = scr_readw(p);
- unsigned short new = old ^ 0x800;
- scr_writew(new, p);
- p++;
- if (currcons != fg_console)
- continue;
- attr = new >> 8;
- sw->con_putc(vc_cons[currcons].d, new & 0xff, yy, xx);
- if (++xx == cols)
- xx = 0, ++yy;
- }
- attr = oldattr;
-}
-
-/* used by selection: complement pointer position */
-void complement_pos(int currcons, int offset)
-{
- static unsigned short *p = NULL;
- static unsigned short old = 0;
- static unsigned short oldx = 0, oldy = 0;
- unsigned short new, oldattr;
-
- oldattr = attr;
- if (p) {
- scr_writew(old, p);
- if (currcons == fg_console) {
- attr = old >> 8;
- sw->con_putc(vc_cons[currcons].d, old & 0xff, oldy, oldx);
- attr = oldattr;
- }
- }
- if (offset == -1)
- p = NULL;
- else {
- p = screenpos(currcons, offset, 1);
- old = scr_readw(p);
- oldx = (offset >> 1) % cols;
- oldy = (offset >> 1) / cols;
- if (can_do_color)
- new = old ^ 0x7700;
- else
- new = old ^ 0x800;
- scr_writew(new, p);
- if (currcons == fg_console) {
- attr = new >> 8;
- sw->con_putc(vc_cons[currcons].d, new & 0xff, oldy, oldx);
- attr = oldattr;
- }
- }
-}
-
-/* used by selection */
-unsigned short screen_word(int currcons, int offset, int viewed)
-{
- return scr_readw(screenpos(currcons, offset, viewed));
-}
-
-/* used by selection - convert a screen word to a glyph number */
-int scrw2glyph(unsigned short scr_word)
-{
- return ( video_mode_512ch )
- ? ((scr_word & 0x0800) >> 3) + (scr_word & 0x00ff)
- : scr_word & 0x00ff;
-}
-
-/* used by vcs - note the word offset */
-unsigned short *screen_pos(int currcons, int w_offset, int viewed)
-{
- return screenpos(currcons, 2 * w_offset, viewed);
-}
-
-void getconsxy(int currcons, char *p)
-{
- p[0] = x;
- p[1] = y;
-}
-
-void putconsxy(int currcons, char *p)
-{
- gotoxy(currcons, p[0], p[1]);
- set_cursor(currcons);
-}
-
-static void set_mode(int currcons, int on_off)
-{
- int i;
-
- for (i=0; i<=npar; i++)
- if (ques) switch(par[i]) { /* DEC private modes set/reset */
- case 1: /* Cursor keys send ^[Ox/^[[x */
- if (on_off)
- set_kbd(decckm);
- else
- clr_kbd(decckm);
- break;
- case 3: /* 80/132 mode switch unimplemented */
- deccolm = on_off;
-#if 0
- (void) vc_resize(rows, deccolm ? 132 : 80);
- /* this alone does not suffice; some user mode
- utility has to change the hardware regs */
-#endif
- break;
- case 5: /* Inverted screen on/off */
- if (decscnm != on_off) {
- decscnm = on_off;
- invert_screen(currcons, 0, screenbuf_size, 0);
- update_attr(currcons);
- }
- break;
- case 6: /* Origin relative/absolute */
- decom = on_off;
- gotoxay(currcons,0,0);
- break;
- case 7: /* Autowrap on/off */
- decawm = on_off;
- break;
- case 8: /* Autorepeat on/off */
- if (on_off)
- set_kbd(decarm);
- else
- clr_kbd(decarm);
- break;
- case 9:
- report_mouse = on_off ? 1 : 0;
- break;
- case 25: /* Cursor on/off */
- deccm = on_off;
- set_cursor(currcons);
- break;
- case 1000:
- report_mouse = on_off ? 2 : 0;
- break;
- } else switch(par[i]) { /* ANSI modes set/reset */
- case 3: /* Monitor (display ctrls) */
- disp_ctrl = on_off;
- break;
- case 4: /* Insert Mode on/off */
- decim = on_off;
- break;
- case 20: /* Lf, Enter == CrLf/Lf */
- if (on_off)
- set_kbd(lnm);
- else
- clr_kbd(lnm);
- break;
- }
-}
-
-static void setterm_command(int currcons)
-{
- switch(par[0]) {
- case 1: /* set color for underline mode */
- if (can_do_color && par[1] < 16) {
- ulcolor = color_table[par[1]];
- if (underline)
- update_attr(currcons);
- }
- break;
- case 2: /* set color for half intensity mode */
- if (can_do_color && par[1] < 16) {
- halfcolor = color_table[par[1]];
- if (intensity == 0)
- update_attr(currcons);
- }
- break;
- case 8: /* store colors as defaults */
- def_color = attr;
- default_attr(currcons);
- update_attr(currcons);
- break;
- case 9: /* set blanking interval */
- blankinterval = ((par[1] < 60) ? par[1] : 60) * 60 * HZ;
- poke_blanked_console();
- break;
- case 10: /* set bell frequency in Hz */
- if (npar >= 1)
- bell_pitch = par[1];
- else
- bell_pitch = DEFAULT_BELL_PITCH;
- break;
- case 11: /* set bell duration in msec */
- if (npar >= 1)
- bell_duration = (par[1] < 2000) ?
- par[1]*HZ/1000 : 0;
- else
- bell_duration = DEFAULT_BELL_DURATION;
- break;
- case 12: /* bring specified console to the front */
- if (par[1] >= 1 && vc_cons_allocated(par[1]-1))
- update_screen(par[1]-1);
- break;
- case 13: /* unblank the screen */
- unblank_screen();
- break;
- case 14: /* set vesa powerdown interval */
- vesa_off_interval = ((par[1] < 60) ? par[1] : 60) * 60 * HZ;
- break;
- }
-}
-
-static inline void insert_char(int currcons)
-{
- int i;
- unsigned short *p = pos;
-
- for (i = cols - x - 2; i >= 0; i--)
- p[i + 1] = p[i];
- *pos = video_erase_char;
- need_wrap = 0;
-
- if (currcons != fg_console)
- return;
-
- /* Arno:
- * Move the remainder of the line (-1 character) one spot to the right
- */
- sw->con_bmove(vc_cons[currcons].d,y,x,y,x+1,1,(cols-x-1));
- /*
- * Print the erase char on the current position
- */
- sw->con_putc(vc_cons[currcons].d,(video_erase_char & 0x00ff),y,x);
-}
-
-static void csi_at(int currcons, unsigned int nr)
-{
- int i;
- unsigned short *p;
-
- if (nr > cols - x)
- nr = cols - x;
- else if (!nr)
- nr = 1;
-
- p = pos + cols - x - nr;
- while (--p >= pos)
- p[nr] = *p;
- for (i = 0; i < nr; i++)
- *++p = video_erase_char;
- need_wrap = 0;
-
- if (currcons != fg_console)
- return;
-
- sw->con_bmove (vc_cons[currcons].d, y, x, y, x + nr,
- 1, cols - x - nr);
- while (nr--)
- sw->con_putc (vc_cons[currcons].d,
- video_erase_char & 0x00ff, y, x + nr);
-}
-
-static void csi_L(int currcons, unsigned int nr)
-{
- if (nr > rows)
- nr = rows;
- else if (!nr)
- nr = 1;
- scrdown (currcons, y, bottom, nr);
- need_wrap = 0;
-}
-
-static void csi_P(int currcons, unsigned int nr)
-{
- int i;
- unsigned short *p, *end;
-
- if (nr > cols - x)
- nr = cols - x;
- else if (!nr)
- nr = 1;
-
- p = pos;
- end = pos + cols - x - nr;
- while (p < end)
- *p = p[nr], p++;
- for (i = 0; i < nr; i++)
- *p++ = video_erase_char;
- need_wrap = 0;
-
- if (currcons != fg_console)
- return;
-
- sw->con_bmove (vc_cons[currcons].d, y, x + nr, y, x,
- 1, cols - x - nr);
-
- while (nr--)
- sw->con_putc (vc_cons[currcons].d, video_erase_char & 0x00ff,
- y, cols - 1 - nr);
-}
-
-static void csi_M(int currcons, unsigned int nr)
-{
- if (nr > rows)
- nr = rows;
- else if (!nr)
- nr=1;
- scrup (currcons, y, bottom, nr);
- need_wrap = 0;
-}
-
-static void save_cur(int currcons)
-{
- saved_x = x;
- saved_y = y;
- s_intensity = intensity;
- s_underline = underline;
- s_blink = blink;
- s_reverse = reverse;
- s_charset = charset;
- s_color = color;
- saved_G0 = G0_charset;
- saved_G1 = G1_charset;
-}
-
-static void restore_cur(int currcons)
-{
- gotoxy(currcons,saved_x,saved_y);
- intensity = s_intensity;
- underline = s_underline;
- blink = s_blink;
- reverse = s_reverse;
- charset = s_charset;
- color = s_color;
- G0_charset = saved_G0;
- G1_charset = saved_G1;
- translate = set_translate(charset ? G1_charset : G0_charset);
- update_attr(currcons);
- need_wrap = 0;
-}
-
-enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey,
- EShash, ESsetG0, ESsetG1, ESpercent, ESignore, ESnonstd,
- ESpalette };
-
-static void reset_terminal(int currcons, int do_clear)
-{
- top = 0;
- bottom = rows;
- vc_state = ESnormal;
- ques = 0;
- translate = set_translate(LAT1_MAP);
- G0_charset = LAT1_MAP;
- G1_charset = GRAF_MAP;
- charset = 0;
- need_wrap = 0;
- report_mouse = 0;
- utf = 0;
- utf_count = 0;
-
- disp_ctrl = 0;
- toggle_meta = 0;
-
- decscnm = 0;
- decom = 0;
- decawm = 1;
- deccm = 1;
- decim = 0;
-
- set_kbd(decarm);
- clr_kbd(decckm);
- clr_kbd(kbdapplic);
- clr_kbd(lnm);
- kbd_table[currcons].lockstate = 0;
- kbd_table[currcons].slockstate = 0;
- kbd_table[currcons].ledmode = LED_SHOW_FLAGS;
- kbd_table[currcons].ledflagstate = kbd_table[currcons].default_ledflagstate;
- set_leds();
-
- default_attr(currcons);
- update_attr(currcons);
-
- tab_stop[0] = 0x01010100;
- tab_stop[1] =
- tab_stop[2] =
- tab_stop[3] =
- tab_stop[4] = 0x01010101;
-
- bell_pitch = DEFAULT_BELL_PITCH;
- bell_duration = DEFAULT_BELL_DURATION;
-
- gotoxy(currcons,0,0);
- save_cur(currcons);
- if (do_clear)
- csi_J(currcons,2);
-}
-
-/*
- * Turn the Scroll-Lock LED on when the tty is stopped
- */
-static void con_stop(struct tty_struct *tty)
-{
- int console_num;
- if (!tty)
- return;
- console_num = MINOR(tty->device) - (tty->driver.minor_start);
- if (!vc_cons_allocated(console_num))
- return;
- set_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK);
- set_leds();
-}
-
-/*
- * Turn the Scroll-Lock LED off when the console is started
- */
-static void con_start(struct tty_struct *tty)
-{
- int console_num;
- if (!tty)
- return;
- console_num = MINOR(tty->device) - (tty->driver.minor_start);
- if (!vc_cons_allocated(console_num))
- return;
- clr_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK);
- set_leds();
-}
-
-static void con_flush_chars(struct tty_struct *tty)
-{
- unsigned int currcons;
- struct vt_struct *vt = (struct vt_struct *)tty->driver_data;
-
- currcons = vt->vc_num;
- if (vcmode != KD_GRAPHICS)
- set_cursor(currcons);
-}
-
-static int do_con_write(struct tty_struct * tty, int from_user,
- const unsigned char *buf, int count)
-{
- int c, tc, ok, n = 0;
- unsigned int currcons;
- struct vt_struct *vt = (struct vt_struct *)tty->driver_data;
-
- currcons = vt->vc_num;
- if (!vc_cons_allocated(currcons)) {
- /* could this happen? */
- static int error = 0;
- if (!error) {
- error = 1;
- printk("con_write: tty %d not allocated\n", currcons+1);
- }
- return 0;
- }
-
- /* undraw cursor first */
- if (currcons == fg_console)
- hide_cursor(currcons);
-
- /* clear the selection */
- if (currcons == sel_cons)
- clear_selection();
-
- disable_bh(CONSOLE_BH);
- while (count) {
- enable_bh(CONSOLE_BH);
- if (from_user)
- get_user(c, buf);
- else
- c = *buf;
- buf++; n++; count--;
- disable_bh(CONSOLE_BH);
-
- if (utf) {
- /* Combine UTF-8 into Unicode */
- /* Incomplete characters silently ignored */
- if(c > 0x7f) {
- if (utf_count > 0 && (c & 0xc0) == 0x80) {
- utf_char = (utf_char << 6) | (c & 0x3f);
- utf_count--;
- if (utf_count == 0)
- tc = c = utf_char;
- else continue;
- } else {
- if ((c & 0xe0) == 0xc0) {
- utf_count = 1;
- utf_char = (c & 0x1f);
- } else if ((c & 0xf0) == 0xe0) {
- utf_count = 2;
- utf_char = (c & 0x0f);
- } else if ((c & 0xf8) == 0xf0) {
- utf_count = 3;
- utf_char = (c & 0x07);
- } else if ((c & 0xfc) == 0xf8) {
- utf_count = 4;
- utf_char = (c & 0x03);
- } else if ((c & 0xfe) == 0xfc) {
- utf_count = 5;
- utf_char = (c & 0x01);
- } else
- utf_count = 0;
- continue;
- }
- } else {
- tc = c;
- utf_count = 0;
- }
- } else { /* no utf */
- tc = translate[toggle_meta ? (c|0x80) : c];
- }
-
- /* If the original code was a control character we
- * only allow a glyph to be displayed if the code is
- * not normally used (such as for cursor movement) or
- * if the disp_ctrl mode has been explicitly enabled.
- * Certain characters (as given by the CTRL_ALWAYS
- * bitmap) are always displayed as control characters,
- * as the console would be pretty useless without
- * them; to display an arbitrary font position use the
- * direct-to-font zone in UTF-8 mode.
- */
- ok = tc && (c >= 32 ||
- (!utf && !(((disp_ctrl ? CTRL_ALWAYS
- : CTRL_ACTION) >> c) & 1)))
- && (c != 127 || disp_ctrl)
- && (c != 128+27);
-
- if (vc_state == ESnormal && ok) {
- /* Now try to find out how to display it */
- tc = conv_uni_to_pc(tc);
- if ( tc == -4 ) {
- /* If we got -4 (not found) then see if we have
- defined a replacement character (U+FFFD) */
- tc = conv_uni_to_pc(0xfffd);
- } else if ( tc == -3 ) {
- /* Bad hash table -- hope for the best */
- tc = c;
- }
- if (tc & ~console_charmask)
- continue; /* Conversion failed */
-
- if (need_wrap) {
- cr(currcons);
- lf(currcons);
- }
-
-#if 1 /* XXX */
- /* DPC: 1994-04-12
- * Speed up overstrike mode, using new putcs.
- *
- * P.S. I hate 8 spaces per tab! Use Emacs!
- */
-
- /* Only use this for the foreground console,
- where we really draw the chars */
-
- if (count > 2 &&
- !decim && !utf && currcons == fg_console) {
- static char putcs_buf[256];
- char *p = putcs_buf;
- int putcs_count = 1;
- ushort nextx = x + 1;
-
- *p++ = tc;
- *pos++ = tc | (attr << 8);
-
- if (nextx == cols) {
- sw->con_putc(vc_cons[currcons].d,
- *putcs_buf, y, x);
- pos--;
- need_wrap = decawm;
- continue;
- }
-
- while (count)
- {
- enable_bh(CONSOLE_BH);
- if (from_user)
- get_user(c, buf);
- else
- c = *buf;
- disable_bh(CONSOLE_BH);
- tc = translate[toggle_meta ? (c|0x80) : c];
- if (!tc ||
- !(c >= 32
- || !(((disp_ctrl ? CTRL_ALWAYS
- : CTRL_ACTION) >> c) & 1)))
- break;
- tc = conv_uni_to_pc(tc);
- if (tc == -4)
- tc = conv_uni_to_pc(0xfffd);
- else if (tc == -3)
- tc = c;
-
- buf++; n++; count--;
- if (tc & ~console_charmask)
- continue; /* Conversion failed */
-
- *p++ = tc;
- *pos++ = tc | (attr << 8);
- ++putcs_count;
- ++nextx;
- if (nextx == cols ||
- putcs_count == sizeof (putcs_buf))
- break;
- }
-
- sw->con_putcs(vc_cons[currcons].d,
- putcs_buf, putcs_count, y, x);
- if (nextx == cols) {
- pos--;
- x = cols-1;
- need_wrap = decawm;
- } else
- x += putcs_count;
- continue;
- }
-
- /* DPC: End of putcs support */
-#endif
-
- if (decim)
- insert_char(currcons);
- *pos = (attr << 8) + tc;
- if (currcons == fg_console)
- sw->con_putc(vc_cons[currcons].d,tc,y,x);
- if (x == cols - 1)
- need_wrap = decawm;
- else {
- pos++;
- x++;
- }
- continue;
- }
-
- /*
- * Control characters can be used in the _middle_
- * of an escape sequence.
- */
- switch (c) {
- case 0:
- continue;
- case 7:
- if (bell_duration)
- kd_mksound(bell_pitch, bell_duration);
- continue;
- case 8:
- bs(currcons);
- continue;
- case 9:
- pos -= x;
- while (x < cols - 1) {
- x++;
- if (tab_stop[x >> 5] & (1 << (x & 31)))
- break;
- }
- pos += x;
- continue;
- case 10: case 11: case 12:
- lf(currcons);
- if (!is_kbd(lnm))
- continue;
- case 13:
- cr(currcons);
- continue;
- case 14:
- charset = 1;
- translate = set_translate(G1_charset);
- disp_ctrl = 1;
- continue;
- case 15:
- charset = 0;
- translate = set_translate(G0_charset);
- disp_ctrl = 0;
- continue;
- case 24: case 26:
- vc_state = ESnormal;
- continue;
- case 27:
- vc_state = ESesc;
- continue;
- case 127:
- del(currcons);
- continue;
- case 128+27:
- vc_state = ESsquare;
- continue;
- }
- switch(vc_state) {
- case ESesc:
- vc_state = ESnormal;
- switch (c) {
- case '[':
- vc_state = ESsquare;
- continue;
- case ']':
- vc_state = ESnonstd;
- continue;
- case '%':
- vc_state = ESpercent;
- continue;
- case 'E':
- cr(currcons);
- lf(currcons);
- continue;
- case 'M':
- ri(currcons);
- continue;
- case 'D':
- lf(currcons);
- continue;
- case 'H':
- tab_stop[x >> 5] |= (1 << (x & 31));
- continue;
- case 'Z':
- respond_ID(tty);
- continue;
- case '7':
- save_cur(currcons);
- continue;
- case '8':
- restore_cur(currcons);
- continue;
- case '(':
- vc_state = ESsetG0;
- continue;
- case ')':
- vc_state = ESsetG1;
- continue;
- case '#':
- vc_state = EShash;
- continue;
- case 'c':
- reset_terminal(currcons,1);
- continue;
- case '>': /* Numeric keypad */
- clr_kbd(kbdapplic);
- continue;
- case '=': /* Appl. keypad */
- set_kbd(kbdapplic);
- continue;
- }
- continue;
- case ESnonstd:
- if (c=='P') { /* palette escape sequence */
- for (npar=0; npar<NPAR; npar++)
- par[npar] = 0 ;
- npar = 0 ;
- vc_state = ESpalette;
- continue;
- } else if (c=='R') { /* reset palette */
- reset_palette (currcons);
- vc_state = ESnormal;
- } else
- vc_state = ESnormal;
- continue;
- case ESpalette:
- if ( (c>='0'&&c<='9') || (c>='A'&&c<='F') || (c>='a'&&c<='f') ) {
- par[npar++] = (c>'9' ? (c&0xDF)-'A'+10 : c-'0') ;
- if (npar==7) {
- int i = par[0]*3, j = 1;
- palette[i] = 16*par[j++];
- palette[i++] += par[j++];
- palette[i] = 16*par[j++];
- palette[i++] += par[j++];
- palette[i] = 16*par[j++];
- palette[i] += par[j];
- set_palette() ;
- vc_state = ESnormal;
- }
- } else
- vc_state = ESnormal;
- continue;
- case ESsquare:
- for(npar = 0 ; npar < NPAR ; npar++)
- par[npar] = 0;
- npar = 0;
- vc_state = ESgetpars;
- if (c == '[') { /* Function key */
- vc_state=ESfunckey;
- continue;
- }
- ques = (c=='?');
- if (ques)
- continue;
- case ESgetpars:
- if (c==';' && npar<NPAR-1) {
- npar++;
- continue;
- } else if (c>='0' && c<='9') {
- par[npar] *= 10;
- par[npar] += c-'0';
- continue;
- } else vc_state=ESgotpars;
- case ESgotpars:
- vc_state = ESnormal;
- switch(c) {
- case 'h':
- set_mode(currcons,1);
- continue;
- case 'l':
- set_mode(currcons,0);
- continue;
- case 'n':
- if (!ques)
- if (par[0] == 5)
- status_report(tty);
- else if (par[0] == 6)
- cursor_report(currcons,tty);
- continue;
- }
- if (ques) {
- ques = 0;
- continue;
- }
- switch(c) {
- case 'G': case '`':
- if (par[0]) par[0]--;
- gotoxy(currcons,par[0],y);
- continue;
- case 'A':
- if (!par[0]) par[0]++;
- gotoxy(currcons,x,y-par[0]);
- continue;
- case 'B': case 'e':
- if (!par[0]) par[0]++;
- gotoxy(currcons,x,y+par[0]);
- continue;
- case 'C': case 'a':
- if (!par[0]) par[0]++;
- gotoxy(currcons,x+par[0],y);
- continue;
- case 'D':
- if (!par[0]) par[0]++;
- gotoxy(currcons,x-par[0],y);
- continue;
- case 'E':
- if (!par[0]) par[0]++;
- gotoxy(currcons,0,y+par[0]);
- continue;
- case 'F':
- if (!par[0]) par[0]++;
- gotoxy(currcons,0,y-par[0]);
- continue;
- case 'd':
- if (par[0]) par[0]--;
- gotoxay(currcons,x,par[0]);
- continue;
- case 'H': case 'f':
- if (par[0]) par[0]--;
- if (par[1]) par[1]--;
- gotoxay(currcons,par[1],par[0]);
- continue;
- case 'J':
- csi_J(currcons,par[0]);
- continue;
- case 'K':
- csi_K(currcons,par[0]);
- continue;
- case 'L':
- csi_L(currcons,par[0]);
- continue;
- case 'M':
- csi_M(currcons,par[0]);
- continue;
- case 'P':
- csi_P(currcons,par[0]);
- continue;
- case 'c':
- if (!par[0])
- respond_ID(tty);
- continue;
- case 'g':
- if (!par[0])
- tab_stop[x >> 5] &= ~(1 << (x & 31));
- else if (par[0] == 3) {
- tab_stop[0] =
- tab_stop[1] =
- tab_stop[2] =
- tab_stop[3] =
- tab_stop[4] = 0;
- }
- continue;
- case 'm':
- csi_m(currcons);
- continue;
- case 'q': /* DECLL - but only 3 leds */
- /* map 0,1,2,3 to 0,1,2,4 */
- if (par[0] < 4)
- setledstate(kbd_table + currcons,
- (par[0] < 3) ? par[0] : 4);
- continue;
- case 'r':
- if (!par[0])
- par[0]++;
- if (!par[1])
- par[1] = rows;
- /* Minimum allowed region is 2 lines */
- if (par[0] < par[1] &&
- par[1] <= rows) {
- top=par[0]-1;
- bottom=par[1];
- gotoxay(currcons,0,0);
- }
- continue;
- case 's':
- save_cur(currcons);
- continue;
- case 'u':
- restore_cur(currcons);
- continue;
- case 'X':
- csi_X(currcons, par[0]);
- continue;
- case '@':
- csi_at(currcons,par[0]);
- continue;
- case ']': /* setterm functions */
- setterm_command(currcons);
- continue;
- }
- continue;
- case ESpercent:
- vc_state = ESnormal;
- switch (c) {
- case '@': /* defined in ISO 2022 */
- utf = 0;
- continue;
- case 'G': /* prelim official escape code */
- case '8': /* retained for compatibility */
- utf = 1;
- continue;
- }
- continue;
- case ESfunckey:
- vc_state = ESnormal;
- continue;
- case EShash:
- vc_state = ESnormal;
- if (c == '8') {
- /* DEC screen alignment test. kludge :-) */
- video_erase_char =
- (video_erase_char & 0xff00) | 'E';
- /* Arno:
- * Doesn't work, because csi_J(c,2)
- * calls con_clear and doesn't print
- * the erase char..
- */
- csi_J(currcons, 2);
- video_erase_char =
- (video_erase_char & 0xff00) | ' ';
- }
- continue;
- case ESsetG0:
- if (c == '0')
- G0_charset = GRAF_MAP;
- else if (c == 'B')
- G0_charset = LAT1_MAP;
- else if (c == 'U')
- G0_charset = IBMPC_MAP;
- else if (c == 'K')
- G0_charset = USER_MAP;
- if (charset == 0)
- translate = set_translate(G0_charset);
- vc_state = ESnormal;
- continue;
- case ESsetG1:
- if (c == '0')
- G1_charset = GRAF_MAP;
- else if (c == 'B')
- G1_charset = LAT1_MAP;
- else if (c == 'U')
- G1_charset = IBMPC_MAP;
- else if (c == 'K')
- G1_charset = USER_MAP;
- if (charset == 1)
- translate = set_translate(G1_charset);
- vc_state = ESnormal;
- continue;
- default:
- vc_state = ESnormal;
- }
- }
- enable_bh(CONSOLE_BH);
- return n;
-}
-
-static int con_write(struct tty_struct * tty, int from_user,
- const unsigned char *buf, int count)
-{
- int retval;
-
- retval = do_con_write(tty, from_user, buf, count);
- con_flush_chars(tty);
-
- return retval;
-}
-
-static void con_put_char(struct tty_struct *tty, unsigned char ch)
-{
- do_con_write(tty, 0, &ch, 1);
-}
-
-static int con_write_room(struct tty_struct *tty)
-{
- if (tty->stopped)
- return 0;
- return 4096; /* No limit, really; we're not buffering */
-}
-
-static int con_chars_in_buffer(struct tty_struct *tty)
-{
- return 0; /* we're not buffering */
-}
-
-void poke_blanked_console(void)
-{
- timer_active &= ~(1<<BLANK_TIMER);
- if (vt_cons[fg_console]->vc_mode == KD_GRAPHICS)
- return;
- if (console_blanked) {
- timer_table[BLANK_TIMER].fn = unblank_screen;
- timer_table[BLANK_TIMER].expires = 0;
- timer_active |= 1<<BLANK_TIMER;
- } else if (blankinterval) {
- timer_table[BLANK_TIMER].expires = jiffies + blankinterval;
- timer_active |= 1<<BLANK_TIMER;
- }
-}
-
-/* DPC: New version of console_print using putcs */
-
-#ifdef CONFIG_VT_CONSOLE
-void vt_console_print(const char * b, unsigned int count)
-{
- int currcons = fg_console;
- unsigned char c;
- const char *start = b;
- ushort cnt = 0;
- ushort myx = x;
- static int printing = 0;
-
- if (!printable || printing)
- return; /* console not yet initialized */
- printing = 1;
-
- if (kmsg_redirect && vc_cons_allocated(kmsg_redirect - 1))
- currcons = kmsg_redirect - 1;
-
- if (!vc_cons_allocated(currcons)) {
- /* impossible */
- printk("vt_console_print: tty %d not allocated ??\n", currcons+1);
- printing = 0;
- return;
- }
-
- /* undraw cursor first */
- hide_cursor(currcons);
-
- /* Contrived structure to try to emulate original need_wrap behaviour
- * Problems caused when we have need_wrap set on '\n' character */
-
- while (count-- > 0) {
- c = *(b++);
- if (c == 10 || c == 13 || c == 8 || need_wrap) {
- if ((cnt = b - start - 1) > 0) {
- sw->con_putcs(vc_cons[currcons].d,
- start, cnt, y, x);
- x += cnt;
- if (need_wrap)
- x--;
- }
-
- if (c == 8) { /* backspace */
- bs(currcons);
- start = b;
- myx = x;
- continue;
- }
- if (c != 13)
- lf(currcons);
- cr(currcons);
-
- if (c == 10 || c == 13) {
- start = b; myx = x; continue;
- }
-
- start = b-1; myx = x;
- }
-
- *pos = c | (attr << 8);
- if (myx == cols - 1) {
- need_wrap = 1;
- continue;
- }
- pos++;
- myx++;
- }
-
- if ((cnt = b - start) > 0) {
- sw->con_putcs(vc_cons[currcons].d, start, cnt, y, x);
- x += cnt;
- if (x == cols){
- x--;
- need_wrap = 1;
- }
- }
-
- set_cursor(currcons);
- poke_blanked_console();
- printing = 0;
-}
-
-static int vt_console_device(void)
-{
- return MKDEV(TTY_MAJOR, fg_console + 1);
-}
-
-extern void keyboard_wait_for_keypress(void);
-
-struct console vt_console_driver = {
- vt_console_print, do_unblank_screen,
- keyboard_wait_for_keypress, vt_console_device
-};
-#endif
-
-/*
- * con_throttle and con_unthrottle are only used for
- * paste_selection(), which has to stuff in a large number of
- * characters...
- */
-static void con_throttle(struct tty_struct *tty)
-{
-}
-
-static void con_unthrottle(struct tty_struct *tty)
-{
- struct vt_struct *vt = (struct vt_struct *) tty->driver_data;
-
- wake_up_interruptible(&vt->paste_wait);
-}
-
-static void vc_init(unsigned int currcons, int do_clear)
-{
- long base = (long) vc_scrbuf[currcons];
-
- pos = (unsigned short *)(origin = (ulong)video_mem_start = base);
- scr_end = base + screenbuf_size;
- video_mem_end = base + screenbuf_size;
- reset_vc(currcons);
- def_color = 0x07; /* white */
- ulcolor = 0x0f; /* bold white */
- halfcolor = 0x08; /* grey */
- vt_cons[currcons]->paste_wait = 0;
- reset_terminal(currcons, do_clear);
-}
-
-/*
- * This is the console switching bottom half handler.
- *
- * Doing console switching in a bottom half handler allows
- * us to do the switches asynchronously (needed when we want
- * to switch due to a keyboard interrupt), while still giving
- * us the option to easily disable it to avoid races when we
- * need to write to the console.
- */
-static void console_bh(void)
-{
- if (want_console >= 0) {
- if (want_console != fg_console) {
- change_console(want_console);
- /* we only changed when the console had already
- been allocated - a new console is not created
- in an interrupt routine */
- }
- want_console = -1;
- }
- if (do_poke_blanked_console) { /* do not unblank for a LED change */
- do_poke_blanked_console = 0;
- poke_blanked_console();
- }
-}
-
-/*
- * unsigned long con_init(unsigned long);
- *
- * This routine initializes console interrupts, and does nothing
- * else. If you want the screen to clear, call tty_write with
- * the appropriate escape-sequence.
- *
- * Reads the information preserved by setup.s to determine the current display
- * type and sets everything accordingly.
- */
-__initfunc(unsigned long con_init(unsigned long kmem_start))
-{
- const char *display_desc = "????";
- unsigned int currcons = 0;
- extern int serial_debug;
-
- memset(&console_driver, 0, sizeof(struct tty_driver));
- console_driver.magic = TTY_DRIVER_MAGIC;
- console_driver.name = "tty";
- console_driver.name_base = 1;
- console_driver.major = TTY_MAJOR;
- console_driver.minor_start = 1;
- console_driver.num = MAX_NR_CONSOLES;
- console_driver.type = TTY_DRIVER_TYPE_CONSOLE;
- console_driver.init_termios = tty_std_termios;
- console_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS;
- console_driver.refcount = &console_refcount;
- console_driver.table = console_table;
- console_driver.termios = console_termios;
- console_driver.termios_locked = console_termios_locked;
-
- console_driver.open = con_open;
- console_driver.write = con_write;
- console_driver.write_room = con_write_room;
- console_driver.put_char = con_put_char;
- console_driver.flush_chars = con_flush_chars;
- console_driver.chars_in_buffer = con_chars_in_buffer;
- console_driver.ioctl = vt_ioctl;
- console_driver.stop = con_stop;
- console_driver.start = con_start;
- console_driver.throttle = con_throttle;
- console_driver.unthrottle = con_unthrottle;
-
- if (tty_register_driver(&console_driver))
- panic("Couldn't register console driver\n");
-
- kmem_start = conswitchp->con_startup (kmem_start, &display_desc);
-
- timer_table[BLANK_TIMER].fn = blank_screen;
- timer_table[BLANK_TIMER].expires = 0;
- if (blankinterval) {
- timer_table[BLANK_TIMER].expires = jiffies + blankinterval;
- timer_active |= 1<<BLANK_TIMER;
- }
-
- /* Due to kmalloc roundup allocating statically is more efficient -
- so provide MIN_NR_CONSOLES for people with very little memory */
- for (currcons = 0; currcons < MIN_NR_CONSOLES; currcons++) {
- vc_cons[currcons].d = (struct vc_data *) kmem_start;
- kmem_start += sizeof(struct vc_data);
- vt_cons[currcons] = (struct vt_struct *) kmem_start;
- kmem_start += sizeof(struct vt_struct);
-
- /* ++Geert: sw->con_init determines console size */
- sw = conswitchp;
- cons_num = currcons;
- sw->con_init (vc_cons[currcons].d);
- size_row = cols<<1;
- screenbuf_size = rows*size_row;
-
- vc_scrbuf[currcons] = (unsigned short *) kmem_start;
- kmem_start += screenbuf_size;
- kmalloced = 0;
- vc_init(currcons, currcons);
- }
-
- currcons = fg_console = 0;
-
- gotoxy(currcons,0,0);
- csi_J(currcons, 0);
- printable = 1;
- update_screen(fg_console);
- sw->con_cursor(vc_cons[currcons].d, CM_DRAW);
- printable = 1;
-
- /* If "serdebug" cmd line option was present, don't register for printk */
-#ifdef CONFIG_VT_CONSOLE
- if (!serial_debug)
- register_console(&vt_console_driver);
- printk("Console: %s %s %ldx%ld, %d virtual console%s (max %d)\n",
- can_do_color ? "colour":"mono",
- display_desc,
- cols,rows,
- MIN_NR_CONSOLES, (MIN_NR_CONSOLES == 1) ? "" : "s", MAX_NR_CONSOLES);
-#endif
- init_bh(CONSOLE_BH, console_bh);
- return kmem_start;
-}
-
-void vesa_powerdown_screen(void)
-{
- int currcons = fg_console;
-
- timer_active &= ~(1<<BLANK_TIMER);
- timer_table[BLANK_TIMER].fn = unblank_screen;
-
- /* Power down if currently suspended (1 or 2),
- * suspend if currently blanked (0),
- * else do nothing (i.e. already powered down (3)).
- * Called only if powerdown features are allowed.
- */
- switch (vesa_blank_mode) {
- case 0:
- sw->con_blank(2);
- break;
- case 1:
- case 2:
- sw->con_blank(4);
- break;
- }
-}
-
-void do_blank_screen(int nopowersave)
-{
- int currcons;
-
- if (console_blanked)
- return;
-
- if (!vc_cons_allocated(fg_console)) {
- /* impossible */
- printk("blank_screen: tty %d not allocated ??\n", fg_console+1);
- return;
- }
-
- /* don't blank graphics */
- if (vt_cons[fg_console]->vc_mode == KD_TEXT) {
- if (vesa_off_interval && !nopowersave) {
- timer_table[BLANK_TIMER].fn = vesa_powerdown_screen;
- timer_table[BLANK_TIMER].expires = jiffies + vesa_off_interval;
- timer_active |= (1<<BLANK_TIMER);
- } else {
- timer_active &= ~(1<<BLANK_TIMER);
- timer_table[BLANK_TIMER].fn = unblank_screen;
- }
-
- /* try not to lose information by blanking,
- and not to waste memory */
- currcons = fg_console;
- has_scrolled = 0;
- sw->con_blank(1);
- if (!nopowersave)
- sw->con_blank(vesa_blank_mode + 1);
- }
- else
- hide_cursor(fg_console);
- console_blanked = fg_console + 1;
-}
-
-void do_unblank_screen(void)
-{
- int currcons;
-
- if (!console_blanked)
- return;
- if (!vc_cons_allocated(fg_console)) {
- /* impossible */
- printk("unblank_screen: tty %d not allocated ??\n", fg_console+1);
- return;
- }
- timer_table[BLANK_TIMER].fn = blank_screen;
- if (blankinterval) {
- timer_table[BLANK_TIMER].expires = jiffies + blankinterval;
- timer_active |= 1<<BLANK_TIMER;
- }
-
- currcons = fg_console;
- console_blanked = 0;
- if (sw->con_blank (0))
- /* Low-level driver cannot restore -> do it ourselves */
- update_screen( fg_console );
- set_cursor (fg_console);
-}
-
-void update_screen(int new_console)
-{
- int currcons = fg_console;
- int xx, yy, startx, attr_save;
- char buf[256], *bufp;
- unsigned short *p;
- static int lock = 0;
-
- if (/* new_console == fg_console || */ lock)
- return;
- if (!vc_cons_allocated(new_console)) {
- /* strange ... */
- printk("update_screen: tty %d not allocated ??\n", new_console+1);
- return;
- }
- lock = 1;
-
- clear_selection();
-
- currcons = fg_console = new_console;
- sw->con_cursor (vc_cons[currcons].d, CM_ERASE);
- sw->con_switch (vc_cons[new_console].d);
- /* Update the screen contents */
- p = video_mem_start;
- attr_save = attr;
- for (yy = 0; yy < rows; yy++)
- {
- bufp = buf;
- for (startx = xx = 0; xx < cols; xx++)
- {
- if (attr != ((*p >> 8) & 0xff))
- {
- if (bufp > buf)
- sw->con_putcs (vc_cons[currcons].d, buf, bufp - buf,
- yy, startx);
- startx = xx;
- bufp = buf;
- attr = (*p >> 8) & 0xff;
- }
- *bufp++ = *p++;
- if (bufp == buf + sizeof (buf))
- {
- sw->con_putcs (vc_cons[currcons].d, buf, bufp - buf,
- yy, startx);
- startx = xx + 1;
- bufp = buf;
- }
- }
- if (bufp > buf)
- sw->con_putcs (vc_cons[currcons].d, buf, bufp - buf,
- yy, startx);
- }
- set_cursor (currcons);
- attr = attr_save;
- set_leds();
- compute_shiftstate();
- lock = 0;
-}
-
-/*
- * If a blank_screen is due to a timer, then a power save is allowed.
- * If it is related to console_switching, then avoid vesa_blank().
- */
-static void blank_screen(void)
-{
- do_blank_screen(0);
-}
-
-static void unblank_screen(void)
-{
- do_unblank_screen();
-}
-
-/*
- * Allocate the console screen memory.
- */
-static int con_open(struct tty_struct *tty, struct file * filp)
-{
- unsigned int currcons;
- int i;
-
- currcons = MINOR(tty->device) - tty->driver.minor_start;
-
- i = vc_allocate(currcons);
- if (i)
- return i;
-
- vt_cons[currcons]->vc_num = currcons;
- tty->driver_data = vt_cons[currcons];
-
- if (!tty->winsize.ws_row && !tty->winsize.ws_col) {
- tty->winsize.ws_row = rows;
- tty->winsize.ws_col = cols;
- }
-
- return 0;
-}
-
-/*
- * PIO_FONT support.
- *
- * Currently we only support 8 pixels wide fonts, at a maximum height
- * of 32 pixels. Userspace fontdata is stored with 32 bytes reserved
- * for each character which is kinda wasty, but this is done in order
- * to maintain compatibility with the EGA/VGA fonts. It is upto the
- * actual low-level console-driver convert data into its favorite
- * format (maybe we should add a `fontoffset' field to the `display'
- * structure so we wont have to convert the fontdata all the time.
- * /Jes
- */
-
-#define cmapsz 8192
-
-static int set_get_font(char * arg, int set, int ch512)
-{
-#ifdef CAN_LOAD_EGA_FONTS
- int i, unit, size;
- char *charmap;
-
- if (!arg)
- return -EINVAL;
-
-
- size = ch512 ? 2*cmapsz : cmapsz;
-
- charmap = (char *)kmalloc(size, GFP_USER);
-
- if (set){
- if (copy_from_user(charmap, arg, size)) {
- kfree(charmap);
- return -EFAULT;
- }
-
- for (unit = 32; unit > 0; unit--)
- for (i = 0; i < (ch512 ? 512 : 256); i++)
- if (charmap[32*i+unit-1])
- goto nonzero;
- nonzero:
- i = conswitchp->con_set_font(vc_cons[fg_console].d, 8,
- unit, charmap);
- }else{
- memset(charmap, 0, size);
- i = conswitchp->con_get_font(vc_cons[fg_console].d,
- &unit, &unit, charmap);
- if (i == 0 && copy_to_user(arg, charmap, size))
- i = -EFAULT;
- }
- kfree(charmap);
-
- return i;
-#else
- return -EINVAL;
-#endif
-}
-
-/*
- * Load palette into the EGA/VGA DAC registers. arg points to a colour
- * map, 3 bytes per colour, 16 colours, range from 0 to 255.
- */
-
-static int set_get_cmap(unsigned char *arg, int set)
-{
- int i, j, k;
-
- for (i = 0; i < 16; i++)
- if (set) {
- get_user(default_red[i], arg++);
- get_user(default_grn[i], arg++);
- get_user(default_blu[i], arg++);
- } else {
- put_user(default_red[i], arg++);
- put_user(default_grn[i], arg++);
- put_user(default_blu[i], arg++);
- }
- if (set) {
- for (i = 0; i < MAX_NR_CONSOLES; i++)
- if (vc_cons_allocated(i))
- for (j = k = 0; j < 16; j++) {
- vc_cons[i].d->vc_palette[k++] =
- default_red[j];
- vc_cons[i].d->vc_palette[k++] =
- default_grn[j];
- vc_cons[i].d->vc_palette[k++] =
- default_blu[j];
- }
- set_palette();
- }
- return 0;
-}
-
-int con_set_cmap (unsigned char *arg)
-{
- return set_get_cmap (arg, 1);
-}
-
-int con_get_cmap (unsigned char *arg)
-{
- return set_get_cmap (arg, 0);
-}
-
-void reset_palette(int currcons)
-{
- int j, k;
- for (j = k = 0; j < 16; j++) {
- palette[k++] = default_red[j];
- palette[k++] = default_grn[j];
- palette[k++] = default_blu[j];
- }
- set_palette() ;
-}
-
-void set_palette(void)
-{
- if (vt_cons[fg_console]->vc_mode != KD_GRAPHICS)
- conswitchp->con_set_palette(vc_cons[fg_console].d, color_table);
-}
-
-/*
- * Load font into the EGA/VGA character generator. arg points to a 8192
- * byte map, 32 bytes per character. Only first H of them are used for
- * 8xH fonts (0 < H <= 32).
- */
-
-int con_set_font (char *arg, int ch512)
-{
- int i;
-
- i = set_get_font (arg,1,ch512);
- if ( !i ) {
- hashtable_contents_valid = 0;
- video_mode_512ch = ch512;
- console_charmask = ch512 ? 0x1ff : 0x0ff;
- }
- return i;
-}
-
-int con_get_font (char *arg)
-{
- return set_get_font (arg,0,video_mode_512ch);
-}
-
-/*
- * Adjust the screen to fit a font of a certain height
- *
- * Returns < 0 for error, 0 if nothing changed, and the number
- * of lines on the adjusted console if changed.
- */
-int con_adjust_height(unsigned long fontheight)
-{
- return -EINVAL;
-}
-
-static void set_vesa_blanking(unsigned long arg)
-{
- char *argp = (char *)arg + 1;
- unsigned int mode;
- get_user(mode, argp);
- vesa_blank_mode = (mode < 4) ? mode : 0;
-}
-
-unsigned long get_video_num_lines(unsigned int currcons)
-{
- return(rows);
-}
-
-unsigned long get_video_num_columns(unsigned int currcons)
-{
- return(cols);
-}
-
-unsigned long get_video_size_row(unsigned int currcons)
-{
- return(size_row);
-}
diff --git a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S
index 5d38e46ca..1c157c26a 100644
--- a/arch/m68k/kernel/entry.S
+++ b/arch/m68k/kernel/entry.S
@@ -37,6 +37,8 @@
#include <asm/setup.h>
#include <asm/segment.h>
+#include "m68k_defs.h"
+
.globl SYMBOL_NAME(system_call), SYMBOL_NAME(buserr), SYMBOL_NAME(trap)
.globl SYMBOL_NAME(resume), SYMBOL_NAME(ret_from_exception)
.globl SYMBOL_NAME(ret_from_signal)
@@ -63,9 +65,7 @@ ENTRY(trap)
ENTRY(reschedule)
| save top of frame
- pea %sp@
- jbsr SYMBOL_NAME(set_esp0)
- addql #4,%sp
+ movel %sp,%curptr@(TS_ESP0)
pea SYMBOL_NAME(ret_from_exception)
jmp SYMBOL_NAME(schedule)
@@ -98,9 +98,7 @@ ENTRY(system_call)
GET_CURRENT(%d0)
| save top of frame
- pea %sp@
- jbsr SYMBOL_NAME(set_esp0)
- addql #4,%sp
+ movel %sp,%curptr@(TS_ESP0)
cmpl #NR_syscalls,%d2
jcc badsys
@@ -112,6 +110,10 @@ ENTRY(system_call)
SYMBOL_NAME_LABEL(ret_from_exception)
btst #5,%sp@(LPT_OFF_SR) | check if returning to kernel
bnes 2f | if so, skip resched, signals
+ | only allow interrupts when we are really the last one on the
+ | kernel stack, otherwise stack overflow can occur during
+ | heavy interupt load
+ andw #ALLOWINT,%sr
tstl SYMBOL_NAME(need_resched)
jne SYMBOL_NAME(reschedule)
cmpl #SYMBOL_NAME(task),%curptr | task[0] cannot have signals
@@ -122,16 +124,8 @@ SYMBOL_NAME_LABEL(ret_from_exception)
5:
tstl %curptr@(LTASK_STATE) | state
jne SYMBOL_NAME(reschedule)
- tstl %curptr@(LTASK_COUNTER) | counter
- jeq SYMBOL_NAME(reschedule)
- movel %curptr@(LTASK_BLOCKED),%d0
- movel %d0,%d1 | save blocked in d1 for sig handling
- notl %d0
- btst #LPF_PTRACED_BIT,%curptr@(LTASK_FLAGS+LPF_PTRACED_OFF)
- jeq 1f
- moveq #-1,%d0 | let the debugger see all signals
-1: andl %curptr@(LTASK_SIGNAL),%d0
+ tstl %curptr@(LTASK_SIGPENDING)
jne Lsignal_return
2: RESTORE_ALL
@@ -139,7 +133,7 @@ Lsignal_return:
subql #4,%sp | dummy return address
SAVE_SWITCH_STACK
pea %sp@(SWITCH_STACK_SIZE)
- movel %d1,%sp@-
+ clrl %sp@-
bsrl SYMBOL_NAME(do_signal)
addql #8,%sp
RESTORE_SWITCH_STACK
@@ -184,11 +178,6 @@ SYMBOL_NAME_LABEL(ret_from_interrupt)
#endif
jhi 2b
#endif
- /* Let the rest run with interrupts allowed. This is safe since
- the kernel never uses a non-standard ipl and this is the outer
- level interrupt. */
- andw #ALLOWINT,%sr
-
/* check if we need to do software interrupts */
movel SYMBOL_NAME(bh_active),%d0
@@ -229,12 +218,26 @@ ENTRY(sys_sigsuspend)
RESTORE_SWITCH_STACK
rts
+ENTRY(sys_rt_sigsuspend)
+ SAVE_SWITCH_STACK
+ pea %sp@(SWITCH_STACK_SIZE)
+ jbsr SYMBOL_NAME(do_rt_sigsuspend)
+ addql #4,%sp
+ RESTORE_SWITCH_STACK
+ rts
+
ENTRY(sys_sigreturn)
SAVE_SWITCH_STACK
jbsr SYMBOL_NAME(do_sigreturn)
RESTORE_SWITCH_STACK
rts
+ENTRY(sys_rt_sigreturn)
+ SAVE_SWITCH_STACK
+ jbsr SYMBOL_NAME(do_rt_sigreturn)
+ RESTORE_SWITCH_STACK
+ rts
+
SYMBOL_NAME_LABEL(resume)
/*
* Beware - when entering resume, offset of tss is in d1,
@@ -251,11 +254,6 @@ SYMBOL_NAME_LABEL(resume)
/* save sr */
movew %sr,%a0@(LTSS_SR)
-#if 0
- /* disable interrupts */
- oriw #0x0700,%sr
-#endif
-
/* save fs (sfc,%dfc) (may be pointing to kernel memory) */
movec %sfc,%d0
movew %d0,%a0@(LTSS_FS)
@@ -415,7 +413,7 @@ SYMBOL_NAME_LABEL(sys_call_table)
.long SYMBOL_NAME(sys_mknod)
.long SYMBOL_NAME(sys_chmod) /* 15 */
.long SYMBOL_NAME(sys_chown)
- .long SYMBOL_NAME(sys_break)
+ .long SYMBOL_NAME(sys_ni_syscall) /* old break syscall holder */
.long SYMBOL_NAME(sys_stat)
.long SYMBOL_NAME(sys_lseek)
.long SYMBOL_NAME(sys_getpid) /* 20 */
@@ -429,11 +427,11 @@ SYMBOL_NAME_LABEL(sys_call_table)
.long SYMBOL_NAME(sys_fstat)
.long SYMBOL_NAME(sys_pause)
.long SYMBOL_NAME(sys_utime) /* 30 */
- .long SYMBOL_NAME(sys_stty)
- .long SYMBOL_NAME(sys_gtty)
+ .long SYMBOL_NAME(sys_ni_syscall) /* old stty syscall holder */
+ .long SYMBOL_NAME(sys_ni_syscall) /* old gtty syscall holder */
.long SYMBOL_NAME(sys_access)
.long SYMBOL_NAME(sys_nice)
- .long SYMBOL_NAME(sys_ftime) /* 35 */
+ .long SYMBOL_NAME(sys_ni_syscall) /* 35 */ /* old ftime syscall holder */
.long SYMBOL_NAME(sys_sync)
.long SYMBOL_NAME(sys_kill)
.long SYMBOL_NAME(sys_rename)
@@ -442,7 +440,7 @@ SYMBOL_NAME_LABEL(sys_call_table)
.long SYMBOL_NAME(sys_dup)
.long SYMBOL_NAME(sys_pipe)
.long SYMBOL_NAME(sys_times)
- .long SYMBOL_NAME(sys_prof)
+ .long SYMBOL_NAME(sys_ni_syscall) /* old prof syscall holder */
.long SYMBOL_NAME(sys_brk) /* 45 */
.long SYMBOL_NAME(sys_setgid)
.long SYMBOL_NAME(sys_getgid)
@@ -450,14 +448,14 @@ SYMBOL_NAME_LABEL(sys_call_table)
.long SYMBOL_NAME(sys_geteuid)
.long SYMBOL_NAME(sys_getegid) /* 50 */
.long SYMBOL_NAME(sys_acct)
- .long SYMBOL_NAME(sys_phys)
- .long SYMBOL_NAME(sys_lock)
+ .long SYMBOL_NAME(sys_ni_syscall) /* old phys syscall holder */
+ .long SYMBOL_NAME(sys_ni_syscall) /* old lock syscall holder */
.long SYMBOL_NAME(sys_ioctl)
.long SYMBOL_NAME(sys_fcntl) /* 55 */
- .long SYMBOL_NAME(sys_mpx)
+ .long SYMBOL_NAME(sys_ni_syscall) /* old mpx syscall holder */
.long SYMBOL_NAME(sys_setpgid)
- .long SYMBOL_NAME(sys_ulimit)
- .long SYMBOL_NAME(sys_olduname)
+ .long SYMBOL_NAME(sys_ni_syscall) /* old ulimit syscall holder */
+ .long SYMBOL_NAME(sys_ni_syscall)
.long SYMBOL_NAME(sys_umask) /* 60 */
.long SYMBOL_NAME(sys_chroot)
.long SYMBOL_NAME(sys_ustat)
@@ -496,7 +494,7 @@ SYMBOL_NAME_LABEL(sys_call_table)
.long SYMBOL_NAME(sys_fchown) /* 95 */
.long SYMBOL_NAME(sys_getpriority)
.long SYMBOL_NAME(sys_setpriority)
- .long SYMBOL_NAME(sys_profil)
+ .long SYMBOL_NAME(sys_ni_syscall) /* old profil syscall holder */
.long SYMBOL_NAME(sys_statfs)
.long SYMBOL_NAME(sys_fstatfs) /* 100 */
.long SYMBOL_NAME(sys_ioperm)
@@ -507,7 +505,7 @@ SYMBOL_NAME_LABEL(sys_call_table)
.long SYMBOL_NAME(sys_newstat)
.long SYMBOL_NAME(sys_newlstat)
.long SYMBOL_NAME(sys_newfstat)
- .long SYMBOL_NAME(sys_uname)
+ .long SYMBOL_NAME(sys_ni_syscall)
.long SYMBOL_NAME(sys_ni_syscall) /* iopl for i386 */ /* 110 */
.long SYMBOL_NAME(sys_vhangup)
.long SYMBOL_NAME(sys_idle)
@@ -568,9 +566,19 @@ SYMBOL_NAME_LABEL(sys_call_table)
.long SYMBOL_NAME(sys_query_module)
.long SYMBOL_NAME(sys_poll)
.long SYMBOL_NAME(sys_nfsservctl)
+ .long SYMBOL_NAME(sys_setresgid) /* 170 */
+ .long SYMBOL_NAME(sys_getresgid)
.long SYMBOL_NAME(sys_prctl)
- .long SYMBOL_NAME(sys_pread)
+ .long SYMBOL_NAME(sys_rt_sigreturn)
+ .long SYMBOL_NAME(sys_rt_sigaction)
+ .long SYMBOL_NAME(sys_rt_sigprocmask) /* 175 */
+ .long SYMBOL_NAME(sys_rt_sigpending)
+ .long SYMBOL_NAME(sys_rt_sigtimedwait)
+ .long SYMBOL_NAME(sys_rt_sigqueueinfo)
+ .long SYMBOL_NAME(sys_rt_sigsuspend)
+ .long SYMBOL_NAME(sys_pread) /* 180 */
.long SYMBOL_NAME(sys_pwrite)
+ .long SYMBOL_NAME(sys_lchown);
.rept NR_syscalls-(.-SYMBOL_NAME(sys_call_table))/4
.long SYMBOL_NAME(sys_ni_syscall)
.endr
diff --git a/arch/m68k/kernel/head.S b/arch/m68k/kernel/head.S
index 116c3cb27..1f3795a7c 100644
--- a/arch/m68k/kernel/head.S
+++ b/arch/m68k/kernel/head.S
@@ -14,6 +14,7 @@
** 94/11/14 Andreas Schwab: put kernel at PAGESIZE
** 94/11/18 Andreas Schwab: remove identity mapping of STRAM for Atari
** ++ Bjoern & Roman: ATARI-68040 support for the Medusa
+** 95/11/18 Richard Hirst: Added MVME166 support
** 96/04/26 Guenther Kelleter: fixed identity mapping for Falcon with
** Magnum- and FX-alternate ram
**
@@ -72,8 +73,7 @@
#include <asm/pgtable.h>
.globl SYMBOL_NAME(kernel_pg_dir), SYMBOL_NAME(kpt)
-.globl SYMBOL_NAME(availmem), SYMBOL_NAME(is_medusa)
-.globl SYMBOL_NAME(is_hades)
+.globl SYMBOL_NAME(availmem), SYMBOL_NAME(mvme_bdid_ptr)
.globl SYMBOL_NAME(m68k_pgtable_cachemode)
.globl SYMBOL_NAME(kernel_pmd_table), SYMBOL_NAME(swapper_pg_dir)
@@ -145,6 +145,7 @@ TABLENR_16MB = 64 /* same for 16 MB */
#define is_not_amiga(lab) moveq &MACH_AMIGA,%d7; cmpl %d4,%d7; jne lab
#define is_not_atari(lab) moveq &MACH_ATARI,%d7; cmpl %d4,%d7; jne lab
+#define is_not_mvme16x(lab) moveq &MACH_MVME16x,%d7; cmpl %d4,%d7; jne lab
#define is_040_or_060(lab) btst &D6B_0460,%d6; jne lab
#define is_not_040_or_060(lab) btst &D6B_0460,%d6; jeq lab
@@ -162,6 +163,7 @@ ENTRY(_stext)
.long BOOTINFOV_MAGIC
.long MACH_AMIGA, AMIGA_BOOTI_VERSION
.long MACH_ATARI, ATARI_BOOTI_VERSION
+ .long MACH_MVME16x, MVME16x_BOOTI_VERSION
.long 0
1: jra SYMBOL_NAME(_start)
@@ -249,33 +251,25 @@ ENTRY(_start)
#ifdef CONFIG_ATARI
is_not_atari(Lnotypetest)
- moveq #0,%d3 /* base addr for others: 0x00000000 */
- moveq #0,%d2 /* no Hades */
- movec %d3,%vbr
- lea %pc@(Ltest_berr),%a0
- movel %a0,0x8
- movel %sp,%a0
- moveb 0x0,%d1
- clrb 0x0
- nop
- moveb %d1,0x0
- nop
- tstb 0x00ff82fe
- nop
- movel #0xff000000,%d3 /* Medusa base addr: 0xff000000 */
- tstb 0xb0000000
- nop
- movel #0xff000000,%d2 /* Computer is a Hades */
- moveq #0,%d3
-Ltest_berr:
- movel %a0,%sp
- lea %pc@(SYMBOL_NAME(is_hades)),%a0
- movel %d2,%a0@
- lea %pc@(SYMBOL_NAME(is_medusa)),%a0
- movel %d3,%a0@
- lea %pc@(Liobase),%a0
- movel %d2,%a0@ /* On a Hades the iobase must be set
- before opening the serial port. */
+ /* get special machine type (Medusa/Hades/AB40) */
+ moveq #0,%d3 /* default if tag doesn't exist */
+ movew #BI_ATARI_MCH_TYPE,%d0
+ jbsr Lget_bi_record
+ tstl %d0
+ jbmi 1f
+ movel %a0@,%d3
+1:
+ /* %d3 is not clobbered until Atari page tables are set up,
+ * where it is used again. */
+
+ /* On the Hades, the iobase must be set up before opening the
+ * serial port. There are no I/O regs at 0x00ffxxxx at all. */
+ moveq #0,%d0
+ cmpl #ATARI_MACH_HADES,%d3
+ jbne 1f
+ movel #0xff000000,%d0 /* Hades I/O base addr: 0xff000000 */
+1: lea %pc@(Liobase),%a0
+ movel %d0,%a0@
Lnotypetest:
#endif
@@ -543,10 +537,15 @@ Lnotami:
area.
*/
- movel %pc@(is_medusa),%d3
- bne 1f
- movel %pc@(is_hades),%d3
-1:
+ /* I/O base addr for non-Medusa, non-Hades: 0x00000000 */
+ moveq #0,%d0
+ cmpl #ATARI_MACH_MEDUSA,%d3
+ jbeq 2f
+ cmpl #ATARI_MACH_HADES,%d3
+ jbne 1f
+2: movel #0xff000000,%d0 /* Medusa/Hades base addr: 0xff000000 */
+1: movel %d0,%d3
+
/* Let the root table point to the new pointer table */
lea %a4@(PTR_TABLE_SIZE<<2),%a4
movel %a4,%a0
@@ -616,6 +615,30 @@ Lspata68040:
Lnotatari:
#endif
+#if defined(CONFIG_MVME16x)
+ is_not_mvme16x(Lnot16x)
+
+ /* Get pointer to board ID data */
+ movel %d2,%sp@-
+ .long 0x4e4f0070 /* trap 0x70 - .BRD_ID */
+ movel %sp@+,%d2
+ lea %pc@(SYMBOL_NAME(mvme_bdid_ptr)),%a0
+ movel %d2,%a0@
+
+ /*
+ * On MVME16x we have already created kernel page tables for
+ * 4MB of RAM at address 0, so now need to do a transparent
+ * mapping of the top of memory space. Make it 0.5GByte for now.
+ */
+
+ movel #0xe01f0000,%d2 /* logical address base */
+ orw #0xa040,%d2 /* add in magic bits */
+ .long 0x4e7b2005 /* movec d2,ittr1 */
+ .long 0x4e7b2007 /* movec d2,dttr1 */
+
+Lnot16x:
+#endif
+
/*
* Setup a transparent mapping of the physical memory we are executing in.
*
@@ -810,6 +833,26 @@ Latarimmu68040:
Lmapphysnotatari:
#endif
+#if defined(CONFIG_MVME16x)
+ is_not_mvme16x(Lmapphysnot16x)
+ /*
+ * save physaddr of phys mem in register a3
+ */
+ moveq #'L',%d7
+ jbsr Lserial_putc
+
+ .word 0xf4d8 /* CINVA I/D */
+ .word 0xf518 /* pflusha */
+ .long 0x4e7bd807 /* movec a5,srp */
+ .long 0x4e7bd806 /* movec a5,urp */
+ movel #(TC_ENABLE+TC_PAGE4K),%d0
+ .long 0x4e7b0003 /* movec d0,tc (enable the MMU) */
+ jra LdoneMMUenable /* branch to continuation of startup */
+
+Lmapphysnot16x:
+
+#endif
+
LdoneMMUenable:
/*
@@ -833,30 +876,6 @@ LdoneMMUenable:
putc('N')
-#if 0
- putr()
- lea SYMBOL_NAME(kernel_pmd_table),%a0
- moveq #63,%d0
-1: moveq #7,%d1
- putn(%a0)
- putc(':')
- putc(' ')
-2: putn(%a0@+)
- dbra %d1,2b
- putr()
- dbra %d0,1b
- putr()
- movel SYMBOL_NAME(kpt),%a0
- moveq #639,%d0
-1: moveq #7,%d1
- putn(%a0)
- putc(':')
- putc(' ')
-2: putn(%a0@+)
- dbra %d1,2b
- putr()
- dbra %d0,1b
-#endif
/*
* Enable caches
*/
@@ -899,6 +918,7 @@ Lcache68060:
/* jump to the kernel start */
putr()
+ subl %a6,%a6 /* clear a6 for gdb */
jbsr SYMBOL_NAME(start_kernel)
/*
@@ -1048,6 +1068,13 @@ Lserial_init:
*/
Lserial_putc:
moveml %a0/%a1,%sp@-
+#if defined(CONFIG_MVME16x)
+ cmpil #MACH_MVME16x,%d4
+ jne 2f
+ moveb %d7,%sp@-
+ .long 0x4e4f0020
+2:
+#endif
#ifdef CONFIG_AMIGA
cmpil #MACH_AMIGA,%d4
jne 2f
@@ -1130,6 +1157,7 @@ L1: roll %d0,%d1
moveml %sp@+,%d0-%d2/%d7
rts
+#if 0
Lshowtest:
moveml %a0/%d7,%sp@-
putc('A')
@@ -1158,7 +1186,7 @@ Lshowtest:
putr()
moveml %sp@+,%a0/%d7
rts
-
+#endif
.data
.even
Lcustom:
@@ -1169,9 +1197,7 @@ SYMBOL_NAME_LABEL(kpt)
.long 0
SYMBOL_NAME_LABEL(availmem)
.long 0
-SYMBOL_NAME_LABEL(is_medusa)
- .long 0
-SYMBOL_NAME_LABEL(is_hades)
- .long 0
SYMBOL_NAME_LABEL(m68k_pgtable_cachemode)
.long 0
+SYMBOL_NAME_LABEL(mvme_bdid_ptr)
+ .long 0
diff --git a/arch/m68k/kernel/ints.c b/arch/m68k/kernel/ints.c
index 39e1fbce6..a9109ab0a 100644
--- a/arch/m68k/kernel/ints.c
+++ b/arch/m68k/kernel/ints.c
@@ -53,7 +53,7 @@ static irq_node_t nodes[NUM_IRQ_NODES];
unsigned int local_irq_count[NR_CPUS];
-int __m68k_bh_counter;
+unsigned int local_bh_count[NR_CPUS];
static void dummy_enable_irq(unsigned int irq);
static void dummy_disable_irq(unsigned int irq);
@@ -214,7 +214,7 @@ asmlinkage void process_int(unsigned long vec, struct pt_regs *fp)
{
if (vec >= VEC_INT1 && vec <= VEC_INT7) {
vec -= VEC_SPUR;
- kstat.interrupts[vec]++;
+ kstat.irqs[0][vec]++;
irq_list[vec].handler(vec, irq_list[vec].dev_id, fp);
} else {
if (mach_process_int)
@@ -233,7 +233,7 @@ int get_irq_list(char *buf)
if (mach_default_handler) {
for (i = 0; i < SYS_IRQS; i++) {
len += sprintf(buf+len, "auto %2d: %10u ", i,
- i ? kstat.interrupts[i] : num_spurious);
+ i ? kstat.irqs[0][i] : num_spurious);
if (irq_list[i].flags & IRQ_FLG_LOCK)
len += sprintf(buf+len, "L ");
else
diff --git a/arch/m68k/kernel/m68k_defs.c b/arch/m68k/kernel/m68k_defs.c
new file mode 100644
index 000000000..122bf63be
--- /dev/null
+++ b/arch/m68k/kernel/m68k_defs.c
@@ -0,0 +1,23 @@
+/*
+ * This program is used to generate definitions needed by
+ * assembly language modules.
+ *
+ * We use the technique used in the OSF Mach kernel code:
+ * generate asm statements containing #defines,
+ * compile this file to assembler, and then extract the
+ * #defines from the assembly-language output.
+ */
+
+#include <linux/stddef.h>
+#include <linux/sched.h>
+
+#define DEFINE(sym, val) \
+ asm volatile("\n#define " #sym " %0" : : "i" (val))
+
+int main(void)
+{
+ DEFINE(TS_TSS, offsetof(struct task_struct, tss));
+ DEFINE(TS_ESP0, offsetof(struct task_struct, tss.esp0));
+ DEFINE(TS_FPU, offsetof(struct task_struct, tss.fp));
+ return 0;
+}
diff --git a/arch/m68k/kernel/m68k_ksyms.c b/arch/m68k/kernel/m68k_ksyms.c
index f6bb0689b..a5c83712b 100644
--- a/arch/m68k/kernel/m68k_ksyms.c
+++ b/arch/m68k/kernel/m68k_ksyms.c
@@ -1,4 +1,3 @@
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/linkage.h>
#include <linux/sched.h>
@@ -26,16 +25,15 @@ extern int dump_fpu(elf_fpregset_t *);
/* platform dependent support */
-EXPORT_SYMBOL(memcmp);
EXPORT_SYMBOL(m68k_machtype);
EXPORT_SYMBOL(m68k_cputype);
EXPORT_SYMBOL(m68k_is040or060);
EXPORT_SYMBOL(cache_push);
-EXPORT_SYMBOL(cache_push_v);
EXPORT_SYMBOL(cache_clear);
EXPORT_SYMBOL(mm_vtop);
EXPORT_SYMBOL(mm_ptov);
EXPORT_SYMBOL(mm_end_of_chunk);
+EXPORT_SYMBOL(kernel_map);
EXPORT_SYMBOL(m68k_debug_device);
EXPORT_SYMBOL(dump_fpu);
EXPORT_SYMBOL(dump_thread);
@@ -43,7 +41,7 @@ EXPORT_SYMBOL(strnlen);
EXPORT_SYMBOL(strrchr);
EXPORT_SYMBOL(strstr);
EXPORT_SYMBOL(local_irq_count);
-EXPORT_SYMBOL(__m68k_bh_counter);
+EXPORT_SYMBOL(local_bh_count);
/* Networking helper routines. */
EXPORT_SYMBOL(csum_partial_copy);
@@ -55,6 +53,7 @@ EXPORT_SYMBOL(csum_partial_copy);
EXPORT_SYMBOL_NOVERS(__ashrdi3);
EXPORT_SYMBOL_NOVERS(memcpy);
EXPORT_SYMBOL_NOVERS(memset);
+EXPORT_SYMBOL_NOVERS(memcmp);
EXPORT_SYMBOL_NOVERS(__down_failed);
EXPORT_SYMBOL_NOVERS(__down_failed_interruptible);
diff --git a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c
index f07a6a038..2318caf81 100644
--- a/arch/m68k/kernel/process.c
+++ b/arch/m68k/kernel/process.c
@@ -65,7 +65,7 @@ asmlinkage int sys_idle(void)
current->priority = -100;
current->counter = -100;
for (;;){
- if (!resched_needed())
+ if (!need_resched)
#if defined(CONFIG_ATARI) && !defined(CONFIG_AMIGA) && !defined(CONFIG_MAC)
/* block out HSYNC on the atari (falcon) */
__asm__("stop #0x2200" : : : "cc");
@@ -113,17 +113,14 @@ void show_regs(struct pt_regs * regs)
printk("USP: %08lx\n", rdusp());
}
-/*
- * Free current thread data structures etc..
- */
-void exit_thread(void)
-{
-}
-
void flush_thread(void)
{
+ unsigned long zero = 0;
set_fs(USER_DS);
- current->tss.fs = USER_DS;
+ current->tss.fs = __USER_DS;
+ asm volatile (".chip 68k/68881\n\t"
+ "frestore %0@\n\t"
+ ".chip 68k" : : "a" (&zero));
}
/*
@@ -160,10 +157,6 @@ asmlinkage int m68k_clone(struct pt_regs *regs)
return ret;
}
-void release_thread(struct task_struct *dead_task)
-{
-}
-
int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
struct task_struct * p, struct pt_regs * regs)
{
@@ -190,13 +183,12 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
* Must save the current SFC/DFC value, NOT the value when
* the parent was last descheduled - RGH 10-08-96
*/
- p->tss.fs = get_fs();
+ p->tss.fs = get_fs().seg;
/* Copy the current fpu state */
asm volatile ("fsave %0" : : "m" (p->tss.fpstate[0]) : "memory");
- if((!CPU_IS_060 && p->tss.fpstate[0]) ||
- (CPU_IS_060 && p->tss.fpstate[2]))
+ if (!CPU_IS_060 ? p->tss.fpstate[0] : p->tss.fpstate[2])
asm volatile ("fmovemx %/fp0-%/fp7,%0\n\t"
"fmoveml %/fpiar/%/fpcr/%/fpsr,%1"
: : "m" (p->tss.fp[0]), "m" (p->tss.fpcntl[0])
@@ -215,7 +207,7 @@ int dump_fpu (struct pt_regs *regs, struct user_m68kfp_struct *fpu)
/* First dump the fpu context to avoid protocol violation. */
asm volatile ("fsave %0" :: "m" (fpustate[0]) : "memory");
- if((!CPU_IS_060 && !fpustate[0]) || (CPU_IS_060 && !fpustate[2]))
+ if (!CPU_IS_060 ? !fpustate[0] : !fpustate[2])
return 0;
asm volatile ("fmovem %/fpiar/%/fpcr/%/fpsr,%0"
diff --git a/arch/m68k/kernel/ptrace.c b/arch/m68k/kernel/ptrace.c
index 6b660118a..fade7ffa6 100644
--- a/arch/m68k/kernel/ptrace.c
+++ b/arch/m68k/kernel/ptrace.c
@@ -10,7 +10,6 @@
* this archive for more details.
*/
-#include <stddef.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/mm.h>
@@ -24,6 +23,7 @@
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/system.h>
+#include <asm/processor.h>
/*
* does not yet catch signals sent when the child dies.
@@ -439,7 +439,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
long tmp;
ret = -EIO;
- if ((unsigned long) data >= NSIG)
+ if ((unsigned long) data >= _NSIG)
goto out;
if (request == PTRACE_SYSCALL)
child->flags |= PF_TRACESYS;
@@ -477,7 +477,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
long tmp;
ret = -EIO;
- if ((unsigned long) data >= NSIG)
+ if ((unsigned long) data >= _NSIG)
goto out;
child->flags &= ~PF_TRACESYS;
tmp = get_reg(child, PT_SR) | (TRACE_BITS << 16);
@@ -494,7 +494,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
long tmp;
ret = -EIO;
- if ((unsigned long) data >= NSIG)
+ if ((unsigned long) data >= _NSIG)
goto out;
child->flags &= ~(PF_PTRACED|PF_TRACESYS);
wake_up_process(child);
@@ -509,6 +509,59 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
goto out;
}
+ case PTRACE_GETREGS: { /* Get all gp regs from the child. */
+ int i;
+ unsigned long tmp;
+ for (i = 0; i < 19; i++) {
+ tmp = get_reg(child, i);
+ if (i == PT_SR)
+ tmp >>= 16;
+ if (put_user(tmp, (unsigned long *) data)) {
+ ret = -EFAULT;
+ goto out;
+ }
+ data += sizeof(long);
+ }
+ ret = 0;
+ goto out;
+ }
+
+ case PTRACE_SETREGS: { /* Set all gp regs in the child. */
+ int i;
+ unsigned long tmp;
+ for (i = 0; i < 19; i++) {
+ if (get_user(tmp, (unsigned long *) data)) {
+ ret = -EFAULT;
+ goto out;
+ }
+ if (i == PT_SR) {
+ tmp &= SR_MASK;
+ tmp <<= 16;
+ tmp |= get_reg(child, PT_SR) & ~(SR_MASK << 16);
+ }
+ put_reg(child, i, tmp);
+ data += sizeof(long);
+ }
+ ret = 0;
+ goto out;
+ }
+
+ case PTRACE_GETFPREGS: { /* Get the child FPU state. */
+ ret = 0;
+ if (copy_to_user((void *)data, &child->tss.fp,
+ sizeof(struct user_m68kfp_struct)))
+ ret = -EFAULT;
+ goto out;
+ }
+
+ case PTRACE_SETFPREGS: { /* Set the child FPU state. */
+ ret = 0;
+ if (copy_from_user(&child->tss.fp, (void *)data,
+ sizeof(struct user_m68kfp_struct)))
+ ret = -EFAULT;
+ goto out;
+ }
+
default:
ret = -EIO;
goto out;
@@ -533,9 +586,10 @@ asmlinkage void syscall_trace(void)
* for normal use. strace only continues with a signal if the
* stopping signal is not SIGTRAP. -brl
*/
- if (current->exit_code)
- current->signal |= (1 << (current->exit_code - 1));
- current->exit_code = 0;
+ if (current->exit_code) {
+ send_sig(current->exit_code, current, 1);
+ current->exit_code = 0;
+ }
out:
unlock_kernel();
}
diff --git a/arch/m68k/kernel/setup.c b/arch/m68k/kernel/setup.c
index c27f7f320..fccf8b4cf 100644
--- a/arch/m68k/kernel/setup.c
+++ b/arch/m68k/kernel/setup.c
@@ -36,15 +36,13 @@
#include <asm/pgtable.h>
#endif
-u_long m68k_machtype;
-u_long m68k_cputype;
-u_long m68k_fputype;
-u_long m68k_mmutype;
+unsigned long m68k_machtype;
+unsigned long m68k_cputype;
+unsigned long m68k_fputype;
+unsigned long m68k_mmutype;
int m68k_is040or060 = 0;
-char m68k_debug_device[6] = "";
-
extern int end;
extern unsigned long availmem;
@@ -56,6 +54,8 @@ static struct mem_info m68k_ramdisk = { 0, 0 };
static char m68k_command_line[CL_SIZE];
char saved_command_line[CL_SIZE];
+char m68k_debug_device[6] = "";
+
void (*mach_sched_init) (void (*handler)(int, void *, struct pt_regs *)) __initdata;
/* machine dependent keyboard functions */
int (*mach_keyb_init) (void) __initdata;
@@ -74,23 +74,34 @@ void (*mach_gettod) (int*, int*, int*, int*, int*, int*);
int (*mach_hwclk) (int, struct hwclk_time*) = NULL;
int (*mach_set_clock_mmss) (unsigned long) = NULL;
void (*mach_reset)( void );
-struct fb_info *(*mach_fb_init)(long *) __initdata;
long mach_max_dma_address = 0x00ffffff; /* default set to the lower 16MB */
-void (*mach_video_setup) (char *, int *) __initdata;
-#ifdef CONFIG_BLK_DEV_FD
-int (*mach_floppy_init) (void) __initdata = NULL;
+#if defined(CONFIG_AMIGA_FLOPPY) || defined(CONFIG_ATARI_FLOPPY)
void (*mach_floppy_setup) (char *, int *) __initdata = NULL;
void (*mach_floppy_eject) (void) = NULL;
#endif
+#ifdef CONFIG_HEARTBEAT
+void (*mach_heartbeat) (int) = NULL;
+#endif
+
+extern void base_trap_init(void);
+
+#ifdef CONFIG_MAGIC_SYSRQ
+int mach_sysrq_key = -1;
+int mach_sysrq_shift_state = 0;
+int mach_sysrq_shift_mask = 0;
+char *mach_sysrq_xlate = NULL;
+#endif
extern int amiga_parse_bootinfo(const struct bi_record *);
extern int atari_parse_bootinfo(const struct bi_record *);
+extern int mac_parse_bootinfo(const struct bi_record *);
extern void config_amiga(void);
extern void config_atari(void);
extern void config_mac(void);
extern void config_sun3(void);
extern void config_apollo(void);
+extern void config_mvme16x(void);
#define MASK_256K 0xfffc0000
@@ -132,6 +143,8 @@ __initfunc(static void m68k_parse_bootinfo(const struct bi_record *record))
unknown = amiga_parse_bootinfo(record);
else if (MACH_IS_ATARI)
unknown = atari_parse_bootinfo(record);
+ else if (MACH_IS_MAC)
+ unknown = mac_parse_bootinfo(record);
else
unknown = 1;
}
@@ -145,7 +158,6 @@ __initfunc(static void m68k_parse_bootinfo(const struct bi_record *record))
__initfunc(void setup_arch(char **cmdline_p, unsigned long * memory_start_p,
unsigned long * memory_end_p))
{
- unsigned long memory_start, memory_end;
extern int _etext, _edata, _end;
int i;
char *p, *q;
@@ -158,19 +170,15 @@ __initfunc(void setup_arch(char **cmdline_p, unsigned long * memory_start_p,
else if (CPU_IS_060)
m68k_is040or060 = 6;
+ base_trap_init();
+
/* clear the fpu if we have one */
if (m68k_fputype & (FPU_68881|FPU_68882|FPU_68040|FPU_68060)) {
volatile int zero = 0;
asm __volatile__ ("frestore %0" : : "m" (zero));
}
- memory_start = availmem;
- memory_end = 0;
-
- for (i = 0; i < m68k_num_memory; i++)
- memory_end += m68k_memory[i].size & MASK_256K;
-
- init_task.mm->start_code = 0;
+ init_task.mm->start_code = PAGE_OFFSET;
init_task.mm->end_code = (unsigned long) &_etext;
init_task.mm->end_data = (unsigned long) &_edata;
init_task.mm->brk = (unsigned long) &_end;
@@ -190,6 +198,15 @@ __initfunc(void setup_arch(char **cmdline_p, unsigned long * memory_start_p,
if ((q = strchr( m68k_debug_device, ' ' ))) *q = 0;
i = 1;
}
+#ifdef CONFIG_ATARI
+ /* This option must be parsed very early */
+ if (!strncmp( p, "switches=", 9 )) {
+ extern void atari_switches_setup( const char *, int );
+ atari_switches_setup( p+9, (q = strchr( p+9, ' ' )) ?
+ (q - (p+9)) : strlen(p+9) );
+ i = 1;
+ }
+#endif
if (i) {
/* option processed, delete it */
@@ -202,9 +219,6 @@ __initfunc(void setup_arch(char **cmdline_p, unsigned long * memory_start_p,
}
}
- *memory_start_p = memory_start;
- *memory_end_p = memory_end;
-
switch (m68k_machtype) {
#ifdef CONFIG_AMIGA
case MACH_AMIGA:
@@ -231,6 +245,11 @@ __initfunc(void setup_arch(char **cmdline_p, unsigned long * memory_start_p,
config_apollo();
break;
#endif
+#ifdef CONFIG_MVME16x
+ case MACH_MVME16x:
+ config_mvme16x();
+ break;
+#endif
default:
panic ("No configuration setup");
}
@@ -241,6 +260,11 @@ __initfunc(void setup_arch(char **cmdline_p, unsigned long * memory_start_p,
initrd_end = initrd_start + m68k_ramdisk.size;
}
#endif
+
+ *memory_start_p = availmem;
+ *memory_end_p = 0;
+ for (i = 0; i < m68k_num_memory; i++)
+ *memory_end_p += m68k_memory[i].size & MASK_256K;
}
int get_cpuinfo(char * buffer)
@@ -337,15 +361,7 @@ int get_hardware_list(char *buffer)
return(len);
}
-#ifdef CONFIG_BLK_DEV_FD
-__initfunc(int floppy_init(void))
-{
- if (mach_floppy_init)
- return mach_floppy_init();
- else
- return 0;
-}
-
+#if defined(CONFIG_AMIGA_FLOPPY) || defined(CONFIG_ATARI_FLOPPY)
__initfunc(void floppy_setup(char *str, int *ints))
{
if (mach_floppy_setup)
@@ -373,8 +389,16 @@ void arch_gettod(int *year, int *mon, int *day, int *hour,
*year = *mon = *day = *hour = *min = *sec = 0;
}
-__initfunc(void video_setup (char *options, int *ints))
+void check_bugs(void)
{
- if (mach_video_setup)
- mach_video_setup (options, ints);
+#ifndef CONFIG_FPU_EMU
+ if (m68k_fputype == 0) {
+ printk( KERN_EMERG "*** YOU DO NOT HAVE A FLOATING POINT UNIT, "
+ "WHICH IS REQUIRED BY LINUX/M68K ***\n" );
+ printk( KERN_EMERG "Upgrade your hardware or join the FPU "
+ "emulation project\n" );
+ printk( KERN_EMERG "(see http://no-fpu.linux-m68k.org)\n" );
+ panic( "no FPU" );
+ }
+#endif
}
diff --git a/arch/m68k/kernel/signal.c b/arch/m68k/kernel/signal.c
index ab887801c..97809d382 100644
--- a/arch/m68k/kernel/signal.c
+++ b/arch/m68k/kernel/signal.c
@@ -12,13 +12,15 @@
* Linux/m68k support by Hamish Macdonald
*
* 68060 fixes by Jesper Skov
+ *
+ * 1997-12-01 Modified for POSIX.1b signals by Andreas Schwab
*/
/*
* ++roman (07/09/96): implemented signal stacks (specially for tosemu on
* Atari :-) Current limitation: Only one sigstack can be active at one time.
- * If a second signal with SA_STACK set arrives while working on a sigstack,
- * SA_STACK is ignored. This behaviour avoids lots of trouble with nested
+ * If a second signal with SA_ONSTACK set arrives while working on a sigstack,
+ * SA_ONSTACK is ignored. This behaviour avoids lots of trouble with nested
* signal handlers!
*/
@@ -30,22 +32,19 @@
#include <linux/wait.h>
#include <linux/ptrace.h>
#include <linux/unistd.h>
+#include <linux/stddef.h>
#include <asm/setup.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/traps.h>
+#include <asm/ucontext.h>
-#define offsetof(type, member) ((size_t)(&((type *)0)->member))
-
-#define _S(nr) (1<<((nr)-1))
-
-#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
+#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
asmlinkage int sys_wait4(pid_t pid, unsigned long *stat_addr,
int options, unsigned long *ru);
-
-asmlinkage int do_signal(unsigned long oldmask, struct pt_regs *regs);
+asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs);
const int frame_extra_sizes[16] = {
0,
@@ -67,54 +66,232 @@ const int frame_extra_sizes[16] = {
};
/*
- * atomically swap in the new signal mask, and wait for a signal.
+ * Atomically swap in the new signal mask, and wait for a signal.
*/
asmlinkage int do_sigsuspend(struct pt_regs *regs)
{
- unsigned long oldmask = current->blocked;
- unsigned long newmask = regs->d3;
+ old_sigset_t mask = regs->d3;
+ sigset_t saveset;
+
+ mask &= _BLOCKABLE;
+ saveset = current->blocked;
+ siginitset(&current->blocked, mask);
+ recalc_sigpending(current);
+
+ regs->d0 = -EINTR;
+ while (1) {
+ current->state = TASK_INTERRUPTIBLE;
+ schedule();
+ if (do_signal(&saveset, regs))
+ return -EINTR;
+ }
+}
+
+asmlinkage int
+do_rt_sigsuspend(struct pt_regs *regs)
+{
+ sigset_t *unewset = (sigset_t *)regs->d1;
+ size_t sigsetsize = (size_t)regs->d2;
+ sigset_t saveset, newset;
+
+ /* XXX: Don't preclude handling different sized sigset_t's. */
+ if (sigsetsize != sizeof(sigset_t))
+ return -EINVAL;
+
+ if (copy_from_user(&newset, unewset, sizeof(newset)))
+ return -EFAULT;
+ sigdelsetmask(&newset, ~_BLOCKABLE);
+
+ saveset = current->blocked;
+ current->blocked = newset;
+ recalc_sigpending(current);
- current->blocked = newmask & _BLOCKABLE;
regs->d0 = -EINTR;
while (1) {
current->state = TASK_INTERRUPTIBLE;
schedule();
- if (do_signal(oldmask, regs))
+ if (do_signal(&saveset, regs))
return -EINTR;
}
}
+asmlinkage int
+sys_sigaction(int sig, const struct old_sigaction *act,
+ struct old_sigaction *oact)
+{
+ struct k_sigaction new_ka, old_ka;
+ int ret;
+
+ if (act) {
+ old_sigset_t mask;
+ if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
+ __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
+ __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
+ return -EFAULT;
+ __get_user(new_ka.sa.sa_flags, &act->sa_flags);
+ __get_user(mask, &act->sa_mask);
+ siginitset(&new_ka.sa.sa_mask, mask);
+ }
+
+ ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
+
+ if (!ret && oact) {
+ if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) ||
+ __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
+ __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
+ return -EFAULT;
+ __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
+ __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
+ }
+
+ return ret;
+}
+
+
+/*
+ * Do a signal return; undo the signal stack.
+ */
+
+struct sigframe
+{
+ char *pretcode;
+ int sig;
+ int code;
+ struct sigcontext *psc;
+ char retcode[8];
+ unsigned long extramask[_NSIG_WORDS-1];
+ struct sigcontext sc;
+};
+
+struct rt_sigframe
+{
+ char *pretcode;
+ int sig;
+ struct siginfo *pinfo;
+ void *puc;
+ struct siginfo info;
+ struct ucontext uc;
+ char retcode[8];
+};
+
+
static unsigned char fpu_version = 0; /* version number of fpu, set by setup_frame */
-asmlinkage int do_sigreturn(unsigned long __unused)
+static inline void restore_fpu_state(struct sigcontext *sc)
{
- struct sigcontext context;
- struct pt_regs *regs;
- struct switch_stack *sw;
- int fsize = 0;
- int formatvec = 0;
- unsigned long fp;
- unsigned long usp = rdusp();
+ if (CPU_IS_060 ? sc->sc_fpstate[2] : sc->sc_fpstate[0]) {
+ /* Verify the frame format. */
+ if (!CPU_IS_060 && (sc->sc_fpstate[0] != fpu_version))
+ goto badframe;
+ if (CPU_IS_020_OR_030) {
+ if (m68k_fputype & FPU_68881 &&
+ !(sc->sc_fpstate[1] == 0x18 || sc->sc_fpstate[1] == 0xb4))
+ goto badframe;
+ if (m68k_fputype & FPU_68882 &&
+ !(sc->sc_fpstate[1] == 0x38 || sc->sc_fpstate[1] == 0xd4))
+ goto badframe;
+ } else if (CPU_IS_040) {
+ if (!(sc->sc_fpstate[1] == 0x00 ||
+ sc->sc_fpstate[1] == 0x28 ||
+ sc->sc_fpstate[1] == 0x60))
+ goto badframe;
+ } else if (CPU_IS_060) {
+ if (!(sc->sc_fpstate[3] == 0x00 ||
+ sc->sc_fpstate[3] == 0x60 ||
+ sc->sc_fpstate[3] == 0xe0))
+ goto badframe;
+ } else
+ goto badframe;
-#if 0
- printk("sys_sigreturn, usp=%08x\n", (unsigned) usp);
-#endif
+ __asm__ volatile (".chip 68k/68881\n\t"
+ "fmovemx %0,%/fp0-%/fp1\n\t"
+ "fmoveml %1,%/fpcr/%/fpsr/%/fpiar\n\t"
+ ".chip 68k"
+ : /* no outputs */
+ : "m" (*sc->sc_fpregs), "m" (*sc->sc_fpcntl));
+ }
+ __asm__ volatile (".chip 68k/68881\n\t"
+ "frestore %0\n\t"
+ ".chip 68k" : : "m" (*sc->sc_fpstate));
+ return;
+
+badframe:
+ do_exit(SIGSEGV);
+}
- /* get stack frame pointer */
- sw = (struct switch_stack *) &__unused;
- regs = (struct pt_regs *) (sw + 1);
+#define FPCONTEXT_SIZE 216
+#define uc_fpstate uc_filler[0]
+#define uc_formatvec uc_filler[FPCONTEXT_SIZE/4]
+#define uc_extra uc_filler[FPCONTEXT_SIZE/4+1]
- /* get previous context (including pointer to possible extra junk) */
- if (copy_from_user(&context,(void *)usp, sizeof(context)))
+static inline void rt_restore_fpu_state(struct ucontext *uc)
+{
+ unsigned char fpstate[FPCONTEXT_SIZE];
+ int context_size = CPU_IS_060 ? 8 : 0;
+ fpregset_t fpregs;
+
+ if (__get_user(*(long *)fpstate, (long *)&uc->uc_fpstate))
+ goto badframe;
+ if (CPU_IS_060 ? fpstate[2] : fpstate[0]) {
+ if (!CPU_IS_060)
+ context_size = fpstate[1];
+ /* Verify the frame format. */
+ if (!CPU_IS_060 && (fpstate[0] != fpu_version))
+ goto badframe;
+ if (CPU_IS_020_OR_030) {
+ if (m68k_fputype & FPU_68881 &&
+ !(context_size == 0x18 || context_size == 0xb4))
+ goto badframe;
+ if (m68k_fputype & FPU_68882 &&
+ !(context_size == 0x38 || context_size == 0xd4))
+ goto badframe;
+ } else if (CPU_IS_040) {
+ if (!(context_size == 0x00 ||
+ context_size == 0x28 ||
+ context_size == 0x60))
+ goto badframe;
+ } else if (CPU_IS_060) {
+ if (!(fpstate[3] == 0x00 ||
+ fpstate[3] == 0x60 ||
+ fpstate[3] == 0xe0))
+ goto badframe;
+ } else
+ goto badframe;
+ if (__copy_from_user(&fpregs, &uc->uc_mcontext.fpregs,
+ sizeof(fpregs)))
+ goto badframe;
+ __asm__ volatile (".chip 68k/68881\n\t"
+ "fmovemx %0,%/fp0-%/fp7\n\t"
+ "fmoveml %1,%/fpcr/%/fpsr/%/fpiar\n\t"
+ ".chip 68k"
+ : /* no outputs */
+ : "m" (*fpregs.f_fpregs),
+ "m" (fpregs.f_pcr));
+ }
+ if (context_size &&
+ __copy_from_user(fpstate + 4, (long *)&uc->uc_fpstate + 1,
+ context_size))
goto badframe;
+ __asm__ volatile (".chip 68k/68881\n\t"
+ "frestore %0\n\t"
+ ".chip 68k" : : "m" (*fpstate));
+ return;
- fp = usp + sizeof (context);
+badframe:
+ do_exit(SIGSEGV);
+}
- /* restore signal mask */
- current->blocked = context.sc_mask & _BLOCKABLE;
+static inline int
+restore_sigcontext(struct pt_regs *regs, struct sigcontext *usc, void *fp)
+{
+ int fsize, formatvec;
+ struct sigcontext context;
+ /* get previous context */
+ if (copy_from_user(&context, usc, sizeof(context)))
+ goto badframe;
+
/* restore passed registers */
- regs->d0 = context.sc_d0;
regs->d1 = context.sc_d1;
regs->a0 = context.sc_a0;
regs->a1 = context.sc_a1;
@@ -125,43 +302,8 @@ asmlinkage int do_sigreturn(unsigned long __unused)
formatvec = context.sc_formatvec;
regs->format = formatvec >> 12;
regs->vector = formatvec & 0xfff;
- if ((!CPU_IS_060 && context.sc_fpstate[0]) || (CPU_IS_060 && context.sc_fpstate[2])){
- /* Verify the frame format. */
- if (!CPU_IS_060 && (context.sc_fpstate[0] != fpu_version))
- goto badframe;
- if (m68k_fputype & FPU_68881)
- {
- if (context.sc_fpstate[1] != 0x18
- && context.sc_fpstate[1] != 0xb4)
- goto badframe;
- }
- else if (m68k_fputype & FPU_68882)
- {
- if (context.sc_fpstate[1] != 0x38
- && context.sc_fpstate[1] != 0xd4)
- goto badframe;
- }
- else if (m68k_fputype & FPU_68040)
- {
- if (!(context.sc_fpstate[1] == 0x00 ||
- context.sc_fpstate[1] == 0x28 ||
- context.sc_fpstate[1] == 0x60))
- goto badframe;
- }
- else if (m68k_fputype & FPU_68060)
- {
- if (!(context.sc_fpstate[3] == 0x00 ||
- context.sc_fpstate[3] == 0x60 ||
- context.sc_fpstate[3] == 0xe0))
- goto badframe;
- }
- __asm__ volatile ("fmovemx %0,%/fp0-%/fp1\n\t"
- "fmoveml %1,%/fpcr/%/fpsr/%/fpiar"
- : /* no outputs */
- : "m" (*context.sc_fpregs),
- "m" (*context.sc_fpcntl));
- }
- __asm__ volatile ("frestore %0" : : "m" (*context.sc_fpstate));
+
+ restore_fpu_state(&context);
fsize = frame_extra_sizes[regs->format];
if (fsize < 0) {
@@ -174,14 +316,13 @@ asmlinkage int do_sigreturn(unsigned long __unused)
goto badframe;
}
- if (context.sc_usp != fp+fsize)
- current->flags &= ~PF_ONSIGSTK;
-
/* OK. Make room on the supervisor stack for the extra junk,
* if necessary.
*/
if (fsize) {
+ struct switch_stack *sw = (struct switch_stack *)regs - 1;
+ regs->d0 = context.sc_d0;
#define frame_offset (sizeof(struct pt_regs)+sizeof(struct switch_stack))
__asm__ __volatile__
(" movel %0,%/a0\n\t"
@@ -215,127 +356,494 @@ asmlinkage int do_sigreturn(unsigned long __unused)
goto badframe;
}
+ return context.sc_d0;
+
+badframe:
+ do_exit(SIGSEGV);
+}
+
+static inline int
+rt_restore_ucontext(struct pt_regs *regs, struct switch_stack *sw,
+ struct ucontext *uc)
+{
+ int fsize, temp;
+ greg_t *gregs = uc->uc_mcontext.gregs;
+
+ __get_user(temp, &uc->uc_mcontext.version);
+ if (temp != MCONTEXT_VERSION)
+ goto badframe;
+ /* restore passed registers */
+ __get_user(regs->d0, &gregs[0]);
+ __get_user(regs->d1, &gregs[1]);
+ __get_user(regs->d2, &gregs[2]);
+ __get_user(regs->d3, &gregs[3]);
+ __get_user(regs->d4, &gregs[4]);
+ __get_user(regs->d5, &gregs[5]);
+ __get_user(sw->d6, &gregs[6]);
+ __get_user(sw->d7, &gregs[7]);
+ __get_user(regs->a0, &gregs[8]);
+ __get_user(regs->a1, &gregs[9]);
+ __get_user(regs->a2, &gregs[10]);
+ __get_user(sw->a3, &gregs[11]);
+ __get_user(sw->a4, &gregs[12]);
+ __get_user(sw->a5, &gregs[13]);
+ __get_user(sw->a6, &gregs[14]);
+ __get_user(temp, &gregs[15]);
+ wrusp(temp);
+ __get_user(regs->pc, &gregs[16]);
+ __get_user(temp, &gregs[17]);
+ regs->sr = (regs->sr & 0xff00) | (temp & 0xff);
+ regs->orig_d0 = -1; /* disable syscall checks */
+ __get_user(temp, &uc->uc_formatvec);
+ regs->format = temp >> 12;
+ regs->vector = temp & 0xfff;
+
+ rt_restore_fpu_state(uc);
+
+ fsize = frame_extra_sizes[regs->format];
+ if (fsize < 0) {
+ /*
+ * user process trying to return with weird frame format
+ */
+#if DEBUG
+ printk("user process returning with weird frame format\n");
+#endif
+ goto badframe;
+ }
+
+ /* OK. Make room on the supervisor stack for the extra junk,
+ * if necessary.
+ */
+
+ if (fsize) {
+#define frame_offset (sizeof(struct pt_regs)+sizeof(struct switch_stack))
+ __asm__ __volatile__
+ (" movel %0,%/a0\n\t"
+ " subl %1,%/a0\n\t" /* make room on stack */
+ " movel %/a0,%/sp\n\t" /* set stack pointer */
+ /* move switch_stack and pt_regs */
+ "1: movel %0@+,%/a0@+\n\t"
+ " dbra %2,1b\n\t"
+ " lea %/sp@(%c3),%/a0\n\t" /* add offset of fmt */
+ " lsrl #2,%1\n\t"
+ " subql #1,%1\n\t"
+ "2: movesl %4@+,%2\n\t"
+ "3: movel %2,%/a0@+\n\t"
+ " dbra %1,2b\n\t"
+ " bral " SYMBOL_NAME_STR(ret_from_signal) "\n"
+ "4:\n"
+ ".section __ex_table,\"a\"\n"
+ " .align 4\n"
+ " .long 2b,4b\n"
+ " .long 3b,4b\n"
+ ".previous"
+ : /* no outputs, it doesn't ever return */
+ : "a" (sw), "d" (fsize), "d" (frame_offset/4-1),
+ "n" (frame_offset), "a" (&uc->uc_extra)
+ : "a0");
+#undef frame_offset
+ /*
+ * If we ever get here an exception occured while
+ * building the above stack-frame.
+ */
+ goto badframe;
+ }
+
return regs->d0;
+
badframe:
do_exit(SIGSEGV);
}
+asmlinkage int do_sigreturn(unsigned long __unused)
+{
+ struct switch_stack *sw = (struct switch_stack *) &__unused;
+ struct pt_regs *regs = (struct pt_regs *) (sw + 1);
+ unsigned long usp = rdusp();
+ struct sigframe *frame = (struct sigframe *)(usp - 24);
+ sigset_t set;
+
+ if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
+ goto badframe;
+ if (__get_user(set.sig[0], &frame->sc.sc_mask) ||
+ (_NSIG_WORDS > 1 &&
+ __copy_from_user(&set.sig[1], &frame->extramask,
+ sizeof(frame->extramask))))
+ goto badframe;
+
+ sigdelsetmask(&set, ~_BLOCKABLE);
+ current->blocked = set;
+ recalc_sigpending(current);
+
+ return restore_sigcontext(regs, &frame->sc, frame + 1);
+
+badframe:
+ do_exit(SIGSEGV);
+}
+
+asmlinkage int do_rt_sigreturn(unsigned long __unused)
+{
+ struct switch_stack *sw = (struct switch_stack *) &__unused;
+ struct pt_regs *regs = (struct pt_regs *) (sw + 1);
+ unsigned long usp = rdusp();
+ struct rt_sigframe *frame = (struct rt_sigframe *)(usp - 4);
+ sigset_t set;
+
+ if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
+ goto badframe;
+ if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
+ goto badframe;
+
+ sigdelsetmask(&set, ~_BLOCKABLE);
+ current->blocked = set;
+ recalc_sigpending(current);
+
+ return rt_restore_ucontext(regs, sw, &frame->uc);
+
+badframe:
+ do_exit(SIGSEGV);
+}
+
/*
- * Set up a signal frame...
- *
- * This routine is somewhat complicated by the fact that if the
- * kernel may be entered by an exception other than a system call;
- * e.g. a bus error or other "bad" exception. If this is the case,
- * then *all* the context on the kernel stack frame must be saved.
- *
- * For a large number of exceptions, the stack frame format is the same
- * as that which will be created when the process traps back to the kernel
- * when finished executing the signal handler. In this case, nothing
- * must be done. This is exception frame format "0". For exception frame
- * formats "2", "9", "A" and "B", the extra information on the frame must
- * be saved. This information is saved on the user stack and restored
- * when the signal handler is returned.
- *
- * The format of the user stack when executing the signal handler is:
- *
- * usp -> RETADDR (points to code below)
- * signum (parm #1)
- * sigcode (parm #2 ; vector number)
- * scp (parm #3 ; sigcontext pointer, pointer to #1 below)
- * code1 (addaw #20,sp) ; pop parms and code off stack
- * code2 (moveq #119,d0; trap #0) ; sigreturn syscall
- * #1| oldmask
- * | old usp
- * | d0 (first saved reg)
- * | d1
- * | a0
- * | a1
- * | sr (saved status register)
- * | pc (old pc; one to return to)
- * | forvec (format and vector word of old supervisor stack frame)
- * | floating point context
- *
- * These are optionally followed by some extra stuff, depending on the
- * stack frame interrupted. This is 1 longword for format "2", 3
- * longwords for format "9", 6 longwords for format "A", and 21
- * longwords for format "B".
+ * Set up a signal frame.
*/
-#define UFRAME_SIZE(fs) (sizeof(struct sigcontext)/4 + 6 + fs/4)
+static inline void save_fpu_state(struct sigcontext *sc, struct pt_regs *regs)
+{
+ __asm__ volatile (".chip 68k/68881\n\t"
+ "fsave %0\n\t"
+ ".chip 68k"
+ : : "m" (*sc->sc_fpstate) : "memory");
-static inline void setup_frame (struct sigaction * sa, struct pt_regs *regs,
- int signr, unsigned long oldmask)
+ if (CPU_IS_060 ? sc->sc_fpstate[2] : sc->sc_fpstate[0]) {
+ fpu_version = sc->sc_fpstate[0];
+ if (CPU_IS_020_OR_030 &&
+ regs->vector >= (VEC_FPBRUC * 4) &&
+ regs->vector <= (VEC_FPNAN * 4)) {
+ /* Clear pending exception in 68882 idle frame */
+ if (*(unsigned short *) sc->sc_fpstate == 0x1f38)
+ sc->sc_fpstate[0x38] |= 1 << 3;
+ }
+ __asm__ volatile (".chip 68k/68881\n\t"
+ "fmovemx %/fp0-%/fp1,%0\n\t"
+ "fmoveml %/fpcr/%/fpsr/%/fpiar,%1\n\t"
+ ".chip 68k"
+ : /* no outputs */
+ : "m" (*sc->sc_fpregs),
+ "m" (*sc->sc_fpcntl)
+ : "memory");
+ }
+}
+
+static inline void rt_save_fpu_state(struct ucontext *uc, struct pt_regs *regs)
{
- struct sigcontext context;
- unsigned long *frame, *tframe;
+ unsigned char fpstate[FPCONTEXT_SIZE];
+ int context_size = CPU_IS_060 ? 8 : 0;
+
+ __asm__ volatile (".chip 68k/68881\n\t"
+ "fsave %0\n\t"
+ ".chip 68k"
+ : : "m" (*fpstate) : "memory");
+
+ __put_user(*(long *)fpstate, (long *)&uc->uc_fpstate);
+ if (CPU_IS_060 ? fpstate[2] : fpstate[0]) {
+ fpregset_t fpregs;
+ if (!CPU_IS_060)
+ context_size = fpstate[1];
+ fpu_version = fpstate[0];
+ if (CPU_IS_020_OR_030 &&
+ regs->vector >= (VEC_FPBRUC * 4) &&
+ regs->vector <= (VEC_FPNAN * 4)) {
+ /* Clear pending exception in 68882 idle frame */
+ if (*(unsigned short *) fpstate == 0x1f38)
+ fpstate[0x38] |= 1 << 3;
+ }
+ __asm__ volatile (".chip 68k/68881\n\t"
+ "fmovemx %/fp0-%/fp7,%0\n\t"
+ "fmoveml %/fpcr/%/fpsr/%/fpiar,%1\n\t"
+ ".chip 68k"
+ : /* no outputs */
+ : "m" (*fpregs.f_fpregs),
+ "m" (fpregs.f_pcr)
+ : "memory");
+ copy_to_user(&uc->uc_mcontext.fpregs, &fpregs, sizeof(fpregs));
+ }
+ if (context_size)
+ copy_to_user((long *)&uc->uc_fpstate + 1, fpstate + 4,
+ context_size);
+}
+
+static void setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs,
+ unsigned long mask)
+{
+ sc->sc_mask = mask;
+ sc->sc_usp = rdusp();
+ sc->sc_d0 = regs->d0;
+ sc->sc_d1 = regs->d1;
+ sc->sc_a0 = regs->a0;
+ sc->sc_a1 = regs->a1;
+ sc->sc_sr = regs->sr;
+ sc->sc_pc = regs->pc;
+ sc->sc_formatvec = regs->format << 12 | regs->vector;
+ save_fpu_state(sc, regs);
+}
+
+static inline void rt_setup_ucontext(struct ucontext *uc, struct pt_regs *regs)
+{
+ struct switch_stack *sw = (struct switch_stack *)regs - 1;
+ greg_t *gregs = uc->uc_mcontext.gregs;
+
+ __put_user(MCONTEXT_VERSION, &uc->uc_mcontext.version);
+ __put_user(regs->d0, &gregs[0]);
+ __put_user(regs->d1, &gregs[1]);
+ __put_user(regs->d2, &gregs[2]);
+ __put_user(regs->d3, &gregs[3]);
+ __put_user(regs->d4, &gregs[4]);
+ __put_user(regs->d5, &gregs[5]);
+ __put_user(sw->d6, &gregs[6]);
+ __put_user(sw->d7, &gregs[7]);
+ __put_user(regs->a0, &gregs[8]);
+ __put_user(regs->a1, &gregs[9]);
+ __put_user(regs->a2, &gregs[10]);
+ __put_user(sw->a3, &gregs[11]);
+ __put_user(sw->a4, &gregs[12]);
+ __put_user(sw->a5, &gregs[13]);
+ __put_user(sw->a6, &gregs[14]);
+ __put_user(rdusp(), &gregs[15]);
+ __put_user(regs->pc, &gregs[16]);
+ __put_user(regs->sr, &gregs[17]);
+ __put_user((regs->format << 12) | regs->vector, &uc->uc_formatvec);
+ rt_save_fpu_state(uc, regs);
+}
+
+static inline void push_cache (unsigned long vaddr)
+{
+ /*
+ * Using the old cache_push_v() was really a big waste.
+ *
+ * What we are trying to do is to flush 8 bytes to ram.
+ * Flushing 2 cache lines of 16 bytes is much cheaper than
+ * flushing 1 or 2 pages, as previously done in
+ * cache_push_v().
+ * Jes
+ */
+ if (CPU_IS_040) {
+ unsigned long temp;
+
+ __asm__ __volatile__ (".chip 68040\n\t"
+ "nop\n\t"
+ "ptestr (%1)\n\t"
+ "movec %%mmusr,%0\n\t"
+ ".chip 68k"
+ : "=r" (temp)
+ : "a" (vaddr));
+
+ temp &= PAGE_MASK;
+ temp |= vaddr & ~PAGE_MASK;
+
+ __asm__ __volatile__ (".chip 68040\n\t"
+ "nop\n\t"
+ "cpushl %%bc,(%0)\n\t"
+ ".chip 68k"
+ : : "a" (temp));
+ if (((vaddr + 8) ^ vaddr) & ~15) {
+ if (((vaddr + 8) ^ vaddr) & PAGE_MASK)
+ __asm__ __volatile__ (".chip 68040\n\t"
+ "nop\n\t"
+ "ptestr (%1)\n\t"
+ "movec %%mmusr,%0\n\t"
+ ".chip 68k"
+ : "=r" (temp)
+ : "a" (vaddr + 8));
+
+ temp &= PAGE_MASK;
+ temp |= (vaddr + 8) & ~PAGE_MASK;
+
+ __asm__ __volatile__ (".chip 68040\n\t"
+ "nop\n\t"
+ "cpushl %%bc,(%0)\n\t"
+ ".chip 68k"
+ : : "a" (temp));
+ }
+ }
+ else if (CPU_IS_060) {
+ unsigned long temp;
+ __asm__ __volatile__ (".chip 68060\n\t"
+ "plpar (%0)\n\t"
+ ".chip 68k"
+ : "=a" (temp)
+ : "0" (vaddr));
+ __asm__ __volatile__ (".chip 68060\n\t"
+ "cpushl %%bc,(%0)\n\t"
+ ".chip 68k"
+ : : "a" (temp));
+ if (((vaddr + 8) ^ vaddr) & ~15) {
+ if (((vaddr + 8) ^ vaddr) & PAGE_MASK)
+ __asm__ __volatile__ (".chip 68060\n\t"
+ "plpar (%0)\n\t"
+ ".chip 68k"
+ : "=a" (temp)
+ : "0" (vaddr + 8));
+ __asm__ __volatile__ (".chip 68060\n\t"
+ "cpushl %%bc,(%0)\n\t"
+ ".chip 68k"
+ : : "a" (temp));
+ }
+ }
+ else {
+ /*
+ * 68030/68020 have no writeback cache;
+ * still need to clear icache.
+ * Note that vaddr is guaranteed to be long word aligned.
+ */
+ unsigned long temp;
+ asm volatile ("movec %%cacr,%0" : "=r" (temp));
+ temp += 4;
+ asm volatile ("movec %0,%%caar\n\t"
+ "movec %1,%%cacr"
+ : : "r" (vaddr), "r" (temp));
+ asm volatile ("movec %0,%%caar\n\t"
+ "movec %1,%%cacr"
+ : : "r" (vaddr + 4), "r" (temp));
+ }
+}
+
+static void setup_frame (int sig, struct k_sigaction *ka,
+ sigset_t *set, struct pt_regs *regs)
+{
+ struct sigframe *frame;
int fsize = frame_extra_sizes[regs->format];
+ struct sigcontext context;
if (fsize < 0) {
+#ifdef DEBUG
printk ("setup_frame: Unknown frame format %#x\n",
regs->format);
- do_exit(SIGSEGV);
+#endif
+ goto segv_and_exit;
}
- frame = (unsigned long *)rdusp();
- if (!(current->flags & PF_ONSIGSTK) && (sa->sa_flags & SA_STACK)) {
- frame = (unsigned long *)sa->sa_restorer;
+ frame = (struct sigframe *)((rdusp() - sizeof(*frame) - fsize) & -8);
+
+ if (!(current->flags & PF_ONSIGSTK) && (ka->sa.sa_flags & SA_ONSTACK)) {
+ frame = (struct sigframe *)(((unsigned long)ka->sa.sa_restorer
+ - sizeof(*frame) - fsize) & -8);
current->flags |= PF_ONSIGSTK;
}
- frame -= UFRAME_SIZE(fsize);
if (fsize) {
- if (copy_to_user (frame + UFRAME_SIZE(0), regs + 1, fsize))
- do_exit(SIGSEGV);
+ if (copy_to_user (frame + 1, regs + 1, fsize))
+ goto segv_and_exit;
regs->stkadj = fsize;
}
-/* set up the "normal" stack seen by the signal handler */
- tframe = frame;
+ __put_user((current->exec_domain
+ && current->exec_domain->signal_invmap
+ && sig < 32
+ ? current->exec_domain->signal_invmap[sig]
+ : sig),
+ &frame->sig);
- /* return address points to code on stack */
+ __put_user(regs->vector, &frame->code);
+ __put_user(&frame->sc, &frame->psc);
- if(put_user((ulong)(frame+4), tframe))
- do_exit(SIGSEGV);
- tframe++;
- if (current->exec_domain && current->exec_domain->signal_invmap)
- __put_user(current->exec_domain->signal_invmap[signr], tframe);
- else
- __put_user(signr, tframe);
- tframe++;
-
- __put_user(regs->vector, tframe); tframe++;
- /* "scp" parameter. points to sigcontext */
- __put_user((ulong)(frame+6), tframe); tframe++;
-
-/* set up the return code... */
- __put_user(0xdefc0014,tframe); tframe++; /* addaw #20,sp */
- __put_user(0x70774e40,tframe); tframe++; /* moveq #119,d0; trap #0 */
-
-/* Flush caches so the instructions will be correctly executed. (MA) */
- cache_push_v ((unsigned long)frame, (int)tframe - (int)frame);
-
-/* setup and copy the sigcontext structure */
- context.sc_mask = oldmask;
- context.sc_usp = rdusp();
- context.sc_d0 = regs->d0;
- context.sc_d1 = regs->d1;
- context.sc_a0 = regs->a0;
- context.sc_a1 = regs->a1;
- context.sc_sr = regs->sr;
- context.sc_pc = regs->pc;
- context.sc_formatvec = (regs->format << 12 | regs->vector);
- __asm__ volatile ("fsave %0" : : "m" (*context.sc_fpstate) : "memory");
- if ((!CPU_IS_060 && context.sc_fpstate[0]) || (CPU_IS_060 && context.sc_fpstate[2])){
- fpu_version = context.sc_fpstate[0];
- __asm__ volatile ("fmovemx %/fp0-%/fp1,%0\n\t"
- "fmoveml %/fpcr/%/fpsr/%/fpiar,%1"
- : /* no outputs */
- : "m" (*context.sc_fpregs),
- "m" (*context.sc_fpcntl)
- : "memory");
+ if (_NSIG_WORDS > 1)
+ copy_to_user(frame->extramask, &set->sig[1],
+ sizeof(frame->extramask));
+
+ setup_sigcontext(&context, regs, set->sig[0]);
+ if (copy_to_user (&frame->sc, &context, sizeof(context)))
+ goto segv_and_exit;
+
+ /* Set up to return from userspace. */
+ __put_user(frame->retcode, &frame->pretcode);
+ /* addaw #20,sp */
+ __put_user(0xdefc0014, (long *)(frame->retcode + 0));
+ /* moveq #,d0; trap #0 */
+ __put_user(0x70004e40 + (__NR_sigreturn << 16),
+ (long *)(frame->retcode + 4));
+
+ push_cache ((unsigned long) &frame->retcode);
+
+ /*
+ * no matter what frame format we were using before, we
+ * will do the "RTE" using a normal 4 word frame.
+ */
+ regs->format = 0;
+
+ /* Set up registers for signal handler */
+ wrusp ((unsigned long) frame);
+ regs->pc = (unsigned long) ka->sa.sa_handler;
+
+ /* Prepare to skip over the extra stuff in the exception frame. */
+ if (regs->stkadj) {
+ struct pt_regs *tregs =
+ (struct pt_regs *)((ulong)regs + regs->stkadj);
+#if DEBUG
+ printk("Performing stackadjust=%04x\n", regs->stkadj);
+#endif
+ /* This must be copied with decreasing addresses to
+ handle overlaps. */
+ tregs->vector = regs->vector;
+ tregs->format = regs->format;
+ tregs->pc = regs->pc;
+ tregs->sr = regs->sr;
}
- if (copy_to_user (tframe, &context, sizeof(context)))
- do_exit(SIGSEGV);
+ return;
+
+segv_and_exit:
+ do_exit(SIGSEGV);
+}
+
+static void setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info,
+ sigset_t *set, struct pt_regs *regs)
+{
+ struct rt_sigframe *frame;
+ int fsize = frame_extra_sizes[regs->format];
+
+ if (fsize < 0) {
+#ifdef DEBUG
+ printk ("setup_frame: Unknown frame format %#x\n",
+ regs->format);
+#endif
+ goto segv_and_exit;
+ }
+
+ frame = (struct rt_sigframe *)((rdusp() - sizeof(*frame)) & -8);
+
+ /* XXX: Check here if we need to switch stacks.. */
+
+ if (fsize) {
+ if (copy_to_user (&frame->uc.uc_extra, regs + 1, fsize))
+ goto segv_and_exit;
+ regs->stkadj = fsize;
+ }
+
+ __put_user((current->exec_domain
+ && current->exec_domain->signal_invmap
+ && sig < 32
+ ? current->exec_domain->signal_invmap[sig]
+ : sig),
+ &frame->sig);
+ __put_user(&frame->info, &frame->pinfo);
+ __put_user(&frame->uc, &frame->puc);
+ __copy_to_user(&frame->info, info, sizeof(*info));
+
+ /* Clear all the bits of the ucontext we don't use. */
+ clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext));
+
+ rt_setup_ucontext(&frame->uc, regs);
+ if (copy_to_user (&frame->uc.uc_sigmask, set, sizeof(*set)))
+ goto segv_and_exit;
+
+ /* Set up to return from userspace. */
+ __put_user(frame->retcode, &frame->pretcode);
+ /* movel #,d0; trap #0 */
+ __put_user(0x203c, (short *)(frame->retcode + 0));
+ __put_user(__NR_rt_sigreturn, (long *)(frame->retcode + 2));
+ __put_user(0x4e40, (short *)(frame->retcode + 6));
+
+ push_cache ((unsigned long) &frame->retcode);
/*
* no matter what frame format we were using before, we
@@ -345,7 +853,7 @@ static inline void setup_frame (struct sigaction * sa, struct pt_regs *regs,
/* Set up registers for signal handler */
wrusp ((unsigned long) frame);
- regs->pc = (unsigned long) sa->sa_handler;
+ regs->pc = (unsigned long) ka->sa.sa_handler;
/* Prepare to skip over the extra stuff in the exception frame. */
if (regs->stkadj) {
@@ -361,13 +869,18 @@ static inline void setup_frame (struct sigaction * sa, struct pt_regs *regs,
tregs->pc = regs->pc;
tregs->sr = regs->sr;
}
+ return;
+
+segv_and_exit:
+ do_exit(SIGSEGV);
}
/*
* OK, we're invoking a handler
*/
-static inline void handle_signal(unsigned long signr, struct sigaction *sa,
- unsigned long oldmask, struct pt_regs *regs)
+static void
+handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info,
+ sigset_t *oldset, struct pt_regs *regs)
{
/* are we from a system call? */
if (regs->orig_d0 >= 0) {
@@ -378,7 +891,7 @@ static inline void handle_signal(unsigned long signr, struct sigaction *sa,
break;
case -ERESTARTSYS:
- if (!(sa->sa_flags & SA_RESTART)) {
+ if (!(ka->sa.sa_flags & SA_RESTART)) {
regs->d0 = -EINTR;
break;
}
@@ -390,12 +903,19 @@ static inline void handle_signal(unsigned long signr, struct sigaction *sa,
}
/* set up the stack frame */
- setup_frame(sa, regs, signr, oldmask);
+ if (ka->sa.sa_flags & SA_SIGINFO)
+ setup_rt_frame(sig, ka, info, oldset, regs);
+ else
+ setup_frame(sig, ka, oldset, regs);
+
+ if (ka->sa.sa_flags & SA_ONESHOT)
+ ka->sa.sa_handler = NULL;
- if (sa->sa_flags & SA_ONESHOT)
- sa->sa_handler = NULL;
- if (!(sa->sa_flags & SA_NOMASK))
- current->blocked |= (sa->sa_mask | _S(signr)) & _BLOCKABLE;
+ if (!(ka->sa.sa_flags & SA_NODEFER)) {
+ sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+ sigaddset(&current->blocked,sig);
+ recalc_sigpending(current);
+ }
}
/*
@@ -407,29 +927,28 @@ static inline void handle_signal(unsigned long signr, struct sigaction *sa,
* 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)
+asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs)
{
- unsigned long mask = ~current->blocked;
- unsigned long signr;
- struct sigaction * sa;
+ siginfo_t info;
+ struct k_sigaction *ka;
current->tss.esp0 = (unsigned long) regs;
- /* If the process is traced, all signals are passed to the debugger. */
- if (current->flags & PF_PTRACED)
- mask = ~0UL;
- while ((signr = current->signal & mask)) {
- __asm__("bfffo %2,#0,#0,%1\n\t"
- "bfclr %0,%1,#1\n\t"
- "eorw #31,%1"
- :"=m" (current->signal),"=d" (signr)
- :"0" (current->signal), "1" (signr));
- sa = current->sig->action + signr;
- signr++;
+ if (!oldset)
+ oldset = &current->blocked;
+
+ for (;;) {
+ int signr;
+
+ signr = dequeue_signal(&current->blocked, &info);
+
+ if (!signr)
+ break;
if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
current->exit_code = signr;
current->state = TASK_STOPPED;
+ regs->sr &= ~PS_T;
/* Did we come from a system call? */
if (regs->orig_d0 >= 0) {
@@ -443,11 +962,12 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs *regs)
}
notify_parent(current, SIGCHLD);
schedule();
+
+ /* We're back. Did the debugger cancel the sig? */
if (!(signr = current->exit_code)) {
discard_frame:
- /* Make sure that a faulted bus cycle
- isn't restarted (only needed on the
- 68030). */
+ /* Make sure that a faulted bus cycle isn't
+ restarted (only needed on the 680[23]0). */
if (regs->format == 10 || regs->format == 11) {
regs->stkadj = frame_extra_sizes[regs->format];
regs->format = 0;
@@ -455,26 +975,43 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs *regs)
continue;
}
current->exit_code = 0;
+
+ /* The debugger continued. Ignore SIGSTOP. */
if (signr == SIGSTOP)
goto discard_frame;
- if (_S(signr) & current->blocked) {
- current->signal |= _S(signr);
- mask &= ~_S(signr);
+
+ /* Update the siginfo structure. Is this good? */
+ if (signr != info.si_signo) {
+ info.si_signo = signr;
+ info.si_errno = 0;
+ info.si_code = SI_USER;
+ info.si_pid = current->p_pptr->pid;
+ info.si_uid = current->p_pptr->uid;
+ }
+
+ /* If the (new) signal is now blocked, requeue it. */
+ if (sigismember(&current->blocked, signr)) {
+ send_sig_info(signr, &info, current);
continue;
}
- sa = current->sig->action + signr - 1;
}
- if (sa->sa_handler == SIG_IGN) {
+
+ ka = &current->sig->action[signr-1];
+ if (ka->sa.sa_handler == SIG_IGN) {
if (signr != SIGCHLD)
continue;
- /* check for SIGCHLD: it's special */
- while (sys_wait4(-1,NULL,WNOHANG, NULL) > 0)
+ /* Check for SIGCHLD: it's special. */
+ while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
/* nothing */;
continue;
}
- if (sa->sa_handler == SIG_DFL) {
+
+ if (ka->sa.sa_handler == SIG_DFL) {
+ int exit_code = signr;
+
if (current->pid == 1)
continue;
+
switch (signr) {
case SIGCONT: case SIGCHLD: case SIGWINCH:
continue;
@@ -482,31 +1019,35 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs *regs)
case SIGTSTP: case SIGTTIN: case SIGTTOU:
if (is_orphaned_pgrp(current->pgrp))
continue;
+ /* FALLTHRU */
+
case SIGSTOP:
- if (current->flags & PF_PTRACED)
- continue;
current->state = TASK_STOPPED;
current->exit_code = signr;
- if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags &
- SA_NOCLDSTOP))
+ if (!(current->p_pptr->sig->action[SIGCHLD-1]
+ .sa.sa_flags & SA_NOCLDSTOP))
notify_parent(current, SIGCHLD);
schedule();
continue;
case SIGQUIT: case SIGILL: case SIGTRAP:
case SIGIOT: case SIGFPE: case SIGSEGV:
- if (current->binfmt && current->binfmt->core_dump) {
- if (current->binfmt->core_dump(signr, regs))
- signr |= 0x80;
- }
- /* fall through */
+ if (current->binfmt
+ && current->binfmt->core_dump
+ && current->binfmt->core_dump(signr, regs))
+ exit_code |= 0x80;
+ /* FALLTHRU */
+
default:
- current->signal |= _S(signr & 0x7f);
+ sigaddset(&current->signal, signr);
current->flags |= PF_SIGNALED;
- do_exit(signr);
+ do_exit(exit_code);
+ /* NOTREACHED */
}
}
- handle_signal(signr, sa, oldmask, regs);
+
+ /* Whee! Actually deliver the signal. */
+ handle_signal(signr, ka, &info, oldset, regs);
return 1;
}
diff --git a/arch/m68k/kernel/sys_m68k.c b/arch/m68k/kernel/sys_m68k.c
index 9c56fed37..b28a43374 100644
--- a/arch/m68k/kernel/sys_m68k.c
+++ b/arch/m68k/kernel/sys_m68k.c
@@ -17,6 +17,7 @@
#include <linux/stat.h>
#include <linux/mman.h>
#include <linux/file.h>
+#include <linux/utsname.h>
#include <asm/setup.h>
#include <asm/uaccess.h>
@@ -308,6 +309,10 @@ cache_flush_040 (unsigned long addr, int scope, int cache, unsigned long len)
}
if (!--i && len)
{
+ /*
+ * No need to page align here since it is done by
+ * virt_to_phys_040().
+ */
addr += PAGE_SIZE;
i = PAGE_SIZE / 16;
/* Recompute physical address when crossing a page
@@ -462,7 +467,14 @@ cache_flush_060 (unsigned long addr, int scope, int cache, unsigned long len)
}
if (!--i && len)
{
+
+ /*
+ * We just want to jump to the first cache line
+ * in the next page.
+ */
addr += PAGE_SIZE;
+ addr &= PAGE_MASK;
+
i = PAGE_SIZE / 16;
/* Recompute physical address when crossing a page
boundary. */
@@ -559,13 +571,13 @@ sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len)
cacr |= 4;
if (cache & FLUSH_CACHE_DATA)
cacr |= 0x400;
- len >>= 4;
+ len >>= 2;
while (len--) {
__asm__ __volatile__ ("movec %1, %%caar\n\t"
"movec %0, %%cacr"
: /* no outputs */
: "r" (cacr), "r" (addr));
- addr += 16;
+ addr += 4;
}
} else {
/* Flush the whole cache, even if page granularity requested. */
@@ -588,3 +600,13 @@ out:
unlock_kernel();
return ret;
}
+
+/*
+ * Old cruft
+ */
+asmlinkage int sys_pause(void)
+{
+ current->state = TASK_INTERRUPTIBLE;
+ schedule();
+ return -ERESTARTNOHAND;
+}
diff --git a/arch/m68k/kernel/time.c b/arch/m68k/kernel/time.c
index 7b3acdfa6..51359f046 100644
--- a/arch/m68k/kernel/time.c
+++ b/arch/m68k/kernel/time.c
@@ -7,6 +7,7 @@
* Most of the stuff is located in the machine specific files.
*/
+#include <linux/config.h> /* CONFIG_HEARTBEAT */
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
@@ -66,11 +67,35 @@ static void timer_interrupt(int irq, void *dummy, struct pt_regs * regs)
*/
if (time_state != TIME_BAD && xtime.tv_sec > last_rtc_update + 660 &&
xtime.tv_usec > 500000 - (tick >> 1) &&
- xtime.tv_usec < 500000 + (tick >> 1))
+ xtime.tv_usec < 500000 + (tick >> 1)) {
if (set_rtc_mmss(xtime.tv_sec) == 0)
last_rtc_update = xtime.tv_sec;
else
last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
+ }
+#ifdef CONFIG_HEARTBEAT
+ /* use power LED as a heartbeat instead -- much more useful
+ for debugging -- based on the version for PReP by Cort */
+ /* acts like an actual heart beat -- ie thump-thump-pause... */
+ if (mach_heartbeat) {
+ static unsigned cnt = 0, period = 0, dist = 0;
+
+ if (cnt == 0 || cnt == dist)
+ mach_heartbeat( 1 );
+ else if (cnt == 7 || cnt == dist+7)
+ mach_heartbeat( 0 );
+
+ if (++cnt > period) {
+ cnt = 0;
+ /* The hyperbolic function below modifies the heartbeat period
+ * length in dependency of the current (5min) load. It goes
+ * through the points f(0)=126, f(1)=86, f(5)=51,
+ * f(inf)->30. */
+ period = ((672<<FSHIFT)/(5*avenrun[0]+(7<<FSHIFT))) + 30;
+ dist = period / 4;
+ }
+ }
+#endif /* CONFIG_HEARTBEAT */
}
/* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
diff --git a/arch/m68k/kernel/traps.c b/arch/m68k/kernel/traps.c
index 44e45b9a0..ff73709b7 100644
--- a/arch/m68k/kernel/traps.c
+++ b/arch/m68k/kernel/traps.c
@@ -36,6 +36,7 @@
#include <asm/traps.h>
#include <asm/pgtable.h>
#include <asm/machdep.h>
+#include <asm/siginfo.h>
#ifdef CONFIG_KGDB
#include <asm/kgdb.h>
#endif
@@ -64,23 +65,10 @@ asm(".text\n"
__ALIGN_STR "\n"
SYMBOL_NAME_STR(nmihandler) ": rte");
-__initfunc(void trap_init (void))
+__initfunc(void base_trap_init(void))
{
- int i;
-
/* setup the exception vector table */
- __asm__ volatile ("movec %0,%/vbr" : : "r" ((void*)vectors));
-
- for (i = 48; i < 64; i++)
- vectors[i] = trap;
-
- for (i = 64; i < 256; i++)
- vectors[i] = inthandler;
-
- /* if running on an amiga, make the NMI interrupt do nothing */
- if (MACH_IS_AMIGA) {
- vectors[VEC_INT7] = nmihandler;
- }
+ __asm__ volatile ("movec %0,%%vbr" : : "r" ((void*)vectors));
if (CPU_IS_040) {
/* set up FPSP entry points */
@@ -134,6 +122,23 @@ __initfunc(void trap_init (void))
}
}
+__initfunc(void trap_init (void))
+{
+ int i;
+
+ for (i = 48; i < 64; i++)
+ if (!vectors[i])
+ vectors[i] = trap;
+
+ for (i = 64; i < 256; i++)
+ vectors[i] = inthandler;
+
+ /* if running on an amiga, make the NMI interrupt do nothing */
+ if (MACH_IS_AMIGA) {
+ vectors[VEC_INT7] = nmihandler;
+ }
+}
+
void set_evector(int vecnum, void (*handler)(void))
{
if (vecnum >= 0 && vecnum <= 256)
@@ -202,7 +207,7 @@ static inline void access_error060 (struct frame *fp)
return;
}
- if (fslw & (MMU060_DESC_ERR | MMU060_WP)) {
+ if (fslw & (MMU060_DESC_ERR | MMU060_WP | MMU060_SP)) {
unsigned long errorcode;
unsigned long addr = fp->un.fmt4.effaddr;
errorcode = ((fslw & MMU060_WP) ? 1 : 0) |
@@ -230,9 +235,9 @@ static inline void access_error060 (struct frame *fp)
static inline unsigned long probe040 (int iswrite, int fc, unsigned long addr)
{
unsigned long mmusr;
- unsigned long fs = get_fs();
+ mm_segment_t fs = get_fs();
- set_fs (fc);
+ set_fs (MAKE_MM_SEG(fc));
if (iswrite)
/* write */
@@ -261,7 +266,7 @@ static inline void do_040writeback (unsigned short ssw,
unsigned long wbd,
struct frame *fp)
{
- unsigned long fs = get_fs ();
+ mm_segment_t fs = get_fs ();
unsigned long mmusr;
unsigned long errorcode;
@@ -277,7 +282,7 @@ static inline void do_040writeback (unsigned short ssw,
/* just return if we can't perform the writeback */
return;
- set_fs (wbs & WBTM_040);
+ set_fs (MAKE_MM_SEG(wbs & WBTM_040));
switch (wbs & WBSIZ_040) {
case BA_SIZE_BYTE:
put_user (wbd & 0xff, (char *)wba);
@@ -833,34 +838,37 @@ void bad_super_trap (struct frame *fp)
asmlinkage void trap_c(struct frame *fp)
{
int sig;
+ siginfo_t info;
- if ((fp->ptregs.sr & PS_S)
- && ((fp->ptregs.vector) >> 2) == VEC_TRACE
- && !(fp->ptregs.sr & PS_T)) {
- /* traced a trapping instruction */
- unsigned char *lp = ((unsigned char *)&fp->un.fmt2) + 4;
- current->flags |= PF_DTRACE;
- /* clear the trace bit */
- (*(unsigned short *)lp) &= ~PS_T;
- return;
- } else if (fp->ptregs.sr & PS_S) {
- bad_super_trap(fp);
+ if (fp->ptregs.sr & PS_S) {
+ if ((fp->ptregs.vector >> 2) == VEC_TRACE) {
+ /* traced a trapping instruction */
+ current->flags |= PF_DTRACE;
+ } else
+ bad_super_trap(fp);
return;
}
/* send the appropriate signal to the user program */
switch ((fp->ptregs.vector) >> 2) {
case VEC_ADDRERR:
+ info.si_code = BUS_ADRALN;
sig = SIGBUS;
break;
- case VEC_BUSERR:
- sig = SIGSEGV;
- break;
case VEC_ILLEGAL:
- case VEC_PRIV:
case VEC_LINE10:
case VEC_LINE11:
+ info.si_code = ILL_ILLOPC;
+ sig = SIGILL;
+ break;
+ case VEC_PRIV:
+ info.si_code = ILL_PRVOPC;
+ sig = SIGILL;
+ break;
case VEC_COPROC:
+ info.si_code = ILL_COPROC;
+ sig = SIGILL;
+ break;
case VEC_TRAP1:
case VEC_TRAP2:
case VEC_TRAP3:
@@ -875,51 +883,76 @@ asmlinkage void trap_c(struct frame *fp)
case VEC_TRAP12:
case VEC_TRAP13:
case VEC_TRAP14:
+ info.si_code = ILL_ILLTRP;
sig = SIGILL;
break;
case VEC_FPBRUC:
+ case VEC_FPOE:
+ case VEC_FPNAN:
+ info.si_code = FPE_FLTINV;
+ sig = SIGFPE;
+ break;
case VEC_FPIR:
+ info.si_code = FPE_FLTRES;
+ sig = SIGFPE;
+ break;
case VEC_FPDIVZ:
+ info.si_code = FPE_FLTDIV;
+ sig = SIGFPE;
+ break;
case VEC_FPUNDER:
- case VEC_FPOE:
+ info.si_code = FPE_FLTUND;
+ sig = SIGFPE;
+ break;
case VEC_FPOVER:
- case VEC_FPNAN:
- {
- unsigned char fstate[FPSTATESIZE];
-
- __asm__ __volatile__ (".chip 68k/68881\n\t"
- "fsave %0@\n\t"
- ".chip 68k" : : "a" (fstate) : "memory");
- /* Set the exception pending bit in the 68882 idle frame */
- if (*(unsigned short *) fstate == 0x1f38)
- {
- fstate[fstate[1]] |= 1 << 3;
- __asm__ __volatile__ (".chip 68k/68881\n\t"
- "frestore %0@\n\t"
- ".chip 68k" : : "a" (fstate));
- }
- }
- /* fall through */
+ info.si_code = FPE_FLTOVF;
+ sig = SIGFPE;
+ break;
case VEC_ZERODIV:
+ info.si_code = FPE_INTDIV;
+ sig = SIGFPE;
+ break;
+ case VEC_CHK:
case VEC_TRAP:
+ info.si_code = FPE_INTOVF;
sig = SIGFPE;
break;
case VEC_TRACE: /* ptrace single step */
- fp->ptregs.sr &= ~PS_T;
+ info.si_code = TRAP_TRACE;
+ sig = SIGTRAP;
+ break;
case VEC_TRAP15: /* breakpoint */
+ info.si_code = TRAP_BRKPT;
sig = SIGTRAP;
break;
default:
+ info.si_code = ILL_ILLOPC;
sig = SIGILL;
break;
}
-
- send_sig (sig, current, 1);
-}
-
-asmlinkage void set_esp0 (unsigned long ssp)
-{
- current->tss.esp0 = ssp;
+ info.si_signo = sig;
+ info.si_errno = 0;
+ switch (fp->ptregs.format) {
+ default:
+ info.si_addr = (void *) fp->ptregs.pc;
+ break;
+ case 2:
+ info.si_addr = (void *) fp->un.fmt2.iaddr;
+ break;
+ case 7:
+ info.si_addr = (void *) fp->un.fmt7.effaddr;
+ break;
+ case 9:
+ info.si_addr = (void *) fp->un.fmt9.iaddr;
+ break;
+ case 10:
+ info.si_addr = (void *) fp->un.fmta.daddr;
+ break;
+ case 11:
+ info.si_addr = (void *) fp->un.fmtb.daddr;
+ break;
+ }
+ force_sig_info (sig, &info, current);
}
void die_if_kernel (char *str, struct pt_regs *fp, int nr)