!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/sparc64/kernel/   drwxr-xr-x
Free 318.33 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 (46.98 KB)      -rw-r--r--
Select action/file-type:
(+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
/* $Id: traps.c,v 1.82 2001/11/18 00:12:56 davem Exp $
 * arch/sparc64/kernel/traps.c
 *
 * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
 * Copyright (C) 1997,1999,2000 Jakub Jelinek (jakub@redhat.com)
 */

/*
 * I like traps on v9, :))))
 */

#include <linux/config.h>
#include <linux/sched.h>  /* for jiffies */
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/mm.h>

#include <asm/delay.h>
#include <asm/system.h>
#include <asm/ptrace.h>
#include <asm/oplib.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/unistd.h>
#include <asm/uaccess.h>
#include <asm/fpumacro.h>
#include <asm/lsu.h>
#include <asm/dcu.h>
#include <asm/estate.h>
#include <asm/chafsr.h>
#include <asm/psrcompat.h>
#include <asm/processor.h>
#ifdef CONFIG_KMOD
#include <linux/kmod.h>
#endif

void bad_trap (struct pt_regs *regs, long lvl)
{
    char buffer[32];
    siginfo_t info;

    if (lvl < 0x100) {
        sprintf(buffer, "Bad hw trap %lx at tl0\n", lvl);
        die_if_kernel(buffer, regs);
    }

    lvl -= 0x100;
    if (regs->tstate & TSTATE_PRIV) {
        sprintf(buffer, "Kernel bad sw trap %lx", lvl);
        die_if_kernel (buffer, regs);
    }
    if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
        regs->tpc &= 0xffffffff;
        regs->tnpc &= 0xffffffff;
    }
    info.si_signo = SIGILL;
    info.si_errno = 0;
    info.si_code = ILL_ILLTRP;
    info.si_addr = (void *)regs->tpc;
    info.si_trapno = lvl;
    force_sig_info(SIGILL, &info, current);
}

void bad_trap_tl1 (struct pt_regs *regs, long lvl)
{
    char buffer[24];
    
    sprintf (buffer, "Bad trap %lx at tl>0", lvl);
    die_if_kernel (buffer, regs);
}

#ifdef CONFIG_DEBUG_BUGVERBOSE
void do_BUG(const char *file, int line)
{
    bust_spinlocks(1);
    printk("kernel BUG at %s:%d!\n", file, line);
}
#endif

void instruction_access_exception (struct pt_regs *regs,
                   unsigned long sfsr, unsigned long sfar)
{
    siginfo_t info;

    if (regs->tstate & TSTATE_PRIV) {
        printk("instruction_access_exception: SFSR[%016lx] SFAR[%016lx], going.\n",
               sfsr, sfar);
        die_if_kernel("Iax", regs);
    }
    if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
        regs->tpc &= 0xffffffff;
        regs->tnpc &= 0xffffffff;
    }
    info.si_signo = SIGSEGV;
    info.si_errno = 0;
    info.si_code = SEGV_MAPERR;
    info.si_addr = (void *)regs->tpc;
    info.si_trapno = 0;
    force_sig_info(SIGSEGV, &info, current);
}

void data_access_exception (struct pt_regs *regs,
                unsigned long sfsr, unsigned long sfar)
{
    siginfo_t info;

    if (regs->tstate & TSTATE_PRIV) {
        /* Test if this comes from uaccess places. */
        unsigned long fixup, g2;

        g2 = regs->u_regs[UREG_G2];
        if ((fixup = search_exception_table (regs->tpc, &g2))) {
            /* Ouch, somebody is trying ugly VM hole tricks on us... */
#ifdef DEBUG_EXCEPTIONS
            printk("Exception: PC<%016lx> faddr<UNKNOWN>\n", regs->tpc);
            printk("EX_TABLE: insn<%016lx> fixup<%016lx> "
                   "g2<%016lx>\n", regs->tpc, fixup, g2);
#endif
            regs->tpc = fixup;
            regs->tnpc = regs->tpc + 4;
            regs->u_regs[UREG_G2] = g2;
            return;
        }
        /* Shit... */
        printk("data_access_exception: SFSR[%016lx] SFAR[%016lx], going.\n",
               sfsr, sfar);
        die_if_kernel("Dax", regs);
    }

    info.si_signo = SIGSEGV;
    info.si_errno = 0;
    info.si_code = SEGV_MAPERR;
    info.si_addr = (void *)sfar;
    info.si_trapno = 0;
    force_sig_info(SIGSEGV, &info, current);
}

#ifdef CONFIG_PCI
/* This is really pathetic... */
extern volatile int pci_poke_in_progress;
extern volatile int pci_poke_cpu;
extern volatile int pci_poke_faulted;
#endif

/* When access exceptions happen, we must do this. */
static void clean_and_reenable_l1_caches(void)
{
    unsigned long va;

    if (tlb_type == spitfire) {
        /* Clean 'em. */
        for (va =  0; va < (PAGE_SIZE << 1); va += 32) {
            spitfire_put_icache_tag(va, 0x0);
            spitfire_put_dcache_tag(va, 0x0);
        }

        /* Re-enable in LSU. */
        __asm__ __volatile__("flush %%g6\n\t"
                     "membar #Sync\n\t"
                     "stxa %0, [%%g0] %1\n\t"
                     "membar #Sync"
                     : /* no outputs */
                     : "r" (LSU_CONTROL_IC | LSU_CONTROL_DC |
                        LSU_CONTROL_IM | LSU_CONTROL_DM),
                     "i" (ASI_LSU_CONTROL)
                     : "memory");
    } else if (tlb_type == cheetah) {
        /* Flush D-cache */
        for (va = 0; va < (1 << 16); va += (1 << 5)) {
            __asm__ __volatile__("stxa %%g0, [%0] %1\n\t"
                         "membar #Sync"
                         : /* no outputs */
                         : "r" (va), "i" (ASI_DCACHE_TAG));
        }
    }
}

void do_iae(struct pt_regs *regs)
{
    siginfo_t info;

    clean_and_reenable_l1_caches();

    info.si_signo = SIGBUS;
    info.si_errno = 0;
    info.si_code = BUS_OBJERR;
    info.si_addr = (void *)0;
    info.si_trapno = 0;
    force_sig_info(SIGBUS, &info, current);
}

void do_dae(struct pt_regs *regs)
{
#ifdef CONFIG_PCI
    if (pci_poke_in_progress && pci_poke_cpu == smp_processor_id()) {
        clean_and_reenable_l1_caches();

        pci_poke_faulted = 1;

        /* Why the fuck did they have to change this? */
        if (tlb_type == cheetah)
            regs->tpc += 4;

        regs->tnpc = regs->tpc + 4;
        return;
    }
#endif
    do_iae(regs);
}

