!C99Shell v. 1.0 pre-release build #13!

Software: Apache/2.0.54 (Unix) mod_perl/1.99_09 Perl/v5.8.0 mod_ssl/2.0.54 OpenSSL/0.9.7l DAV/2 FrontPage/5.0.2.2635 PHP/4.4.0 mod_gzip/2.0.26.1a 

uname -a: Linux snow.he.net 4.4.276-v2-mono-1 #1 SMP Wed Jul 21 11:21:17 PDT 2021 i686 

uid=99(nobody) gid=98(nobody) groups=98(nobody) 

Safe-mode: OFF (not secure)

/usr/src/linux-2.4.18-xfs-1.1/arch/i386/kernel/   drwxr-xr-x
Free 318.32 GB of 458.09 GB (69.49%)
Home    Back    Forward    UPDIR    Refresh    Search    Buffer    Encoder    Tools    Proc.    FTP brute    Sec.    SQL    PHP-code    Update    Feedback    Self remove    Logout    


Viewing file:     traps.c (29.44 KB)      -rw-r--r--
Select action/file-type:
(+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
/*
 *  linux/arch/i386/traps.c
 *
 *  Copyright (C) 1991, 1992  Linus Torvalds
 *
 *  Pentium III FXSR, SSE support
 *    Gareth Hughes <gareth@valinux.com>, May 2000
 */

/*
 * 'Traps.c' handles hardware traps and faults after we have saved some
 * state in 'asm.s'.
 */
#include <linux/config.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/ptrace.h>
#include <linux/timer.h>
#include <linux/mm.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <linux/highmem.h>

#ifdef CONFIG_MCA
#include <linux/mca.h>
#include <asm/processor.h>
#endif

#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/atomic.h>
#include <asm/debugreg.h>
#include <asm/desc.h>
#include <asm/i387.h>

#include <asm/smp.h>
#include <asm/pgalloc.h>

#ifdef CONFIG_X86_VISWS_APIC
#include <asm/fixmap.h>
#include <asm/cobalt.h>
#include <asm/lithium.h>
#endif

#include <linux/irq.h>
#include <linux/module.h>

asmlinkage int system_call(void);
asmlinkage void lcall7(void);
asmlinkage void lcall27(void);

struct desc_struct default_ldt[] = { { 0, 0 }, { 0, 0 }, { 0, 0 },
        { 0, 0 }, { 0, 0 } };

/*
 * The IDT has to be page-aligned to simplify the Pentium
 * F0 0F bug workaround.. We have a special link segment
 * for this.
 */
struct desc_struct idt_table[256] __attribute__((__section__(".data.idt"))) = { {0, 0}, };

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 simd_coprocessor_error(void);
asmlinkage void alignment_check(void);
asmlinkage void spurious_interrupt_bug(void);
asmlinkage void machine_check(void);

int kstack_depth_to_print = 24;


/*
 * If the address is either in the .text section of the
 * kernel, or in the vmalloc'ed module regions, it *may* 
 * be the address of a calling routine
 */

#ifdef CONFIG_MODULES

extern struct module *module_list;
extern struct module kernel_module;

static inline int kernel_text_address(unsigned long addr)
{
    int retval = 0;
    struct module *mod;

    if (addr >= (unsigned long) &_stext &&
        addr <= (unsigned long) &_etext)
        return 1;

    for (mod = module_list; mod != &kernel_module; mod = mod->next) {
        /* mod_bound tests for addr being inside the vmalloc'ed
         * module area. Of course it'd be better to test only
         * for the .text subset... */
        if (mod_bound(addr, 0, mod)) {
            retval = 1;
            break;
        }
    }

    return retval;
}

#else

static inline int kernel_text_address(unsigned long addr)
{
    return (addr >= (unsigned long) &_stext &&
        addr <= (unsigned long) &_etext);
}

#endif

void show_trace(unsigned long * stack)
{
    int i;
    unsigned long addr;

    if (!stack)
        stack = (unsigned long*)&stack;

    printk("Call Trace: ");
    i = 1;
    while (((long) stack & (THREAD_SIZE-1)) != 0) {
        addr = *stack++;
        if (kernel_text_address(addr)) {
            if (i && ((i % 6) == 0))
                printk("\n   ");
            printk("[<%08lx>] ", addr);
            i++;
        }
    }
    printk("\n");
}

void show_trace_task(struct task_struct *tsk)
{
    unsigned long esp = tsk->thread.esp;

    /* User space on another CPU? */
    if ((esp ^ (unsigned long)tsk) & (PAGE_MASK<<1))
        return;
    show_trace((unsigned long *)esp);
}

void show_stack(unsigned long * esp)
{
    unsigned long *stack;
    int i;

    // debugging aid: "show_stack(NULL);" prints the
    // back trace for this cpu.

    if(esp==NULL)
        esp=(unsigned long*)&esp;

    stack = esp;
    for(i=0; i < kstack_depth_to_print; i++) {
        if (((long) stack & (THREAD_SIZE-1)) == 0)
            break;
        if (i && ((i % 8) == 0))
            printk("\n       ");
        printk("%08lx ", *stack++);
    }
    printk("\n");
    show_trace(esp);
}

void show_registers(struct pt_regs *regs)
{
    int i;
    int in_kernel = 1;
    unsigned long esp;
    unsigned short ss;

    esp = (unsigned long) (&regs->esp);
    ss = __KERNEL_DS;
    if (regs->xcs & 3) {
        in_kernel = 0;
        esp = regs->esp;
        ss = regs->xss & 0xffff;
    }
    printk("CPU:    %d\nEIP:    %04x:[<%08lx>]    %s\nEFLAGS: %08lx\n",
        smp_processor_id(), 0xffff & regs->xcs, regs->eip, print_tainted(), 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   ss: %04x\n",
        regs->xds & 0xffff, regs->xes & 0xffff, ss);
    printk("Process %s (pid: %d, stackpage=%08lx)",
        current->comm, current->pid, 4096+(unsigned long)current);
    /*
     * When in-kernel, we also print out the stack and code at the
     * time of the fault..
     */
    if (in_kernel) {

        printk("\nStack: ");
        show_stack((unsigned long*)esp);

        printk("\nCode: ");
        if(regs->eip < PAGE_OFFSET)
            goto bad;

        for(i=0;i<20;i++)
        {
            unsigned char c;
            if(__get_user(c, &((unsigned char*)regs->eip)[i])) {
bad:
                printk(" Bad EIP value.");
                break;
            }
            printk("%02x ", c);
        }
    }
    printk("\n");
}    

spinlock_t die_lock = SPIN_LOCK_UNLOCKED;

void die(const char * str, struct pt_regs * regs, long err)
{
    console_verbose();
    spin_lock_irq(&die_lock);
    bust_spinlocks(1);
    printk("%s: %04lx\n", str, err & 0xffff);
    show_registers(regs);
    bust_spinlocks(0);
    spin_unlock_irq(&die_lock);
    do_exit(SIGSEGV);
}

static inline void die_if_kernel(const char * str, struct pt_regs * regs, long err)
{
    if (!(regs->eflags & VM_MASK) && !(3 & regs->xcs))
        die(str, regs, err);
}

static inline unsigned long get_cr2(void)
{
    unsigned long address;

    /* get the address */
    __asm__("movl %%cr2,%0":"=r" (address));
    return address;
}

static void inline do_trap(int trapnr, int signr, char *str, int vm86,
               struct pt_regs * regs, long error_code, siginfo_t *info)
{
    if (vm86 && regs->eflags & VM_MASK)
        goto vm86_trap;
    if (!(regs->xcs & 3))
        goto kernel_trap;

    trap_signal: {
        struct task_struct *tsk = current;
        tsk->thread.error_code = error_code;
        tsk->thread.trap_no = trapnr;
        if (info)
            force_sig_info(signr, info, tsk);
        else
            force_sig(signr, tsk);
        return;
    }

    kernel_trap: {
        unsigned long fixup = search_exception_table(regs->eip);
        if (fixup)
            regs->eip = fixup;
        else    
            die(str, regs, error_code);
        return;
    }

    vm86_trap: {
        int ret = handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, trapnr);
        if (ret) goto trap_signal;
        return;
    }
}

#define DO_ERROR(trapnr, signr, str, name) \
asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
{ \
    do_trap(trapnr, signr, str, 0, regs, error_code, NULL); \
}

#define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \
asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
{ \
    siginfo_t info; \
    info.si_signo = signr; \
    info.si_errno = 0; \
    info.si_code = sicode; \
    info.si_addr = (void *)siaddr; \
    do_trap(trapnr, signr, str, 0, regs, error_code, &info); \
}

#define DO_VM86_ERROR(trapnr, signr, str, name) \
asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
{ \
    do_trap(trapnr, signr, str, 1, regs, error_code, NULL); \
}

#define DO_VM86_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \
asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
{ \
    siginfo_t info; \
    info.si_signo = signr; \
    info.si_errno = 0; \
    info.si_code = sicode; \
    info.si_addr = (void *)siaddr; \
    do_trap(trapnr, signr, str, 1, regs, error_code, &info); \
}

DO_VM86_ERROR_INFO( 0, SIGFPE,  "divide error", divide_error, FPE_INTDIV, regs->eip)
DO_VM86_ERROR( 3, SIGTRAP, "int3", int3)
DO_VM86_ERROR( 4, SIGSEGV, "overflow", overflow)
DO_VM86_ERROR( 5, SIGSEGV, "bounds", bounds)
DO_ERROR_INFO( 6, SIGILL,  "invalid operand", invalid_op, ILL_ILLOPN, regs->eip)
DO_VM86_ERROR( 7, SIGSEGV, "device not available", device_not_available)
DO_ERROR( 8, SIGSEGV, "double fault", double_fault)
DO_ERROR( 9, SIGFPE,  "coprocessor segment overrun", coprocessor_segment_overrun)
DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS)
DO_ERROR(11, SIGBUS,  "segment not present", segment_not_present)
DO_ERROR(12, SIGBUS,  "stack segment", stack_segment)
DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, get_cr2())

