diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1998-03-17 22:05:47 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1998-03-17 22:05:47 +0000 |
commit | 27cfca1ec98e91261b1a5355d10a8996464b63af (patch) | |
tree | 8e895a53e372fa682b4c0a585b9377d67ed70d0e /arch/m68k/kernel | |
parent | 6a76fb7214c477ccf6582bd79c5b4ccc4f9c41b1 (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/Makefile | 17 | ||||
-rw-r--r-- | arch/m68k/kernel/bios32.c | 580 | ||||
-rw-r--r-- | arch/m68k/kernel/console.c | 2748 | ||||
-rw-r--r-- | arch/m68k/kernel/entry.S | 86 | ||||
-rw-r--r-- | arch/m68k/kernel/head.S | 150 | ||||
-rw-r--r-- | arch/m68k/kernel/ints.c | 6 | ||||
-rw-r--r-- | arch/m68k/kernel/m68k_defs.c | 23 | ||||
-rw-r--r-- | arch/m68k/kernel/m68k_ksyms.c | 7 | ||||
-rw-r--r-- | arch/m68k/kernel/process.c | 26 | ||||
-rw-r--r-- | arch/m68k/kernel/ptrace.c | 68 | ||||
-rw-r--r-- | arch/m68k/kernel/setup.c | 90 | ||||
-rw-r--r-- | arch/m68k/kernel/signal.c | 971 | ||||
-rw-r--r-- | arch/m68k/kernel/sys_m68k.c | 26 | ||||
-rw-r--r-- | arch/m68k/kernel/time.c | 27 | ||||
-rw-r--r-- | arch/m68k/kernel/traps.c | 155 |
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(¤t->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(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + sigaddset(¤t->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 = ¤t->blocked; + + for (;;) { + int signr; + + signr = dequeue_signal(¤t->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(¤t->blocked, signr)) { + send_sig_info(signr, &info, current); continue; } - sa = current->sig->action + signr - 1; } - if (sa->sa_handler == SIG_IGN) { + + ka = ¤t->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(¤t->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) |