summaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1994-12-01 08:00:00 +0000
committer <ralf@linux-mips.org>1994-12-01 08:00:00 +0000
commit90ecc248e200fee448001248dde0ca540dd3ef64 (patch)
treea3fe89494ce63b4835f0f9cf5c45e74cde88252b /kernel
parent1513ff9b7899ab588401c89db0e99903dbf5f886 (diff)
Import of Linux/MIPS 1.1.68
Diffstat (limited to 'kernel')
-rw-r--r--kernel/Makefile4
-rw-r--r--kernel/bios32.c476
-rw-r--r--kernel/dma.c9
-rw-r--r--kernel/exit.c2
-rw-r--r--kernel/fork.c159
-rw-r--r--kernel/ioport.c194
-rw-r--r--kernel/irq.c354
-rw-r--r--kernel/ksyms.c2
-rw-r--r--kernel/ldt.c103
-rw-r--r--kernel/ptrace.c517
-rw-r--r--kernel/sched.c861
-rw-r--r--kernel/signal.c407
-rw-r--r--kernel/splx.c27
-rw-r--r--kernel/sys.c11
-rw-r--r--kernel/time.c2
-rw-r--r--kernel/traps.c245
-rw-r--r--kernel/vm86.c404
17 files changed, 145 insertions, 3632 deletions
diff --git a/kernel/Makefile b/kernel/Makefile
index 6de499ca7..99ced21ae 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -12,14 +12,14 @@
.c.s:
$(CC) $(CFLAGS) -S $<
.s.o:
- $(AS) -o $*.o $<
+ $(AS) $(ASFLAGS) -o $*.o $<
.c.o:
$(CC) $(CFLAGS) -c $<
OBJS = sched.o entry.o traps.o irq.o dma.o fork.o exec_domain.o \
panic.o printk.o vsprintf.o sys.o module.o ksyms.o exit.o \
signal.o ptrace.o ioport.o itimer.o \
- info.o ldt.o time.o tqueue.o vm86.o bios32.o splx.o
+ info.o ldt.o time.o tqueue.o vm86.o bios32.o splx.o dummy.o
all: kernel.o
diff --git a/kernel/bios32.c b/kernel/bios32.c
deleted file mode 100644
index 311dd111e..000000000
--- a/kernel/bios32.c
+++ /dev/null
@@ -1,476 +0,0 @@
-/*
- * bios32.c - BIOS32, PCI BIOS functions.
- *
- * Sponsored by
- * iX Multiuser Multitasking Magazine
- * Hannover, Germany
- * hm@ix.de
- *
- * Copyright 1993, 1994 Drew Eckhardt
- * Visionary Computing
- * (Unix and Linux consulting and custom programming)
- * Drew@Colorado.EDU
- * +1 (303) 786-7975
- *
- * For more information, please consult
- *
- * PCI BIOS Specification Revision
- * PCI Local Bus Specification
- * PCI System Design Guide
- *
- * PCI Special Interest Group
- * M/S HF3-15A
- * 5200 N.E. Elam Young Parkway
- * Hillsboro, Oregon 97124-6497
- * +1 (503) 696-2000
- * +1 (800) 433-5177
- *
- * Manuals are $25 each or $50 for all three, plus $7 shipping
- * within the United States, $35 abroad.
- *
- *
- * CHANGELOG :
- * Jun 17, 1994 : Modified to accommodate the broken pre-PCI BIOS SPECIFICATION
- * Revision 2.0 present on <thys@dennis.ee.up.ac.za>'s ASUS mainboard.
- */
-
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/bios32.h>
-#include <linux/pci.h>
-
-#include <asm/segment.h>
-
-/*
- * It would seem some PCI bioses are buggy, so we don't actually use these
- * routines unless we need to..
- */
-#ifdef CONFIG_SCSI_NCR53C7xx
- #define CONFIG_PCI
-#else
- #undef CONFIG_PCI
-#endif
-
-#define PCIBIOS_PCI_FUNCTION_ID 0xb1XX
-#define PCIBIOS_PCI_BIOS_PRESENT 0xb101
-#define PCIBIOS_FIND_PCI_DEVICE 0xb102
-#define PCIBIOS_FIND_PCI_CLASS_CODE 0xb103
-#define PCIBIOS_GENERATE_SPECIAL_CYCLE 0xb106
-#define PCIBIOS_READ_CONFIG_BYTE 0xb108
-#define PCIBIOS_READ_CONFIG_WORD 0xb109
-#define PCIBIOS_READ_CONFIG_DWORD 0xb10a
-#define PCIBIOS_WRITE_CONFIG_BYTE 0xb10b
-#define PCIBIOS_WRITE_CONFIG_WORD 0xb10c
-#define PCIBIOS_WRITE_CONFIG_DWORD 0xb10d
-
-/* BIOS32 signature: "_32_" */
-#define BIOS32_SIGNATURE (('_' << 0) + ('3' << 8) + ('2' << 16) + ('_' << 24))
-
-/* PCI signature: "PCI " */
-#define PCI_SIGNATURE (('P' << 0) + ('C' << 8) + ('I' << 16) + (' ' << 24))
-
-/* PCI service signature: "$PCI" */
-#define PCI_SERVICE (('$' << 0) + ('P' << 8) + ('C' << 16) + ('I' << 24))
-
-/*
- * This is the standard structure used to identify the entry point
- * to the BIOS32 Service Directory, as documented in
- * Standard BIOS 32-bit Service Directory Proposal
- * Revision 0.4 May 24, 1993
- * Phoenix Technologies Ltd.
- * Norwood, MA
- * and the PCI BIOS specification.
- */
-
-union bios32 {
- struct {
- unsigned long signature; /* _32_ */
- unsigned long entry; /* 32 bit physical address */
- unsigned char revision; /* Revision level, 0 */
- unsigned char length; /* Length in paragraphs should be 01 */
- unsigned char checksum; /* All bytes must add up to zero */
- unsigned char reserved[5]; /* Must be zero */
- } fields;
- char chars[16];
-};
-
-/*
- * Physical address of the service directory. I don't know if we're
- * allowed to have more than one of these or not, so just in case
- * we'll make bios32_init() take a memory start parameter and store
- * the array there.
- */
-
-static unsigned long bios32_entry = 0;
-static struct {
- unsigned long address;
- unsigned short segment;
-} bios32_indirect = { 0, KERNEL_CS };
-
-#ifdef CONFIG_PCI
-/*
- * Returns the entry point for the given service, NULL on error
- */
-
-static unsigned long bios32_service(unsigned long service)
-{
- unsigned char return_code; /* %al */
- unsigned long address; /* %ebx */
- unsigned long length; /* %ecx */
- unsigned long entry; /* %edx */
-
- __asm__("lcall (%%edi)"
- : "=a" (return_code),
- "=b" (address),
- "=c" (length),
- "=d" (entry)
- : "0" (service),
- "1" (0),
- "D" (&bios32_indirect));
-
- switch (return_code) {
- case 0:
- return address + entry;
- case 0x80: /* Not present */
- printk("bios32_service(%ld) : not present\n", service);
- return 0;
- default: /* Shouldn't happen */
- printk("bios32_service(%ld) : returned 0x%x, mail drew@colorado.edu\n",
- service, return_code);
- return 0;
- }
-}
-
-static long pcibios_entry = 0;
-static struct {
- unsigned long address;
- unsigned short segment;
-} pci_indirect = { 0, KERNEL_CS };
-
-void NCR53c810_test(void);
-
-static unsigned long pcibios_init(unsigned long memory_start, unsigned long memory_end)
-{
- unsigned long signature;
- unsigned char present_status;
- unsigned char major_revision;
- unsigned char minor_revision;
- int pack;
-
- if ((pcibios_entry = bios32_service(PCI_SERVICE))) {
- pci_indirect.address = pcibios_entry;
-
- __asm__("lcall (%%edi)\n\t"
- "jc 1f\n\t"
- "xor %%ah, %%ah\n"
- "1:\tshl $8, %%eax\n\t"
- "movw %%bx, %%ax"
- : "=d" (signature),
- "=a" (pack)
- : "1" (PCIBIOS_PCI_BIOS_PRESENT),
- "D" (&pci_indirect)
- : "bx", "cx");
-
- present_status = (pack >> 16) & 0xff;
- major_revision = (pack >> 8) & 0xff;
- minor_revision = pack & 0xff;
- if (present_status || (signature != PCI_SIGNATURE)) {
- printk ("pcibios_init : %s : BIOS32 Service Directory says PCI BIOS is present,\n"
- " but PCI_BIOS_PRESENT subfunction fails with present status of 0x%x\n"
- " and signature of 0x%08lx (%c%c%c%c). mail drew@Colorado.EDU\n",
- (signature == PCI_SIGNATURE) ? "WARNING" : "ERROR",
- present_status, signature,
- (char) (signature >> 0), (char) (signature >> 8),
- (char) (signature >> 16), (char) (signature >> 24));
-
- if (signature != PCI_SIGNATURE)
- pcibios_entry = 0;
- }
- if (pcibios_entry) {
- printk ("pcibios_init : PCI BIOS revision %x.%02x entry at 0x%lx\n",
- major_revision, minor_revision, pcibios_entry);
- }
- }
-
-#if 0
- NCR53c810_test();
-#endif
- return memory_start;
-}
-
-int pcibios_present(void)
-{
- return pcibios_entry ? 1 : 0;
-}
-
-int pcibios_find_class_code (unsigned long class_code, unsigned short index,
- unsigned char *bus, unsigned char *device_fn)
-{
- unsigned long bx;
- unsigned long ret;
-
- __asm__ ("lcall (%%edi)\n\t"
- "jc 1f\n\t"
- "xor %%ah, %%ah\n"
- "1:"
- : "=b" (bx),
- "=a" (ret)
- : "1" (PCIBIOS_FIND_PCI_CLASS_CODE),
- "c" (class_code),
- "S" ((int) index),
- "D" (&pci_indirect));
- *bus = (bx >> 8) & 0xff;
- *device_fn = bx & 0xff;
- return (int) (ret & 0xff00) >> 8;
-}
-
-
-int pcibios_find_device (unsigned short vendor, unsigned short device_id,
- unsigned short index, unsigned char *bus, unsigned char *device_fn)
-{
- unsigned short bx;
- unsigned short ret;
-
- __asm__("lcall (%%edi)\n\t"
- "jc 1f\n\t"
- "xor %%ah, %%ah\n"
- "1:"
- : "=b" (bx),
- "=a" (ret)
- : "1" (PCIBIOS_FIND_PCI_DEVICE),
- "c" (device_id),
- "d" (vendor),
- "S" ((int) index),
- "D" (&pci_indirect));
- *bus = (bx >> 8) & 0xff;
- *device_fn = bx & 0xff;
- return (int) (ret & 0xff00) >> 8;
-}
-
-int pcibios_read_config_byte(unsigned char bus,
- unsigned char device_fn, unsigned char where, unsigned char *value)
-{
- unsigned long ret;
- unsigned long bx = (bus << 8) | device_fn;
-
- __asm__("lcall (%%esi)\n\t"
- "jc 1f\n\t"
- "xor %%ah, %%ah\n"
- "1:"
- : "=c" (*value),
- "=a" (ret)
- : "1" (PCIBIOS_READ_CONFIG_BYTE),
- "b" (bx),
- "D" ((long) where),
- "S" (&pci_indirect));
- return (int) (ret & 0xff00) >> 8;
-}
-
-int pcibios_read_config_word (unsigned char bus,
- unsigned char device_fn, unsigned char where, unsigned short *value)
-{
- unsigned long ret;
- unsigned long bx = (bus << 8) | device_fn;
-
- __asm__("lcall (%%esi)\n\t"
- "jc 1f\n\t"
- "xor %%ah, %%ah\n"
- "1:"
- : "=c" (*value),
- "=a" (ret)
- : "1" (PCIBIOS_READ_CONFIG_WORD),
- "b" (bx),
- "D" ((long) where),
- "S" (&pci_indirect));
- return (int) (ret & 0xff00) >> 8;
-}
-
-int pcibios_read_config_dword (unsigned char bus,
- unsigned char device_fn, unsigned char where, unsigned long *value)
-{
- unsigned long ret;
- unsigned long bx = (bus << 8) | device_fn;
-
- __asm__("lcall (%%esi)\n\t"
- "jc 1f\n\t"
- "xor %%ah, %%ah\n"
- "1:"
- : "=c" (*value),
- "=a" (ret)
- : "1" (PCIBIOS_READ_CONFIG_DWORD),
- "b" (bx),
- "D" ((long) where),
- "S" (&pci_indirect));
- return (int) (ret & 0xff00) >> 8;
-}
-
-int pcibios_write_config_byte (unsigned char bus,
- unsigned char device_fn, unsigned char where, unsigned char value)
-{
- unsigned long ret;
- unsigned long bx = (bus << 8) | device_fn;
-
- __asm__("lcall (%%esi)\n\t"
- "jc 1f\n\t"
- "xor %%ah, %%ah\n"
- "1:"
- : "=a" (ret)
- : "0" (PCIBIOS_WRITE_CONFIG_BYTE),
- "c" (value),
- "b" (bx),
- "D" ((long) where),
- "S" (&pci_indirect));
- return (int) (ret & 0xff00) >> 8;
-}
-
-int pcibios_write_config_word (unsigned char bus,
- unsigned char device_fn, unsigned char where, unsigned short value)
-{
- unsigned long ret;
- unsigned long bx = (bus << 8) | device_fn;
-
- __asm__("lcall (%%esi)\n\t"
- "jc 1f\n\t"
- "xor %%ah, %%ah\n"
- "1:"
- : "=a" (ret)
- : "0" (PCIBIOS_WRITE_CONFIG_WORD),
- "c" (value),
- "b" (bx),
- "D" ((long) where),
- "S" (&pci_indirect));
- return (int) (ret & 0xff00) >> 8;
-}
-
-int pcibios_write_config_dword (unsigned char bus,
- unsigned char device_fn, unsigned char where, unsigned long value)
-{
- unsigned long ret;
- unsigned long bx = (bus << 8) | device_fn;
-
- __asm__("lcall (%%esi)\n\t"
- "jc 1f\n\t"
- "xor %%ah, %%ah\n"
- "1:"
- : "=a" (ret)
- : "0" (PCIBIOS_WRITE_CONFIG_DWORD),
- "c" (value),
- "b" (bx),
- "D" ((long) where),
- "S" (&pci_indirect));
- return (int) (ret & 0xff00) >> 8;
-}
-
-void NCR53c810_test(void)
-{
- unsigned char bus, device_fn;
- unsigned short index;
- int ret;
- unsigned char row, col;
- unsigned long val;
-
- for (index = 0; index < 4; ++index) {
- ret = pcibios_find_device (
- (unsigned short) PCI_VENDOR_ID_NCR,
- (unsigned short) PCI_DEVICE_ID_NCR_53C810,
- index, &bus, &device_fn);
- if (ret)
- break;
- printk ("ncr53c810 : at PCI bus %d, device %d, function %d.",
- bus, ((device_fn & 0xf8) >> 3), (device_fn & 7));
- for (row = 0; row < 0x3c; row += 0x10) {
- printk ("\n reg 0x%02x ", row);
- for (col = 0; col < 0x10; col += 4) {
- if (!(ret = pcibios_read_config_dword (bus, device_fn, row+col, &val)))
- printk ("0x%08lx ", val);
- else
- printk ("error 0x%02x ", ret);
- }
- }
- printk ("\n");
- }
-}
-
-char *pcibios_strerror (int error)
-{
- static char buf[80];
-
- switch (error) {
- case PCIBIOS_SUCCESSFUL:
- return "SUCCESSFUL";
-
- case PCIBIOS_FUNC_NOT_SUPPORTED:
- return "FUNC_NOT_SUPPORTED";
-
- case PCIBIOS_BAD_VENDOR_ID:
- return "SUCCESSFUL";
-
- case PCIBIOS_DEVICE_NOT_FOUND:
- return "DEVICE_NOT_FOUND";
-
- case PCIBIOS_BAD_REGISTER_NUMBER:
- return "BAD_REGISTER_NUMBER";
-
- default:
- sprintf (buf, "UNKNOWN RETURN 0x%x", error);
- return buf;
- }
-}
-
-#endif
-
-unsigned long bios32_init(unsigned long memory_start, unsigned long memory_end)
-{
- union bios32 *check;
- unsigned char sum;
- int i, length;
-
- /*
- * Follow the standard procedure for locating the BIOS32 Service
- * directory by scanning the permissible address range from
- * 0xe0000 through 0xfffff for a valid BIOS32 structure.
- *
- * The PCI BIOS doesn't seem to work too well on many machines,
- * so we disable this unless it's really needed (NCR SCSI driver)
- */
-
- for (check = (union bios32 *) 0xe0000; check <= (union bios32 *) 0xffff0; ++check) {
- if (check->fields.signature != BIOS32_SIGNATURE)
- continue;
- length = check->fields.length * 16;
- if (!length)
- continue;
- sum = 0;
- for (i = 0; i < length ; ++i)
- sum += check->chars[i];
- if (sum != 0)
- continue;
- if (check->fields.revision != 0) {
- printk("bios32_init : unsupported revision %d at 0x%p, mail drew@colorado.edu\n",
- check->fields.revision, check);
- continue;
- }
- printk ("bios32_init : BIOS32 Service Directory structure at 0x%p\n", check);
- if (!bios32_entry) {
- bios32_indirect.address = bios32_entry = check->fields.entry;
- printk ("bios32_init : BIOS32 Service Directory entry at 0x%lx\n", bios32_entry);
- } else {
- printk ("bios32_init : multiple entries, mail drew@colorado.edu\n");
- /*
- * Jeremy Fitzhardinge reports at least one PCI BIOS
- * with two different service directories, and as both
- * worked for him, we'll just mention the fact, and
- * not actually disallow it..
- */
-#if 0
- return memory_start;
-#endif
- }
- }
-#ifdef CONFIG_PCI
- if (bios32_entry) {
- memory_start = pcibios_init (memory_start, memory_end);
- }
-#endif
- return memory_start;
-}
diff --git a/kernel/dma.c b/kernel/dma.c
index ce80c2fa6..799439ed6 100644
--- a/kernel/dma.c
+++ b/kernel/dma.c
@@ -5,6 +5,7 @@
#include <linux/kernel.h>
#include <linux/errno.h>
+#include <asm/system.h>
#include <asm/dma.h>
@@ -62,10 +63,18 @@ static __inline__ unsigned int mutex_atomic_swap(volatile unsigned int * p, unsi
* the swap may not be atomic.
*/
+#if 0
asm __volatile__ ("xchgl %2, %0\n"
: /* outputs: semval */ "=r" (semval)
: /* inputs: newval, p */ "0" (semval), "m" (*p)
); /* p is a var, containing an address */
+#else
+ /*
+ * RB: Try atomic exchange from include/asm/system.h
+ * This should be portable...
+ */
+ atomic_exchange(p,semval)
+#endif
return semval;
} /* mutex_atomic_swap */
diff --git a/kernel/exit.c b/kernel/exit.c
index b2a8c4fb0..3a48c5c23 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -370,6 +370,7 @@ static void exit_mm(void)
mpnt = next;
}
+#ifdef __i386__
/* forget local segments */
__asm__ __volatile__("mov %w0,%%fs ; mov %w0,%%gs ; lldt %w0"
: /* no outputs */
@@ -380,6 +381,7 @@ static void exit_mm(void)
current->ldt = NULL;
vfree(ldt);
}
+#endif
free_page_tables(current);
}
diff --git a/kernel/fork.c b/kernel/fork.c
index 63a54e999..ceb6e09c1 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -157,7 +157,101 @@ static void copy_fs(unsigned long clone_flags, struct task_struct * p)
current->fs->root->i_count++;
}
-#define IS_CLONE (regs.orig_eax == __NR_clone)
+/*
+ * FIXME: This functions shouldn't be in this file
+ */
+#if defined (__i386__)
+
+#define IS_CLONE (regs->orig_eax == __NR_clone)
+
+static unsigned long
+arch_clone(struct task_struct *p, int nr, unsigned long clone_flags
+ struct pt_regs *regs)
+{
+ struct pt_regs * childregs;
+ int i;
+
+ /*
+ * set up new TSS
+ */
+ p->tss.es = KERNEL_DS;
+ p->tss.cs = KERNEL_CS;
+ p->tss.ss = KERNEL_DS;
+ p->tss.ds = KERNEL_DS;
+ p->tss.fs = USER_DS;
+ p->tss.gs = KERNEL_DS;
+ p->tss.ss0 = KERNEL_DS;
+ p->tss.esp0 = p->kernel_stack_page + PAGE_SIZE;
+ p->tss.tr = _TSS(nr);
+ childregs = ((struct pt_regs *) (p->kernel_stack_page + PAGE_SIZE)) - 1;
+ p->tss.esp = (unsigned long) childregs;
+ p->tss.eip = (unsigned long) ret_from_sys_call;
+ *childregs = *regs;
+ childregs->eax = 0;
+ p->tss.back_link = 0;
+ /*
+ * iopl is always 0 for a new process
+ */
+ p->tss.eflags = regs->eflags & 0xffffcfff;
+ if (IS_CLONE) {
+ if (regs->ebx)
+ childregs->esp = regs->ebx;
+ clone_flags = regs->ecx;
+ if (childregs->esp == regs->esp)
+ clone_flags |= COPYVM;
+ }
+ p->tss.ldt = _LDT(nr);
+ if (p->ldt) {
+ p->ldt = (struct desc_struct*) vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE);
+ if (p->ldt != NULL)
+ memcpy(p->ldt, current->ldt, LDT_ENTRIES*LDT_ENTRY_SIZE);
+ }
+ p->tss.bitmap = offsetof(struct tss_struct,io_bitmap);
+ for (i = 0; i < IO_BITMAP_SIZE+1 ; i++) /* IO bitmap is actually SIZE+1 */
+ p->tss.io_bitmap[i] = ~0;
+ if (last_task_used_math == current)
+ __asm__("clts ; fnsave %0 ; frstor %0":"=m" (p->tss.i387));
+
+ return clone_flags;
+}
+#elif defined (__mips__)
+
+#include <asm/mipsregs.h>
+
+#define IS_CLONE (regs->orig_reg2 == __NR_clone)
+
+static unsigned long
+arch_clone(struct task_struct *p, int nr, unsigned long clone_flags,
+ struct pt_regs *regs)
+{
+ struct pt_regs * childregs;
+
+ /*
+ * set up new TSS
+ */
+ p->tss.fs = KERNEL_DS;
+ p->tss.ksp = p->kernel_stack_page + PAGE_SIZE;
+ childregs = ((struct pt_regs *) (p->kernel_stack_page + PAGE_SIZE)) - 1;
+ p->tss.reg29 = (unsigned long) childregs; /* new sp */
+ p->tss.cp0_epc = (unsigned long) ret_from_sys_call;
+ *childregs = *regs;
+ childregs->reg1 = 0;
+ /*
+ * New tasks loose permission to use the fpa. This accelerates task
+ * switching for non fp programms, which true for the most programms.
+ */
+ p->tss.cp0_status = regs->cp0_status & ~ST0_CU0;
+ if (IS_CLONE) {
+ if (regs->reg2)
+ childregs->reg29 = regs->reg2;
+ clone_flags = regs->reg3;
+ if (childregs->reg29 == regs->reg29)
+ clone_flags |= COPYVM;
+ }
+
+ return clone_flags;
+}
+#endif
/*
* Ok, this is the main fork-routine. It copies the system process
@@ -166,11 +260,13 @@ static void copy_fs(unsigned long clone_flags, struct task_struct * p)
*/
asmlinkage int sys_fork(struct pt_regs regs)
{
- struct pt_regs * childregs;
struct task_struct *p;
- int i,nr;
+ int nr;
unsigned long clone_flags = COPYVM | SIGCHLD;
+ /*
+ * Clone the machine independend part of every process
+ */
if(!(p = (struct task_struct*)__get_free_page(GFP_KERNEL)))
goto bad_fork;
nr = find_empty_process();
@@ -199,58 +295,38 @@ asmlinkage int sys_fork(struct pt_regs regs)
p->utime = p->stime = 0;
p->cutime = p->cstime = 0;
p->start_time = jiffies;
-/*
- * set up new TSS and kernel stack
- */
+
+ /*
+ * set up new kernel stack
+ */
if (!(p->kernel_stack_page = get_free_page(GFP_KERNEL)))
goto bad_fork_cleanup;
*(unsigned long *)p->kernel_stack_page = STACK_MAGIC;
- p->tss.es = KERNEL_DS;
- p->tss.cs = KERNEL_CS;
- p->tss.ss = KERNEL_DS;
- p->tss.ds = KERNEL_DS;
- p->tss.fs = USER_DS;
- p->tss.gs = KERNEL_DS;
- p->tss.ss0 = KERNEL_DS;
- p->tss.esp0 = p->kernel_stack_page + PAGE_SIZE;
- p->tss.tr = _TSS(nr);
- childregs = ((struct pt_regs *) (p->kernel_stack_page + PAGE_SIZE)) - 1;
- p->tss.esp = (unsigned long) childregs;
- p->tss.eip = (unsigned long) ret_from_sys_call;
- *childregs = regs;
- childregs->eax = 0;
- p->tss.back_link = 0;
- p->tss.eflags = regs.eflags & 0xffffcfff; /* iopl is always 0 for a new process */
- if (IS_CLONE) {
- if (regs.ebx)
- childregs->esp = regs.ebx;
- clone_flags = regs.ecx;
- if (childregs->esp == regs.esp)
- clone_flags |= COPYVM;
- }
- p->exit_signal = clone_flags & CSIGNAL;
- p->tss.ldt = _LDT(nr);
- if (p->ldt) {
- p->ldt = (struct desc_struct*) vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE);
- if (p->ldt != NULL)
- memcpy(p->ldt, current->ldt, LDT_ENTRIES*LDT_ENTRY_SIZE);
- }
- p->tss.bitmap = offsetof(struct tss_struct,io_bitmap);
- for (i = 0; i < IO_BITMAP_SIZE+1 ; i++) /* IO bitmap is actually SIZE+1 */
- p->tss.io_bitmap[i] = ~0;
- if (last_task_used_math == current)
- __asm__("clts ; fnsave %0 ; frstor %0":"=m" (p->tss.i387));
+
+ /*
+ * And now let's do the processor dependend things...
+ */
+
+ clone_flags = arch_clone(p, nr, clone_flags, &regs);
+
if (copy_mm(clone_flags, p))
goto bad_fork_cleanup;
p->semundo = NULL;
copy_files(clone_flags, p);
copy_fs(clone_flags, p);
+
+#if defined (__i386__)
+ /*
+ * May I move this into arch_clone without trouble, Linus???
+ */
set_tss_desc(gdt+(nr<<1)+FIRST_TSS_ENTRY,&(p->tss));
if (p->ldt)
set_ldt_desc(gdt+(nr<<1)+FIRST_LDT_ENTRY,p->ldt, 512);
else
set_ldt_desc(gdt+(nr<<1)+FIRST_LDT_ENTRY,&default_ldt, 1);
+#endif
+ p->exit_signal = clone_flags & CSIGNAL;
p->counter = current->counter >> 1;
p->state = TASK_RUNNING; /* do this last, just in case */
return p->pid;
@@ -263,3 +339,4 @@ bad_fork_free:
bad_fork:
return -EAGAIN;
}
+
diff --git a/kernel/ioport.c b/kernel/ioport.c
deleted file mode 100644
index c61690e3c..000000000
--- a/kernel/ioport.c
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- * linux/kernel/ioport.c
- *
- * This contains the io-permission bitmap code - written by obz, with changes
- * by Linus.
- */
-
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/types.h>
-#include <linux/ioport.h>
-
-static unsigned long ioport_registrar[IO_BITMAP_SIZE] = {0, /* ... */};
-
-#define _IODEBUG
-
-#ifdef IODEBUG
-static char * ios(unsigned long l)
-{
- static char str[33] = { '\0' };
- int i;
- unsigned long mask;
-
- for (i = 0, mask = 0x80000000; i < 32; ++i, mask >>= 1)
- str[i] = (l & mask) ? '1' : '0';
- return str;
-}
-
-static void dump_io_bitmap(void)
-{
- int i, j;
- int numl = sizeof(current->tss.io_bitmap) >> 2;
-
- for (i = j = 0; j < numl; ++i)
- {
- printk("%4d [%3x]: ", 64*i, 64*i);
- printk("%s ", ios(current->tss.io_bitmap[j++]));
- if (j < numl)
- printk("%s", ios(current->tss.io_bitmap[j++]));
- printk("\n");
- }
-}
-#endif
-
-/* Set EXTENT bits starting at BASE in BITMAP to value TURN_ON. */
-asmlinkage void set_bitmap(unsigned long *bitmap,
- short base, short extent, int new_value)
-{
- int mask;
- unsigned long *bitmap_base = bitmap + (base >> 5);
- unsigned short low_index = base & 0x1f;
- int length = low_index + extent;
-
- if (low_index != 0) {
- mask = (~0 << low_index);
- if (length < 32)
- mask &= ~(~0 << length);
- if (new_value)
- *bitmap_base++ |= mask;
- else
- *bitmap_base++ &= ~mask;
- length -= 32;
- }
-
- mask = (new_value ? ~0 : 0);
- while (length >= 32) {
- *bitmap_base++ = mask;
- length -= 32;
- }
-
- if (length > 0) {
- mask = ~(~0 << length);
- if (new_value)
- *bitmap_base++ |= mask;
- else
- *bitmap_base++ &= ~mask;
- }
-}
-
-/* Check for set bits in BITMAP starting at BASE, going to EXTENT. */
-asmlinkage int check_bitmap(unsigned long *bitmap, short base, short extent)
-{
- int mask;
- unsigned long *bitmap_base = bitmap + (base >> 5);
- unsigned short low_index = base & 0x1f;
- int length = low_index + extent;
-
- if (low_index != 0) {
- mask = (~0 << low_index);
- if (length < 32)
- mask &= ~(~0 << length);
- if (*bitmap_base++ & mask)
- return 1;
- length -= 32;
- }
- while (length >= 32) {
- if (*bitmap_base++ != 0)
- return 1;
- length -= 32;
- }
-
- if (length > 0) {
- mask = ~(~0 << length);
- if (*bitmap_base++ & mask)
- return 1;
- }
- return 0;
-}
-
-/*
- * this changes the io permissions bitmap in the current task.
- */
-asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int turn_on)
-{
- if (from + num <= from)
- return -EINVAL;
- if (from + num > IO_BITMAP_SIZE*32)
- return -EINVAL;
- if (!suser())
- return -EPERM;
-
-#ifdef IODEBUG
- printk("io: from=%d num=%d %s\n", from, num, (turn_on ? "on" : "off"));
-#endif
- set_bitmap((unsigned long *)current->tss.io_bitmap, from, num, !turn_on);
- return 0;
-}
-
-unsigned int *stack;
-
-/*
- * sys_iopl has to be used when you want to access the IO ports
- * beyond the 0x3ff range: to get the full 65536 ports bitmapped
- * you'd need 8kB of bitmaps/process, which is a bit excessive.
- *
- * Here we just change the eflags value on the stack: we allow
- * only the super-user to do it. This depends on the stack-layout
- * on system-call entry - see also fork() and the signal handling
- * code.
- */
-asmlinkage int sys_iopl(long ebx,long ecx,long edx,
- long esi, long edi, long ebp, long eax, long ds,
- long es, long fs, long gs, long orig_eax,
- long eip,long cs,long eflags,long esp,long ss)
-{
- unsigned int level = ebx;
-
- if (level > 3)
- return -EINVAL;
- if (!suser())
- return -EPERM;
- *(&eflags) = (eflags & 0xffffcfff) | (level << 12);
- return 0;
-}
-
-
-void snarf_region(unsigned int from, unsigned int num)
-{
- if (from > IO_BITMAP_SIZE*32)
- return;
- if (from + num > IO_BITMAP_SIZE*32)
- num = IO_BITMAP_SIZE*32 - from;
- set_bitmap(ioport_registrar, from, num, 1);
- return;
-}
-
-void release_region(unsigned int from, unsigned int num)
-{
- if (from > IO_BITMAP_SIZE*32)
- return;
- if (from + num > IO_BITMAP_SIZE*32)
- num = IO_BITMAP_SIZE*32 - from;
- set_bitmap(ioport_registrar, from, num, 0);
- return;
-}
-
-int check_region(unsigned int from, unsigned int num)
-{
- if (from > IO_BITMAP_SIZE*32)
- return 0;
- if (from + num > IO_BITMAP_SIZE*32)
- num = IO_BITMAP_SIZE*32 - from;
- return check_bitmap(ioport_registrar, from, num);
-}
-
-/* Called from init/main.c to reserve IO ports. */
-void reserve_setup(char *str, int *ints)
-{
- int i;
-
- for (i = 1; i < ints[0]; i += 2)
- snarf_region(ints[i], ints[i+1]);
-}
diff --git a/kernel/irq.c b/kernel/irq.c
deleted file mode 100644
index 2de16db53..000000000
--- a/kernel/irq.c
+++ /dev/null
@@ -1,354 +0,0 @@
-/*
- * linux/kernel/irq.c
- *
- * Copyright (C) 1992 Linus Torvalds
- *
- * This file contains the code used by various IRQ handling routines:
- * asking for different IRQ's should be done through these routines
- * instead of just grabbing them. Thus setups with different IRQ numbers
- * shouldn't result in any weird surprises, and installing new handlers
- * should be easier.
- */
-
-/*
- * IRQ's are in fact implemented a bit like signal handlers for the kernel.
- * The same sigaction struct is used, and with similar semantics (ie there
- * is a SA_INTERRUPT flag etc). Naturally it's not a 1:1 relation, but there
- * are similarities.
- *
- * sa_handler(int irq_NR) is the default function called (0 if no).
- * sa_mask is horribly ugly (I won't even mention it)
- * sa_flags contains various info: SA_INTERRUPT etc
- * sa_restorer is the unused
- */
-
-#include <linux/ptrace.h>
-#include <linux/errno.h>
-#include <linux/kernel_stat.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#define CR0_NE 32
-
-static unsigned char cache_21 = 0xff;
-static unsigned char cache_A1 = 0xff;
-
-unsigned long intr_count = 0;
-unsigned long bh_active = 0;
-unsigned long bh_mask = 0xFFFFFFFF;
-struct bh_struct bh_base[32];
-
-void disable_irq(unsigned int irq_nr)
-{
- unsigned long flags;
- unsigned char mask;
-
- mask = 1 << (irq_nr & 7);
- save_flags(flags);
- if (irq_nr < 8) {
- cli();
- cache_21 |= mask;
- outb(cache_21,0x21);
- restore_flags(flags);
- return;
- }
- cli();
- cache_A1 |= mask;
- outb(cache_A1,0xA1);
- restore_flags(flags);
-}
-
-void enable_irq(unsigned int irq_nr)
-{
- unsigned long flags;
- unsigned char mask;
-
- mask = ~(1 << (irq_nr & 7));
- save_flags(flags);
- if (irq_nr < 8) {
- cli();
- cache_21 &= mask;
- outb(cache_21,0x21);
- restore_flags(flags);
- return;
- }
- cli();
- cache_A1 &= mask;
- outb(cache_A1,0xA1);
- restore_flags(flags);
-}
-
-/*
- * do_bottom_half() runs at normal kernel priority: all interrupts
- * enabled. do_bottom_half() is atomic with respect to itself: a
- * bottom_half handler need not be re-entrant.
- */
-asmlinkage void do_bottom_half(void)
-{
- unsigned long active;
- unsigned long mask, left;
- struct bh_struct *bh;
-
- bh = bh_base;
- active = bh_active & bh_mask;
- for (mask = 1, left = ~0 ; left & active ; bh++,mask += mask,left += left) {
- if (mask & active) {
- void (*fn)(void *);
- bh_active &= ~mask;
- fn = bh->routine;
- if (!fn)
- goto bad_bh;
- fn(bh->data);
- }
- }
- return;
-bad_bh:
- printk ("irq.c:bad bottom half entry\n");
-}
-
-/*
- * This builds up the IRQ handler stubs using some ugly macros in irq.h
- *
- * These macros create the low-level assembly IRQ routines that do all
- * the operations that are needed to keep the AT interrupt-controller
- * happy. They are also written to be fast - and to disable interrupts
- * as little as humanly possible.
- *
- * NOTE! These macros expand to three different handlers for each line: one
- * complete handler that does all the fancy stuff (including signal handling),
- * and one fast handler that is meant for simple IRQ's that want to be
- * atomic. The specific handler is chosen depending on the SA_INTERRUPT
- * flag when installing a handler. Finally, one "bad interrupt" handler, that
- * is used when no handler is present.
- */
-BUILD_IRQ(FIRST,0,0x01)
-BUILD_IRQ(FIRST,1,0x02)
-BUILD_IRQ(FIRST,2,0x04)
-BUILD_IRQ(FIRST,3,0x08)
-BUILD_IRQ(FIRST,4,0x10)
-BUILD_IRQ(FIRST,5,0x20)
-BUILD_IRQ(FIRST,6,0x40)
-BUILD_IRQ(FIRST,7,0x80)
-BUILD_IRQ(SECOND,8,0x01)
-BUILD_IRQ(SECOND,9,0x02)
-BUILD_IRQ(SECOND,10,0x04)
-BUILD_IRQ(SECOND,11,0x08)
-BUILD_IRQ(SECOND,12,0x10)
-BUILD_IRQ(SECOND,13,0x20)
-BUILD_IRQ(SECOND,14,0x40)
-BUILD_IRQ(SECOND,15,0x80)
-
-/*
- * Pointers to the low-level handlers: first the general ones, then the
- * fast ones, then the bad ones.
- */
-static void (*interrupt[16])(void) = {
- IRQ0_interrupt, IRQ1_interrupt, IRQ2_interrupt, IRQ3_interrupt,
- IRQ4_interrupt, IRQ5_interrupt, IRQ6_interrupt, IRQ7_interrupt,
- IRQ8_interrupt, IRQ9_interrupt, IRQ10_interrupt, IRQ11_interrupt,
- IRQ12_interrupt, IRQ13_interrupt, IRQ14_interrupt, IRQ15_interrupt
-};
-
-static void (*fast_interrupt[16])(void) = {
- fast_IRQ0_interrupt, fast_IRQ1_interrupt,
- fast_IRQ2_interrupt, fast_IRQ3_interrupt,
- fast_IRQ4_interrupt, fast_IRQ5_interrupt,
- fast_IRQ6_interrupt, fast_IRQ7_interrupt,
- fast_IRQ8_interrupt, fast_IRQ9_interrupt,
- fast_IRQ10_interrupt, fast_IRQ11_interrupt,
- fast_IRQ12_interrupt, fast_IRQ13_interrupt,
- fast_IRQ14_interrupt, fast_IRQ15_interrupt
-};
-
-static void (*bad_interrupt[16])(void) = {
- bad_IRQ0_interrupt, bad_IRQ1_interrupt,
- bad_IRQ2_interrupt, bad_IRQ3_interrupt,
- bad_IRQ4_interrupt, bad_IRQ5_interrupt,
- bad_IRQ6_interrupt, bad_IRQ7_interrupt,
- bad_IRQ8_interrupt, bad_IRQ9_interrupt,
- bad_IRQ10_interrupt, bad_IRQ11_interrupt,
- bad_IRQ12_interrupt, bad_IRQ13_interrupt,
- bad_IRQ14_interrupt, bad_IRQ15_interrupt
-};
-
-/*
- * Initial irq handlers.
- */
-static struct sigaction irq_sigaction[16] = {
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL }
-};
-
-int get_irq_list(char *buf)
-{
- int i, len = 0;
- struct sigaction * sa = irq_sigaction;
-
- for (i = 0 ; i < 16 ; i++, sa++) {
- if (!sa->sa_handler)
- continue;
- len += sprintf(buf+len, "%2d: %8d %c %s\n",
- i, kstat.interrupts[i],
- (sa->sa_flags & SA_INTERRUPT) ? '+' : ' ',
- (char *) sa->sa_mask);
- }
- return len;
-}
-
-/*
- * do_IRQ handles IRQ's that have been installed without the
- * SA_INTERRUPT flag: it uses the full signal-handling return
- * and runs with other interrupts enabled. All relatively slow
- * IRQ's should use this format: notably the keyboard/timer
- * routines.
- */
-asmlinkage void do_IRQ(int irq, struct pt_regs * regs)
-{
- struct sigaction * sa = irq + irq_sigaction;
-
- kstat.interrupts[irq]++;
- sa->sa_handler((int) regs);
-}
-
-/*
- * do_fast_IRQ handles IRQ's that don't need the fancy interrupt return
- * stuff - the handler is also running with interrupts disabled unless
- * it explicitly enables them later.
- */
-asmlinkage void do_fast_IRQ(int irq)
-{
- struct sigaction * sa = irq + irq_sigaction;
-
- kstat.interrupts[irq]++;
- sa->sa_handler(irq);
-}
-
-/*
- * Using "struct sigaction" is slightly silly, but there
- * are historical reasons and it works well, so..
- */
-static int irqaction(unsigned int irq, struct sigaction * new_sa)
-{
- struct sigaction * sa;
- unsigned long flags;
-
- if (irq > 15)
- return -EINVAL;
- sa = irq + irq_sigaction;
- if (sa->sa_handler)
- return -EBUSY;
- if (!new_sa->sa_handler)
- return -EINVAL;
- save_flags(flags);
- cli();
- *sa = *new_sa;
- if (sa->sa_flags & SA_INTERRUPT)
- set_intr_gate(0x20+irq,fast_interrupt[irq]);
- else
- set_intr_gate(0x20+irq,interrupt[irq]);
- if (irq < 8) {
- cache_21 &= ~(1<<irq);
- outb(cache_21,0x21);
- } else {
- cache_21 &= ~(1<<2);
- cache_A1 &= ~(1<<(irq-8));
- outb(cache_21,0x21);
- outb(cache_A1,0xA1);
- }
- restore_flags(flags);
- return 0;
-}
-
-int request_irq(unsigned int irq, void (*handler)(int),
- unsigned long flags, const char * devname)
-{
- struct sigaction sa;
-
- sa.sa_handler = handler;
- sa.sa_flags = flags;
- sa.sa_mask = (unsigned long) devname;
- sa.sa_restorer = NULL;
- return irqaction(irq,&sa);
-}
-
-void free_irq(unsigned int irq)
-{
- struct sigaction * sa = irq + irq_sigaction;
- unsigned long flags;
-
- if (irq > 15) {
- printk("Trying to free IRQ%d\n",irq);
- return;
- }
- if (!sa->sa_handler) {
- printk("Trying to free free IRQ%d\n",irq);
- return;
- }
- save_flags(flags);
- cli();
- if (irq < 8) {
- cache_21 |= 1 << irq;
- outb(cache_21,0x21);
- } else {
- cache_A1 |= 1 << (irq-8);
- outb(cache_A1,0xA1);
- }
- set_intr_gate(0x20+irq,bad_interrupt[irq]);
- sa->sa_handler = NULL;
- sa->sa_flags = 0;
- sa->sa_mask = 0;
- sa->sa_restorer = NULL;
- restore_flags(flags);
-}
-
-/*
- * Note that on a 486, we don't want to do a SIGFPE on a irq13
- * as the irq is unreliable, and exception 16 works correctly
- * (ie as explained in the intel literature). On a 386, you
- * can't use exception 16 due to bad IBM design, so we have to
- * rely on the less exact irq13.
- *
- * Careful.. Not only is IRQ13 unreliable, but it is also
- * leads to races. IBM designers who came up with it should
- * be shot.
- */
-static void math_error_irq(int cpl)
-{
- outb(0,0xF0);
- if (ignore_irq13 || !hard_math)
- return;
- math_error();
-}
-
-static void no_action(int cpl) { }
-
-void init_IRQ(void)
-{
- int i;
-
- for (i = 0; i < 16 ; i++)
- set_intr_gate(0x20+i,bad_interrupt[i]);
- if (request_irq(2, no_action, SA_INTERRUPT, "cascade"))
- printk("Unable to get IRQ2 for cascade\n");
- if (request_irq(13,math_error_irq, 0, "math error"))
- printk("Unable to get IRQ13 for math-error handler\n");
-
- /* initialize the bottom half routines. */
- for (i = 0; i < 32; i++) {
- bh_base[i].routine = NULL;
- bh_base[i].data = NULL;
- }
- bh_active = 0;
- intr_count = 0;
-}
diff --git a/kernel/ksyms.c b/kernel/ksyms.c
index 62bca052c..d13e3c4a4 100644
--- a/kernel/ksyms.c
+++ b/kernel/ksyms.c
@@ -68,7 +68,9 @@ struct symbol_table symbol_table = { 0, 0, 0, /* for stacked module support */
/* system info variables */
X(EISA_bus),
+#ifdef __i386__
X(wp_works_ok),
+#endif
/* process memory management */
X(verify_area),
diff --git a/kernel/ldt.c b/kernel/ldt.c
deleted file mode 100644
index dd0e477d4..000000000
--- a/kernel/ldt.c
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * linux/kernel/ldt.c
- *
- * Copyright (C) 1992 Krishna Balasubramanian and Linus Torvalds
- */
-
-#include <linux/config.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <asm/segment.h>
-#include <asm/system.h>
-#include <linux/ldt.h>
-
-static int read_ldt(void * ptr, unsigned long bytecount)
-{
- int error;
- void * address = current->ldt;
- unsigned long size;
-
- if (!ptr)
- return -EINVAL;
- size = LDT_ENTRIES*LDT_ENTRY_SIZE;
- if (!address) {
- address = &default_ldt;
- size = sizeof(default_ldt);
- }
- if (size > bytecount)
- size = bytecount;
- error = verify_area(VERIFY_WRITE, ptr, size);
- if (error)
- return error;
- memcpy_tofs(ptr, address, size);
- return size;
-}
-
-static int write_ldt(void * ptr, unsigned long bytecount)
-{
- struct modify_ldt_ldt_s ldt_info;
- unsigned long *lp;
- unsigned long base, limit;
- int error, i;
-
- if (bytecount != sizeof(ldt_info))
- return -EINVAL;
- error = verify_area(VERIFY_READ, ptr, sizeof(ldt_info));
- if (error)
- return error;
-
- memcpy_fromfs(&ldt_info, ptr, sizeof(ldt_info));
-
- if (ldt_info.contents == 3 || ldt_info.entry_number >= LDT_ENTRIES)
- return -EINVAL;
-
- limit = ldt_info.limit;
- base = ldt_info.base_addr;
- if (ldt_info.limit_in_pages)
- limit *= PAGE_SIZE;
-
- limit += base;
- if (limit < base || limit >= 0xC0000000)
- return -EINVAL;
-
- if (!current->ldt) {
- for (i=1 ; i<NR_TASKS ; i++) {
- if (task[i] == current) {
- if (!(current->ldt = (struct desc_struct*) vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE)))
- return -ENOMEM;
- set_ldt_desc(gdt+(i<<1)+FIRST_LDT_ENTRY, current->ldt, LDT_ENTRIES);
- load_ldt(i);
- }
- }
- }
-
- lp = (unsigned long *) &current->ldt[ldt_info.entry_number];
- /* Allow LDTs to be cleared by the user. */
- if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
- *lp = 0;
- *(lp+1) = 0;
- return 0;
- }
- *lp = ((ldt_info.base_addr & 0x0000ffff) << 16) |
- (ldt_info.limit & 0x0ffff);
- *(lp+1) = (ldt_info.base_addr & 0xff000000) |
- ((ldt_info.base_addr & 0x00ff0000)>>16) |
- (ldt_info.limit & 0xf0000) |
- (ldt_info.contents << 10) |
- ((ldt_info.read_exec_only ^ 1) << 9) |
- (ldt_info.seg_32bit << 22) |
- (ldt_info.limit_in_pages << 23) |
- ((ldt_info.seg_not_present ^1) << 15) |
- 0x7000;
- return 0;
-}
-
-asmlinkage int sys_modify_ldt(int func, void *ptr, unsigned long bytecount)
-{
- if (func == 0)
- return read_ldt(ptr, bytecount);
- if (func == 1)
- return write_ldt(ptr, bytecount);
- return -ENOSYS;
-}
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
deleted file mode 100644
index cade04750..000000000
--- a/kernel/ptrace.c
+++ /dev/null
@@ -1,517 +0,0 @@
-/* ptrace.c */
-/* By Ross Biro 1/23/92 */
-/* edited by Linus Torvalds */
-
-#include <linux/head.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/errno.h>
-#include <linux/ptrace.h>
-#include <linux/user.h>
-
-#include <asm/segment.h>
-#include <asm/system.h>
-#include <linux/debugreg.h>
-
-/*
- * does not yet catch signals sent when the child dies.
- * in exit.c or in signal.c.
- */
-
-/* determines which flags the user has access to. */
-/* 1 = access 0 = no access */
-#define FLAG_MASK 0x00044dd5
-
-/* set's the trap flag. */
-#define TRAP_FLAG 0x100
-
-/*
- * this is the number to subtract from the top of the stack. To find
- * the local frame.
- */
-#define MAGICNUMBER 68
-
-/* change a pid into a task struct. */
-static inline struct task_struct * get_task(int pid)
-{
- int i;
-
- for (i = 1; i < NR_TASKS; i++) {
- if (task[i] != NULL && (task[i]->pid == pid))
- return task[i];
- }
- return NULL;
-}
-
-/*
- * this routine will get a word off of the processes privileged stack.
- * the offset is how far from the base addr as stored in the TSS.
- * this routine assumes that all the privileged stacks are in our
- * data space.
- */
-static inline int get_stack_long(struct task_struct *task, int offset)
-{
- unsigned char *stack;
-
- stack = (unsigned char *)task->tss.esp0;
- stack += offset;
- return (*((int *)stack));
-}
-
-/*
- * this routine will put a word on the processes privileged stack.
- * the offset is how far from the base addr as stored in the TSS.
- * this routine assumes that all the privileged stacks are in our
- * data space.
- */
-static inline int put_stack_long(struct task_struct *task, int offset,
- unsigned long data)
-{
- unsigned char * stack;
-
- stack = (unsigned char *) task->tss.esp0;
- stack += offset;
- *(unsigned long *) stack = data;
- return 0;
-}
-
-/*
- * This routine gets a long from any process space by following the page
- * tables. NOTE! You should check that the long isn't on a page boundary,
- * and that it is in the task area before calling this: this routine does
- * no checking.
- */
-static unsigned long get_long(struct vm_area_struct * vma, unsigned long addr)
-{
- unsigned long page;
-
-repeat:
- page = *PAGE_DIR_OFFSET(vma->vm_task->tss.cr3, addr);
- if (page & PAGE_PRESENT) {
- page &= PAGE_MASK;
- page += PAGE_PTR(addr);
- page = *((unsigned long *) page);
- }
- if (!(page & PAGE_PRESENT)) {
- do_no_page(vma, addr, 0);
- goto repeat;
- }
-/* this is a hack for non-kernel-mapped video buffers and similar */
- if (page >= high_memory)
- return 0;
- page &= PAGE_MASK;
- page += addr & ~PAGE_MASK;
- return *(unsigned long *) page;
-}
-
-/*
- * This routine puts a long into any process space by following the page
- * tables. NOTE! You should check that the long isn't on a page boundary,
- * and that it is in the task area before calling this: this routine does
- * no checking.
- *
- * Now keeps R/W state of page so that a text page stays readonly
- * even if a debugger scribbles breakpoints into it. -M.U-
- */
-static void put_long(struct vm_area_struct * vma, unsigned long addr,
- unsigned long data)
-{
- unsigned long page, pte = 0;
- int readonly = 0;
-
-repeat:
- page = *PAGE_DIR_OFFSET(vma->vm_task->tss.cr3, addr);
- if (page & PAGE_PRESENT) {
- page &= PAGE_MASK;
- page += PAGE_PTR(addr);
- pte = page;
- page = *((unsigned long *) page);
- }
- if (!(page & PAGE_PRESENT)) {
- do_no_page(vma, addr, 0 /* PAGE_RW */);
- goto repeat;
- }
- if (!(page & PAGE_RW)) {
- if (!(page & PAGE_COW))
- readonly = 1;
- do_wp_page(vma, addr, PAGE_RW | PAGE_PRESENT);
- goto repeat;
- }
-/* this is a hack for non-kernel-mapped video buffers and similar */
- if (page >= high_memory)
- return;
-/* we're bypassing pagetables, so we have to set the dirty bit ourselves */
- *(unsigned long *) pte |= (PAGE_DIRTY|PAGE_COW);
- page &= PAGE_MASK;
- page += addr & ~PAGE_MASK;
- *(unsigned long *) page = data;
- if (readonly) {
- *(unsigned long *) pte &=~ (PAGE_RW|PAGE_COW);
- invalidate();
- }
-}
-
-static struct vm_area_struct * find_vma(struct task_struct * tsk, unsigned long addr)
-{
- struct vm_area_struct * vma;
-
- addr &= PAGE_MASK;
- for (vma = tsk->mm->mmap ; ; vma = vma->vm_next) {
- if (!vma)
- return NULL;
- if (vma->vm_end > addr)
- break;
- }
- if (vma->vm_start <= addr)
- return vma;
- if (!(vma->vm_flags & VM_GROWSDOWN))
- return NULL;
- if (vma->vm_end - addr > tsk->rlim[RLIMIT_STACK].rlim_cur)
- return NULL;
- vma->vm_offset -= vma->vm_start - addr;
- vma->vm_start = addr;
- return vma;
-}
-
-/*
- * This routine checks the page boundaries, and that the offset is
- * within the task area. It then calls get_long() to read a long.
- */
-static int read_long(struct task_struct * tsk, unsigned long addr,
- unsigned long * result)
-{
- struct vm_area_struct * vma = find_vma(tsk, addr);
-
- if (!vma)
- return -EIO;
- if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) {
- unsigned long low,high;
- struct vm_area_struct * vma_high = vma;
-
- if (addr + sizeof(long) >= vma->vm_end) {
- vma_high = vma->vm_next;
- if (!vma_high || vma_high->vm_start != vma->vm_end)
- return -EIO;
- }
- low = get_long(vma, addr & ~(sizeof(long)-1));
- high = get_long(vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1));
- switch (addr & (sizeof(long)-1)) {
- case 1:
- low >>= 8;
- low |= high << 24;
- break;
- case 2:
- low >>= 16;
- low |= high << 16;
- break;
- case 3:
- low >>= 24;
- low |= high << 8;
- break;
- }
- *result = low;
- } else
- *result = get_long(vma, addr);
- return 0;
-}
-
-/*
- * This routine checks the page boundaries, and that the offset is
- * within the task area. It then calls put_long() to write a long.
- */
-static int write_long(struct task_struct * tsk, unsigned long addr,
- unsigned long data)
-{
- struct vm_area_struct * vma = find_vma(tsk, addr);
-
- if (!vma)
- return -EIO;
- if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) {
- unsigned long low,high;
- struct vm_area_struct * vma_high = vma;
-
- if (addr + sizeof(long) >= vma->vm_end) {
- vma_high = vma->vm_next;
- if (!vma_high || vma_high->vm_start != vma->vm_end)
- return -EIO;
- }
- low = get_long(vma, addr & ~(sizeof(long)-1));
- high = get_long(vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1));
- switch (addr & (sizeof(long)-1)) {
- case 0: /* shouldn't happen, but safety first */
- low = data;
- break;
- case 1:
- low &= 0x000000ff;
- low |= data << 8;
- high &= ~0xff;
- high |= data >> 24;
- break;
- case 2:
- low &= 0x0000ffff;
- low |= data << 16;
- high &= ~0xffff;
- high |= data >> 16;
- break;
- case 3:
- low &= 0x00ffffff;
- low |= data << 24;
- high &= ~0xffffff;
- high |= data >> 8;
- break;
- }
- put_long(vma, addr & ~(sizeof(long)-1),low);
- put_long(vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1),high);
- } else
- put_long(vma, addr, data);
- return 0;
-}
-
-asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
-{
- struct task_struct *child;
- struct user * dummy;
- int i;
-
- dummy = NULL;
-
- if (request == PTRACE_TRACEME) {
- /* are we already being traced? */
- if (current->flags & PF_PTRACED)
- return -EPERM;
- /* set the ptrace bit in the process flags. */
- current->flags |= PF_PTRACED;
- return 0;
- }
- if (pid == 1) /* you may not mess with init */
- return -EPERM;
- if (!(child = get_task(pid)))
- return -ESRCH;
- if (request == PTRACE_ATTACH) {
- if (child == current)
- return -EPERM;
- if ((!child->dumpable ||
- (current->uid != child->euid) ||
- (current->uid != child->uid) ||
- (current->gid != child->egid) ||
- (current->gid != child->gid)) && !suser())
- return -EPERM;
- /* the same process cannot be attached many times */
- if (child->flags & PF_PTRACED)
- return -EPERM;
- child->flags |= PF_PTRACED;
- if (child->p_pptr != current) {
- REMOVE_LINKS(child);
- child->p_pptr = current;
- SET_LINKS(child);
- }
- send_sig(SIGSTOP, child, 1);
- return 0;
- }
- if (!(child->flags & PF_PTRACED))
- return -ESRCH;
- if (child->state != TASK_STOPPED) {
- if (request != PTRACE_KILL)
- return -ESRCH;
- }
- if (child->p_pptr != current)
- return -ESRCH;
-
- switch (request) {
- /* when I and D space are separate, these will need to be fixed. */
- case PTRACE_PEEKTEXT: /* read word at location addr. */
- case PTRACE_PEEKDATA: {
- unsigned long tmp;
- int res;
-
- res = read_long(child, addr, &tmp);
- if (res < 0)
- return res;
- res = verify_area(VERIFY_WRITE, (void *) data, sizeof(long));
- if (!res)
- put_fs_long(tmp,(unsigned long *) data);
- return res;
- }
-
- /* read the word at location addr in the USER area. */
- case PTRACE_PEEKUSR: {
- unsigned long tmp;
- int res;
-
- if ((addr & 3) || addr < 0 ||
- addr > sizeof(struct user) - 3)
- return -EIO;
-
- res = verify_area(VERIFY_WRITE, (void *) data, sizeof(long));
- if (res)
- return res;
- tmp = 0; /* Default return condition */
- if(addr < 17*sizeof(long)) {
- addr = addr >> 2; /* temporary hack. */
-
- tmp = get_stack_long(child, sizeof(long)*addr - MAGICNUMBER);
- if (addr == DS || addr == ES ||
- addr == FS || addr == GS ||
- addr == CS || addr == SS)
- tmp &= 0xffff;
- };
- if(addr >= (long) &dummy->u_debugreg[0] &&
- addr <= (long) &dummy->u_debugreg[7]){
- addr -= (long) &dummy->u_debugreg[0];
- addr = addr >> 2;
- tmp = child->debugreg[addr];
- };
- put_fs_long(tmp,(unsigned long *) data);
- return 0;
- }
-
- /* when I and D space are separate, this will have to be fixed. */
- case PTRACE_POKETEXT: /* write the word at location addr. */
- case PTRACE_POKEDATA:
- return write_long(child,addr,data);
-
- case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
- if ((addr & 3) || addr < 0 ||
- addr > sizeof(struct user) - 3)
- return -EIO;
-
- addr = addr >> 2; /* temporary hack. */
-
- if (addr == ORIG_EAX)
- return -EIO;
- if (addr == DS || addr == ES ||
- addr == FS || addr == GS ||
- addr == CS || addr == SS) {
- data &= 0xffff;
- if (data && (data & 3) != 3)
- return -EIO;
- }
- if (addr == EFL) { /* flags. */
- data &= FLAG_MASK;
- data |= get_stack_long(child, EFL*sizeof(long)-MAGICNUMBER) & ~FLAG_MASK;
- }
- /* Do not allow the user to set the debug register for kernel
- address space */
- if(addr < 17){
- if (put_stack_long(child, sizeof(long)*addr-MAGICNUMBER, data))
- return -EIO;
- return 0;
- };
-
- /* We need to be very careful here. We implicitly
- want to modify a portion of the task_struct, and we
- have to be selective about what portions we allow someone
- to modify. */
-
- addr = addr << 2; /* Convert back again */
- if(addr >= (long) &dummy->u_debugreg[0] &&
- addr <= (long) &dummy->u_debugreg[7]){
-
- if(addr == (long) &dummy->u_debugreg[4]) return -EIO;
- if(addr == (long) &dummy->u_debugreg[5]) return -EIO;
- if(addr < (long) &dummy->u_debugreg[4] &&
- ((unsigned long) data) >= 0xbffffffd) return -EIO;
-
- if(addr == (long) &dummy->u_debugreg[7]) {
- data &= ~DR_CONTROL_RESERVED;
- for(i=0; i<4; i++)
- if ((0x5f54 >> ((data >> (16 + 4*i)) & 0xf)) & 1)
- return -EIO;
- };
-
- addr -= (long) &dummy->u_debugreg;
- addr = addr >> 2;
- child->debugreg[addr] = data;
- return 0;
- };
- return -EIO;
-
- case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
- case PTRACE_CONT: { /* restart after signal. */
- long tmp;
-
- if ((unsigned long) data > NSIG)
- return -EIO;
- if (request == PTRACE_SYSCALL)
- child->flags |= PF_TRACESYS;
- else
- child->flags &= ~PF_TRACESYS;
- child->exit_code = data;
- child->state = TASK_RUNNING;
- /* make sure the single step bit is not set. */
- tmp = get_stack_long(child, sizeof(long)*EFL-MAGICNUMBER) & ~TRAP_FLAG;
- put_stack_long(child, sizeof(long)*EFL-MAGICNUMBER,tmp);
- return 0;
- }
-
-/*
- * make the child exit. Best I can do is send it a sigkill.
- * perhaps it should be put in the status that it wants to
- * exit.
- */
- case PTRACE_KILL: {
- long tmp;
-
- child->state = TASK_RUNNING;
- child->exit_code = SIGKILL;
- /* make sure the single step bit is not set. */
- tmp = get_stack_long(child, sizeof(long)*EFL-MAGICNUMBER) & ~TRAP_FLAG;
- put_stack_long(child, sizeof(long)*EFL-MAGICNUMBER,tmp);
- return 0;
- }
-
- case PTRACE_SINGLESTEP: { /* set the trap flag. */
- long tmp;
-
- if ((unsigned long) data > NSIG)
- return -EIO;
- child->flags &= ~PF_TRACESYS;
- tmp = get_stack_long(child, sizeof(long)*EFL-MAGICNUMBER) | TRAP_FLAG;
- put_stack_long(child, sizeof(long)*EFL-MAGICNUMBER,tmp);
- child->state = TASK_RUNNING;
- child->exit_code = data;
- /* give it a chance to run. */
- return 0;
- }
-
- case PTRACE_DETACH: { /* detach a process that was attached. */
- long tmp;
-
- if ((unsigned long) data > NSIG)
- return -EIO;
- child->flags &= ~(PF_PTRACED|PF_TRACESYS);
- child->state = TASK_RUNNING;
- child->exit_code = data;
- REMOVE_LINKS(child);
- child->p_pptr = child->p_opptr;
- SET_LINKS(child);
- /* make sure the single step bit is not set. */
- tmp = get_stack_long(child, sizeof(long)*EFL-MAGICNUMBER) & ~TRAP_FLAG;
- put_stack_long(child, sizeof(long)*EFL-MAGICNUMBER,tmp);
- return 0;
- }
-
- default:
- return -EIO;
- }
-}
-
-asmlinkage void syscall_trace(void)
-{
- if ((current->flags & (PF_PTRACED|PF_TRACESYS))
- != (PF_PTRACED|PF_TRACESYS))
- return;
- current->exit_code = SIGTRAP;
- current->state = TASK_STOPPED;
- notify_parent(current);
- schedule();
- /*
- * this isn't the same as continuing with a signal, but it will do
- * 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;
-}
diff --git a/kernel/sched.c b/kernel/sched.c
deleted file mode 100644
index 6eed6e8f5..000000000
--- a/kernel/sched.c
+++ /dev/null
@@ -1,861 +0,0 @@
-/*
- * linux/kernel/sched.c
- *
- * Copyright (C) 1991, 1992 Linus Torvalds
- */
-
-/*
- * 'sched.c' is the main kernel file. It contains scheduling primitives
- * (sleep_on, wakeup, schedule etc) as well as a number of simple system
- * call functions (type getpid(), which just extracts a field from
- * current-task
- */
-
-#include <linux/config.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/kernel.h>
-#include <linux/kernel_stat.h>
-#include <linux/fdreg.h>
-#include <linux/errno.h>
-#include <linux/time.h>
-#include <linux/ptrace.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/tqueue.h>
-#include <linux/resource.h>
-
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/segment.h>
-
-#define TIMER_IRQ 0
-
-#include <linux/timex.h>
-
-/*
- * kernel variables
- */
-long tick = 1000000 / HZ; /* timer interrupt period */
-volatile struct timeval xtime; /* The current time */
-int tickadj = 500/HZ; /* microsecs */
-
-DECLARE_TASK_QUEUE(tq_timer);
-DECLARE_TASK_QUEUE(tq_immediate);
-
-/*
- * phase-lock loop variables
- */
-int time_status = TIME_BAD; /* clock synchronization status */
-long time_offset = 0; /* time adjustment (us) */
-long time_constant = 0; /* pll time constant */
-long time_tolerance = MAXFREQ; /* frequency tolerance (ppm) */
-long time_precision = 1; /* clock precision (us) */
-long time_maxerror = 0x70000000;/* maximum error */
-long time_esterror = 0x70000000;/* estimated error */
-long time_phase = 0; /* phase offset (scaled us) */
-long time_freq = 0; /* frequency offset (scaled ppm) */
-long time_adj = 0; /* tick adjust (scaled 1 / HZ) */
-long time_reftime = 0; /* time at last adjustment (s) */
-
-long time_adjust = 0;
-long time_adjust_step = 0;
-
-int need_resched = 0;
-unsigned long event = 0;
-
-/*
- * Tell us the machine setup..
- */
-int hard_math = 0; /* set by boot/head.S */
-int x86 = 0; /* set by boot/head.S to 3 or 4 */
-int ignore_irq13 = 0; /* set if exception 16 works */
-int wp_works_ok = 0; /* set if paging hardware honours WP */
-int hlt_works_ok = 1; /* set if the "hlt" instruction works */
-
-/*
- * Bus types ..
- */
-int EISA_bus = 0;
-
-extern int _setitimer(int, struct itimerval *, struct itimerval *);
-unsigned long * prof_buffer = NULL;
-unsigned long prof_len = 0;
-
-#define _S(nr) (1<<((nr)-1))
-
-extern void mem_use(void);
-
-extern int timer_interrupt(void);
-asmlinkage int system_call(void);
-
-static unsigned long init_kernel_stack[1024] = { STACK_MAGIC, };
-static struct vm_area_struct init_mmap = INIT_MMAP;
-struct task_struct init_task = INIT_TASK;
-
-unsigned long volatile jiffies=0;
-
-struct task_struct *current = &init_task;
-struct task_struct *last_task_used_math = NULL;
-
-struct task_struct * task[NR_TASKS] = {&init_task, };
-
-long user_stack [ PAGE_SIZE>>2 ] = { STACK_MAGIC, };
-
-struct {
- long * a;
- short b;
- } stack_start = { & user_stack [PAGE_SIZE>>2] , KERNEL_DS };
-
-struct kernel_stat kstat = { 0 };
-
-/*
- * 'math_state_restore()' saves the current math information in the
- * old math state array, and gets the new ones from the current task
- *
- * Careful.. There are problems with IBM-designed IRQ13 behaviour.
- * Don't touch unless you *really* know how it works.
- */
-asmlinkage void math_state_restore(void)
-{
- __asm__ __volatile__("clts");
- if (last_task_used_math == current)
- return;
- timer_table[COPRO_TIMER].expires = jiffies+50;
- timer_active |= 1<<COPRO_TIMER;
- if (last_task_used_math)
- __asm__("fnsave %0":"=m" (last_task_used_math->tss.i387));
- else
- __asm__("fnclex");
- last_task_used_math = current;
- if (current->used_math) {
- __asm__("frstor %0": :"m" (current->tss.i387));
- } else {
- __asm__("fninit");
- current->used_math=1;
- }
- timer_active &= ~(1<<COPRO_TIMER);
-}
-
-#ifndef CONFIG_MATH_EMULATION
-
-asmlinkage void math_emulate(long arg)
-{
- printk("math-emulation not enabled and no coprocessor found.\n");
- printk("killing %s.\n",current->comm);
- send_sig(SIGFPE,current,1);
- schedule();
-}
-
-#endif /* CONFIG_MATH_EMULATION */
-
-unsigned long itimer_ticks = 0;
-unsigned long itimer_next = ~0;
-
-/*
- * 'schedule()' is the scheduler function. It's a very simple and nice
- * scheduler: it's not perfect, but certainly works for most things.
- * The one thing you might take a look at is the signal-handler code here.
- *
- * NOTE!! Task 0 is the 'idle' task, which gets called when no other
- * tasks can run. It can not be killed, and it cannot sleep. The 'state'
- * information in task[0] is never used.
- *
- * The "confuse_gcc" goto is used only to get better assembly code..
- * Dijkstra probably hates me.
- */
-asmlinkage void schedule(void)
-{
- int c;
- struct task_struct * p;
- struct task_struct * next;
- unsigned long ticks;
-
-/* check alarm, wake up any interruptible tasks that have got a signal */
-
- if (intr_count) {
- printk("Aiee: scheduling in interrupt\n");
- intr_count = 0;
- }
- cli();
- ticks = itimer_ticks;
- itimer_ticks = 0;
- itimer_next = ~0;
- sti();
- need_resched = 0;
- p = &init_task;
- for (;;) {
- if ((p = p->next_task) == &init_task)
- goto confuse_gcc1;
- if (ticks && p->it_real_value) {
- if (p->it_real_value <= ticks) {
- send_sig(SIGALRM, p, 1);
- if (!p->it_real_incr) {
- p->it_real_value = 0;
- goto end_itimer;
- }
- do {
- p->it_real_value += p->it_real_incr;
- } while (p->it_real_value <= ticks);
- }
- p->it_real_value -= ticks;
- if (p->it_real_value < itimer_next)
- itimer_next = p->it_real_value;
- }
-end_itimer:
- if (p->state != TASK_INTERRUPTIBLE)
- continue;
- if (p->signal & ~p->blocked) {
- p->state = TASK_RUNNING;
- continue;
- }
- if (p->timeout && p->timeout <= jiffies) {
- p->timeout = 0;
- p->state = TASK_RUNNING;
- }
- }
-confuse_gcc1:
-
-/* this is the scheduler proper: */
-#if 0
- /* give processes that go to sleep a bit higher priority.. */
- /* This depends on the values for TASK_XXX */
- /* This gives smoother scheduling for some things, but */
- /* can be very unfair under some circumstances, so.. */
- if (TASK_UNINTERRUPTIBLE >= (unsigned) current->state &&
- current->counter < current->priority*2) {
- ++current->counter;
- }
-#endif
- c = -1000;
- next = p = &init_task;
- for (;;) {
- if ((p = p->next_task) == &init_task)
- goto confuse_gcc2;
- if (p->state == TASK_RUNNING && p->counter > c)
- c = p->counter, next = p;
- }
-confuse_gcc2:
- if (!c) {
- for_each_task(p)
- p->counter = (p->counter >> 1) + p->priority;
- }
- if (current == next)
- return;
- kstat.context_swtch++;
- switch_to(next);
- /* Now maybe reload the debug registers */
- if(current->debugreg[7]){
- loaddebug(0);
- loaddebug(1);
- loaddebug(2);
- loaddebug(3);
- loaddebug(6);
- };
-}
-
-asmlinkage int sys_pause(void)
-{
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- return -ERESTARTNOHAND;
-}
-
-/*
- * wake_up doesn't wake up stopped processes - they have to be awakened
- * with signals or similar.
- *
- * Note that this doesn't need cli-sti pairs: interrupts may not change
- * the wait-queue structures directly, but only call wake_up() to wake
- * a process. The process itself must remove the queue once it has woken.
- */
-void wake_up(struct wait_queue **q)
-{
- struct wait_queue *tmp;
- struct task_struct * p;
-
- if (!q || !(tmp = *q))
- return;
- do {
- if ((p = tmp->task) != NULL) {
- if ((p->state == TASK_UNINTERRUPTIBLE) ||
- (p->state == TASK_INTERRUPTIBLE)) {
- p->state = TASK_RUNNING;
- if (p->counter > current->counter + 3)
- need_resched = 1;
- }
- }
- if (!tmp->next) {
- printk("wait_queue is bad (eip = %p)\n",
- __builtin_return_address(0));
- printk(" q = %p\n",q);
- printk(" *q = %p\n",*q);
- printk(" tmp = %p\n",tmp);
- break;
- }
- tmp = tmp->next;
- } while (tmp != *q);
-}
-
-void wake_up_interruptible(struct wait_queue **q)
-{
- struct wait_queue *tmp;
- struct task_struct * p;
-
- if (!q || !(tmp = *q))
- return;
- do {
- if ((p = tmp->task) != NULL) {
- if (p->state == TASK_INTERRUPTIBLE) {
- p->state = TASK_RUNNING;
- if (p->counter > current->counter + 3)
- need_resched = 1;
- }
- }
- if (!tmp->next) {
- printk("wait_queue is bad (eip = %p)\n",
- __builtin_return_address(0));
- printk(" q = %p\n",q);
- printk(" *q = %p\n",*q);
- printk(" tmp = %p\n",tmp);
- break;
- }
- tmp = tmp->next;
- } while (tmp != *q);
-}
-
-void __down(struct semaphore * sem)
-{
- struct wait_queue wait = { current, NULL };
- add_wait_queue(&sem->wait, &wait);
- current->state = TASK_UNINTERRUPTIBLE;
- while (sem->count <= 0) {
- schedule();
- current->state = TASK_UNINTERRUPTIBLE;
- }
- current->state = TASK_RUNNING;
- remove_wait_queue(&sem->wait, &wait);
-}
-
-static inline void __sleep_on(struct wait_queue **p, int state)
-{
- unsigned long flags;
- struct wait_queue wait = { current, NULL };
-
- if (!p)
- return;
- if (current == task[0])
- panic("task[0] trying to sleep");
- current->state = state;
- add_wait_queue(p, &wait);
- save_flags(flags);
- sti();
- schedule();
- remove_wait_queue(p, &wait);
- restore_flags(flags);
-}
-
-void interruptible_sleep_on(struct wait_queue **p)
-{
- __sleep_on(p,TASK_INTERRUPTIBLE);
-}
-
-void sleep_on(struct wait_queue **p)
-{
- __sleep_on(p,TASK_UNINTERRUPTIBLE);
-}
-
-/*
- * The head for the timer-list has a "expires" field of MAX_UINT,
- * and the sorting routine counts on this..
- */
-static struct timer_list timer_head = { &timer_head, &timer_head, ~0, 0, NULL };
-#define SLOW_BUT_DEBUGGING_TIMERS 1
-
-void add_timer(struct timer_list * timer)
-{
- unsigned long flags;
- struct timer_list *p;
-
-#if SLOW_BUT_DEBUGGING_TIMERS
- if (timer->next || timer->prev) {
- printk("add_timer() called with non-zero list from %p\n",
- __builtin_return_address(0));
- return;
- }
-#endif
- p = &timer_head;
- timer->expires += jiffies;
- save_flags(flags);
- cli();
- do {
- p = p->next;
- } while (timer->expires > p->expires);
- timer->next = p;
- timer->prev = p->prev;
- p->prev = timer;
- timer->prev->next = timer;
- restore_flags(flags);
-}
-
-int del_timer(struct timer_list * timer)
-{
- unsigned long flags;
-#if SLOW_BUT_DEBUGGING_TIMERS
- struct timer_list * p;
-
- p = &timer_head;
- save_flags(flags);
- cli();
- while ((p = p->next) != &timer_head) {
- if (p == timer) {
- timer->next->prev = timer->prev;
- timer->prev->next = timer->next;
- timer->next = timer->prev = NULL;
- restore_flags(flags);
- timer->expires -= jiffies;
- return 1;
- }
- }
- if (timer->next || timer->prev)
- printk("del_timer() called from %p with timer not initialized\n",
- __builtin_return_address(0));
- restore_flags(flags);
- return 0;
-#else
- save_flags(flags);
- cli();
- if (timer->next) {
- timer->next->prev = timer->prev;
- timer->prev->next = timer->next;
- timer->next = timer->prev = NULL;
- restore_flags(flags);
- timer->expires -= jiffies;
- return 1;
- }
- restore_flags(flags);
- return 0;
-#endif
-}
-
-unsigned long timer_active = 0;
-struct timer_struct timer_table[32];
-
-/*
- * Hmm.. Changed this, as the GNU make sources (load.c) seems to
- * imply that avenrun[] is the standard name for this kind of thing.
- * Nothing else seems to be standardized: the fractional size etc
- * all seem to differ on different machines.
- */
-unsigned long avenrun[3] = { 0,0,0 };
-
-/*
- * Nr of active tasks - counted in fixed-point numbers
- */
-static unsigned long count_active_tasks(void)
-{
- struct task_struct **p;
- unsigned long nr = 0;
-
- for(p = &LAST_TASK; p > &FIRST_TASK; --p)
- if (*p && ((*p)->state == TASK_RUNNING ||
- (*p)->state == TASK_UNINTERRUPTIBLE ||
- (*p)->state == TASK_SWAPPING))
- nr += FIXED_1;
- return nr;
-}
-
-static inline void calc_load(void)
-{
- unsigned long active_tasks; /* fixed-point */
- static int count = LOAD_FREQ;
-
- if (count-- > 0)
- return;
- count = LOAD_FREQ;
- active_tasks = count_active_tasks();
- CALC_LOAD(avenrun[0], EXP_1, active_tasks);
- CALC_LOAD(avenrun[1], EXP_5, active_tasks);
- CALC_LOAD(avenrun[2], EXP_15, active_tasks);
-}
-
-/*
- * this routine handles the overflow of the microsecond field
- *
- * The tricky bits of code to handle the accurate clock support
- * were provided by Dave Mills (Mills@UDEL.EDU) of NTP fame.
- * They were originally developed for SUN and DEC kernels.
- * All the kudos should go to Dave for this stuff.
- *
- * These were ported to Linux by Philip Gladstone.
- */
-static void second_overflow(void)
-{
- long ltemp;
- /* last time the cmos clock got updated */
- static long last_rtc_update=0;
- extern int set_rtc_mmss(unsigned long);
-
- /* Bump the maxerror field */
- time_maxerror = (0x70000000-time_maxerror < time_tolerance) ?
- 0x70000000 : (time_maxerror + time_tolerance);
-
- /* Run the PLL */
- if (time_offset < 0) {
- ltemp = (-(time_offset+1) >> (SHIFT_KG + time_constant)) + 1;
- time_adj = ltemp << (SHIFT_SCALE - SHIFT_HZ - SHIFT_UPDATE);
- time_offset += (time_adj * HZ) >> (SHIFT_SCALE - SHIFT_UPDATE);
- time_adj = - time_adj;
- } else if (time_offset > 0) {
- ltemp = ((time_offset-1) >> (SHIFT_KG + time_constant)) + 1;
- time_adj = ltemp << (SHIFT_SCALE - SHIFT_HZ - SHIFT_UPDATE);
- time_offset -= (time_adj * HZ) >> (SHIFT_SCALE - SHIFT_UPDATE);
- } else {
- time_adj = 0;
- }
-
- time_adj += (time_freq >> (SHIFT_KF + SHIFT_HZ - SHIFT_SCALE))
- + FINETUNE;
-
- /* Handle the leap second stuff */
- switch (time_status) {
- case TIME_INS:
- /* ugly divide should be replaced */
- if (xtime.tv_sec % 86400 == 0) {
- xtime.tv_sec--; /* !! */
- time_status = TIME_OOP;
- printk("Clock: inserting leap second 23:59:60 GMT\n");
- }
- break;
-
- case TIME_DEL:
- /* ugly divide should be replaced */
- if (xtime.tv_sec % 86400 == 86399) {
- xtime.tv_sec++;
- time_status = TIME_OK;
- printk("Clock: deleting leap second 23:59:59 GMT\n");
- }
- break;
-
- case TIME_OOP:
- time_status = TIME_OK;
- break;
- }
- if (xtime.tv_sec > last_rtc_update + 660)
- 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 one min */
-}
-
-/*
- * disregard lost ticks for now.. We don't care enough.
- */
-static void timer_bh(void * unused)
-{
- unsigned long mask;
- struct timer_struct *tp;
- struct timer_list * timer;
-
- cli();
- while ((timer = timer_head.next) != &timer_head && timer->expires < jiffies) {
- void (*fn)(unsigned long) = timer->function;
- unsigned long data = timer->data;
- timer->next->prev = timer->prev;
- timer->prev->next = timer->next;
- timer->next = timer->prev = NULL;
- sti();
- fn(data);
- cli();
- }
- sti();
-
- for (mask = 1, tp = timer_table+0 ; mask ; tp++,mask += mask) {
- if (mask > timer_active)
- break;
- if (!(mask & timer_active))
- continue;
- if (tp->expires > jiffies)
- continue;
- timer_active &= ~mask;
- tp->fn();
- sti();
- }
-}
-
-void tqueue_bh(void * unused)
-{
- run_task_queue(&tq_timer);
-}
-
-void immediate_bh(void * unused)
-{
- run_task_queue(&tq_immediate);
-}
-
-/*
- * The int argument is really a (struct pt_regs *), in case the
- * interrupt wants to know from where it was called. The timer
- * irq uses this to decide if it should update the user or system
- * times.
- */
-static void do_timer(struct pt_regs * regs)
-{
- unsigned long mask;
- struct timer_struct *tp;
-
- long ltemp, psecs;
-
- /* Advance the phase, once it gets to one microsecond, then
- * advance the tick more.
- */
- time_phase += time_adj;
- if (time_phase < -FINEUSEC) {
- ltemp = -time_phase >> SHIFT_SCALE;
- time_phase += ltemp << SHIFT_SCALE;
- xtime.tv_usec += tick + time_adjust_step - ltemp;
- }
- else if (time_phase > FINEUSEC) {
- ltemp = time_phase >> SHIFT_SCALE;
- time_phase -= ltemp << SHIFT_SCALE;
- xtime.tv_usec += tick + time_adjust_step + ltemp;
- } else
- xtime.tv_usec += tick + time_adjust_step;
-
- if (time_adjust)
- {
- /* We are doing an adjtime thing.
- *
- * Modify the value of the tick for next time.
- * Note that a positive delta means we want the clock
- * to run fast. This means that the tick should be bigger
- *
- * Limit the amount of the step for *next* tick to be
- * in the range -tickadj .. +tickadj
- */
- if (time_adjust > tickadj)
- time_adjust_step = tickadj;
- else if (time_adjust < -tickadj)
- time_adjust_step = -tickadj;
- else
- time_adjust_step = time_adjust;
-
- /* Reduce by this step the amount of time left */
- time_adjust -= time_adjust_step;
- }
- else
- time_adjust_step = 0;
-
- if (xtime.tv_usec >= 1000000) {
- xtime.tv_usec -= 1000000;
- xtime.tv_sec++;
- second_overflow();
- }
-
- jiffies++;
- calc_load();
- if ((VM_MASK & regs->eflags) || (3 & regs->cs)) {
- current->utime++;
- if (current != task[0]) {
- if (current->priority < 15)
- kstat.cpu_nice++;
- else
- kstat.cpu_user++;
- }
- /* Update ITIMER_VIRT for current task if not in a system call */
- if (current->it_virt_value && !(--current->it_virt_value)) {
- current->it_virt_value = current->it_virt_incr;
- send_sig(SIGVTALRM,current,1);
- }
- } else {
- current->stime++;
- if(current != task[0])
- kstat.cpu_system++;
-#ifdef CONFIG_PROFILE
- if (prof_buffer && current != task[0]) {
- unsigned long eip = regs->eip;
- eip >>= 2;
- if (eip < prof_len)
- prof_buffer[eip]++;
- }
-#endif
- }
- /*
- * check the cpu time limit on the process.
- */
- if ((current->rlim[RLIMIT_CPU].rlim_max != RLIM_INFINITY) &&
- (((current->stime + current->utime) / HZ) >= current->rlim[RLIMIT_CPU].rlim_max))
- send_sig(SIGKILL, current, 1);
- if ((current->rlim[RLIMIT_CPU].rlim_cur != RLIM_INFINITY) &&
- (((current->stime + current->utime) % HZ) == 0)) {
- psecs = (current->stime + current->utime) / HZ;
- /* send when equal */
- if (psecs == current->rlim[RLIMIT_CPU].rlim_cur)
- send_sig(SIGXCPU, current, 1);
- /* and every five seconds thereafter. */
- else if ((psecs > current->rlim[RLIMIT_CPU].rlim_cur) &&
- ((psecs - current->rlim[RLIMIT_CPU].rlim_cur) % 5) == 0)
- send_sig(SIGXCPU, current, 1);
- }
-
- if (current != task[0] && 0 > --current->counter) {
- current->counter = 0;
- need_resched = 1;
- }
- /* Update ITIMER_PROF for the current task */
- if (current->it_prof_value && !(--current->it_prof_value)) {
- current->it_prof_value = current->it_prof_incr;
- send_sig(SIGPROF,current,1);
- }
- for (mask = 1, tp = timer_table+0 ; mask ; tp++,mask += mask) {
- if (mask > timer_active)
- break;
- if (!(mask & timer_active))
- continue;
- if (tp->expires > jiffies)
- continue;
- mark_bh(TIMER_BH);
- }
- cli();
- itimer_ticks++;
- if (itimer_ticks > itimer_next)
- need_resched = 1;
- if (timer_head.next->expires < jiffies)
- mark_bh(TIMER_BH);
- if (tq_timer != &tq_last)
- mark_bh(TQUEUE_BH);
- sti();
-}
-
-asmlinkage int sys_alarm(long seconds)
-{
- struct itimerval it_new, it_old;
-
- it_new.it_interval.tv_sec = it_new.it_interval.tv_usec = 0;
- it_new.it_value.tv_sec = seconds;
- it_new.it_value.tv_usec = 0;
- _setitimer(ITIMER_REAL, &it_new, &it_old);
- return(it_old.it_value.tv_sec + (it_old.it_value.tv_usec / 1000000));
-}
-
-asmlinkage int sys_getpid(void)
-{
- return current->pid;
-}
-
-asmlinkage int sys_getppid(void)
-{
- return current->p_opptr->pid;
-}
-
-asmlinkage int sys_getuid(void)
-{
- return current->uid;
-}
-
-asmlinkage int sys_geteuid(void)
-{
- return current->euid;
-}
-
-asmlinkage int sys_getgid(void)
-{
- return current->gid;
-}
-
-asmlinkage int sys_getegid(void)
-{
- return current->egid;
-}
-
-asmlinkage int sys_nice(long increment)
-{
- int newprio;
-
- if (increment < 0 && !suser())
- return -EPERM;
- newprio = current->priority - increment;
- if (newprio < 1)
- newprio = 1;
- if (newprio > 35)
- newprio = 35;
- current->priority = newprio;
- return 0;
-}
-
-static void show_task(int nr,struct task_struct * p)
-{
- unsigned long free;
- static char * stat_nam[] = { "R", "S", "D", "Z", "T", "W" };
-
- printk("%-8s %3d ", p->comm, (p == current) ? -nr : nr);
- if (((unsigned) p->state) < sizeof(stat_nam)/sizeof(char *))
- printk(stat_nam[p->state]);
- else
- printk(" ");
- if (p == current)
- printk(" current ");
- else
- printk(" %08lX ", ((unsigned long *)p->tss.esp)[3]);
- for (free = 1; free < 1024 ; free++) {
- if (((unsigned long *)p->kernel_stack_page)[free])
- break;
- }
- printk("%5lu %5d %6d ", free << 2, p->pid, p->p_pptr->pid);
- if (p->p_cptr)
- printk("%5d ", p->p_cptr->pid);
- else
- printk(" ");
- if (p->p_ysptr)
- printk("%7d", p->p_ysptr->pid);
- else
- printk(" ");
- if (p->p_osptr)
- printk(" %5d\n", p->p_osptr->pid);
- else
- printk("\n");
-}
-
-void show_state(void)
-{
- int i;
-
- printk(" free sibling\n");
- printk(" task PC stack pid father child younger older\n");
- for (i=0 ; i<NR_TASKS ; i++)
- if (task[i])
- show_task(i,task[i]);
-}
-
-void sched_init(void)
-{
- int i;
- struct desc_struct * p;
-
- bh_base[TIMER_BH].routine = timer_bh;
- bh_base[TQUEUE_BH].routine = tqueue_bh;
- bh_base[IMMEDIATE_BH].routine = immediate_bh;
- if (sizeof(struct sigaction) != 16)
- panic("Struct sigaction MUST be 16 bytes");
- set_tss_desc(gdt+FIRST_TSS_ENTRY,&init_task.tss);
- set_ldt_desc(gdt+FIRST_LDT_ENTRY,&default_ldt,1);
- set_system_gate(0x80,&system_call);
- p = gdt+2+FIRST_TSS_ENTRY;
- for(i=1 ; i<NR_TASKS ; i++) {
- task[i] = NULL;
- p->a=p->b=0;
- p++;
- p->a=p->b=0;
- p++;
- }
-/* Clear NT, so that we won't have troubles with that later on */
- __asm__("pushfl ; andl $0xffffbfff,(%esp) ; popfl");
- load_TR(0);
- load_ldt(0);
- outb_p(0x34,0x43); /* binary, mode 2, LSB/MSB, ch 0 */
- outb_p(LATCH & 0xff , 0x40); /* LSB */
- outb(LATCH >> 8 , 0x40); /* MSB */
- if (request_irq(TIMER_IRQ,(void (*)(int)) do_timer, 0, "timer") != 0)
- panic("Could not allocate timer IRQ!");
-}
diff --git a/kernel/signal.c b/kernel/signal.c
deleted file mode 100644
index df7324294..000000000
--- a/kernel/signal.c
+++ /dev/null
@@ -1,407 +0,0 @@
-/*
- * linux/kernel/signal.c
- *
- * Copyright (C) 1991, 1992 Linus Torvalds
- */
-
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/signal.h>
-#include <linux/errno.h>
-#include <linux/wait.h>
-#include <linux/ptrace.h>
-#include <linux/unistd.h>
-
-#include <asm/segment.h>
-
-#define _S(nr) (1<<((nr)-1))
-
-#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
-
-asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs);
-
-asmlinkage int sys_sigprocmask(int how, sigset_t *set, sigset_t *oset)
-{
- sigset_t new_set, old_set = current->blocked;
- int error;
-
- if (set) {
- error = verify_area(VERIFY_READ, set, sizeof(sigset_t));
- if (error)
- return error;
- new_set = get_fs_long((unsigned long *) set) & _BLOCKABLE;
- switch (how) {
- case SIG_BLOCK:
- current->blocked |= new_set;
- break;
- case SIG_UNBLOCK:
- current->blocked &= ~new_set;
- break;
- case SIG_SETMASK:
- current->blocked = new_set;
- break;
- default:
- return -EINVAL;
- }
- }
- if (oset) {
- error = verify_area(VERIFY_WRITE, oset, sizeof(sigset_t));
- if (error)
- return error;
- put_fs_long(old_set, (unsigned long *) oset);
- }
- return 0;
-}
-
-asmlinkage int sys_sgetmask(void)
-{
- return current->blocked;
-}
-
-asmlinkage int sys_ssetmask(int newmask)
-{
- int old=current->blocked;
-
- current->blocked = newmask & _BLOCKABLE;
- return old;
-}
-
-asmlinkage int sys_sigpending(sigset_t *set)
-{
- int error;
- /* fill in "set" with signals pending but blocked. */
- error = verify_area(VERIFY_WRITE, set, 4);
- if (!error)
- put_fs_long(current->blocked & current->signal, (unsigned long *)set);
- return error;
-}
-
-/*
- * atomically swap in the new signal mask, and wait for a signal.
- */
-asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, unsigned long set)
-{
- unsigned long mask;
- struct pt_regs * regs = (struct pt_regs *) &restart;
-
- mask = current->blocked;
- current->blocked = set & _BLOCKABLE;
- regs->eax = -EINTR;
- while (1) {
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- if (do_signal(mask,regs))
- return -EINTR;
- }
-}
-
-/*
- * POSIX 3.3.1.3:
- * "Setting a signal action to SIG_IGN for a signal that is pending
- * shall cause the pending signal to be discarded, whether or not
- * it is blocked" (but SIGCHLD is unspecified: linux leaves it alone).
- *
- * "Setting a signal action to SIG_DFL for a signal that is pending
- * and whose default action is to ignore the signal (for example,
- * SIGCHLD), shall cause the pending signal to be discarded, whether
- * or not it is blocked"
- *
- * Note the silly behaviour of SIGCHLD: SIG_IGN means that the signal
- * isn't actually ignored, but does automatic child reaping, while
- * SIG_DFL is explicitly said by POSIX to force the signal to be ignored..
- */
-static void check_pending(int signum)
-{
- struct sigaction *p;
-
- p = signum - 1 + current->sigaction;
- if (p->sa_handler == SIG_IGN) {
- if (signum == SIGCHLD)
- return;
- current->signal &= ~_S(signum);
- return;
- }
- if (p->sa_handler == SIG_DFL) {
- if (signum != SIGCONT && signum != SIGCHLD && signum != SIGWINCH)
- return;
- current->signal &= ~_S(signum);
- return;
- }
-}
-
-asmlinkage int sys_signal(int signum, unsigned long handler)
-{
- struct sigaction tmp;
-
- if (signum<1 || signum>32)
- return -EINVAL;
- if (signum==SIGKILL || signum==SIGSTOP)
- return -EINVAL;
- if (handler >= TASK_SIZE)
- return -EFAULT;
- tmp.sa_handler = (void (*)(int)) handler;
- tmp.sa_mask = 0;
- tmp.sa_flags = SA_ONESHOT | SA_NOMASK;
- tmp.sa_restorer = NULL;
- handler = (long) current->sigaction[signum-1].sa_handler;
- current->sigaction[signum-1] = tmp;
- check_pending(signum);
- return handler;
-}
-
-asmlinkage int sys_sigaction(int signum, const struct sigaction * action,
- struct sigaction * oldaction)
-{
- struct sigaction new_sa, *p;
-
- if (signum<1 || signum>32)
- return -EINVAL;
- if (signum==SIGKILL || signum==SIGSTOP)
- return -EINVAL;
- p = signum - 1 + current->sigaction;
- if (action) {
- int err = verify_area(VERIFY_READ, action, sizeof(*action));
- if (err)
- return err;
- memcpy_fromfs(&new_sa, action, sizeof(struct sigaction));
- if (new_sa.sa_flags & SA_NOMASK)
- new_sa.sa_mask = 0;
- else {
- new_sa.sa_mask |= _S(signum);
- new_sa.sa_mask &= _BLOCKABLE;
- }
- if (TASK_SIZE <= (unsigned long) new_sa.sa_handler)
- return -EFAULT;
- }
- if (oldaction) {
- int err = verify_area(VERIFY_WRITE, oldaction, sizeof(*oldaction));
- if (err)
- return err;
- memcpy_tofs(oldaction, p, sizeof(struct sigaction));
- }
- if (action) {
- *p = new_sa;
- check_pending(signum);
- }
- return 0;
-}
-
-asmlinkage int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options);
-
-/*
- * This sets regs->esp even though we don't actually use sigstacks yet..
- */
-asmlinkage int sys_sigreturn(unsigned long __unused)
-{
-#define COPY(x) regs->x = context.x
-#define COPY_SEG(x) \
-if ((context.x & 0xfffc) && (context.x & 3) != 3) goto badframe; COPY(x);
-#define COPY_SEG_STRICT(x) \
-if (!(context.x & 0xfffc) || (context.x & 3) != 3) goto badframe; COPY(x);
- struct sigcontext_struct context;
- struct pt_regs * regs;
-
- regs = (struct pt_regs *) &__unused;
- if (verify_area(VERIFY_READ, (void *) regs->esp, sizeof(context)))
- goto badframe;
- memcpy_fromfs(&context,(void *) regs->esp, sizeof(context));
- current->blocked = context.oldmask & _BLOCKABLE;
- COPY_SEG(ds);
- COPY_SEG(es);
- COPY_SEG(fs);
- COPY_SEG(gs);
- COPY_SEG_STRICT(ss);
- COPY_SEG_STRICT(cs);
- COPY(eip);
- COPY(ecx); COPY(edx);
- COPY(ebx);
- COPY(esp); COPY(ebp);
- COPY(edi); COPY(esi);
- regs->eflags &= ~0x40DD5;
- regs->eflags |= context.eflags & 0x40DD5;
- regs->orig_eax = -1; /* disable syscall checks */
- return context.eax;
-badframe:
- do_exit(SIGSEGV);
-}
-
-/*
- * Set up a signal frame... Make the stack look the way iBCS2 expects
- * it to look.
- */
-static void setup_frame(struct sigaction * sa, unsigned long ** fp, unsigned long eip,
- struct pt_regs * regs, int signr, unsigned long oldmask)
-{
- unsigned long * frame;
-
-#define __CODE ((unsigned long)(frame+24))
-#define CODE(x) ((unsigned long *) ((x)+__CODE))
- frame = *fp;
- if (regs->ss != USER_DS)
- frame = (unsigned long *) sa->sa_restorer;
- frame -= 32;
- if (verify_area(VERIFY_WRITE,frame,32*4))
- do_exit(SIGSEGV);
-/* set up the "normal" stack seen by the signal handler (iBCS2) */
- put_fs_long(__CODE,frame);
- if (current->exec_domain && current->exec_domain->signal_invmap)
- put_fs_long(current->exec_domain->signal_invmap[signr], frame+1);
- else
- put_fs_long(signr, frame+1);
- put_fs_long(regs->gs, frame+2);
- put_fs_long(regs->fs, frame+3);
- put_fs_long(regs->es, frame+4);
- put_fs_long(regs->ds, frame+5);
- put_fs_long(regs->edi, frame+6);
- put_fs_long(regs->esi, frame+7);
- put_fs_long(regs->ebp, frame+8);
- put_fs_long((long)*fp, frame+9);
- put_fs_long(regs->ebx, frame+10);
- put_fs_long(regs->edx, frame+11);
- put_fs_long(regs->ecx, frame+12);
- put_fs_long(regs->eax, frame+13);
- put_fs_long(current->tss.trap_no, frame+14);
- put_fs_long(current->tss.error_code, frame+15);
- put_fs_long(eip, frame+16);
- put_fs_long(regs->cs, frame+17);
- put_fs_long(regs->eflags, frame+18);
- put_fs_long(regs->esp, frame+19);
- put_fs_long(regs->ss, frame+20);
- put_fs_long(0,frame+21); /* 387 state pointer - not implemented*/
-/* non-iBCS2 extensions.. */
- put_fs_long(oldmask, frame+22);
- put_fs_long(current->tss.cr2, frame+23);
-/* set up the return code... */
- put_fs_long(0x0000b858, CODE(0)); /* popl %eax ; movl $,%eax */
- put_fs_long(0x80cd0000, CODE(4)); /* int $0x80 */
- put_fs_long(__NR_sigreturn, CODE(2));
- *fp = frame;
-#undef __CODE
-#undef CODE
-}
-
-/*
- * Note that 'init' is a special process: it doesn't get signals it doesn't
- * want to handle. Thus you cannot kill init even with a SIGKILL even by
- * mistake.
- *
- * Note that we go through the signals twice: once to check the signals that
- * the kernel can handle, and then we build all the user-level signal handling
- * stack-frames in one go after that.
- */
-asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
-{
- unsigned long mask = ~current->blocked;
- unsigned long handler_signal = 0;
- unsigned long *frame = NULL;
- unsigned long eip = 0;
- unsigned long signr;
- struct sigaction * sa;
-
- while ((signr = current->signal & mask)) {
- __asm__("bsf %2,%1\n\t"
- "btrl %1,%0"
- :"=m" (current->signal),"=r" (signr)
- :"1" (signr));
- sa = current->sigaction + signr;
- signr++;
- if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
- current->exit_code = signr;
- current->state = TASK_STOPPED;
- notify_parent(current);
- schedule();
- if (!(signr = current->exit_code))
- continue;
- current->exit_code = 0;
- if (signr == SIGSTOP)
- continue;
- if (_S(signr) & current->blocked) {
- current->signal |= _S(signr);
- continue;
- }
- sa = current->sigaction + signr - 1;
- }
- if (sa->sa_handler == SIG_IGN) {
- if (signr != SIGCHLD)
- continue;
- /* check for SIGCHLD: it's special */
- while (sys_waitpid(-1,NULL,WNOHANG) > 0)
- /* nothing */;
- continue;
- }
- if (sa->sa_handler == SIG_DFL) {
- if (current->pid == 1)
- continue;
- switch (signr) {
- case SIGCONT: case SIGCHLD: case SIGWINCH:
- continue;
-
- case SIGSTOP: case SIGTSTP: case SIGTTIN: case SIGTTOU:
- if (current->flags & PF_PTRACED)
- continue;
- current->state = TASK_STOPPED;
- current->exit_code = signr;
- if (!(current->p_pptr->sigaction[SIGCHLD-1].sa_flags &
- SA_NOCLDSTOP))
- notify_parent(current);
- schedule();
- continue;
-
- case SIGQUIT: case SIGILL: case SIGTRAP:
- case SIGIOT: case SIGFPE: case SIGSEGV:
- if (current->binfmt && current->binfmt->core_dump) {
- if (current->binfmt->core_dump(signr, regs))
- signr |= 0x80;
- }
- /* fall through */
- default:
- current->signal |= _S(signr & 0x7f);
- do_exit(signr);
- }
- }
- /*
- * OK, we're invoking a handler
- */
- if (regs->orig_eax >= 0) {
- if (regs->eax == -ERESTARTNOHAND ||
- (regs->eax == -ERESTARTSYS && !(sa->sa_flags & SA_RESTART)))
- regs->eax = -EINTR;
- }
- handler_signal |= 1 << (signr-1);
- mask &= ~sa->sa_mask;
- }
- if (regs->orig_eax >= 0 &&
- (regs->eax == -ERESTARTNOHAND ||
- regs->eax == -ERESTARTSYS ||
- regs->eax == -ERESTARTNOINTR)) {
- regs->eax = regs->orig_eax;
- regs->eip -= 2;
- }
- if (!handler_signal) /* no handler will be called - return 0 */
- return 0;
- eip = regs->eip;
- frame = (unsigned long *) regs->esp;
- signr = 1;
- sa = current->sigaction;
- for (mask = 1 ; mask ; sa++,signr++,mask += mask) {
- if (mask > handler_signal)
- break;
- if (!(mask & handler_signal))
- continue;
- setup_frame(sa,&frame,eip,regs,signr,oldmask);
- eip = (unsigned long) sa->sa_handler;
- if (sa->sa_flags & SA_ONESHOT)
- sa->sa_handler = NULL;
-/* force a supervisor-mode page-in of the signal handler to reduce races */
- __asm__("testb $0,%%fs:%0": :"m" (*(char *) eip));
- regs->cs = USER_CS; regs->ss = USER_DS;
- regs->ds = USER_DS; regs->es = USER_DS;
- regs->gs = USER_DS; regs->fs = USER_DS;
- current->blocked |= sa->sa_mask;
- oldmask |= sa->sa_mask;
- }
- regs->esp = (unsigned long) frame;
- regs->eip = eip; /* "return" to the first handler */
- current->tss.trap_no = current->tss.error_code = 0;
- return 1;
-}
diff --git a/kernel/splx.c b/kernel/splx.c
deleted file mode 100644
index c1b292ec9..000000000
--- a/kernel/splx.c
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * splx.c - SYSV DDI/DKI ipl manipulation functions
- *
- * Internally, many unices use a range of different interrupt
- * privilege levels, ie from "allow all interrupts" (7) to
- * "allow no interrupts." (0) under SYSV.
- *
- * This a simple splx() function behaves as the SYSV DDI/DKI function does,
- * although since Linux only implements the equivalent of level 0 (cli) and
- * level 7 (sti), this implementation only implements those levels.
- *
- * Also, unlike the current Linux routines, splx() also returns the
- * old privilege level so that it can be restored.
- */
-
-#include <asm/system.h>
-
-int splx (int new_level) {
- register int old_level, tmp;
- save_flags(tmp);
- old_level = (tmp & 0x200) ? 7 : 0;
- if (new_level)
- sti();
- else
- cli();
- return old_level;
-}
diff --git a/kernel/sys.c b/kernel/sys.c
index 1ce3ee387..706e3d66e 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -42,15 +42,26 @@ asmlinkage int sys_idle(void)
if (current->pid != 0)
return -EPERM;
+#ifdef __i386__
/* Map out the low memory: it's no longer needed */
for (i = 0 ; i < 768 ; i++)
swapper_pg_dir[i] = 0;
+#endif
/* endless idle loop with no priority at all */
current->counter = -100;
for (;;) {
+#if defined (__i386__)
if (hlt_works_ok && !need_resched)
__asm__("hlt");
+#elif defined (__mips__)
+ /*
+ * R4[26]00 have wait, the R4000 doesn't.
+ * Dunno about the R4400...
+ */
+ if (!need_resched)
+ __asm__("wait");
+#endif
schedule();
}
}
diff --git a/kernel/time.c b/kernel/time.c
index e290a3654..1a25d43ef 100644
--- a/kernel/time.c
+++ b/kernel/time.c
@@ -200,7 +200,7 @@ static inline unsigned long do_gettimeoffset(void)
*/
static inline void do_gettimeofday(struct timeval *tv)
{
-#ifdef __i386__
+#if defined (__i386__) || defined (__mips__)
cli();
*tv = xtime;
tv->tv_usec += do_gettimeoffset();
diff --git a/kernel/traps.c b/kernel/traps.c
deleted file mode 100644
index 150b702b3..000000000
--- a/kernel/traps.c
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * linux/kernel/traps.c
- *
- * Copyright (C) 1991, 1992 Linus Torvalds
- */
-
-/*
- * 'Traps.c' handles hardware traps and faults after we have saved some
- * state in 'asm.s'. Currently mostly a debugging-aid, will be extended
- * to mainly kill the offending process (probably by giving it a signal,
- * but possibly by killing it outright if necessary).
- */
-#include <linux/head.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/ptrace.h>
-
-#include <asm/system.h>
-#include <asm/segment.h>
-#include <asm/io.h>
-
-static inline void console_verbose(void)
-{
- extern int console_loglevel;
- console_loglevel = 15;
-}
-
-#define DO_ERROR(trapnr, signr, str, name, tsk) \
-asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
-{ \
- tsk->tss.error_code = error_code; \
- tsk->tss.trap_no = trapnr; \
- if (signr == SIGTRAP && current->flags & PF_PTRACED) \
- current->blocked &= ~(1 << (SIGTRAP-1)); \
- send_sig(signr, tsk, 1); \
- die_if_kernel(str,regs,error_code); \
-}
-
-#define get_seg_byte(seg,addr) ({ \
-register unsigned char __res; \
-__asm__("push %%fs;mov %%ax,%%fs;movb %%fs:%2,%%al;pop %%fs" \
- :"=a" (__res):"0" (seg),"m" (*(addr))); \
-__res;})
-
-#define get_seg_long(seg,addr) ({ \
-register unsigned long __res; \
-__asm__("push %%fs;mov %%ax,%%fs;movl %%fs:%2,%%eax;pop %%fs" \
- :"=a" (__res):"0" (seg),"m" (*(addr))); \
-__res;})
-
-#define _fs() ({ \
-register unsigned short __res; \
-__asm__("mov %%fs,%%ax":"=a" (__res):); \
-__res;})
-
-void page_exception(void);
-
-asmlinkage void divide_error(void);
-asmlinkage void debug(void);
-asmlinkage void nmi(void);
-asmlinkage void int3(void);
-asmlinkage void overflow(void);
-asmlinkage void bounds(void);
-asmlinkage void invalid_op(void);
-asmlinkage void device_not_available(void);
-asmlinkage void double_fault(void);
-asmlinkage void coprocessor_segment_overrun(void);
-asmlinkage void invalid_TSS(void);
-asmlinkage void segment_not_present(void);
-asmlinkage void stack_segment(void);
-asmlinkage void general_protection(void);
-asmlinkage void page_fault(void);
-asmlinkage void coprocessor_error(void);
-asmlinkage void reserved(void);
-asmlinkage void alignment_check(void);
-
-/*static*/ void die_if_kernel(char * str, struct pt_regs * regs, long err)
-{
- int i;
- unsigned long esp;
- unsigned short ss;
-
- esp = (unsigned long) &regs->esp;
- ss = KERNEL_DS;
- if ((regs->eflags & VM_MASK) || (3 & regs->cs) == 3)
- return;
- if (regs->cs & 3) {
- esp = regs->esp;
- ss = regs->ss;
- }
- console_verbose();
- printk("%s: %04lx\n", str, err & 0xffff);
- printk("EIP: %04x:%08lx\nEFLAGS: %08lx\n", 0xffff & regs->cs,regs->eip,regs->eflags);
- printk("eax: %08lx ebx: %08lx ecx: %08lx edx: %08lx\n",
- regs->eax, regs->ebx, regs->ecx, regs->edx);
- printk("esi: %08lx edi: %08lx ebp: %08lx esp: %08lx\n",
- regs->esi, regs->edi, regs->ebp, esp);
- printk("ds: %04x es: %04x fs: %04x gs: %04x ss: %04x\n",
- regs->ds, regs->es, regs->fs, regs->gs, ss);
- store_TR(i);
- if (STACK_MAGIC != *(unsigned long *)current->kernel_stack_page)
- printk("Corrupted stack page\n");
- printk("Process %s (pid: %d, process nr: %d, stackpage=%08lx)\nStack: ",
- current->comm, current->pid, 0xffff & i, current->kernel_stack_page);
- for(i=0;i<5;i++)
- printk("%08lx ", get_seg_long(ss,(i+(unsigned long *)esp)));
- printk("\nCode: ");
- for(i=0;i<20;i++)
- printk("%02x ",0xff & get_seg_byte(regs->cs,(i+(char *)regs->eip)));
- printk("\n");
- do_exit(SIGSEGV);
-}
-
-DO_ERROR( 0, SIGFPE, "divide error", divide_error, current)
-DO_ERROR( 3, SIGTRAP, "int3", int3, current)
-DO_ERROR( 4, SIGSEGV, "overflow", overflow, current)
-DO_ERROR( 5, SIGSEGV, "bounds", bounds, current)
-DO_ERROR( 6, SIGILL, "invalid operand", invalid_op, current)
-DO_ERROR( 7, SIGSEGV, "device not available", device_not_available, current)
-DO_ERROR( 8, SIGSEGV, "double fault", double_fault, current)
-DO_ERROR( 9, SIGFPE, "coprocessor segment overrun", coprocessor_segment_overrun, last_task_used_math)
-DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS, current)
-DO_ERROR(11, SIGBUS, "segment not present", segment_not_present, current)
-DO_ERROR(12, SIGBUS, "stack segment", stack_segment, current)
-DO_ERROR(15, SIGSEGV, "reserved", reserved, current)
-DO_ERROR(17, SIGSEGV, "alignment check", alignment_check, current)
-
-asmlinkage void do_general_protection(struct pt_regs * regs, long error_code)
-{
- int signr = SIGSEGV;
-
- if (regs->eflags & VM_MASK) {
- handle_vm86_fault((struct vm86_regs *) regs, error_code);
- return;
- }
- die_if_kernel("general protection",regs,error_code);
- switch (get_seg_byte(regs->cs, (char *)regs->eip)) {
- case 0xCD: /* INT */
- case 0xF4: /* HLT */
- case 0xFA: /* CLI */
- case 0xFB: /* STI */
- signr = SIGILL;
- }
- current->tss.error_code = error_code;
- current->tss.trap_no = 13;
- send_sig(signr, current, 1);
-}
-
-asmlinkage void do_nmi(struct pt_regs * regs, long error_code)
-{
- printk("Uhhuh. NMI received. Dazed and confused, but trying to continue\n");
- printk("You probably have a hardware problem with your RAM chips\n");
-}
-
-asmlinkage void do_debug(struct pt_regs * regs, long error_code)
-{
- if (regs->eflags & VM_MASK) {
- handle_vm86_debug((struct vm86_regs *) regs, error_code);
- return;
- }
- if (current->flags & PF_PTRACED)
- current->blocked &= ~(1 << (SIGTRAP-1));
- send_sig(SIGTRAP, current, 1);
- current->tss.trap_no = 1;
- current->tss.error_code = error_code;
- if ((regs->cs & 3) == 0) {
- /* If this is a kernel mode trap, then reset db7 and allow us to continue */
- __asm__("movl %0,%%db7"
- : /* no output */
- : "r" (0));
- return;
- }
- die_if_kernel("debug",regs,error_code);
-}
-
-/*
- * Allow the process which triggered the interrupt to recover the error
- * condition.
- * - the status word is saved in the cs selector.
- * - the tag word is saved in the operand selector.
- * - the status word is then cleared and the tags all set to Empty.
- *
- * This will give sufficient information for complete recovery provided that
- * the affected process knows or can deduce the code and data segments
- * which were in force when the exception condition arose.
- *
- * Note that we play around with the 'TS' bit to hopefully get
- * the correct behaviour even in the presence of the asynchronous
- * IRQ13 behaviour
- */
-void math_error(void)
-{
- struct i387_hard_struct * env;
-
- clts();
- if (!last_task_used_math) {
- __asm__("fnclex");
- return;
- }
- env = &last_task_used_math->tss.i387.hard;
- send_sig(SIGFPE, last_task_used_math, 1);
- last_task_used_math->tss.trap_no = 16;
- last_task_used_math->tss.error_code = 0;
- __asm__ __volatile__("fnsave %0":"=m" (*env));
- last_task_used_math = NULL;
- stts();
- env->fcs = (env->swd & 0x0000ffff) | (env->fcs & 0xffff0000);
- env->fos = env->twd;
- env->swd &= 0xffff3800;
- env->twd = 0xffffffff;
-}
-
-asmlinkage void do_coprocessor_error(struct pt_regs * regs, long error_code)
-{
- ignore_irq13 = 1;
- math_error();
-}
-
-void trap_init(void)
-{
- int i;
-
- set_trap_gate(0,&divide_error);
- set_trap_gate(1,&debug);
- set_trap_gate(2,&nmi);
- set_system_gate(3,&int3); /* int3-5 can be called from all */
- set_system_gate(4,&overflow);
- set_system_gate(5,&bounds);
- set_trap_gate(6,&invalid_op);
- set_trap_gate(7,&device_not_available);
- set_trap_gate(8,&double_fault);
- set_trap_gate(9,&coprocessor_segment_overrun);
- set_trap_gate(10,&invalid_TSS);
- set_trap_gate(11,&segment_not_present);
- set_trap_gate(12,&stack_segment);
- set_trap_gate(13,&general_protection);
- set_trap_gate(14,&page_fault);
- set_trap_gate(15,&reserved);
- set_trap_gate(16,&coprocessor_error);
- set_trap_gate(17,&alignment_check);
- for (i=18;i<48;i++)
- set_trap_gate(i,&reserved);
-}
diff --git a/kernel/vm86.c b/kernel/vm86.c
deleted file mode 100644
index 144d93a02..000000000
--- a/kernel/vm86.c
+++ /dev/null
@@ -1,404 +0,0 @@
-/*
- * linux/kernel/vm86.c
- *
- * Copyright (C) 1994 Linus Torvalds
- */
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/signal.h>
-#include <linux/string.h>
-#include <linux/ptrace.h>
-
-#include <asm/segment.h>
-#include <asm/io.h>
-
-/*
- * Known problems:
- *
- * Interrupt handling is not guaranteed:
- * - a real x86 will disable all interrupts for one instruction
- * after a "mov ss,xx" to make stack handling atomic even without
- * the 'lss' instruction. We can't guarantee this in v86 mode,
- * as the next instruction might result in a page fault or similar.
- * - a real x86 will have interrupts disabled for one instruction
- * past the 'sti' that enables them. We don't bother with all the
- * details yet..
- *
- * Hopefully these problems do not actually matter for anything.
- */
-
-/*
- * 8- and 16-bit register defines..
- */
-#define AL(regs) (((unsigned char *)&((regs)->eax))[0])
-#define AH(regs) (((unsigned char *)&((regs)->eax))[1])
-#define IP(regs) (*(unsigned short *)&((regs)->eip))
-#define SP(regs) (*(unsigned short *)&((regs)->esp))
-
-/*
- * virtual flags (16 and 32-bit versions)
- */
-#define VFLAGS (*(unsigned short *)&(current->v86flags))
-#define VEFLAGS (current->v86flags)
-
-#define set_flags(X,new,mask) \
-((X) = ((X) & ~(mask)) | ((new) & (mask)))
-
-#define SAFE_MASK (0xDD5)
-#define RETURN_MASK (0xDFF)
-
-asmlinkage struct pt_regs * save_v86_state(struct vm86_regs * regs)
-{
- unsigned long tmp;
-
- if (!current->vm86_info) {
- printk("no vm86_info: BAD\n");
- do_exit(SIGSEGV);
- }
- set_flags(regs->eflags, VEFLAGS, VIF_MASK | current->v86mask);
- memcpy_tofs(&current->vm86_info->regs,regs,sizeof(*regs));
- put_fs_long(current->screen_bitmap,&current->vm86_info->screen_bitmap);
- tmp = current->tss.esp0;
- current->tss.esp0 = current->saved_kernel_stack;
- current->saved_kernel_stack = 0;
- return (struct pt_regs *) tmp;
-}
-
-static void mark_screen_rdonly(struct task_struct * tsk)
-{
- unsigned long tmp;
- unsigned long *pg_table;
-
- if ((tmp = tsk->tss.cr3) != 0) {
- tmp = *(unsigned long *) tmp;
- if (tmp & PAGE_PRESENT) {
- tmp &= PAGE_MASK;
- pg_table = (0xA0000 >> PAGE_SHIFT) + (unsigned long *) tmp;
- tmp = 32;
- while (tmp--) {
- if (PAGE_PRESENT & *pg_table)
- *pg_table &= ~PAGE_RW;
- pg_table++;
- }
- }
- }
-}
-
-asmlinkage int sys_vm86(struct vm86_struct * v86)
-{
- struct vm86_struct info;
- struct pt_regs * pt_regs = (struct pt_regs *) &v86;
- int error;
-
- if (current->saved_kernel_stack)
- return -EPERM;
- /* v86 must be readable (now) and writable (for save_v86_state) */
- error = verify_area(VERIFY_WRITE,v86,sizeof(*v86));
- if (error)
- return error;
- memcpy_fromfs(&info,v86,sizeof(info));
-/*
- * make sure the vm86() system call doesn't try to do anything silly
- */
- info.regs.__null_ds = 0;
- info.regs.__null_es = 0;
- info.regs.__null_fs = 0;
- info.regs.__null_gs = 0;
-/*
- * The eflags register is also special: we cannot trust that the user
- * has set it up safely, so this makes sure interrupt etc flags are
- * inherited from protected mode.
- */
- VEFLAGS = info.regs.eflags;
- info.regs.eflags &= SAFE_MASK;
- info.regs.eflags |= pt_regs->eflags & ~SAFE_MASK;
- info.regs.eflags |= VM_MASK;
-
- switch (info.cpu_type) {
- case CPU_286:
- current->v86mask = 0;
- break;
- case CPU_386:
- current->v86mask = NT_MASK | IOPL_MASK;
- break;
- case CPU_486:
- current->v86mask = AC_MASK | NT_MASK | IOPL_MASK;
- break;
- default:
- current->v86mask = ID_MASK | AC_MASK | NT_MASK | IOPL_MASK;
- break;
- }
-
-/*
- * Save old state, set default return value (%eax) to 0
- */
- pt_regs->eax = 0;
- current->saved_kernel_stack = current->tss.esp0;
- current->tss.esp0 = (unsigned long) pt_regs;
- current->vm86_info = v86;
-
- current->screen_bitmap = info.screen_bitmap;
- if (info.flags & VM86_SCREEN_BITMAP)
- mark_screen_rdonly(current);
- __asm__ __volatile__("movl %0,%%esp\n\t"
- "jmp ret_from_sys_call"
- : /* no outputs */
- :"r" (&info.regs));
- return 0;
-}
-
-static inline void return_to_32bit(struct vm86_regs * regs16, int retval)
-{
- struct pt_regs * regs32;
-
- regs32 = save_v86_state(regs16);
- regs32->eax = retval;
- __asm__ __volatile__("movl %0,%%esp\n\t"
- "jmp ret_from_sys_call"
- : : "r" (regs32));
-}
-
-static inline void set_IF(struct vm86_regs * regs)
-{
- VEFLAGS |= VIF_MASK;
- if (VEFLAGS & VIP_MASK)
- return_to_32bit(regs, VM86_STI);
-}
-
-static inline void clear_IF(struct vm86_regs * regs)
-{
- VEFLAGS &= ~VIF_MASK;
-}
-
-static inline void clear_TF(struct vm86_regs * regs)
-{
- regs->eflags &= ~TF_MASK;
-}
-
-static inline void set_vflags_long(unsigned long eflags, struct vm86_regs * regs)
-{
- set_flags(VEFLAGS, eflags, current->v86mask);
- set_flags(regs->eflags, eflags, SAFE_MASK);
- if (eflags & IF_MASK)
- set_IF(regs);
-}
-
-static inline void set_vflags_short(unsigned short flags, struct vm86_regs * regs)
-{
- set_flags(VFLAGS, flags, current->v86mask);
- set_flags(regs->eflags, flags, SAFE_MASK);
- if (flags & IF_MASK)
- set_IF(regs);
-}
-
-static inline unsigned long get_vflags(struct vm86_regs * regs)
-{
- unsigned long flags = regs->eflags & RETURN_MASK;
-
- if (VEFLAGS & VIF_MASK)
- flags |= IF_MASK;
- return flags | (VEFLAGS & current->v86mask);
-}
-
-static inline int is_revectored(int nr, struct revectored_struct * bitmap)
-{
- __asm__ __volatile__("btl %2,%%fs:%1\n\tsbbl %0,%0"
- :"=r" (nr)
- :"m" (*bitmap),"r" (nr));
- return nr;
-}
-
-/*
- * Boy are these ugly, but we need to do the correct 16-bit arithmetic.
- * Gcc makes a mess of it, so we do it inline and use non-obvious calling
- * conventions..
- */
-#define pushb(base, ptr, val) \
-__asm__ __volatile__( \
- "decw %w0\n\t" \
- "movb %2,%%fs:0(%1,%0)" \
- : "=r" (ptr) \
- : "r" (base), "q" (val), "0" (ptr))
-
-#define pushw(base, ptr, val) \
-__asm__ __volatile__( \
- "decw %w0\n\t" \
- "movb %h2,%%fs:0(%1,%0)\n\t" \
- "decw %w0\n\t" \
- "movb %b2,%%fs:0(%1,%0)" \
- : "=r" (ptr) \
- : "r" (base), "q" (val), "0" (ptr))
-
-#define pushl(base, ptr, val) \
-__asm__ __volatile__( \
- "decw %w0\n\t" \
- "rorl $16,%2\n\t" \
- "movb %h2,%%fs:0(%1,%0)\n\t" \
- "decw %w0\n\t" \
- "movb %b2,%%fs:0(%1,%0)\n\t" \
- "decw %w0\n\t" \
- "rorl $16,%2\n\t" \
- "movb %h2,%%fs:0(%1,%0)\n\t" \
- "decw %w0\n\t" \
- "movb %b2,%%fs:0(%1,%0)" \
- : "=r" (ptr) \
- : "r" (base), "q" (val), "0" (ptr))
-
-#define popb(base, ptr) \
-({ unsigned long __res; \
-__asm__ __volatile__( \
- "movb %%fs:0(%1,%0),%b2\n\t" \
- "incw %w0" \
- : "=r" (ptr), "=r" (base), "=q" (__res) \
- : "0" (ptr), "1" (base), "2" (0)); \
-__res; })
-
-#define popw(base, ptr) \
-({ unsigned long __res; \
-__asm__ __volatile__( \
- "movb %%fs:0(%1,%0),%b2\n\t" \
- "incw %w0\n\t" \
- "movb %%fs:0(%1,%0),%h2\n\t" \
- "incw %w0" \
- : "=r" (ptr), "=r" (base), "=q" (__res) \
- : "0" (ptr), "1" (base), "2" (0)); \
-__res; })
-
-#define popl(base, ptr) \
-({ unsigned long __res; \
-__asm__ __volatile__( \
- "movb %%fs:0(%1,%0),%b2\n\t" \
- "incw %w0\n\t" \
- "movb %%fs:0(%1,%0),%h2\n\t" \
- "incw %w0\n\t" \
- "rorl $16,%2\n\t" \
- "movb %%fs:0(%1,%0),%b2\n\t" \
- "incw %w0\n\t" \
- "movb %%fs:0(%1,%0),%h2\n\t" \
- "incw %w0\n\t" \
- "rorl $16,%2" \
- : "=r" (ptr), "=r" (base), "=q" (__res) \
- : "0" (ptr), "1" (base)); \
-__res; })
-
-static void do_int(struct vm86_regs *regs, int i, unsigned char * ssp, unsigned long sp)
-{
- unsigned short seg = get_fs_word((void *) ((i<<2)+2));
-
- if (seg == BIOSSEG || regs->cs == BIOSSEG ||
- is_revectored(i, &current->vm86_info->int_revectored))
- return_to_32bit(regs, VM86_INTx + (i << 8));
- if (i==0x21 && is_revectored(AH(regs),&current->vm86_info->int21_revectored))
- return_to_32bit(regs, VM86_INTx + (i << 8));
- pushw(ssp, sp, get_vflags(regs));
- pushw(ssp, sp, regs->cs);
- pushw(ssp, sp, IP(regs));
- regs->cs = seg;
- SP(regs) -= 6;
- IP(regs) = get_fs_word((void *) (i<<2));
- clear_TF(regs);
- clear_IF(regs);
- return;
-}
-
-void handle_vm86_debug(struct vm86_regs * regs, long error_code)
-{
-#if 0
- do_int(regs, 1, (unsigned char *) (regs->ss << 4), SP(regs));
-#else
- if (current->flags & PF_PTRACED)
- current->blocked &= ~(1 << (SIGTRAP-1));
- send_sig(SIGTRAP, current, 1);
- current->tss.trap_no = 1;
- current->tss.error_code = error_code;
-#endif
-}
-
-void handle_vm86_fault(struct vm86_regs * regs, long error_code)
-{
- unsigned char *csp, *ssp;
- unsigned long ip, sp;
-
- csp = (unsigned char *) (regs->cs << 4);
- ssp = (unsigned char *) (regs->ss << 4);
- sp = SP(regs);
- ip = IP(regs);
-
- switch (popb(csp, ip)) {
-
- /* operand size override */
- case 0x66:
- switch (popb(csp, ip)) {
-
- /* pushfd */
- case 0x9c:
- SP(regs) -= 4;
- IP(regs) += 2;
- pushl(ssp, sp, get_vflags(regs));
- return;
-
- /* popfd */
- case 0x9d:
- SP(regs) += 4;
- IP(regs) += 2;
- set_vflags_long(popl(ssp, sp), regs);
- return;
- }
-
- /* pushf */
- case 0x9c:
- SP(regs) -= 2;
- IP(regs)++;
- pushw(ssp, sp, get_vflags(regs));
- return;
-
- /* popf */
- case 0x9d:
- SP(regs) += 2;
- IP(regs)++;
- set_vflags_short(popw(ssp, sp), regs);
- return;
-
- /* int 3 */
- case 0xcc:
- IP(regs)++;
- do_int(regs, 3, ssp, sp);
- return;
-
- /* int xx */
- case 0xcd:
- IP(regs) += 2;
- do_int(regs, popb(csp, ip), ssp, sp);
- return;
-
- /* iret */
- case 0xcf:
- SP(regs) += 6;
- IP(regs) = popw(ssp, sp);
- regs->cs = popw(ssp, sp);
- set_vflags_short(popw(ssp, sp), regs);
- return;
-
- /* cli */
- case 0xfa:
- IP(regs)++;
- clear_IF(regs);
- return;
-
- /* sti */
- /*
- * Damn. This is incorrect: the 'sti' instruction should actually
- * enable interrupts after the /next/ instruction. Not good.
- *
- * Probably needs some horsing around with the TF flag. Aiee..
- */
- case 0xfb:
- IP(regs)++;
- set_IF(regs);
- return;
-
- default:
- return_to_32bit(regs, VM86_UNKNOWN);
- }
-}