#if defined(CONFIG_HARDEN_STACK) && defined(CONFIG_HARDEN_STACK_SMART)
/*
 * These two functions aren't performance critical (trampolines are
 * extremely rare and slow even without emulation).
 */
static unsigned long *get_reg(struct pt_regs *regs, unsigned char regnum)
{
    switch (regnum) {
        case 0: return &regs->eax;
        case 1: return &regs->ecx;
        case 2: return &regs->edx;
        case 3: return &regs->ebx;
        case 4: return &regs->esp;
        case 5: return &regs->ebp;
        case 6: return &regs->esi;
        case 7: return &regs->edi;
    }

    return NULL;
}

static unsigned long get_modrm(struct pt_regs *regs, int *err)
{
    unsigned char modrm, sib;
    signed char rel8;
    unsigned long rel32;
    int size, regnum, scale;
    unsigned long index, base, addr, value;

    *err |= __get_user(modrm, (unsigned char *)(regs->eip + 1));
    size = 2;
    regnum = modrm & 7;
    addr = *get_reg(regs, regnum);
    if (regnum == 4 && (modrm & 0xC0) != 0xC0) {
        *err |= __get_user(sib, (unsigned char *)(regs->eip + 2));
        size = 3;
        scale = sib >> 6;
        index = *get_reg(regs, (sib >> 3) & 7);
        base = *get_reg(regs, sib & 7);
        addr = base + (index << scale);
    }

    switch (modrm & 0xC0) {
    case 0x00:
        if (regnum == 5) {
            *err |= __get_user(addr,
                (unsigned long *)(regs->eip + 2));
            size = 6;
        }
        *err |= __get_user(value, (unsigned long *)addr);
        break;

    case 0x40:
        *err |= __get_user(rel8, (signed char *)(regs->eip + size));
        size++;
        addr += rel8;
        *err |= __get_user(value, (unsigned long *)addr);
        break;

    case 0x80:
        *err |= __get_user(rel32, (unsigned long *)(regs->eip + size));
        size += 4;
        addr += rel32;
        *err |= __get_user(value, (unsigned long *)addr);
        break;

    case 0xC0:
    default:
        value = addr;
    }

    if (*err) return 0;
    regs->eip += size;
    return value;
}
#endif

