diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/Makefile | 4 | ||||
-rw-r--r-- | kernel/bios32.c | 476 | ||||
-rw-r--r-- | kernel/dma.c | 9 | ||||
-rw-r--r-- | kernel/exit.c | 2 | ||||
-rw-r--r-- | kernel/fork.c | 159 | ||||
-rw-r--r-- | kernel/ioport.c | 194 | ||||
-rw-r--r-- | kernel/irq.c | 354 | ||||
-rw-r--r-- | kernel/ksyms.c | 2 | ||||
-rw-r--r-- | kernel/ldt.c | 103 | ||||
-rw-r--r-- | kernel/ptrace.c | 517 | ||||
-rw-r--r-- | kernel/sched.c | 861 | ||||
-rw-r--r-- | kernel/signal.c | 407 | ||||
-rw-r--r-- | kernel/splx.c | 27 | ||||
-rw-r--r-- | kernel/sys.c | 11 | ||||
-rw-r--r-- | kernel/time.c | 2 | ||||
-rw-r--r-- | kernel/traps.c | 245 | ||||
-rw-r--r-- | kernel/vm86.c | 404 |
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, ®s); + 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 *) ¤t->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) ®s->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,÷_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(¤t->vm86_info->regs,regs,sizeof(*regs)); - put_fs_long(current->screen_bitmap,¤t->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, ¤t->vm86_info->int_revectored)) - return_to_32bit(regs, VM86_INTx + (i << 8)); - if (i==0x21 && is_revectored(AH(regs),¤t->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); - } -} |