static char ecc_syndrome_table[] = {
    0x4c, 0x40, 0x41, 0x48, 0x42, 0x48, 0x48, 0x49,
    0x43, 0x48, 0x48, 0x49, 0x48, 0x49, 0x49, 0x4a,
    0x44, 0x48, 0x48, 0x20, 0x48, 0x39, 0x4b, 0x48,
    0x48, 0x25, 0x31, 0x48, 0x28, 0x48, 0x48, 0x2c,
    0x45, 0x48, 0x48, 0x21, 0x48, 0x3d, 0x04, 0x48,
    0x48, 0x4b, 0x35, 0x48, 0x2d, 0x48, 0x48, 0x29,
    0x48, 0x00, 0x01, 0x48, 0x0a, 0x48, 0x48, 0x4b,
    0x0f, 0x48, 0x48, 0x4b, 0x48, 0x49, 0x49, 0x48,
    0x46, 0x48, 0x48, 0x2a, 0x48, 0x3b, 0x27, 0x48,
    0x48, 0x4b, 0x33, 0x48, 0x22, 0x48, 0x48, 0x2e,
    0x48, 0x19, 0x1d, 0x48, 0x1b, 0x4a, 0x48, 0x4b,
    0x1f, 0x48, 0x4a, 0x4b, 0x48, 0x4b, 0x4b, 0x48,
    0x48, 0x4b, 0x24, 0x48, 0x07, 0x48, 0x48, 0x36,
    0x4b, 0x48, 0x48, 0x3e, 0x48, 0x30, 0x38, 0x48,
    0x49, 0x48, 0x48, 0x4b, 0x48, 0x4b, 0x16, 0x48,
    0x48, 0x12, 0x4b, 0x48, 0x49, 0x48, 0x48, 0x4b,
    0x47, 0x48, 0x48, 0x2f, 0x48, 0x3f, 0x4b, 0x48,
    0x48, 0x06, 0x37, 0x48, 0x23, 0x48, 0x48, 0x2b,
    0x48, 0x05, 0x4b, 0x48, 0x4b, 0x48, 0x48, 0x32,
    0x26, 0x48, 0x48, 0x3a, 0x48, 0x34, 0x3c, 0x48,
    0x48, 0x11, 0x15, 0x48, 0x13, 0x4a, 0x48, 0x4b,
    0x17, 0x48, 0x4a, 0x4b, 0x48, 0x4b, 0x4b, 0x48,
    0x49, 0x48, 0x48, 0x4b, 0x48, 0x4b, 0x1e, 0x48,
    0x48, 0x1a, 0x4b, 0x48, 0x49, 0x48, 0x48, 0x4b,
    0x48, 0x08, 0x0d, 0x48, 0x02, 0x48, 0x48, 0x49,
    0x03, 0x48, 0x48, 0x49, 0x48, 0x4b, 0x4b, 0x48,
    0x49, 0x48, 0x48, 0x49, 0x48, 0x4b, 0x10, 0x48,
    0x48, 0x14, 0x4b, 0x48, 0x4b, 0x48, 0x48, 0x4b,
    0x49, 0x48, 0x48, 0x49, 0x48, 0x4b, 0x18, 0x48,
    0x48, 0x1c, 0x4b, 0x48, 0x4b, 0x48, 0x48, 0x4b,
    0x4a, 0x0c, 0x09, 0x48, 0x0e, 0x48, 0x48, 0x4b,
    0x0b, 0x48, 0x48, 0x4b, 0x48, 0x4b, 0x4b, 0x4a
};

/* cee_trap in entry.S encodes AFSR/UDBH/UDBL error status
 * in the following format.  The AFAR is left as is, with
 * reserved bits cleared, and is a raw 40-bit physical
 * address.
 */
#define CE_STATUS_UDBH_UE        (1UL << (43 + 9))
#define CE_STATUS_UDBH_CE        (1UL << (43 + 8))
#define CE_STATUS_UDBH_ESYNDR        (0xffUL << 43)
#define CE_STATUS_UDBH_SHIFT        43
#define CE_STATUS_UDBL_UE        (1UL << (33 + 9))
#define CE_STATUS_UDBL_CE        (1UL << (33 + 8))
#define CE_STATUS_UDBL_ESYNDR        (0xffUL << 33)
#define CE_STATUS_UDBL_SHIFT        33
#define CE_STATUS_AFSR_MASK        (0x1ffffffffUL)
#define CE_STATUS_AFSR_ME        (1UL << 32)
#define CE_STATUS_AFSR_PRIV        (1UL << 31)
#define CE_STATUS_AFSR_ISAP        (1UL << 30)
#define CE_STATUS_AFSR_ETP        (1UL << 29)
#define CE_STATUS_AFSR_IVUE        (1UL << 28)
#define CE_STATUS_AFSR_TO        (1UL << 27)
#define CE_STATUS_AFSR_BERR        (1UL << 26)
#define CE_STATUS_AFSR_LDP        (1UL << 25)
#define CE_STATUS_AFSR_CP        (1UL << 24)
#define CE_STATUS_AFSR_WP        (1UL << 23)
#define CE_STATUS_AFSR_EDP        (1UL << 22)
#define CE_STATUS_AFSR_UE        (1UL << 21)
#define CE_STATUS_AFSR_CE        (1UL << 20)
#define CE_STATUS_AFSR_ETS        (0xfUL << 16)
#define CE_STATUS_AFSR_ETS_SHIFT    16
#define CE_STATUS_AFSR_PSYND        (0xffffUL << 0)
#define CE_STATUS_AFSR_PSYND_SHIFT    0

/* Layout of Ecache TAG Parity Syndrome of AFSR */
#define AFSR_ETSYNDROME_7_0        0x1UL /* E$-tag bus bits  <7:0> */
#define AFSR_ETSYNDROME_15_8        0x2UL /* E$-tag bus bits <15:8> */
#define AFSR_ETSYNDROME_21_16        0x4UL /* E$-tag bus bits <21:16> */
#define AFSR_ETSYNDROME_24_22        0x8UL /* E$-tag bus bits <24:22> */

static char *syndrome_unknown = "<Unknown>";

asmlinkage void cee_log(unsigned long ce_status,
            unsigned long afar,
            struct pt_regs *regs)
{
    char memmod_str[64];
    char *p;
    unsigned short scode, udb_reg;

    printk(KERN_WARNING "CPU[%d]: Correctable ECC Error "
           "AFSR[%lx] AFAR[%016lx] UDBL[%lx] UDBH[%lx]\n",
           smp_processor_id(),
           (ce_status & CE_STATUS_AFSR_MASK),
           afar,
           ((ce_status >> CE_STATUS_UDBL_SHIFT) & 0x3ffUL),
           ((ce_status >> CE_STATUS_UDBH_SHIFT) & 0x3ffUL));

    udb_reg = ((ce_status >> CE_STATUS_UDBL_SHIFT) & 0x3ffUL);
    if (udb_reg & (1 << 8)) {
        scode = ecc_syndrome_table[udb_reg & 0xff];
        if (prom_getunumber(scode, afar,
                    memmod_str, sizeof(memmod_str)) == -1)
            p = syndrome_unknown;
        else
            p = memmod_str;
        printk(KERN_WARNING "CPU[%d]: UDBL Syndrome[%x] "
               "Memory Module \"%s\"\n",
               smp_processor_id(), scode, p);
    }

    udb_reg = ((ce_status >> CE_STATUS_UDBH_SHIFT) & 0x3ffUL);
    if (udb_reg & (1 << 8)) {
        scode = ecc_syndrome_table[udb_reg & 0xff];
        if (prom_getunumber(scode, afar,
                    memmod_str, sizeof(memmod_str)) == -1)
            p = syndrome_unknown;
        else
            p = memmod_str;
        printk(KERN_WARNING "CPU[%d]: UDBH Syndrome[%x] "
               "Memory Module \"%s\"\n",
               smp_processor_id(), scode, p);
    }
}

/* Cheetah error trap handling. */
static unsigned long ecache_flush_physbase;
static unsigned long ecache_flush_linesize;
static unsigned long ecache_flush_size;

/* WARNING: The error trap handlers in assembly know the precise
 *        layout of the following structure.
 *
 * C-level handlers below use this information to log the error
 * and then determine how to recover (if possible).
 */
struct cheetah_err_info {
/*0x00*/u64 afsr;
/*0x08*/u64 afar;

    /* D-cache state */
/*0x10*/u64 dcache_data[4];    /* The actual data    */
/*0x30*/u64 dcache_index;    /* D-cache index    */
/*0x38*/u64 dcache_tag;        /* D-cache tag/valid    */
/*0x40*/u64 dcache_utag;    /* D-cache microtag    */
/*0x48*/u64 dcache_stag;    /* D-cache snooptag    */

    /* I-cache state */
/*0x50*/u64 icache_data[8];    /* The actual insns + predecode    */
/*0x90*/u64 icache_index;    /* I-cache index    */
/*0x98*/u64 icache_tag;        /* I-cache phys tag    */
/*0xa0*/u64 icache_utag;    /* I-cache microtag    */
/*0xa8*/u64 icache_stag;    /* I-cache snooptag    */
/*0xb0*/u64 icache_upper;    /* I-cache upper-tag    */
/*0xb8*/u64 icache_lower;    /* I-cache lower-tag    */

    /* E-cache state */
/*0xc0*/u64 ecache_data[4];    /* 32 bytes from staging registers */
/*0xe0*/u64 ecache_index;    /* E-cache index    */
/*0xe8*/u64 ecache_tag;        /* E-cache tag/state    */

/*0xf0*/u64 __pad[32 - 30];
};
#define CHAFSR_INVALID        ((u64)-1L)

/* This is allocated at boot time based upon the largest hardware
 * cpu ID in the system.  We allocate two entries per cpu, one for
 * TL==0 logging and one for TL >= 1 logging.
 */
struct cheetah_err_info *cheetah_error_log;

static __inline__ struct cheetah_err_info *cheetah_get_error_log(unsigned long afsr)
{
    struct cheetah_err_info *p;
    int cpu = smp_processor_id();

    if (!cheetah_error_log)
        return NULL;

    p = cheetah_error_log + (cpu * 2);
    if ((afsr & CHAFSR_TL1) != 0UL)
        p++;

    return p;
}

extern unsigned int tl0_fecc[], tl1_fecc[];
extern unsigned int tl0_cee[], tl1_cee[];
extern unsigned int tl0_iae[], tl1_iae[];
extern unsigned int tl0_dae[], tl1_dae[];
extern unsigned int cheetah_fecc_trap_vector[], cheetah_fecc_trap_vector_tl1[];
extern unsigned int cheetah_cee_trap_vector[], cheetah_cee_trap_vector_tl1[];
extern unsigned int cheetah_deferred_trap_vector[], cheetah_deferred_trap_vector_tl1[];

void cheetah_ecache_flush_init(void)
{
    unsigned long largest_size, smallest_linesize, order;
    char type[16];
    int node, highest_cpu, i;

    /* Scan all cpu device tree nodes, note two values:
     * 1) largest E-cache size
     * 2) smallest E-cache line size
     */
    largest_size = 0UL;
    smallest_linesize = ~0UL;
    node = prom_getchild(prom_root_node);
    while ((node = prom_getsibling(node)) != 0) {
        prom_getstring(node, "device_type", type, sizeof(type));
        if (!strcmp(type, "cpu")) {
            unsigned long val;

            val = prom_getintdefault(node, "ecache-size",
                         (2 * 1024 * 1024));
            if (val > largest_size)
                largest_size = val;
            val = prom_getintdefault(node, "ecache-line-size", 64);
            if (val < smallest_linesize)
                smallest_linesize = val;
        }
    }
    if (largest_size == 0UL || smallest_linesize == ~0UL) {
        prom_printf("cheetah_ecache_flush_init: Cannot probe cpu E-cache "
                "parameters.\n");
        prom_halt();
    }

    ecache_flush_size = (2 * largest_size);
    ecache_flush_linesize = smallest_linesize;

    /* Discover a physically contiguous chunk of physical
     * memory in 'sp_banks' of size ecache_flush_size calculated
     * above.  Store the physical base of this area at
     * ecache_flush_physbase.
     */
    for (node = 0; ; node++) {
        if (sp_banks[node].num_bytes == 0)
            break;
        if (sp_banks[node].num_bytes >= ecache_flush_size) {
            ecache_flush_physbase = sp_banks[node].base_addr;
            break;
        }
    }

    /* Note: Zero would be a valid value of ecache_flush_physbase so
     * don't use that as the success test. :-)
     */
    if (sp_banks[node].num_bytes == 0) {
        prom_printf("cheetah_ecache_flush_init: Cannot find %d byte "
                "contiguous physical memory.\n", ecache_flush_size);
        prom_halt();
    }

    /* Now allocate error trap reporting scoreboard. */
    highest_cpu = 0;
#ifdef CONFIG_SMP
    for (i = 0; i < NR_CPUS; i++) {
        if ((1UL << i) & cpu_present_map)
            highest_cpu = i;
    }
#endif
    highest_cpu++;
    node = highest_cpu * (2 * sizeof(struct cheetah_err_info));
    for (order = 0; order < MAX_ORDER; order++) {
        if ((PAGE_SIZE << order) >= node)
            break;
    }
    cheetah_error_log = (struct cheetah_err_info *)
        __get_free_pages(GFP_KERNEL, order);
    if (!cheetah_error_log) {
        prom_printf("cheetah_ecache_flush_init: Failed to allocate "
                "error logging scoreboard (%d bytes).\n", node);
        prom_halt();
    }
    memset(cheetah_error_log, 0, PAGE_SIZE << order);

    /* Mark all AFSRs as invalid so that the trap handler will
     * log new new information there.
     */
    for (i = 0; i < 2 * highest_cpu; i++)
        cheetah_error_log[i].afsr = CHAFSR_INVALID;

    /* Now patch trap tables. */
    memcpy(tl0_fecc, cheetah_fecc_trap_vector, (8 * 4));
    memcpy(tl1_fecc, cheetah_fecc_trap_vector_tl1, (8 * 4));
    memcpy(tl0_cee, cheetah_cee_trap_vector, (8 * 4));
    memcpy(tl1_cee, cheetah_cee_trap_vector_tl1, (8 * 4));
    memcpy(tl0_iae, cheetah_deferred_trap_vector, (8 * 4));
    memcpy(tl1_iae, cheetah_deferred_trap_vector_tl1, (8 * 4));
    memcpy(tl0_dae, cheetah_deferred_trap_vector, (8 * 4));
    memcpy(tl1_dae, cheetah_deferred_trap_vector_tl1, (8 * 4));
    flushi(PAGE_OFFSET);
}

static void cheetah_flush_ecache(void)
{
    unsigned long flush_base = ecache_flush_physbase;
    unsigned long flush_linesize = ecache_flush_linesize;
    unsigned long flush_size = ecache_flush_size;

    __asm__ __volatile__("1: subcc    %0, %4, %0\n\t"
                 "   bne,pt    %%xcc, 1b\n\t"
                 "    ldxa    [%2 + %0] %3, %%g0\n\t"
                 : "=&r" (flush_size)
                 : "0" (flush_size), "r" (flush_base),
                   "i" (ASI_PHYS_USE_EC), "r" (flush_linesize));
}

static void cheetah_flush_ecache_line(unsigned long physaddr)
{
    unsigned long alias;

    physaddr &= ~(8UL - 1UL);
    physaddr = (ecache_flush_physbase +
            (physaddr & ((ecache_flush_size>>1UL) - 1UL)));
    alias = physaddr + (ecache_flush_size >> 1UL);
    __asm__ __volatile__("ldxa [%0] %2, %%g0\n\t"
                 "ldxa [%1] %2, %%g0\n\t"
                 "membar #Sync"
                 : /* no outputs */
                 : "r" (physaddr), "r" (alias),
                   "i" (ASI_PHYS_USE_EC));
}

/* Unfortunately, the diagnostic access to the I-cache tags we need to
 * use to clear the thing interferes with I-cache coherency transactions.
 *
 * So we must only flush the I-cache when it is disabled.
 */
static void cheetah_flush_icache(void)
{
    unsigned long dcu_save, i;

    /* Save current DCU, disable I-cache. */
    __asm__ __volatile__("ldxa [%%g0] %1, %0\n\t"
                 "or %0, %2, %%g1\n\t"
                 "stxa %%g1, [%%g0] %1\n\t"
                 "membar #Sync"
                 : "=r" (dcu_save)
                 : "i" (ASI_DCU_CONTROL_REG), "i" (DCU_IC)
                 : "g1");

    /* Clear the valid bits in all the tags. */
    for (i = 0; i < (1 << 16); i += (1 << 5)) {
        __asm__ __volatile__("stxa %%g0, [%0] %1\n\t"
                     "membar #Sync"
                     : /* no outputs */
                     : "r" (i | (2 << 3)), "i" (ASI_IC_TAG));
    }

    /* Restore DCU register */
    __asm__ __volatile__("stxa %0, [%%g0] %1\n\t"
                 "membar #Sync"
                 : /* no outputs */
                 : "r" (dcu_save), "i" (ASI_DCU_CONTROL_REG));
}

static void cheetah_flush_dcache(void)
{
    unsigned long i;

    for (i = 0; i < (1 << 16); i += (1 << 5)) {
        __asm__ __volatile__("stxa %%g0, [%0] %1\n\t"
                     "membar #Sync"
                     : /* no outputs */
                     : "r" (i), "i" (ASI_DCACHE_TAG));
    }
}

/* Conversion tables used to frob Cheetah AFSR syndrome values into
 * something palatable to the memory controller driver get_unumber
 * routine.
 */
#define MT0    137
#define MT1    138
#define MT2    139
#define NONE    254
#define MTC0    140
#define MTC1    141
#define MTC2    142
#define MTC3    143
#define C0    128
#define C1    129
#define C2    130
#define C3    131
#define C4    132
#define C5    133
#define C6    134
#define C7    135
#define C8    136
#define M2    144
#define M3    145
#define M4    146
#define M    147
static unsigned char cheetah_ecc_syntab[] = {
/*00*/NONE, C0, C1, M2, C2, M2, M3, 47, C3, M2, M2, 53, M2, 41, 29, M,
/*01*/C4, M, M, 50, M2, 38, 25, M2, M2, 33, 24, M2, 11, M, M2, 16,
/*02*/C5, M, M, 46, M2, 37, 19, M2, M, 31, 32, M, 7, M2, M2, 10,
/*03*/M2, 40, 13, M2, 59, M, M2, 66, M, M2, M2, 0, M2, 67, 71, M,
/*04*/C6, M, M, 43, M, 36, 18, M, M2, 49, 15, M, 63, M2, M2, 6,
/*05*/M2, 44, 28, M2, M, M2, M2, 52, 68, M2, M2, 62, M2, M3, M3, M4,
/*06*/M2, 26, 106, M2, 64, M, M2, 2, 120, M, M2, M3, M, M3, M3, M4,
/*07*/116, M2, M2, M3, M2, M3, M, M4, M2, 58, 54, M2, M, M4, M4, M3,
/*08*/C7, M2, M, 42, M, 35, 17, M2, M, 45, 14, M2, 21, M2, M2, 5,
/*09*/M, 27, M, M, 99, M, M, 3, 114, M2, M2, 20, M2, M3, M3, M,
/*0a*/M2, 23, 113, M2, 112, M2, M, 51, 95, M, M2, M3, M2, M3, M3, M2,
/*0b*/103, M, M2, M3, M2, M3, M3, M4, M2, 48, M, M, 73, M2, M, M3,
/*0c*/M2, 22, 110, M2, 109, M2, M, 9, 108, M2, M, M3, M2, M3, M3, M,
/*0d*/102, M2, M, M, M2, M3, M3, M, M2, M3, M3, M2, M, M4, M, M3,
/*0e*/98, M, M2, M3, M2, M, M3, M4, M2, M3, M3, M4, M3, M, M, M,
/*0f*/M2, M3, M3, M, M3, M, M, M, 56, M4, M, M3, M4, M, M, M,
/*10*/C8, M, M2, 39, M, 34, 105, M2, M, 30, 104, M, 101, M, M, 4,
/*11*/M, M, 100, M, 83, M, M2, 12, 87, M, M, 57, M2, M, M3, M,
/*12*/M2, 97, 82, M2, 78, M2, M2, 1, 96, M, M, M, M, M, M3, M2,
/*13*/94, M, M2, M3, M2, M, M3, M, M2, M, 79, M, 69, M, M4, M,
/*14*/M2, 93, 92, M, 91, M, M2, 8, 90, M2, M2, M, M, M, M, M4,
/*15*/89, M, M, M3, M2, M3, M3, M, M, M, M3, M2, M3, M2, M, M3,
/*16*/86, M, M2, M3, M2, M, M3, M, M2, M, M3, M, M3, M, M, M3,
/*17*/M, M, M3, M2, M3, M2, M4, M, 60, M, M2, M3, M4, M, M, M2,
/*18*/M2, 88, 85, M2, 84, M, M2, 55, 81, M2, M2, M3, M2, M3, M3, M4,
/*19*/77, M, M, M, M2, M3, M, M, M2, M3, M3, M4, M3, M2, M, M,
/*1a*/74, M, M2, M3, M, M, M3, M, M, M, M3, M, M3, M, M4, M3,
/*1b*/M2, 70, 107, M4, 65, M2, M2, M, 127, M, M, M, M2, M3, M3, M,
/*1c*/80, M2, M2, 72, M, 119, 118, M, M2, 126, 76, M, 125, M, M4, M3,
/*1d*/M2, 115, 124, M, 75, M, M, M3, 61, M, M4, M, M4, M, M, M,
/*1e*/M, 123, 122, M4, 121, M4, M, M3, 117, M2, M2, M3, M4, M3, M, M,
/*1f*/111, M, M, M, M4, M3, M3, M, M, M, M3, M, M3, M2, M, M
};
static unsigned char cheetah_mtag_syntab[] = {
       NONE, MTC0,
       MTC1, NONE,
       MTC2, NONE,
       NONE, MT0,
       MTC3, NONE,
       NONE, MT1,
       NONE, MT2,
       NONE, NONE
};

/* This table is ordered in priority of errors and matches the
 * AFAR overwrite policy as well.
 */
static struct {
    unsigned long mask;
    char *name;
} cheetah_error_table[] = {
    {    CHAFSR_PERR,    "System interface protocol error"            },
    {    CHAFSR_IERR,    "Internal processor error"                },
    {    CHAFSR_ISAP,    "System request parity error on incoming addresss"    },
    {    CHAFSR_UCU,    "Uncorrectable E-cache ECC error for ifetch/data"    },
    {    CHAFSR_UCC,    "SW Correctable E-cache ECC error for ifetch/data"    },
    {    CHAFSR_UE,    "Uncorrectable system bus data ECC error for read"    },
    {    CHAFSR_EDU,    "Uncorrectable E-cache ECC error for stmerge/blkld"    },
    {    CHAFSR_EMU,    "Uncorrectable system bus MTAG error"            },
    {    CHAFSR_WDU,    "Uncorrectable E-cache ECC error for writeback"        },
    {    CHAFSR_CPU,    "Uncorrectable ECC error for copyout"            },
    {    CHAFSR_CE,    "HW corrected system bus data ECC error for read"    },
    {    CHAFSR_EDC,    "HW corrected E-cache ECC error for stmerge/blkld"    },
    {    CHAFSR_EMC,    "HW corrected system bus MTAG ECC error"        },
    {    CHAFSR_WDC,    "HW corrected E-cache ECC error for writeback"        },
    {    CHAFSR_CPC,    "HW corrected ECC error for copyout"            },
    {    CHAFSR_TO,    "Unmapped error from system bus"            },
    {    CHAFSR_BERR,    "Bus error response from system bus"            },
    /* These two do not update the AFAR. */
    {    CHAFSR_IVC,    "HW corrected system bus data ECC error for ivec read"    },
    {    CHAFSR_IVU,    "Uncorrectable system bus data ECC error for ivec read"    },
    {    0,        NULL                            }
};

/* Return the highest priority error conditon mentioned. */
static __inline__ unsigned long cheetah_get_hipri(unsigned long afsr)
{
    unsigned long tmp = 0;
    int i;

    for (i = 0; cheetah_error_table[i].mask; i++) {
        if ((tmp = (afsr & cheetah_error_table[i].mask)) != 0UL)
            return tmp;
    }
    return tmp;
}

static char *cheetah_get_string(unsigned long bit)
{
    int i;

    for (i = 0; cheetah_error_table[i].mask; i++) {
        if ((bit & cheetah_error_table[i].mask) != 0UL)
            return cheetah_error_table[i].name;
    }
    return "???";
}

extern int chmc_getunumber(int, unsigned long, char *, int);

static void cheetah_log_errors(struct pt_regs *regs, struct cheetah_err_info *info,
                   unsigned long afsr, unsigned long afar, int recoverable)
{
    unsigned long hipri;
    char unum[256];

    printk("%s" "ERROR(%d): Cheetah error trap taken afsr[%016lx] afar[%016lx] TL1(%d)\n",
           (recoverable ? KERN_WARNING : KERN_CRIT), smp_processor_id(),
           afsr, afar,
           (afsr & CHAFSR_TL1) ? 1 : 0);
    printk("%s" "ERROR(%d): TPC[%016lx] TNPC[%016lx] TSTATE[%016lx]\n",
           (recoverable ? KERN_WARNING : KERN_CRIT), smp_processor_id(),
           regs->tpc, regs->tnpc, regs->tstate);
    printk("%s" "ERROR(%d): M_SYND(%lx),  E_SYND(%lx)%s%s\n",
           (recoverable ? KERN_WARNING : KERN_CRIT), smp_processor_id(),
           (afsr & CHAFSR_M_SYNDROME) >> CHAFSR_M_SYNDROME_SHIFT,
           (afsr & CHAFSR_E_SYNDROME) >> CHAFSR_E_SYNDROME_SHIFT,
           (afsr & CHAFSR_ME) ? ", Multiple Errors" : "",
           (afsr & CHAFSR_PRIV) ? ", Privileged" : "");
    hipri = cheetah_get_hipri(afsr);
    printk("%s" "ERROR(%d): Highest priority error (%016lx) \"%s\"\n",
           (recoverable ? KERN_WARNING : KERN_CRIT), smp_processor_id(),
           hipri, cheetah_get_string(hipri));

    /* Try to get unumber if relevant. */
#define ESYND_ERRORS    (CHAFSR_IVC | CHAFSR_IVU | \
             CHAFSR_CPC | CHAFSR_CPU | \
             CHAFSR_UE  | CHAFSR_CE  | \
             CHAFSR_EDC | CHAFSR_EDU  | \
             CHAFSR_UCC | CHAFSR_UCU  | \
             CHAFSR_WDU | CHAFSR_WDC)
#define MSYND_ERRORS    (CHAFSR_EMC | CHAFSR_EMU)
    if (afsr & ESYND_ERRORS) {
        int syndrome;
        int ret;

        syndrome = (afsr & CHAFSR_E_SYNDROME) >> CHAFSR_E_SYNDROME_SHIFT;
        syndrome = cheetah_ecc_syntab[syndrome];
        ret = chmc_getunumber(syndrome, afar, unum, sizeof(unum));
        if (ret != -1)
            printk("%s" "ERROR(%d): AFAR E-syndrome [%s]\n",
                   (recoverable ? KERN_WARNING : KERN_CRIT),
                   smp_processor_id(), unum);
    } else if (afsr & MSYND_ERRORS) {
        int syndrome;
        int ret;

        syndrome = (afsr & CHAFSR_M_SYNDROME) >> CHAFSR_M_SYNDROME_SHIFT;
        syndrome = cheetah_mtag_syntab[syndrome];
        ret = chmc_getunumber(syndrome, afar, unum, sizeof(unum));
        if (ret != -1)
            printk("%s" "ERROR(%d): AFAR M-syndrome [%s]\n",
                   (recoverable ? KERN_WARNING : KERN_CRIT),
                   smp_processor_id(), unum);
    }

    /* Now dump the cache snapshots. */
    printk("%s" "ERROR(%d): D-cache idx[%x] tag[%016lx] utag[%016lx] stag[%016lx]\n",
           (recoverable ? KERN_WARNING : KERN_CRIT), smp_processor_id(),
           (int) info->dcache_index,
           info->dcache_tag,
           info->dcache_utag,
           info->dcache_stag);
    printk("%s" "ERROR(%d): D-cache data0[%016lx] data1[%016lx] data2[%016lx] data3[%016lx]\n",
           (recoverable ? KERN_WARNING : KERN_CRIT), smp_processor_id(),
           info->dcache_data[0],
           info->dcache_data[1],
           info->dcache_data[2],
           info->dcache_data[3]);
    printk("%s" "ERROR(%d): I-cache idx[%x] tag[%016lx] utag[%016lx] stag[%016lx] "
           "u[%016lx] l[%016lx]\n",
           (recoverable ? KERN_WARNING : KERN_CRIT), smp_processor_id(),
           (int) info->icache_index,
           info->icache_tag,
           info->icache_utag,
           info->icache_stag,
           info->icache_upper,
           info->icache_lower);
    printk("%s" "ERROR(%d): I-cache INSN0[%016lx] INSN1[%016lx] INSN2[%016lx] INSN3[%016lx]\n",
           (recoverable ? KERN_WARNING : KERN_CRIT), smp_processor_id(),
           info->icache_data[0],
           info->icache_data[1],
           info->icache_data[2],
           info->icache_data[3]);
    printk("%s" "ERROR(%d): I-cache INSN4[%016lx] INSN5[%016lx] INSN6[%016lx] INSN7[%016lx]\n",
           (recoverable ? KERN_WARNING : KERN_CRIT), smp_processor_id(),
           info->icache_data[4],
           info->icache_data[5],
           info->icache_data[6],
           info->icache_data[7]);
    printk("%s" "ERROR(%d): E-cache idx[%x] tag[%016lx]\n",
           (recoverable ? KERN_WARNING : KERN_CRIT), smp_processor_id(),
           (int) info->ecache_index, info->ecache_tag);
    printk("%s" "ERROR(%d): E-cache data0[%016lx] data1[%016lx] data2[%016lx] data3[%016lx]\n",
           (recoverable ? KERN_WARNING : KERN_CRIT), smp_processor_id(),
           info->ecache_data[0],
           info->ecache_data[1],
           info->ecache_data[2],
           info->ecache_data[3]);

    afsr = (afsr & ~hipri) & CHAFSR_ERRORS;
    while (afsr != 0UL) {
        unsigned long bit = cheetah_get_hipri(afsr);

        printk("%s" "ERROR: Multiple-error (%016lx) \"%s\"\n",
               (recoverable ? KERN_WARNING : KERN_CRIT),
               bit, cheetah_get_string(bit));

        afsr &= ~bit;
    }

    if (!recoverable)
        printk(KERN_CRIT "ERROR: This condition is not recoverable.\n");
}

static int cheetah_recheck_errors(struct cheetah_err_info *logp)
{
    unsigned long afsr, afar;
    int ret = 0;

    __asm__ __volatile__("ldxa [%%g0] %1, %0\n\t"
                 : "=r" (afsr)
                 : "i" (ASI_AFSR));
    if ((afsr & CHAFSR_ERRORS) != 0) {
        if (logp != NULL) {
            __asm__ __volatile__("ldxa [%%g0] %1, %0\n\t"
                         : "=r" (afar)
                         : "i" (ASI_AFAR));
            logp->afsr = afsr;
            logp->afar = afar;
        }
        ret = 1;
    }
    __asm__ __volatile__("stxa %0, [%%g0] %1\n\t"
                 "membar #Sync\n\t"
                 : : "r" (afsr), "i" (ASI_AFSR));

    return ret;
}

void cheetah_fecc_handler(struct pt_regs *regs, unsigned long afsr, unsigned long afar)
{
    struct cheetah_err_info local_snapshot, *p;
    int recoverable;

    /* Flush E-cache */
    cheetah_flush_ecache();

    p = cheetah_get_error_log(afsr);
    if (!p) {
        prom_printf("ERROR: Early Fast-ECC error afsr[%016lx] afar[%016lx]\n",
                afsr, afar);
        prom_printf("ERROR: CPU(%d) TPC[%016lx] TNPC[%016lx] TSTATE[%016lx]\n",
                smp_processor_id(), regs->tpc, regs->tnpc, regs->tstate);
        prom_halt();
    }

    /* Grab snapshot of logged error. */
    memcpy(&local_snapshot, p, sizeof(local_snapshot));

    /* If the current trap snapshot does not match what the
     * trap handler passed along into our args, big trouble.
     * In such a case, mark the local copy as invalid.
     *
     * Else, it matches and we mark the afsr in the non-local
     * copy as invalid so we may log new error traps there.
     */
    if (p->afsr != afsr || p->afar != afar)
        local_snapshot.afsr = CHAFSR_INVALID;
    else
        p->afsr = CHAFSR_INVALID;

    cheetah_flush_icache();
    cheetah_flush_dcache();

    /* Re-enable I-cache/D-cache */
    __asm__ __volatile__("ldxa [%%g0] %0, %%g1\n\t"
                 "or %%g1, %1, %%g1\n\t"
                 "stxa %%g1, [%%g0] %0\n\t"
                 "membar #Sync"
                 : /* no outputs */
                 : "i" (ASI_DCU_CONTROL_REG),
                   "i" (DCU_DC | DCU_IC)
                 : "g1");

    /* Re-enable error reporting */
    __asm__ __volatile__("ldxa [%%g0] %0, %%g1\n\t"
                 "or %%g1, %1, %%g1\n\t"
                 "stxa %%g1, [%%g0] %0\n\t"
                 "membar #Sync"
                 : /* no outputs */
                 : "i" (ASI_ESTATE_ERROR_EN),
                   "i" (ESTATE_ERROR_NCEEN | ESTATE_ERROR_CEEN)
                 : "g1");

    /* Decide if we can continue after handling this trap and
     * logging the error.
     */
    recoverable = 1;
    if (afsr & (CHAFSR_PERR | CHAFSR_IERR | CHAFSR_ISAP))
        recoverable = 0;

    /* Re-check AFSR/AFAR.  What we are looking for here is whether a new
     * error was logged while we had error reporting traps disabled.
     */
    if (cheetah_recheck_errors(&local_snapshot)) {
        unsigned long new_afsr = local_snapshot.afsr;

        /* If we got a new asynchronous error, die... */
        if (new_afsr & (CHAFSR_EMU | CHAFSR_EDU |
                CHAFSR_WDU | CHAFSR_CPU |
                CHAFSR_IVU | CHAFSR_UE |
                CHAFSR_BERR | CHAFSR_TO))
            recoverable = 0;
    }

    /* Log errors. */
    cheetah_log_errors(regs, &local_snapshot, afsr, afar, recoverable);

    if (!recoverable)
        panic("Irrecoverable Fast-ECC error trap.\n");

    /* Flush E-cache to kick the error trap handlers out. */
    cheetah_flush_ecache();
}

/* Try to fix a correctable error by pushing the line out from
 * the E-cache.  Recheck error reporting registers to see if the
 * problem is intermittent.
 */
static int cheetah_fix_ce(unsigned long physaddr)
{
    unsigned long orig_estate;
    unsigned long alias1, alias2;
    int ret;

    /* Make sure correctable error traps are disabled. */
    __asm__ __volatile__("ldxa    [%%g0] %2, %0\n\t"
                 "andn    %0, %1, %%g1\n\t"
                 "stxa    %%g1, [%%g0] %2\n\t"
                 "membar    #Sync"
                 : "=&r" (orig_estate)
                 : "i" (ESTATE_ERROR_CEEN),
                   "i" (ASI_ESTATE_ERROR_EN)
                 : "g1");

    /* We calculate alias addresses that will force the
     * cache line in question out of the E-cache.  Then
     * we bring it back in with an atomic instruction so
     * that we get it in some modified/exclusive state,
     * then we displace it again to try and get proper ECC
     * pushed back into the system.
     */
    physaddr &= ~(8UL - 1UL);
    alias1 = (ecache_flush_physbase +
          (physaddr & ((ecache_flush_size >> 1) - 1)));
    alias2 = alias1 + (ecache_flush_size >> 1);
    __asm__ __volatile__("ldxa    [%0] %3, %%g0\n\t"
                 "ldxa    [%1] %3, %%g0\n\t"
                 "casxa    [%2] %3, %%g0, %%g0\n\t"
                 "membar    #StoreLoad | #StoreStore\n\t"
                 "ldxa    [%0] %3, %%g0\n\t"
                 "ldxa    [%1] %3, %%g0\n\t"
                 "membar    #Sync"
                 : /* no outputs */
                 : "r" (alias1), "r" (alias2),
                   "r" (physaddr), "i" (ASI_PHYS_USE_EC));

    /* Did that trigger another error? */
    if (cheetah_recheck_errors(NULL)) {
        /* Try one more time. */
        __asm__ __volatile__("ldxa [%0] %1, %%g0\n\t"
                     "membar #Sync"
                     : : "r" (physaddr), "i" (ASI_PHYS_USE_EC));
        if (cheetah_recheck_errors(NULL))
            ret = 2;
        else
            ret = 1;
    } else {
        /* No new error, intermittent problem. */
        ret = 0;
    }

    /* Restore error enables. */
    __asm__ __volatile__("stxa    %0, [%%g0] %1\n\t"
                 "membar    #Sync"
                 : : "r" (orig_estate), "i" (ASI_ESTATE_ERROR_EN));

    return ret;
}

/* Return non-zero if PADDR is a valid physical memory address. */
static int cheetah_check_main_memory(unsigned long paddr)
{
    int i;

    for (i = 0; ; i++) {
        if (sp_banks[i].num_bytes == 0)
            break;
        if (paddr >= sp_banks[i].base_addr &&
            paddr < (sp_banks[i].base_addr + sp_banks[i].num_bytes))
            return 1;
    }
    return 0;
}

void cheetah_cee_handler(struct pt_regs *regs, unsigned long afsr, unsigned long afar)
{
    struct cheetah_err_info local_snapshot, *p;
    int recoverable, is_memory;

    p = cheetah_get_error_log(afsr);
    if (!p) {
        prom_printf("ERROR: Early CEE error afsr[%016lx] afar[%016lx]\n",
                afsr, afar);
        prom_printf("ERROR: CPU(%d) TPC[%016lx] TNPC[%016lx] TSTATE[%016lx]\n",
                smp_processor_id(), regs->tpc, regs->tnpc, regs->tstate);
        prom_halt();
    }

    /* Grab snapshot of logged error. */
    memcpy(&local_snapshot, p, sizeof(local_snapshot));

    /* If the current trap snapshot does not match what the
     * trap handler passed along into our args, big trouble.
     * In such a case, mark the local copy as invalid.
     *
     * Else, it matches and we mark the afsr in the non-local
     * copy as invalid so we may log new error traps there.
     */
    if (p->afsr != afsr || p->afar != afar)
        local_snapshot.afsr = CHAFSR_INVALID;
    else
        p->afsr = CHAFSR_INVALID;

    is_memory = cheetah_check_main_memory(afar);

    if (is_memory && (afsr & CHAFSR_CE) != 0UL) {
        /* XXX Might want to log the results of this operation
         * XXX somewhere... -DaveM
         */
        cheetah_fix_ce(afar);
    }

    {
        int flush_all, flush_line;

        flush_all = flush_line = 0;
        if ((afsr & CHAFSR_EDC) != 0UL) {
            if ((afsr & CHAFSR_ERRORS) == CHAFSR_EDC)
                flush_line = 1;
            else
                flush_all = 1;
        } else if ((afsr & CHAFSR_CPC) != 0UL) {
            if ((afsr & CHAFSR_ERRORS) == CHAFSR_CPC)
                flush_line = 1;
            else
                flush_all = 1;
        }

        /* Trap handler only disabled I-cache, flush it. */
        cheetah_flush_icache();

        /* Re-enable I-cache */
        __asm__ __volatile__("ldxa [%%g0] %0, %%g1\n\t"
                     "or %%g1, %1, %%g1\n\t"
                     "stxa %%g1, [%%g0] %0\n\t"
                     "membar #Sync"
                     : /* no outputs */
                     : "i" (ASI_DCU_CONTROL_REG),
                     "i" (DCU_IC)
                     : "g1");

        if (flush_all)
            cheetah_flush_ecache();
        else if (flush_line)
            cheetah_flush_ecache_line(afar);
    }

    /* Re-enable error reporting */
    __asm__ __volatile__("ldxa [%%g0] %0, %%g1\n\t"
                 "or %%g1, %1, %%g1\n\t"
                 "stxa %%g1, [%%g0] %0\n\t"
                 "membar #Sync"
                 : /* no outputs */
                 : "i" (ASI_ESTATE_ERROR_EN),
                   "i" (ESTATE_ERROR_CEEN)
                 : "g1");

    /* Decide if we can continue after handling this trap and
     * logging the error.
     */
    recoverable = 1;
    if (afsr & (CHAFSR_PERR | CHAFSR_IERR | CHAFSR_ISAP))
        recoverable = 0;

    /* Re-check AFSR/AFAR */
    (void) cheetah_recheck_errors(&local_snapshot);

    /* Log errors. */
    cheetah_log_errors(regs, &local_snapshot, afsr, afar, recoverable);

    if (!recoverable)
        panic("Irrecoverable Correctable-ECC error trap.\n");
}

void cheetah_deferred_handler(struct pt_regs *regs, unsigned long afsr, unsigned long afar)
{
    struct cheetah_err_info local_snapshot, *p;
    int recoverable, is_memory;

#ifdef CONFIG_PCI
    /* Check for the special PCI poke sequence. */
    if (pci_poke_in_progress && pci_poke_cpu == smp_processor_id()) {
        cheetah_flush_icache();
        cheetah_flush_dcache();

        /* Re-enable I-cache/D-cache */
        __asm__ __volatile__("ldxa [%%g0] %0, %%g1\n\t"
                     "or %%g1, %1, %%g1\n\t"
                     "stxa %%g1, [%%g0] %0\n\t"
                     "membar #Sync"
                     : /* no outputs */
                     : "i" (ASI_DCU_CONTROL_REG),
                       "i" (DCU_DC | DCU_IC)
                     : "g1");

        /* Re-enable error reporting */
        __asm__ __volatile__("ldxa [%%g0] %0, %%g1\n\t"
                     "or %%g1, %1, %%g1\n\t"
                     "stxa %%g1, [%%g0] %0\n\t"
                     "membar #Sync"
                     : /* no outputs */
                     : "i" (ASI_ESTATE_ERROR_EN),
                       "i" (ESTATE_ERROR_NCEEN | ESTATE_ERROR_CEEN)
                     : "g1");

        (void) cheetah_recheck_errors(NULL);

        pci_poke_faulted = 1;
        regs->tpc += 4;
        regs->tnpc = regs->tpc + 4;
        return;
    }
#endif

    p = cheetah_get_error_log(afsr);
    if (!p) {
        prom_printf("ERROR: Early deferred error afsr[%016lx] afar[%016lx]\n",
                afsr, afar);
        prom_printf("ERROR: CPU(%d) TPC[%016lx] TNPC[%016lx] TSTATE[%016lx]\n",
                smp_processor_id(), regs->tpc, regs->tnpc, regs->tstate);
        prom_halt();
    }

    /* Grab snapshot of logged error. */
    memcpy(&local_snapshot, p, sizeof(local_snapshot));

    /* If the current trap snapshot does not match what the
     * trap handler passed along into our args, big trouble.
     * In such a case, mark the local copy as invalid.
     *
     * Else, it matches and we mark the afsr in the non-local
     * copy as invalid so we may log new error traps there.
     */
    if (p->afsr != afsr || p->afar != afar)
        local_snapshot.afsr = CHAFSR_INVALID;
    else
        p->afsr = CHAFSR_INVALID;

    is_memory = cheetah_check_main_memory(afar);

    {
        int flush_all, flush_line;

        flush_all = flush_line = 0;
        if ((afsr & CHAFSR_EDU) != 0UL) {
            if ((afsr & CHAFSR_ERRORS) == CHAFSR_EDU)
                flush_line = 1;
            else
                flush_all = 1;
        } else if ((afsr & CHAFSR_BERR) != 0UL) {
            if ((afsr & CHAFSR_ERRORS) == CHAFSR_BERR)
                flush_line = 1;
            else
                flush_all = 1;
        }

        cheetah_flush_icache();
        cheetah_flush_dcache();

        /* Re-enable I/D caches */
        __asm__ __volatile__("ldxa [%%g0] %0, %%g1\n\t"
                     "or %%g1, %1, %%g1\n\t"
                     "stxa %%g1, [%%g0] %0\n\t"
                     "membar #Sync"
                     : /* no outputs */
                     : "i" (ASI_DCU_CONTROL_REG),
                     "i" (DCU_IC | DCU_DC)
                     : "g1");

        if (flush_all)
            cheetah_flush_ecache();
        else if (flush_line)
            cheetah_flush_ecache_line(afar);
    }

    /* Re-enable error reporting */
    __asm__ __volatile__("ldxa [%%g0] %0, %%g1\n\t"
                 "or %%g1, %1, %%g1\n\t"
                 "stxa %%g1, [%%g0] %0\n\t"
                 "membar #Sync"
                 : /* no outputs */
                 : "i" (ASI_ESTATE_ERROR_EN),
                 "i" (ESTATE_ERROR_NCEEN | ESTATE_ERROR_CEEN)
                 : "g1");

    /* Decide if we can continue after handling this trap and
     * logging the error.
     */
    recoverable = 1;
    if (afsr & (CHAFSR_PERR | CHAFSR_IERR | CHAFSR_ISAP))
        recoverable = 0;

    /* Re-check AFSR/AFAR.  What we are looking for here is whether a new
     * error was logged while we had error reporting traps disabled.
     */
    if (cheetah_recheck_errors(&local_snapshot)) {
        unsigned long new_afsr = local_snapshot.afsr;

        /* If we got a new asynchronous error, die... */
        if (new_afsr & (CHAFSR_EMU | CHAFSR_EDU |
                CHAFSR_WDU | CHAFSR_CPU |
                CHAFSR_IVU | CHAFSR_UE |
                CHAFSR_BERR | CHAFSR_TO))
            recoverable = 0;
    }

    /* Log errors. */
    cheetah_log_errors(regs, &local_snapshot, afsr, afar, recoverable);

    /* "Recoverable" here means we try to yank the page from ever
     * being newly used again.  This depends upon a few things:
     * 1) Must be main memory, and AFAR must be valid.
     * 2) If we trapped from use, OK.
     * 3) Else, if we trapped from kernel we must find exception
     *    table entry (ie. we have to have been accessing user
     *    space).
     *
     * If AFAR is not in main memory, or we trapped from kernel
     * and cannot find an exception table entry, it is unacceptable
     * to try and continue.
     */
    if (recoverable && is_memory) {
        if ((regs->tstate & TSTATE_PRIV) == 0UL) {
            /* OK, usermode access. */
            recoverable = 1;
        } else {
            unsigned long g2 = regs->u_regs[UREG_G2];
            unsigned long fixup = search_exception_table(regs->tpc, &g2);

            if (fixup != 0UL) {
                /* OK, kernel access to userspace. */
                recoverable = 1;

            } else {
                /* BAD, privileged state is corrupted. */
                recoverable = 0;
            }

            if (recoverable) {
                struct page *page = virt_to_page(__va(afar));

                if (VALID_PAGE(page))
                    get_page(page);
                else
                    recoverable = 0;

                /* Only perform fixup if we still have a
                 * recoverable condition.
                 */
                if (fixup != 0UL && recoverable) {
                    regs->tpc = fixup;
                    regs->tnpc = regs->tpc + 4;
                    regs->u_regs[UREG_G2] = g2;
                }
            }
        }
    } else {
        recoverable = 0;
    }

    if (!recoverable)
        panic("Irrecoverable deferred error trap.\n");
}

void do_fpe_common(struct pt_regs *regs)
{
    if(regs->tstate & TSTATE_PRIV) {
        regs->tpc = regs->tnpc;
        regs->tnpc += 4;
    } else {
        unsigned long fsr = current->thread.xfsr[0];
        siginfo_t info;

        if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
            regs->tpc &= 0xffffffff;
            regs->tnpc &= 0xffffffff;
        }
        info.si_signo = SIGFPE;
        info.si_errno = 0;
        info.si_addr = (void *)regs->tpc;
        info.si_trapno = 0;
        info.si_code = __SI_FAULT;
        if ((fsr & 0x1c000) == (1 << 14)) {
            if (fsr & 0x10)
                info.si_code = FPE_FLTINV;
            else if (fsr & 0x08)
                info.si_code = FPE_FLTOVF;
            else if (fsr & 0x04)
                info.si_code = FPE_FLTUND;
            else if (fsr & 0x02)
                info.si_code = FPE_FLTDIV;
            else if (fsr & 0x01)
                info.si_code = FPE_FLTRES;
        }
        force_sig_info(SIGFPE, &info, current);
    }
}

void do_fpieee(struct pt_regs *regs)
{
    do_fpe_common(regs);
}

extern int do_mathemu(struct pt_regs *, struct fpustate *);

void do_fpother(struct pt_regs *regs)
{
    struct fpustate *f = FPUSTATE;
    int ret = 0;

    switch ((current->thread.xfsr[0] & 0x1c000)) {
    case (2 << 14): /* unfinished_FPop */
    case (3 << 14): /* unimplemented_FPop */
        ret = do_mathemu(regs, f);
        break;
    }
    if (ret)
        return;
    do_fpe_common(regs);
}

void do_tof(struct pt_regs *regs)
{
    siginfo_t info;

    if(regs->tstate & TSTATE_PRIV)
        die_if_kernel("Penguin overflow trap from kernel mode", regs);
    if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
        regs->tpc &= 0xffffffff;
        regs->tnpc &= 0xffffffff;
    }
    info.si_signo = SIGEMT;
    info.si_errno = 0;
    info.si_code = EMT_TAGOVF;
    info.si_addr = (void *)regs->tpc;
    info.si_trapno = 0;
    force_sig_info(SIGEMT, &info, current);
}

void do_div0(struct pt_regs *regs)
{
    siginfo_t info;

    if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
        regs->tpc &= 0xffffffff;
        regs->tnpc &= 0xffffffff;
    }
    info.si_signo = SIGFPE;
    info.si_errno = 0;
    info.si_code = FPE_INTDIV;
    info.si_addr = (void *)regs->tpc;
    info.si_trapno = 0;
    force_sig_info(SIGFPE, &info, current);
}

void instruction_dump (unsigned int *pc)
{
    int i;

    if((((unsigned long) pc) & 3))
        return;

    printk("Instruction DUMP:");
    for(i = -3; i < 6; i++)
        printk("%c%08x%c",i?' ':'<',pc[i],i?' ':'>');
    printk("\n");
}

void user_instruction_dump (unsigned int *pc)
{
    int i;
    unsigned int buf[9];
    
    if((((unsigned long) pc) & 3))
        return;
        
    if(copy_from_user(buf, pc - 3, sizeof(buf)))
        return;

    printk("Instruction DUMP:");
    for(i = 0; i < 9; i++)
        printk("%c%08x%c",i==3?' ':'<',buf[i],i==3?' ':'>');
    printk("\n");
}

void show_trace_task(struct task_struct *tsk)
{
    unsigned long pc, fp;
    unsigned long task_base = (unsigned long)tsk;
    struct reg_window *rw;
    int count = 0;

    if (!tsk)
        return;

    fp = tsk->thread.ksp + STACK_BIAS;
    do {
        /* Bogus frame pointer? */
        if (fp < (task_base + sizeof(struct task_struct)) ||
            fp >= (task_base + THREAD_SIZE))
            break;
        rw = (struct reg_window *)fp;
        pc = rw->ins[7];
        printk("[%016lx] ", pc);
        fp = rw->ins[6] + STACK_BIAS;
    } while (++count < 16);
    printk("\n");
}

void die_if_kernel(char *str, struct pt_regs *regs)
{
    extern void __show_regs(struct pt_regs * regs);
    extern void smp_report_regs(void);
    int count = 0;
    struct reg_window *lastrw;
    
    /* Amuse the user. */
    printk(
"              \\|/ ____ \\|/\n"
"              \"@'/ .. \\`@\"\n"
"              /_| \\__/ |_\\\n"
"                 \\__U_/\n");

    printk("%s(%d): %s\n", current->comm, current->pid, str);
    __asm__ __volatile__("flushw");
    __show_regs(regs);
    if(regs->tstate & TSTATE_PRIV) {
        struct reg_window *rw = (struct reg_window *)
            (regs->u_regs[UREG_FP] + STACK_BIAS);

        /* Stop the back trace when we hit userland or we
         * find some badly aligned kernel stack.
         */
        lastrw = (struct reg_window *)current;
        while(rw                    &&
              count++ < 30                &&
              rw >= lastrw                &&
              (char *) rw < ((char *) current)
                + sizeof (union task_union)         &&
              !(((unsigned long) rw) & 0x7)) {
            printk("Caller[%016lx]\n", rw->ins[7]);
            lastrw = rw;
            rw = (struct reg_window *)
                (rw->ins[6] + STACK_BIAS);
        }
        instruction_dump ((unsigned int *) regs->tpc);
    } else {
        if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
            regs->tpc &= 0xffffffff;
            regs->tnpc &= 0xffffffff;
        }
        user_instruction_dump ((unsigned int *) regs->tpc);
    }
#ifdef CONFIG_SMP
    smp_report_regs();
#endif
                                                    
    if(regs->tstate & TSTATE_PRIV)
        do_exit(SIGKILL);
    do_exit(SIGSEGV);
}

extern int handle_popc(u32 insn, struct pt_regs *regs);
extern int handle_ldf_stq(u32 insn, struct pt_regs *regs);

void do_illegal_instruction(struct pt_regs *regs)
{
    unsigned long pc = regs->tpc;
    unsigned long tstate = regs->tstate;
    u32 insn;
    siginfo_t info;

    if(tstate & TSTATE_PRIV)
        die_if_kernel("Kernel illegal instruction", regs);
    if(current->thread.flags & SPARC_FLAG_32BIT)
        pc = (u32)pc;
    if (get_user(insn, (u32 *)pc) != -EFAULT) {
        if ((insn & 0xc1ffc000) == 0x81700000) /* POPC */ {
            if (handle_popc(insn, regs))
                return;
        } else if ((insn & 0xc1580000) == 0xc1100000) /* LDQ/STQ */ {
            if (handle_ldf_stq(insn, regs))
                return;
        }
    }
    info.si_signo = SIGILL;
    info.si_errno = 0;
    info.si_code = ILL_ILLOPC;
    info.si_addr = (void *)pc;
    info.si_trapno = 0;
    force_sig_info(SIGILL, &info, current);
}

void mem_address_unaligned(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr)
{
    siginfo_t info;

    if(regs->tstate & TSTATE_PRIV) {
        extern void kernel_unaligned_trap(struct pt_regs *regs,
                          unsigned int insn, 
                          unsigned long sfar, unsigned long sfsr);

        return kernel_unaligned_trap(regs, *((unsigned int *)regs->tpc), sfar, sfsr);
    }
    info.si_signo = SIGBUS;
    info.si_errno = 0;
    info.si_code = BUS_ADRALN;
    info.si_addr = (void *)sfar;
    info.si_trapno = 0;
    force_sig_info(SIGBUS, &info, current);
}

void do_privop(struct pt_regs *regs)
{
    siginfo_t info;

    if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
        regs->tpc &= 0xffffffff;
        regs->tnpc &= 0xffffffff;
    }
    info.si_signo = SIGILL;
    info.si_errno = 0;
    info.si_code = ILL_PRVOPC;
    info.si_addr = (void *)regs->tpc;
    info.si_trapno = 0;
    force_sig_info(SIGILL, &info, current);
}

void do_privact(struct pt_regs *regs)
{
    do_privop(regs);
}

/* Trap level 1 stuff or other traps we should never see... */
void do_cee(struct pt_regs *regs)
{
    die_if_kernel("TL0: Cache Error Exception", regs);
}

void do_cee_tl1(struct pt_regs *regs)
{
    die_if_kernel("TL1: Cache Error Exception", regs);
}

void do_dae_tl1(struct pt_regs *regs)
{
    die_if_kernel("TL1: Data Access Exception", regs);
}

void do_iae_tl1(struct pt_regs *regs)
{
    die_if_kernel("TL1: Instruction Access Exception", regs);
}

void do_div0_tl1(struct pt_regs *regs)
{
    die_if_kernel("TL1: DIV0 Exception", regs);
}

void do_fpdis_tl1(struct pt_regs *regs)
{
    die_if_kernel("TL1: FPU Disabled", regs);
}

void do_fpieee_tl1(struct pt_regs *regs)
{
    die_if_kernel("TL1: FPU IEEE Exception", regs);
}

void do_fpother_tl1(struct pt_regs *regs)
{
    die_if_kernel("TL1: FPU Other Exception", regs);
}

void do_ill_tl1(struct pt_regs *regs)
{
    die_if_kernel("TL1: Illegal Instruction Exception", regs);
}

void do_irq_tl1(struct pt_regs *regs)
{
    die_if_kernel("TL1: IRQ Exception", regs);
}

void do_lddfmna_tl1(struct pt_regs *regs)
{
    die_if_kernel("TL1: LDDF Exception", regs);
}

void do_stdfmna_tl1(struct pt_regs *regs)
{
    die_if_kernel("TL1: STDF Exception", regs);
}

void do_paw(struct pt_regs *regs)
{
    die_if_kernel("TL0: Phys Watchpoint Exception", regs);
}

void do_paw_tl1(struct pt_regs *regs)
{
    die_if_kernel("TL1: Phys Watchpoint Exception", regs);
}

void do_vaw(struct pt_regs *regs)
{
    die_if_kernel("TL0: Virt Watchpoint Exception", regs);
}

void do_vaw_tl1(struct pt_regs *regs)
{
    die_if_kernel("TL1: Virt Watchpoint Exception", regs);
}

void do_tof_tl1(struct pt_regs *regs)
{
    die_if_kernel("TL1: Tag Overflow Exception", regs);
}

void do_getpsr(struct pt_regs *regs)
{
    regs->u_regs[UREG_I0] = tstate_to_psr(regs->tstate);
    regs->tpc   = regs->tnpc;
    regs->tnpc += 4;
    if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) {
        regs->tpc &= 0xffffffff;
        regs->tnpc &= 0xffffffff;
    }
}

void trap_init(void)
{
    /* Attach to the address space of init_task. */
    atomic_inc(&init_mm.mm_count);
    current->active_mm = &init_mm;

    /* NOTE: Other cpus have this done as they are started
     *       up on SMP.
     */
}

:: 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.0287 ]--