asmlinkage void do_general_protection(struct pt_regs * regs, long error_code)
{
#ifdef CONFIG_HARDEN_STACK
    unsigned long addr;
#ifdef CONFIG_HARDEN_STACK_SMART
    unsigned char insn;
    int err, count;
#endif
#endif

    if (regs->eflags & VM_MASK)
        goto gp_in_vm86;

    if (!(regs->xcs & 3))
        goto gp_in_kernel;

#ifdef CONFIG_HARDEN_STACK
/* Check if it was return from a signal handler */
    if ((regs->xcs & 0xFFFF) == __USER_CS)
    if (*(unsigned char *)regs->eip == 0xC3)
    if (!__get_user(addr, (unsigned long *)regs->esp)) {
        if ((addr & 0xFFFFFFFE) == MAGIC_SIGRETURN) {
/* Call sys_sigreturn() or sys_rt_sigreturn() to restore the context */
            regs->esp += 8;
            __asm__("movl %3,%%esi\n\t"
                "subl %1,%%esp\n\t"
                "movl %2,%%ecx\n\t"
                "movl %%esp,%%edi\n\t"
                "rep; movsl\n\t"
                "testl $1,%4\n\t"
                "jnz 1f\n\t"
                "call sys_sigreturn\n\t"
                "leal %3,%%edi\n\t"
                "jmp 2f\n\t"
                "1:\n\t"
                "call sys_rt_sigreturn\n\t"
                "leal %3,%%edi\n\t"
                "2:\n\t"
                "addl %1,%%edi\n\t"
                "movl %%esp,%%esi\n\t"
                "movl %2,%%ecx\n\t"
                "movl (%%edi),%%edi\n\t"
                "rep; movsl\n\t"
                "movl %%esi,%%esp"
            :
/* %eax is returned separately */
            "=a" (regs->eax)
            :
            "i" (sizeof(*regs)),
            "i" (sizeof(*regs) >> 2),
            "m" (regs),
            "r" (addr)
            :
            "cx", "dx", "si", "di", "cc", "memory");
            return;
        }

/*
 * Check if we're returning to the stack area, which is only likely to happen
 * when attempting to exploit a buffer overflow.
 */
        if (addr >= PAGE_OFFSET - _STK_LIM && addr < PAGE_OFFSET)
            security_alert("return onto stack running as "
                "UID %d, EUID %d, process %s:%d",
                "returns onto stack",
                current->uid, current->euid,
                current->comm, current->pid);
    }

#ifdef CONFIG_HARDEN_STACK_SMART
/* Check if it could have been a trampoline call */
    if ((regs->xcs & 0xFFFF) == __USER_CS)
    if (*(unsigned char *)regs->eip == 0xFF)
    if (!__get_user(insn, (unsigned char *)(regs->eip + 1)))
    if ((insn & 0x38) == 0x10 && insn != 0xD4) {    /* call mod r/m */
/* First, emulate the call */
        err = 0;
        addr = get_modrm(regs, &err);
        if (!err) {
            regs->esp -= 4;
            err = __put_user(regs->eip, (unsigned long *)regs->esp);
            regs->eip = addr;
        }
/* Then, start emulating the trampoline itself */
        count = 0;
        while (!err && !__get_user(insn, (unsigned char *)regs->eip++))
        if ((insn & 0xF8) == 0xB8) {        /* movl imm32,%reg */
/* We only have 8 GP registers, no reason to initialize one twice */
            if (count++ >= 8) break;
            err |= __get_user(addr, (unsigned long *)regs->eip);
            regs->eip += 4;
            *get_reg(regs, insn & 7) = addr;
        } else
        if (insn == 0xFF) {
            err |= __get_user(insn, (unsigned char *)regs->eip);
            if ((insn & 0xF8) == 0xE0) {    /* jmp *%reg */
                regs->eip = *get_reg(regs, insn & 7);
                if (err) break; else return;
            }
            break;
        } else
        if (insn == 0xE9) {            /* jmp rel32 */
            err |= __get_user(addr, (unsigned long *)regs->eip);
            if (err) break;
            regs->eip += 4 + addr;
            return;
        } else
            break;
    }
#endif
#endif

    current->thread.error_code = error_code;
    current->thread.trap_no = 13;
    force_sig(SIGSEGV, current);
    return;

gp_in_vm86:
    handle_vm86_fault((struct kernel_vm86_regs *) regs, error_code);
    return;

gp_in_kernel:
    {
        unsigned long fixup;
        fixup = search_exception_table(regs->eip);
        if (fixup) {
            regs->eip = fixup;
            return;
        }
        die("general protection fault", regs, error_code);
    }
}

static void mem_parity_error(unsigned char reason, struct pt_regs * regs)
{
    printk("Uhhuh. NMI received. Dazed and confused, but trying to continue\n");
    printk("You probably have a hardware problem with your RAM chips\n");

    /* Clear and disable the memory parity error line. */
    reason = (reason & 0xf) | 4;
    outb(reason, 0x61);
}

static void io_check_error(unsigned char reason, struct pt_regs * regs)
{
    unsigned long i;

    printk("NMI: IOCK error (debug interrupt?)\n");
    show_registers(regs);

    /* Re-enable the IOCK line, wait for a few seconds */
    reason = (reason & 0xf) | 8;
    outb(reason, 0x61);
    i = 2000;
    while (--i) udelay(1000);
    reason &= ~8;
    outb(reason, 0x61);
}

static void unknown_nmi_error(unsigned char reason, struct pt_regs * regs)
{
#ifdef CONFIG_MCA
    /* Might actually be able to figure out what the guilty party
    * is. */
    if( MCA_bus ) {
        mca_handle_nmi();
        return;
    }
#endif
    printk("Uhhuh. NMI received for unknown reason %02x.\n", reason);
    printk("Dazed and confused, but trying to continue\n");
    printk("Do you have a strange power saving mode enabled?\n");
}

asmlinkage void do_nmi(struct pt_regs * regs, long error_code)
{
    unsigned char reason = inb(0x61);

    ++nmi_count(smp_processor_id());

    if (!(reason & 0xc0)) {
#if CONFIG_X86_LOCAL_APIC
        /*
         * Ok, so this is none of the documented NMI sources,
         * so it must be the NMI watchdog.
         */
        if (nmi_watchdog) {
            nmi_watchdog_tick(regs);
            return;
        }
#endif
        unknown_nmi_error(reason, regs);
        return;
    }
    if (reason & 0x80)
        mem_parity_error(reason, regs);
    if (reason & 0x40)
        io_check_error(reason, regs);
    /*
     * Reassert NMI in case it became active meanwhile
     * as it's edge-triggered.
     */
    outb(0x8f, 0x70);
    inb(0x71);        /* dummy */
    outb(0x0f, 0x70);
    inb(0x71);        /* dummy */
}

/*
 * Our handling of the processor debug registers is non-trivial.
 * We do not clear them on entry and exit from the kernel. Therefore
 * it is possible to get a watchpoint trap here from inside the kernel.
 * However, the code in ./ptrace.c has ensured that the user can
 * only set watchpoints on userspace addresses. Therefore the in-kernel
 * watchpoint trap can only occur in code which is reading/writing
 * from user space. Such code must not hold kernel locks (since it
 * can equally take a page fault), therefore it is safe to call
 * force_sig_info even though that claims and releases locks.
 * 
 * Code in ./signal.c ensures that the debug control register
 * is restored before we deliver any signal, and therefore that
 * user code runs with the correct debug control register even though
 * we clear it here.
 *
 * Being careful here means that we don't have to be as careful in a
 * lot of more complicated places (task switching can be a bit lazy
 * about restoring all the debug state, and ptrace doesn't have to
 * find every occurrence of the TF bit that could be saved away even
 * by user code)
 */
asmlinkage void do_debug(struct pt_regs * regs, long error_code)
{
    unsigned int condition;
    struct task_struct *tsk = current;
    siginfo_t info;

    __asm__ __volatile__("movl %%db6,%0" : "=r" (condition));

    /* Mask out spurious debug traps due to lazy DR7 setting */
    if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) {
        if (!tsk->thread.debugreg[7])
            goto clear_dr7;
    }

    if (regs->eflags & VM_MASK)
        goto debug_vm86;

    /* Save debug status register where ptrace can see it */
    tsk->thread.debugreg[6] = condition;

    /* Mask out spurious TF errors due to lazy TF clearing */
    if (condition & DR_STEP) {
        /*
         * The TF error should be masked out only if the current
         * process is not traced and if the TRAP flag has been set
         * previously by a tracing process (condition detected by
         * the PT_DTRACE flag); remember that the i386 TRAP flag
         * can be modified by the process itself in user mode,
         * allowing programs to debug themselves without the ptrace()
         * interface.
         */
        if ((tsk->ptrace & (PT_DTRACE|PT_PTRACED)) == PT_DTRACE)
            goto clear_TF;
    }

    /*
     * If we entered the kernel via lcall and seem to have TF set,
     * clear it right after saving the flags ("pushfl", a one-byte
     * instruction).
     */
    if (regs->eip == (unsigned long)&lcall7 + 1 ||
        regs->eip == (unsigned long)&lcall27 + 1)
        goto clear_TF;

    /* Ok, finally something we can handle */
    tsk->thread.trap_no = 1;
    tsk->thread.error_code = error_code;
    info.si_signo = SIGTRAP;
    info.si_errno = 0;
    info.si_code = TRAP_BRKPT;
    
    /* If this is a kernel mode trap, save the user PC on entry to 
     * the kernel, that's what the debugger can make sense of.
     */
    info.si_addr = ((regs->xcs & 3) == 0) ? (void *)tsk->thread.eip : 
                                            (void *)regs->eip;
    force_sig_info(SIGTRAP, &info, tsk);

    /* Disable additional traps. They'll be re-enabled when
     * the signal is delivered.
     */
clear_dr7:
    __asm__("movl %0,%%db7"
        : /* no output */
        : "r" (0));
    return;

debug_vm86:
    handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, 1);
    return;

clear_TF:
    regs->eflags &= ~TF_MASK;
    return;
}

/*
 * Note that we play around with the 'TS' bit in an attempt to get
 * the correct behaviour even in the presence of the asynchronous
 * IRQ13 behaviour
 */
void math_error(void *eip)
{
    struct task_struct * task;
    siginfo_t info;
    unsigned short cwd, swd;

    /*
     * Save the info for the exception handler and clear the error.
     */
    task = current;
    save_init_fpu(task);
    task->thread.trap_no = 16;
    task->thread.error_code = 0;
    info.si_signo = SIGFPE;
    info.si_errno = 0;
    info.si_code = __SI_FAULT;
    info.si_addr = eip;
    /*
     * (~cwd & swd) will mask out exceptions that are not set to unmasked
     * status.  0x3f is the exception bits in these regs, 0x200 is the
     * C1 reg you need in case of a stack fault, 0x040 is the stack
     * fault bit.  We should only be taking one exception at a time,
     * so if this combination doesn't produce any single exception,
     * then we have a bad program that isn't syncronizing its FPU usage
     * and it will suffer the consequences since we won't be able to
     * fully reproduce the context of the exception
     */
    cwd = get_fpu_cwd(task);
    swd = get_fpu_swd(task);
    switch (((~cwd) & swd & 0x3f) | (swd & 0x240)) {
        case 0x000:
        default:
            break;
        case 0x001: /* Invalid Op */
        case 0x040: /* Stack Fault */
        case 0x240: /* Stack Fault | Direction */
            info.si_code = FPE_FLTINV;
            break;
        case 0x002: /* Denormalize */
        case 0x010: /* Underflow */
            info.si_code = FPE_FLTUND;
            break;
        case 0x004: /* Zero Divide */
            info.si_code = FPE_FLTDIV;
            break;
        case 0x008: /* Overflow */
            info.si_code = FPE_FLTOVF;
            break;
        case 0x020: /* Precision */
            info.si_code = FPE_FLTRES;
            break;
    }
    force_sig_info(SIGFPE, &info, task);
}

asmlinkage void do_coprocessor_error(struct pt_regs * regs, long error_code)
{
    ignore_irq13 = 1;
    math_error((void *)regs->eip);
}

void simd_math_error(void *eip)
{
    struct task_struct * task;
    siginfo_t info;
    unsigned short mxcsr;

    /*
     * Save the info for the exception handler and clear the error.
     */
    task = current;
    save_init_fpu(task);
    task->thread.trap_no = 19;
    task->thread.error_code = 0;
    info.si_signo = SIGFPE;
    info.si_errno = 0;
    info.si_code = __SI_FAULT;
    info.si_addr = eip;
    /*
     * The SIMD FPU exceptions are handled a little differently, as there
     * is only a single status/control register.  Thus, to determine which
     * unmasked exception was caught we must mask the exception mask bits
     * at 0x1f80, and then use these to mask the exception bits at 0x3f.
     */
    mxcsr = get_fpu_mxcsr(task);
    switch (~((mxcsr & 0x1f80) >> 7) & (mxcsr & 0x3f)) {
        case 0x000:
        default:
            break;
        case 0x001: /* Invalid Op */
            info.si_code = FPE_FLTINV;
            break;
        case 0x002: /* Denormalize */
        case 0x010: /* Underflow */
            info.si_code = FPE_FLTUND;
            break;
        case 0x004: /* Zero Divide */
            info.si_code = FPE_FLTDIV;
            break;
        case 0x008: /* Overflow */
            info.si_code = FPE_FLTOVF;
            break;
        case 0x020: /* Precision */
            info.si_code = FPE_FLTRES;
            break;
    }
    force_sig_info(SIGFPE, &info, task);
}

asmlinkage void do_simd_coprocessor_error(struct pt_regs * regs,
                      long error_code)
{
    if (cpu_has_xmm) {
        /* Handle SIMD FPU exceptions on PIII+ processors. */
        ignore_irq13 = 1;
        simd_math_error((void *)regs->eip);
    } else {
        /*
         * Handle strange cache flush from user space exception
         * in all other cases.  This is undocumented behaviour.
         */
        if (regs->eflags & VM_MASK) {
            handle_vm86_fault((struct kernel_vm86_regs *)regs,
                      error_code);
            return;
        }
        die_if_kernel("cache flush denied", regs, error_code);
        current->thread.trap_no = 19;
        current->thread.error_code = error_code;
        force_sig(SIGSEGV, current);
    }
}

asmlinkage void do_spurious_interrupt_bug(struct pt_regs * regs,
                      long error_code)
{
#if 0
    /* No need to warn about this any longer. */
    printk("Ignoring P6 Local APIC Spurious Interrupt Bug...\n");
#endif
}

/*
 *  '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(struct pt_regs regs)
{
    __asm__ __volatile__("clts");        /* Allow maths ops (or we recurse) */

    if (current->used_math) {
        restore_fpu(current);
    } else {
        init_fpu();
    }
    current->flags |= PF_USEDFPU;    /* So we fnsave on switch_to() */
}

#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);
    force_sig(SIGFPE,current);
    schedule();
}

#endif /* CONFIG_MATH_EMULATION */

#ifndef CONFIG_M686
void __init trap_init_f00f_bug(void)
{
    unsigned long page;
    pgd_t * pgd;
    pmd_t * pmd;
    pte_t * pte;

    /*
     * Allocate a new page in virtual address space, 
     * move the IDT into it and write protect this page.
     */
    page = (unsigned long) vmalloc(PAGE_SIZE);
    pgd = pgd_offset(&init_mm, page);
    pmd = pmd_offset(pgd, page);
    pte = pte_offset(pmd, page);
    __free_page(pte_page(*pte));
    *pte = mk_pte_phys(__pa(&idt_table), PAGE_KERNEL_RO);
    /*
     * Not that any PGE-capable kernel should have the f00f bug ...
     */
    __flush_tlb_all();

    /*
     * "idt" is magic - it overlaps the idt_descr
     * variable so that updating idt will automatically
     * update the idt descriptor..
     */
    idt = (struct desc_struct *)page;
    __asm__ __volatile__("lidt %0": "=m" (idt_descr));
}
#endif

#define _set_gate(gate_addr,type,dpl,addr) \
do { \
  int __d0, __d1; \
  __asm__ __volatile__ ("movw %%dx,%%ax\n\t" \
    "movw %4,%%dx\n\t" \
    "movl %%eax,%0\n\t" \
    "movl %%edx,%1" \
    :"=m" (*((long *) (gate_addr))), \
     "=m" (*(1+(long *) (gate_addr))), "=&a" (__d0), "=&d" (__d1) \
    :"i" ((short) (0x8000+(dpl<<13)+(type<<8))), \
     "3" ((char *) (addr)),"2" (__KERNEL_CS << 16)); \
} while (0)


/*
 * This needs to use 'idt_table' rather than 'idt', and
 * thus use the _nonmapped_ version of the IDT, as the
 * Pentium F0 0F bugfix can have resulted in the mapped
 * IDT being write-protected.
 */
void set_intr_gate(unsigned int n, void *addr)
{
    _set_gate(idt_table+n,14,0,addr);
}

static void __init set_trap_gate(unsigned int n, void *addr)
{
    _set_gate(idt_table+n,15,0,addr);
}

static void __init set_system_gate(unsigned int n, void *addr)
{
    _set_gate(idt_table+n,15,3,addr);
}

static void __init set_call_gate(void *a, void *addr)
{
    _set_gate(a,12,3,addr);
}

#define _set_seg_desc(gate_addr,type,dpl,base,limit) {\
    *((gate_addr)+1) = ((base) & 0xff000000) | \
        (((base) & 0x00ff0000)>>16) | \
        ((limit) & 0xf0000) | \
        ((dpl)<<13) | \
        (0x00408000) | \
        ((type)<<8); \
    *(gate_addr) = (((base) & 0x0000ffff)<<16) | \
        ((limit) & 0x0ffff); }

#define _set_tssldt_desc(n,addr,limit,type) \
__asm__ __volatile__ ("movw %w3,0(%2)\n\t" \
    "movw %%ax,2(%2)\n\t" \
    "rorl $16,%%eax\n\t" \
    "movb %%al,4(%2)\n\t" \
    "movb %4,5(%2)\n\t" \
    "movb $0,6(%2)\n\t" \
    "movb %%ah,7(%2)\n\t" \
    "rorl $16,%%eax" \
    : "=m"(*(n)) : "a" (addr), "r"(n), "ir"(limit), "i"(type))

void set_tss_desc(unsigned int n, void *addr)
{
    _set_tssldt_desc(gdt_table+__TSS(n), (int)addr, 235, 0x89);
}

void set_ldt_desc(unsigned int n, void *addr, unsigned int size)
{
    _set_tssldt_desc(gdt_table+__LDT(n), (int)addr, ((size << 3)-1), 0x82);
}

#ifdef CONFIG_X86_VISWS_APIC

/*
 * On Rev 005 motherboards legacy device interrupt lines are wired directly
 * to Lithium from the 307.  But the PROM leaves the interrupt type of each
 * 307 logical device set appropriate for the 8259.  Later we'll actually use
 * the 8259, but for now we have to flip the interrupt types to
 * level triggered, active lo as required by Lithium.
 */

#define    REG    0x2e    /* The register to read/write */
#define    DEV    0x07    /* Register: Logical device select */
#define    VAL    0x2f    /* The value to read/write */

static void
superio_outb(int dev, int reg, int val)
{
    outb(DEV, REG);
    outb(dev, VAL);
    outb(reg, REG);
    outb(val, VAL);
}

static int __attribute__ ((unused))
superio_inb(int dev, int reg)
{
    outb(DEV, REG);
    outb(dev, VAL);
    outb(reg, REG);
    return inb(VAL);
}

#define    FLOP    3    /* floppy logical device */
#define    PPORT    4    /* parallel logical device */
#define    UART5    5    /* uart2 logical device (not wired up) */
#define    UART6    6    /* uart1 logical device (THIS is the serial port!) */
#define    IDEST    0x70    /* int. destination (which 307 IRQ line) reg. */
#define    ITYPE    0x71    /* interrupt type register */

/* interrupt type bits */
#define    LEVEL    0x01    /* bit 0, 0 == edge triggered */
#define    ACTHI    0x02    /* bit 1, 0 == active lo */

static void
superio_init(void)
{
    if (visws_board_type == VISWS_320 && visws_board_rev == 5) {
        superio_outb(UART6, IDEST, 0);    /* 0 means no intr propagated */
        printk("SGI 320 rev 5: disabling 307 uart1 interrupt\n");
    }
}

static void
lithium_init(void)
{
    set_fixmap(FIX_LI_PCIA, LI_PCI_A_PHYS);
    printk("Lithium PCI Bridge A, Bus Number: %d\n",
                li_pcia_read16(LI_PCI_BUSNUM) & 0xff);
    set_fixmap(FIX_LI_PCIB, LI_PCI_B_PHYS);
    printk("Lithium PCI Bridge B (PIIX4), Bus Number: %d\n",
                li_pcib_read16(LI_PCI_BUSNUM) & 0xff);

    /* XXX blindly enables all interrupts */
    li_pcia_write16(LI_PCI_INTEN, 0xffff);
    li_pcib_write16(LI_PCI_INTEN, 0xffff);
}

static void
cobalt_init(void)
{
    /*
     * On normal SMP PC this is used only with SMP, but we have to
     * use it and set it up here to start the Cobalt clock
     */
    set_fixmap(FIX_APIC_BASE, APIC_DEFAULT_PHYS_BASE);
    printk("Local APIC ID %lx\n", apic_read(APIC_ID));
    printk("Local APIC Version %lx\n", apic_read(APIC_LVR));

    set_fixmap(FIX_CO_CPU, CO_CPU_PHYS);
    printk("Cobalt Revision %lx\n", co_cpu_read(CO_CPU_REV));

    set_fixmap(FIX_CO_APIC, CO_APIC_PHYS);
    printk("Cobalt APIC ID %lx\n", co_apic_read(CO_APIC_ID));

    /* Enable Cobalt APIC being careful to NOT change the ID! */
    co_apic_write(CO_APIC_ID, co_apic_read(CO_APIC_ID)|CO_APIC_ENABLE);

    printk("Cobalt APIC enabled: ID reg %lx\n", co_apic_read(CO_APIC_ID));
}
#endif
void __init trap_init(void)
{
#ifdef CONFIG_EISA
    if (isa_readl(0x0FFFD9) == 'E'+('I'<<8)+('S'<<16)+('A'<<24))
        EISA_bus = 1;
#endif

    set_trap_gate(0,&divide_error);
    set_trap_gate(1,&debug);
    set_intr_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_intr_gate(14,&page_fault);
    set_trap_gate(15,&spurious_interrupt_bug);
    set_trap_gate(16,&coprocessor_error);
    set_trap_gate(17,&alignment_check);
    set_trap_gate(18,&machine_check);
    set_trap_gate(19,&simd_coprocessor_error);

    set_system_gate(SYSCALL_VECTOR,&system_call);

    /*
     * default LDT is a single-entry callgate to lcall7 for iBCS
     * and a callgate to lcall27 for Solaris/x86 binaries
     */
    set_call_gate(&default_ldt[0],lcall7);
    set_call_gate(&default_ldt[4],lcall27);

    /*
     * Should be a barrier for any external CPU state.
     */
    cpu_init();

#ifdef CONFIG_X86_VISWS_APIC
    superio_init();
    lithium_init();
    cobalt_init();
#endif
}

:: Command execute ::

Enter:
 
Select:
 

:: Search ::
  - regexp 

:: Upload ::
 
[ Read-Only ]

:: Make Dir ::
 
[ Read-Only ]
:: Make File ::
 
[ Read-Only ]

:: Go Dir ::
 
:: Go File ::
 

--[ c99shell v. 1.0 pre-release build #13 powered by Captain Crunch Security Team | http://ccteam.ru | Generation time: 0.0333 ]--