Commit 96d803da authored by Richard Henderson's avatar Richard Henderson

Merge are.twiddle.net:/home/rth/BK/linus-2.5

into are.twiddle.net:/home/rth/BK/axp-2.5
parents 37e093c1 353cc80d
......@@ -522,6 +522,9 @@ config ALPHA_LARGE_VMALLOC
Say N unless you know you need gobs and gobs of vmalloc space.
config VERBOSE_MCHECK
bool "Verbose Machine Checks"
source "drivers/pci/Kconfig"
config HOTPLUG
......
......@@ -59,6 +59,7 @@ CONFIG_ALPHA_GENERIC=y
# CONFIG_ALPHA_TAKARA is not set
# CONFIG_ALPHA_TITAN is not set
# CONFIG_ALPHA_WILDFIRE is not set
CONFIG_VERBOSE_MCHECK=y
CONFIG_ISA=y
CONFIG_EISA=y
# CONFIG_SBUS is not set
......
......@@ -10,7 +10,7 @@ export-objs := alpha_ksyms.o
obj-y := entry.o traps.o process.o init_task.o osf_sys.o irq.o \
irq_alpha.o signal.o setup.o ptrace.o time.o semaphore.o \
alpha_ksyms.o systbls.o
alpha_ksyms.o systbls.o err_common.o
#
# FIXME!
......
......@@ -755,6 +755,7 @@ cia_pci_clr_err(void)
*(vip)CIA_IOC_CIA_ERR; /* re-read to force write. */
}
#ifdef CONFIG_VERBOSE_MCHECK
static void
cia_decode_pci_error(struct el_CIA_sysdata_mcheck *cia, const char *msg)
{
......@@ -1022,13 +1023,13 @@ cia_decode_parity_error(struct el_CIA_sysdata_mcheck *cia)
printk(KERN_CRIT " Command: %s, Parity bit: %d\n", cmd, par);
printk(KERN_CRIT " Address: %#010lx, Mask: %#lx\n", addr, mask);
}
#endif
static int
cia_decode_mchk(unsigned long la_ptr)
{
struct el_common *com;
struct el_CIA_sysdata_mcheck *cia;
int which;
com = (void *)la_ptr;
cia = (void *)(la_ptr + com->sys_offset);
......@@ -1036,8 +1037,8 @@ cia_decode_mchk(unsigned long la_ptr)
if ((cia->cia_err & CIA_ERR_VALID) == 0)
return 0;
which = cia->cia_err & 0xfff;
switch (ffs(which) - 1) {
#ifdef CONFIG_VERBOSE_MCHECK
switch (ffs(cia->cia_err & 0xfff) - 1) {
case 0: /* CIA_ERR_COR_ERR */
cia_decode_ecc_error(cia, "Corrected ECC error");
break;
......@@ -1109,6 +1110,7 @@ cia_decode_mchk(unsigned long la_ptr)
if (cia->cia_err & CIA_ERR_LOST_IOA_TIMEOUT)
printk(KERN_CRIT "CIA lost machine check: "
"I/O timeout\n");
#endif
return 1;
}
......
......@@ -452,7 +452,8 @@ sys_fork:
bsr $1,do_switch_stack
bis $31,SIGCHLD,$16
mov $31,$17
mov $30,$18
mov $31,$18
mov $30,$19
jsr $26,alpha_clone
bsr $1,undo_switch_stack
ret $31,($26),1
......@@ -463,8 +464,9 @@ sys_fork:
.ent sys_clone
sys_clone:
bsr $1,do_switch_stack
/* arg1 and arg2 come from the user */
mov $30,$18
/* $16, $17, $18, $19 come from the user; $19 is used later
via pt_regs->r19. */
mov $30,$19
jsr $26,alpha_clone
bsr $1,undo_switch_stack
ret $31,($26),1
......
This diff is collapsed.
/*
* linux/arch/alpha/kernel/err_impl.h
*
* Copyright (C) 2000 Jeff Wiedemeier (Compaq Computer Corporation)
*
* Contains declarations and macros to support Alpha error handling
* implementations.
*/
/*
* SCB Vector definitions
*/
#define SCB_Q_SYSERR 0x620
#define SCB_Q_PROCERR 0x630
#define SCB_Q_SYSMCHK 0x660
#define SCB_Q_PROCMCHK 0x670
#define SCB_Q_SYSEVENT 0x680
/*
* Disposition definitions for logout frame parser
*/
#define MCHK_DISPOSITION_UNKNOWN_ERROR 0x00
#define MCHK_DISPOSITION_REPORT 0x01
#define MCHK_DISPOSITION_DISMISS 0x02
/*
* Error Log definitions
*/
/*
* Types
*/
#define EL_CLASS__TERMINATION (0)
# define EL_TYPE__TERMINATION__TERMINATION (0)
#define EL_CLASS__HEADER (5)
# define EL_TYPE__HEADER__SYSTEM_ERROR_FRAME (1)
# define EL_TYPE__HEADER__SYSTEM_EVENT_FRAME (2)
# define EL_TYPE__HEADER__HALT_FRAME (3)
# define EL_TYPE__HEADER__LOGOUT_FRAME (19)
#define EL_CLASS__GENERAL_NOTIFICATION (9)
#define EL_CLASS__PCI_ERROR_FRAME (11)
#define EL_CLASS__REGATTA_FAMILY (12)
# define EL_TYPE__REGATTA__PROCESSOR_ERROR_FRAME (1)
# define EL_TYPE__REGATTA__SYSTEM_ERROR_FRAME (2)
# define EL_TYPE__REGATTA__ENVIRONMENTAL_FRAME (3)
# define EL_TYPE__REGATTA__TITAN_PCHIP0_EXTENDED (8)
# define EL_TYPE__REGATTA__TITAN_PCHIP1_EXTENDED (9)
# define EL_TYPE__REGATTA__TITAN_MEMORY_EXTENDED (10)
# define EL_TYPE__REGATTA__PROCESSOR_DBL_ERROR_HALT (11)
# define EL_TYPE__REGATTA__SYSTEM_DBL_ERROR_HALT (12)
#define EL_CLASS__PAL (14)
# define EL_TYPE__PAL__LOGOUT_FRAME (1)
# define EL_TYPE__PAL__EV7_PROCESSOR (4)
# define EL_TYPE__PAL__EV7_ZBOX (5)
# define EL_TYPE__PAL__EV7_RBOX (6)
# define EL_TYPE__PAL__EV7_IO (7)
union el_timestamp {
struct {
u8 second;
u8 minute;
u8 hour;
u8 day;
u8 month;
u8 year;
} b;
u64 as_int;
};
struct el_subpacket {
u16 length; /* length of header (in bytes) */
u16 class; /* header class and type... */
u16 type; /* ...determine content */
u16 revision; /* header revision */
union {
struct { /* Class 5, Type 1 - System Error */
u32 frame_length;
u32 frame_packet_count;
} sys_err;
struct { /* Class 5, Type 2 - System Event */
union el_timestamp timestamp;
u32 frame_length;
u32 frame_packet_count;
} sys_event;
struct { /* Class 5, Type 3 - Double Error Halt */
u16 halt_code;
u16 reserved;
union el_timestamp timestamp;
u32 frame_length;
u32 frame_packet_count;
} err_halt;
struct { /* Clasee 5, Type 19 - Logout Frame Header */
u32 frame_length;
u32 frame_flags;
u32 cpu_offset;
u32 system_offset;
} logout_header;
struct { /* Class 12 - Regatta */
u64 cpuid;
u64 data_start[1];
} regatta_frame;
struct { /* Raw */
u64 data_start[1];
} raw;
} by_type;
};
struct el_subpacket_annotation {
struct el_subpacket_annotation *next;
u16 class;
u16 type;
u16 revision;
char *description;
char **annotation;
};
#define SUBPACKET_ANNOTATION(c, t, r, d, a) {NULL, (c), (t), (r), (d), (a)}
struct el_subpacket_handler {
struct el_subpacket_handler *next;
u16 class;
struct el_subpacket *(*handler)(struct el_subpacket *);
};
#define SUBPACKET_HANDLER_INIT(c, h) {NULL, (c), (h)}
/*
* Extract a field from a register given it's name. defines
* for the LSB (__S - shift count) and bitmask (__M) are required
*/
#define EXTRACT(u, f) (((u) >> f##__S) & f##__M)
/*
* err_common.c
*/
extern char *err_print_prefix;
extern void mchk_dump_mem(void *, int, char **);
extern void mchk_dump_logout_frame(struct el_common *);
extern void ev7_register_error_handlers(void);
extern void ev7_machine_check(u64, u64, struct pt_regs *);
extern void ev6_register_error_handlers(void);
extern int ev6_process_logout_frame(struct el_common *, int);
extern void ev6_machine_check(u64, u64, struct pt_regs *);
extern struct el_subpacket *el_process_subpacket(struct el_subpacket *);
extern void el_annotate_subpacket(struct el_subpacket *);
extern void cdl_check_console_data_log(void);
extern int cdl_register_subpacket_annotation(struct el_subpacket_annotation *);
extern int cdl_register_subpacket_handler(struct el_subpacket_handler *);
......@@ -147,10 +147,10 @@ process_mcheck_info(unsigned long vector, unsigned long la_ptr,
mchk_header = (struct el_common *)la_ptr;
printk(KERN_CRIT "%s machine check: vector=0x%lx pc=0x%lx code=0x%lx\n",
printk(KERN_CRIT "%s machine check: vector=0x%lx pc=0x%lx code=0x%x\n",
machine, vector, regs->pc, mchk_header->code);
switch ((unsigned int) mchk_header->code) {
switch (mchk_header->code) {
/* Machine check reasons. Defined according to PALcode sources. */
case 0x80: reason = "tag parity error"; break;
case 0x82: reason = "tag control parity error"; break;
......
......@@ -844,7 +844,7 @@ osf_setsysinfo(unsigned long op, void *buffer, unsigned long nbytes,
{
switch (op) {
case SSI_IEEE_FP_CONTROL: {
unsigned long swcr, fpcr;
unsigned long swcr, fpcr, fex;
/*
* Alpha Architecture Handbook 4.7.7.3:
......@@ -867,9 +867,24 @@ osf_setsysinfo(unsigned long op, void *buffer, unsigned long nbytes,
wrfpcr(fpcr);
/* If any exceptions are now unmasked, send a signal. */
if (((swcr & IEEE_STATUS_MASK)
>> IEEE_STATUS_TO_EXCSUM_SHIFT) & swcr) {
send_sig(SIGFPE, current, 1);
fex = ((swcr & IEEE_STATUS_MASK)
>> IEEE_STATUS_TO_EXCSUM_SHIFT) & swcr;
if (fex) {
siginfo_t info;
int si_code = 0;
if (fex & IEEE_TRAP_ENABLE_DNO) si_code = FPE_FLTUND;
if (fex & IEEE_TRAP_ENABLE_INE) si_code = FPE_FLTRES;
if (fex & IEEE_TRAP_ENABLE_UNF) si_code = FPE_FLTUND;
if (fex & IEEE_TRAP_ENABLE_OVF) si_code = FPE_FLTOVF;
if (fex & IEEE_TRAP_ENABLE_DZE) si_code = FPE_FLTDIV;
if (fex & IEEE_TRAP_ENABLE_INV) si_code = FPE_FLTINV;
info.si_signo = SIGFPE;
info.si_errno = 0;
info.si_code = si_code;
info.si_addr = 0; /* FIXME */
send_sig_info(SIGFPE, &info, current);
}
return 0;
......
......@@ -245,11 +245,10 @@ release_thread(struct task_struct *dead_task)
*/
int
alpha_clone(unsigned long clone_flags, unsigned long usp,
struct switch_stack * swstack)
int *user_tid, struct switch_stack * swstack)
{
struct task_struct *p;
struct pt_regs *u_regs = (struct pt_regs *) (swstack+1);
int *user_tid = (int *)u_regs->r19;
if (!usp)
usp = rdusp();
......@@ -314,6 +313,10 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
childti->pcb.ksp = (unsigned long) childstack;
childti->pcb.flags = 1; /* set FEN, clear everything else */
/* Set a new TLS for the child thread? Peek back into the
syscall arguments that we saved on syscall entry. */
childti->pcb.unique = (clone_flags & CLONE_SETTLS ? regs->r19 : 0);
return 0;
}
......
......@@ -293,8 +293,16 @@ do_sigreturn(struct sigframe *frame, struct pt_regs *regs,
goto give_sigsegv;
/* Send SIGTRAP if we're single-stepping: */
if (ptrace_cancel_bpt (current))
send_sig(SIGTRAP, current, 1);
if (ptrace_cancel_bpt (current)) {
siginfo_t info;
info.si_signo = SIGTRAP;
info.si_errno = 0;
info.si_code = TRAP_BRKPT;
info.si_addr = (void *) regs->pc;
info.si_trapno = 0;
send_sig_info(SIGTRAP, &info, current);
}
return;
give_sigsegv:
......@@ -330,8 +338,16 @@ do_rt_sigreturn(struct rt_sigframe *frame, struct pt_regs *regs,
do_sigaltstack(&st, NULL, rdusp());
/* Send SIGTRAP if we're single-stepping: */
if (ptrace_cancel_bpt (current))
send_sig(SIGTRAP, current, 1);
if (ptrace_cancel_bpt (current)) {
siginfo_t info;
info.si_signo = SIGTRAP;
info.si_errno = 0;
info.si_code = TRAP_BRKPT;
info.si_addr = (void *) regs->pc;
info.si_trapno = 0;
send_sig_info(SIGTRAP, &info, current);
}
return;
give_sigsegv:
......
This diff is collapsed.
......@@ -213,25 +213,25 @@ do_entArith(unsigned long summary, unsigned long write_mask,
unsigned long a2, unsigned long a3, unsigned long a4,
unsigned long a5, struct pt_regs regs)
{
long si_code = FPE_FLTINV;
siginfo_t info;
if (summary & 1) {
/* Software-completion summary bit is set, so try to
emulate the instruction. */
if (!amask(AMASK_PRECISE_TRAP)) {
/* 21264 (except pass 1) has precise exceptions. */
if (alpha_fp_emul(regs.pc - 4))
return;
} else {
if (alpha_fp_emul_imprecise(&regs, write_mask))
return;
}
emulate the instruction. If the processor supports
precise exceptions, we don't have to search. */
if (!amask(AMASK_PRECISE_TRAP))
si_code = alpha_fp_emul(regs.pc - 4);
else
si_code = alpha_fp_emul_imprecise(&regs, write_mask);
}
#if 0
printk("%s: arithmetic trap at %016lx: %02lx %016lx\n",
current->comm, regs.pc, summary, write_mask);
#endif
die_if_kernel("Arithmetic fault", &regs, 0, 0);
send_sig(SIGFPE, current, 1);
info.si_signo = SIGFPE;
info.si_errno = 0;
info.si_code = si_code;
info.si_addr = (void *) regs.pc;
send_sig_info(SIGFPE, &info, current);
}
asmlinkage void
......@@ -239,6 +239,9 @@ do_entIF(unsigned long type, unsigned long a1,
unsigned long a2, unsigned long a3, unsigned long a4,
unsigned long a5, struct pt_regs regs)
{
siginfo_t info;
int signo, code;
if (!opDEC_testing || type != 4) {
if (type == 1) {
const unsigned int *data
......@@ -253,30 +256,64 @@ do_entIF(unsigned long type, unsigned long a1,
switch (type) {
case 0: /* breakpoint */
info.si_signo = SIGTRAP;
info.si_errno = 0;
info.si_code = TRAP_BRKPT;
info.si_trapno = 0;
info.si_addr = (void *) regs.pc;
if (ptrace_cancel_bpt(current)) {
regs.pc -= 4; /* make pc point to former bpt */
}
send_sig(SIGTRAP, current, 1);
send_sig_info(SIGTRAP, &info, current);
return;
case 1: /* bugcheck */
send_sig(SIGTRAP, current, 1);
info.si_signo = SIGTRAP;
info.si_errno = 0;
info.si_code = __SI_FAULT;
info.si_addr = (void *) regs.pc;
info.si_trapno = 0;
send_sig_info(SIGTRAP, &info, current);
return;
case 2: /* gentrap */
/*
* The exception code should be passed on to the signal
* handler as the second argument. Linux doesn't do that
* yet (also notice that Linux *always* behaves like
* DEC Unix with SA_SIGINFO off; see DEC Unix man page
* for sigaction(2)).
*/
info.si_addr = (void *) regs.pc;
info.si_trapno = regs.r16;
switch ((long) regs.r16) {
case GEN_INTOVF: case GEN_INTDIV: case GEN_FLTOVF:
case GEN_FLTDIV: case GEN_FLTUND: case GEN_FLTINV:
case GEN_FLTINE: case GEN_ROPRAND:
send_sig(SIGFPE, current, 1);
return;
case GEN_INTOVF:
signo = SIGFPE;
code = FPE_INTOVF;
break;
case GEN_INTDIV:
signo = SIGFPE;
code = FPE_INTDIV;
break;
case GEN_FLTOVF:
signo = SIGFPE;
code = FPE_FLTOVF;
break;
case GEN_FLTDIV:
signo = SIGFPE;
code = FPE_FLTDIV;
break;
case GEN_FLTUND:
signo = SIGFPE;
code = FPE_FLTUND;
break;
case GEN_FLTINV:
signo = SIGFPE;
code = FPE_FLTINV;
break;
case GEN_FLTINE:
signo = SIGFPE;
code = FPE_FLTRES;
break;
case GEN_ROPRAND:
signo = SIGFPE;
code = __SI_FAULT;
break;
case GEN_DECOVF:
case GEN_DECDIV:
......@@ -295,13 +332,23 @@ do_entIF(unsigned long type, unsigned long a1,
case GEN_SUBRNG5:
case GEN_SUBRNG6:
case GEN_SUBRNG7:
send_sig(SIGTRAP, current, 1);
return;
}
default:
signo = SIGTRAP;
code = __SI_FAULT;
break;
}
info.si_signo = signo;
info.si_errno = 0;
info.si_code = code;
info.si_addr = (void *) regs.pc;
send_sig_info(signo, &info, current);
return;
case 4: /* opDEC */
if (implver() == IMPLVER_EV4) {
long si_code;
/* The some versions of SRM do not handle
the opDEC properly - they return the PC of the
opDEC fault, not the instruction after as the
......@@ -309,8 +356,7 @@ do_entIF(unsigned long type, unsigned long a1,
We do this by intentionally causing an opDEC
fault during the boot sequence and testing if
we get the correct PC. If not, we set a flag
to correct it every time through.
*/
to correct it every time through. */
if (opDEC_testing) {
if (regs.pc == opDEC_test_pc) {
opDEC_fix = 4;
......@@ -324,9 +370,18 @@ do_entIF(unsigned long type, unsigned long a1,
/* EV4 does not implement anything except normal
rounding. Everything else will come here as
an illegal instruction. Emulate them. */
if (alpha_fp_emul(regs.pc-4))
si_code = alpha_fp_emul(regs.pc - 4);
if (si_code == 0)
return;
if (si_code > 0) {
info.si_signo = SIGFPE;
info.si_errno = 0;
info.si_code = si_code;
info.si_addr = (void *) regs.pc;
send_sig_info(SIGFPE, &info, current);
return;
}
}
break;
case 3: /* FEN fault */
......@@ -347,7 +402,12 @@ do_entIF(unsigned long type, unsigned long a1,
default: /* unexpected instruction-fault type */
;
}
send_sig(SIGILL, current, 1);
info.si_signo = SIGILL;
info.si_errno = 0;
info.si_code = ILL_ILLOPC;
info.si_addr = regs.pc;
send_sig_info(SIGILL, &info, current);
}
/* There is an ifdef in the PALcode in MILO that enables a
......@@ -362,8 +422,15 @@ do_entDbg(unsigned long type, unsigned long a1,
unsigned long a2, unsigned long a3, unsigned long a4,
unsigned long a5, struct pt_regs regs)
{
siginfo_t info;
die_if_kernel("Instruction fault", &regs, type, 0);
force_sig(SIGILL, current);
info.si_signo = SIGILL;
info.si_errno = 0;
info.si_code = ILL_ILLOPC;
info.si_addr = regs.pc;
force_sig_info(SIGILL, &info, current);
}
......@@ -720,6 +787,7 @@ do_entUnaUser(void * va, unsigned long opcode,
unsigned long tmp1, tmp2, tmp3, tmp4;
unsigned long fake_reg, *reg_addr = &fake_reg;
siginfo_t info;
long error;
/* Check the UAC bits to decide what the user wants us to do
......@@ -984,12 +1052,34 @@ do_entUnaUser(void * va, unsigned long opcode,
give_sigsegv:
regs->pc -= 4; /* make pc point to faulting insn */
send_sig(SIGSEGV, current, 1);
info.si_signo = SIGSEGV;
info.si_errno = 0;
/* We need to replicate some of the logic in mm/fault.c,
since we don't have access to the fault code in the
exception handling return path. */
if (!__access_ok((unsigned long)va, 0, USER_DS))
info.si_code = SEGV_ACCERR;
else {
struct mm_struct *mm = current->mm;
down_read(&mm->mmap_sem);
if (find_vma(mm, (unsigned long)va))
info.si_code = SEGV_ACCERR;
else
info.si_code = SEGV_MAPERR;
up_read(&mm->mmap_sem);
}
info.si_addr = va;
send_sig_info(SIGSEGV, &info, current);
return;
give_sigbus:
regs->pc -= 4;
send_sig(SIGBUS, current, 1);
info.si_signo = SIGBUS;
info.si_errno = 0;
info.si_code = BUS_ADRALN;
info.si_addr = va;
send_sig_info(SIGBUS, &info, current);
return;
}
......
......@@ -86,11 +86,13 @@ void cleanup_module(void)
/*
* Emulate the floating point instruction at address PC. Returns 0 if
* emulation fails. Notice that the kernel does not and cannot use FP
* regs. This is good because it means that instead of
* saving/restoring all fp regs, we simply stick the result of the
* operation into the appropriate register.
* Emulate the floating point instruction at address PC. Returns -1 if the
* instruction to be emulated is illegal (such as with the opDEC trap), else
* the SI_CODE for a SIGFPE signal, else 0 if everything's ok.
*
* Notice that the kernel does not and cannot use FP regs. This is good
* because it means that instead of saving/restoring all fp regs, we simply
* stick the result of the operation into the appropriate register.
*/
long
alpha_fp_emul (unsigned long pc)
......@@ -102,6 +104,7 @@ alpha_fp_emul (unsigned long pc)
unsigned long fa, fb, fc, func, mode, src;
unsigned long res, va, vb, vc, swcr, fpcr;
__u32 insn;
long si_code;
MOD_INC_USE_COUNT;
......@@ -306,10 +309,19 @@ alpha_fp_emul (unsigned long pc)
wrfpcr(fpcr);
/* Do we generate a signal? */
if (_fex & swcr & IEEE_TRAP_ENABLE_MASK) {
MOD_DEC_USE_COUNT;
return 0;
_fex = _fex & swcr & IEEE_TRAP_ENABLE_MASK;
si_code = 0;
if (_fex) {
if (_fex & IEEE_TRAP_ENABLE_DNO) si_code = FPE_FLTUND;
if (_fex & IEEE_TRAP_ENABLE_INE) si_code = FPE_FLTRES;
if (_fex & IEEE_TRAP_ENABLE_UNF) si_code = FPE_FLTUND;
if (_fex & IEEE_TRAP_ENABLE_OVF) si_code = FPE_FLTOVF;
if (_fex & IEEE_TRAP_ENABLE_DZE) si_code = FPE_FLTDIV;
if (_fex & IEEE_TRAP_ENABLE_INV) si_code = FPE_FLTINV;
}
MOD_DEC_USE_COUNT;
return si_code;
}
/* We used to write the destination register here, but DEC FORTRAN
......@@ -317,20 +329,20 @@ alpha_fp_emul (unsigned long pc)
immediately after the operations above. */
MOD_DEC_USE_COUNT;
return 1;
return 0;
bad_insn:
printk(KERN_ERR "alpha_fp_emul: Invalid FP insn %#x at %#lx\n",
insn, pc);
MOD_DEC_USE_COUNT;
return 0;
return -1;
}
long
alpha_fp_emul_imprecise (struct pt_regs *regs, unsigned long write_mask)
{
unsigned long trigger_pc = regs->pc - 4;
unsigned long insn, opcode, rc, no_signal = 0;
unsigned long insn, opcode, rc, si_code = 0;
MOD_INC_USE_COUNT;
......@@ -384,7 +396,7 @@ alpha_fp_emul_imprecise (struct pt_regs *regs, unsigned long write_mask)
if (!write_mask) {
/* Re-execute insns in the trap-shadow. */
regs->pc = trigger_pc + 4;
no_signal = alpha_fp_emul(trigger_pc);
si_code = alpha_fp_emul(trigger_pc);
goto egress;
}
trigger_pc -= 4;
......@@ -392,5 +404,5 @@ alpha_fp_emul_imprecise (struct pt_regs *regs, unsigned long write_mask)
egress:
MOD_DEC_USE_COUNT;
return no_signal;
return si_code;
}
......@@ -89,7 +89,8 @@ do_page_fault(unsigned long address, unsigned long mmcsr,
struct vm_area_struct * vma;
struct mm_struct *mm = current->mm;
unsigned int fixup;
int fault;
int fault, si_code = SEGV_MAPERR;
siginfo_t info;
/* As of EV6, a load into $31/$f31 is a prefetch, and never faults
(or is suppressed by the PALcode). Support that for older CPUs
......@@ -129,6 +130,7 @@ do_page_fault(unsigned long address, unsigned long mmcsr,
/* Ok, we have a good vm_area for this memory access, so
we can handle it. */
good_area:
si_code = SEGV_ACCERR;
if (cause < 0) {
if (!(vma->vm_flags & VM_EXEC))
goto bad_area;
......@@ -148,10 +150,20 @@ do_page_fault(unsigned long address, unsigned long mmcsr,
fault = handle_mm_fault(mm, vma, address, cause > 0);
up_read(&mm->mmap_sem);
if (fault < 0)
goto out_of_memory;
if (fault == 0)
switch (fault) {
case VM_FAULT_MINOR:
current->min_flt++;
break;
case VM_FAULT_MAJOR:
current->maj_flt++;
break;
case VM_FAULT_SIGBUS:
goto do_sigbus;
case VM_FAULT_OOM:
goto out_of_memory;
default:
BUG();
}
return;
/* Something tried to access memory that isn't in our memory map.
......@@ -159,20 +171,14 @@ do_page_fault(unsigned long address, unsigned long mmcsr,
bad_area:
up_read(&mm->mmap_sem);
if (user_mode(regs)) {
force_sig(SIGSEGV, current);
return;
}
if (user_mode(regs))
goto do_sigsegv;
no_context:
/* Are we prepared to handle this fault as an exception? */
if ((fixup = search_exception_table(regs->pc, regs->gp)) != 0) {
unsigned long newpc;
newpc = fixup_exception(dpf_reg, fixup, regs->pc);
#if 0
printk("%s: Exception at [<%lx>] (%lx) handled successfully\n",
current->comm, regs->pc, newpc);
#endif
regs->pc = newpc;
return;
}
......@@ -201,17 +207,28 @@ do_page_fault(unsigned long address, unsigned long mmcsr,
do_sigbus:
/* Send a sigbus, regardless of whether we were in kernel
or user mode. */
force_sig(SIGBUS, current);
info.si_signo = SIGBUS;
info.si_errno = 0;
info.si_code = BUS_ADRERR;
info.si_addr = (void *) address;
force_sig_info(SIGBUS, &info, current);
if (!user_mode(regs))
goto no_context;
return;
do_sigsegv:
info.si_signo = SIGSEGV;
info.si_errno = 0;
info.si_code = si_code;
info.si_addr = (void *) address;
force_sig_info(SIGSEGV, &info, current);
return;
#ifdef CONFIG_ALPHA_LARGE_VMALLOC
vmalloc_fault:
if (user_mode(regs)) {
force_sig(SIGSEGV, current);
return;
} else {
if (user_mode(regs))
goto do_sigsegv;
else {
/* Synchronize this task's top level page-table
with the "reference" page table from init. */
long offset = __pgd_offset(address);
......
......@@ -109,6 +109,9 @@ struct percpu_struct {
unsigned long ipc_buffer[21];
unsigned long palcode_avail[16];
unsigned long compatibility;
unsigned long console_data_log_pa;
unsigned long console_data_log_length;
unsigned long bcache_info;
};
struct procdesc_struct {
......
#ifndef _ALPHA_SIGINFO_H
#define _ALPHA_SIGINFO_H
#define SI_PAD_SIZE ((SI_MAX_SIZE/sizeof(int)) - 4)
#define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int))
#define __ARCH_SI_TRAPNO
#define SIGEV_PAD_SIZE ((SIGEV_MAX_SIZE/sizeof(int)) - 4)
#define HAVE_ARCH_COPY_SIGINFO
#include <asm-generic/siginfo.h>
#ifdef __KERNEL__
#include <linux/string.h>
extern inline void copy_siginfo(siginfo_t *to, siginfo_t *from)
{
if (from->si_code < 0)
memcpy(to, from, sizeof(siginfo_t));
else
/* _sigchld is currently the largest know union member */
memcpy(to, from, 4*sizeof(int) + sizeof(from->_sifields._sigchld));
}
#endif /* __KERNEL__ */
#endif
......@@ -61,7 +61,8 @@ struct el_common {
int retry : 1; /* retry flag */
unsigned int proc_offset; /* processor-specific offset */
unsigned int sys_offset; /* system-specific offset */
unsigned long code; /* machine check code */
unsigned int code; /* machine check code */
unsigned int frame_rev; /* frame revision */
};
/* Machine Check Frame for uncorrectable errors (Large format)
......@@ -117,11 +118,11 @@ struct el_common_EV6_mcheck {
unsigned long DC0_SYNDROME;
unsigned long C_STAT;
unsigned long C_STS;
unsigned long RESERVED0;
unsigned long MM_STAT;
unsigned long EXC_ADDR;
unsigned long IER_CM;
unsigned long ISUM;
unsigned long MM_STAT;
unsigned long RESERVED0;
unsigned long PAL_BASE;
unsigned long I_CTL;
unsigned long PCTX;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment