Commit 68c1e696 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 0630b89d 31045ad2
...@@ -452,7 +452,8 @@ sys_fork: ...@@ -452,7 +452,8 @@ sys_fork:
bsr $1,do_switch_stack bsr $1,do_switch_stack
bis $31,SIGCHLD,$16 bis $31,SIGCHLD,$16
mov $31,$17 mov $31,$17
mov $30,$18 mov $31,$18
mov $30,$19
jsr $26,alpha_clone jsr $26,alpha_clone
bsr $1,undo_switch_stack bsr $1,undo_switch_stack
ret $31,($26),1 ret $31,($26),1
...@@ -463,8 +464,9 @@ sys_fork: ...@@ -463,8 +464,9 @@ sys_fork:
.ent sys_clone .ent sys_clone
sys_clone: sys_clone:
bsr $1,do_switch_stack bsr $1,do_switch_stack
/* arg1 and arg2 come from the user */ /* $16, $17, $18, $19 come from the user; $19 is used later
mov $30,$18 via pt_regs->r19. */
mov $30,$19
jsr $26,alpha_clone jsr $26,alpha_clone
bsr $1,undo_switch_stack bsr $1,undo_switch_stack
ret $31,($26),1 ret $31,($26),1
......
...@@ -844,7 +844,7 @@ osf_setsysinfo(unsigned long op, void *buffer, unsigned long nbytes, ...@@ -844,7 +844,7 @@ osf_setsysinfo(unsigned long op, void *buffer, unsigned long nbytes,
{ {
switch (op) { switch (op) {
case SSI_IEEE_FP_CONTROL: { case SSI_IEEE_FP_CONTROL: {
unsigned long swcr, fpcr; unsigned long swcr, fpcr, fex;
/* /*
* Alpha Architecture Handbook 4.7.7.3: * Alpha Architecture Handbook 4.7.7.3:
...@@ -867,9 +867,24 @@ osf_setsysinfo(unsigned long op, void *buffer, unsigned long nbytes, ...@@ -867,9 +867,24 @@ osf_setsysinfo(unsigned long op, void *buffer, unsigned long nbytes,
wrfpcr(fpcr); wrfpcr(fpcr);
/* If any exceptions are now unmasked, send a signal. */ /* If any exceptions are now unmasked, send a signal. */
if (((swcr & IEEE_STATUS_MASK) fex = ((swcr & IEEE_STATUS_MASK)
>> IEEE_STATUS_TO_EXCSUM_SHIFT) & swcr) { >> IEEE_STATUS_TO_EXCSUM_SHIFT) & swcr;
send_sig(SIGFPE, current, 1); 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; return 0;
......
...@@ -245,11 +245,10 @@ release_thread(struct task_struct *dead_task) ...@@ -245,11 +245,10 @@ release_thread(struct task_struct *dead_task)
*/ */
int int
alpha_clone(unsigned long clone_flags, unsigned long usp, 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 task_struct *p;
struct pt_regs *u_regs = (struct pt_regs *) (swstack+1); struct pt_regs *u_regs = (struct pt_regs *) (swstack+1);
int *user_tid = (int *)u_regs->r19;
if (!usp) if (!usp)
usp = rdusp(); usp = rdusp();
...@@ -314,6 +313,10 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long usp, ...@@ -314,6 +313,10 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
childti->pcb.ksp = (unsigned long) childstack; childti->pcb.ksp = (unsigned long) childstack;
childti->pcb.flags = 1; /* set FEN, clear everything else */ 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; return 0;
} }
......
...@@ -293,8 +293,16 @@ do_sigreturn(struct sigframe *frame, struct pt_regs *regs, ...@@ -293,8 +293,16 @@ do_sigreturn(struct sigframe *frame, struct pt_regs *regs,
goto give_sigsegv; goto give_sigsegv;
/* Send SIGTRAP if we're single-stepping: */ /* Send SIGTRAP if we're single-stepping: */
if (ptrace_cancel_bpt (current)) if (ptrace_cancel_bpt (current)) {
send_sig(SIGTRAP, current, 1); 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; return;
give_sigsegv: give_sigsegv:
...@@ -330,8 +338,16 @@ do_rt_sigreturn(struct rt_sigframe *frame, struct pt_regs *regs, ...@@ -330,8 +338,16 @@ do_rt_sigreturn(struct rt_sigframe *frame, struct pt_regs *regs,
do_sigaltstack(&st, NULL, rdusp()); do_sigaltstack(&st, NULL, rdusp());
/* Send SIGTRAP if we're single-stepping: */ /* Send SIGTRAP if we're single-stepping: */
if (ptrace_cancel_bpt (current)) if (ptrace_cancel_bpt (current)) {
send_sig(SIGTRAP, current, 1); 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; return;
give_sigsegv: give_sigsegv:
......
...@@ -213,25 +213,25 @@ do_entArith(unsigned long summary, unsigned long write_mask, ...@@ -213,25 +213,25 @@ do_entArith(unsigned long summary, unsigned long write_mask,
unsigned long a2, unsigned long a3, unsigned long a4, unsigned long a2, unsigned long a3, unsigned long a4,
unsigned long a5, struct pt_regs regs) unsigned long a5, struct pt_regs regs)
{ {
long si_code = FPE_FLTINV;
siginfo_t info;
if (summary & 1) { if (summary & 1) {
/* Software-completion summary bit is set, so try to /* Software-completion summary bit is set, so try to
emulate the instruction. */ emulate the instruction. If the processor supports
if (!amask(AMASK_PRECISE_TRAP)) { precise exceptions, we don't have to search. */
/* 21264 (except pass 1) has precise exceptions. */ if (!amask(AMASK_PRECISE_TRAP))
if (alpha_fp_emul(regs.pc - 4)) si_code = alpha_fp_emul(regs.pc - 4);
return; else
} else { si_code = alpha_fp_emul_imprecise(&regs, write_mask);
if (alpha_fp_emul_imprecise(&regs, write_mask))
return;
}
} }
#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); 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 asmlinkage void
...@@ -239,6 +239,9 @@ do_entIF(unsigned long type, unsigned long a1, ...@@ -239,6 +239,9 @@ do_entIF(unsigned long type, unsigned long a1,
unsigned long a2, unsigned long a3, unsigned long a4, unsigned long a2, unsigned long a3, unsigned long a4,
unsigned long a5, struct pt_regs regs) unsigned long a5, struct pt_regs regs)
{ {
siginfo_t info;
int signo, code;
if (!opDEC_testing || type != 4) { if (!opDEC_testing || type != 4) {
if (type == 1) { if (type == 1) {
const unsigned int *data const unsigned int *data
...@@ -253,55 +256,99 @@ do_entIF(unsigned long type, unsigned long a1, ...@@ -253,55 +256,99 @@ do_entIF(unsigned long type, unsigned long a1,
switch (type) { switch (type) {
case 0: /* breakpoint */ 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)) { if (ptrace_cancel_bpt(current)) {
regs.pc -= 4; /* make pc point to former bpt */ regs.pc -= 4; /* make pc point to former bpt */
} }
send_sig(SIGTRAP, current, 1);
send_sig_info(SIGTRAP, &info, current);
return; return;
case 1: /* bugcheck */ 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; return;
case 2: /* gentrap */ case 2: /* gentrap */
/* info.si_addr = (void *) regs.pc;
* The exception code should be passed on to the signal info.si_trapno = regs.r16;
* 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)).
*/
switch ((long) regs.r16) { switch ((long) regs.r16) {
case GEN_INTOVF: case GEN_INTDIV: case GEN_FLTOVF: case GEN_INTOVF:
case GEN_FLTDIV: case GEN_FLTUND: case GEN_FLTINV: signo = SIGFPE;
case GEN_FLTINE: case GEN_ROPRAND: code = FPE_INTOVF;
send_sig(SIGFPE, current, 1); break;
return; case GEN_INTDIV:
signo = SIGFPE;
case GEN_DECOVF: code = FPE_INTDIV;
case GEN_DECDIV: break;
case GEN_DECINV: case GEN_FLTOVF:
case GEN_ASSERTERR: signo = SIGFPE;
case GEN_NULPTRERR: code = FPE_FLTOVF;
case GEN_STKOVF: break;
case GEN_STRLENERR: case GEN_FLTDIV:
case GEN_SUBSTRERR: signo = SIGFPE;
case GEN_RANGERR: code = FPE_FLTDIV;
case GEN_SUBRNG: break;
case GEN_SUBRNG1: case GEN_FLTUND:
case GEN_SUBRNG2: signo = SIGFPE;
case GEN_SUBRNG3: code = FPE_FLTUND;
case GEN_SUBRNG4: break;
case GEN_SUBRNG5: case GEN_FLTINV:
case GEN_SUBRNG6: signo = SIGFPE;
case GEN_SUBRNG7: code = FPE_FLTINV;
send_sig(SIGTRAP, current, 1); break;
return; case GEN_FLTINE:
signo = SIGFPE;
code = FPE_FLTRES;
break;
case GEN_ROPRAND:
signo = SIGFPE;
code = __SI_FAULT;
break;
case GEN_DECOVF:
case GEN_DECDIV:
case GEN_DECINV:
case GEN_ASSERTERR:
case GEN_NULPTRERR:
case GEN_STKOVF:
case GEN_STRLENERR:
case GEN_SUBSTRERR:
case GEN_RANGERR:
case GEN_SUBRNG:
case GEN_SUBRNG1:
case GEN_SUBRNG2:
case GEN_SUBRNG3:
case GEN_SUBRNG4:
case GEN_SUBRNG5:
case GEN_SUBRNG6:
case GEN_SUBRNG7:
default:
signo = SIGTRAP;
code = __SI_FAULT;
break;
} }
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 */ case 4: /* opDEC */
if (implver() == IMPLVER_EV4) { if (implver() == IMPLVER_EV4) {
long si_code;
/* The some versions of SRM do not handle /* The some versions of SRM do not handle
the opDEC properly - they return the PC of the the opDEC properly - they return the PC of the
opDEC fault, not the instruction after as the opDEC fault, not the instruction after as the
...@@ -309,8 +356,7 @@ do_entIF(unsigned long type, unsigned long a1, ...@@ -309,8 +356,7 @@ do_entIF(unsigned long type, unsigned long a1,
We do this by intentionally causing an opDEC We do this by intentionally causing an opDEC
fault during the boot sequence and testing if fault during the boot sequence and testing if
we get the correct PC. If not, we set a flag 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 (opDEC_testing) {
if (regs.pc == opDEC_test_pc) { if (regs.pc == opDEC_test_pc) {
opDEC_fix = 4; opDEC_fix = 4;
...@@ -324,8 +370,17 @@ do_entIF(unsigned long type, unsigned long a1, ...@@ -324,8 +370,17 @@ do_entIF(unsigned long type, unsigned long a1,
/* EV4 does not implement anything except normal /* EV4 does not implement anything except normal
rounding. Everything else will come here as rounding. Everything else will come here as
an illegal instruction. Emulate them. */ 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; 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; break;
...@@ -347,7 +402,12 @@ do_entIF(unsigned long type, unsigned long a1, ...@@ -347,7 +402,12 @@ do_entIF(unsigned long type, unsigned long a1,
default: /* unexpected instruction-fault type */ 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 /* There is an ifdef in the PALcode in MILO that enables a
...@@ -362,8 +422,15 @@ do_entDbg(unsigned long type, unsigned long a1, ...@@ -362,8 +422,15 @@ do_entDbg(unsigned long type, unsigned long a1,
unsigned long a2, unsigned long a3, unsigned long a4, unsigned long a2, unsigned long a3, unsigned long a4,
unsigned long a5, struct pt_regs regs) unsigned long a5, struct pt_regs regs)
{ {
siginfo_t info;
die_if_kernel("Instruction fault", &regs, type, 0); 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, ...@@ -720,6 +787,7 @@ do_entUnaUser(void * va, unsigned long opcode,
unsigned long tmp1, tmp2, tmp3, tmp4; unsigned long tmp1, tmp2, tmp3, tmp4;
unsigned long fake_reg, *reg_addr = &fake_reg; unsigned long fake_reg, *reg_addr = &fake_reg;
siginfo_t info;
long error; long error;
/* Check the UAC bits to decide what the user wants us to do /* Check the UAC bits to decide what the user wants us to do
...@@ -984,12 +1052,34 @@ do_entUnaUser(void * va, unsigned long opcode, ...@@ -984,12 +1052,34 @@ do_entUnaUser(void * va, unsigned long opcode,
give_sigsegv: give_sigsegv:
regs->pc -= 4; /* make pc point to faulting insn */ 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; return;
give_sigbus: give_sigbus:
regs->pc -= 4; 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; return;
} }
......
...@@ -86,11 +86,13 @@ void cleanup_module(void) ...@@ -86,11 +86,13 @@ void cleanup_module(void)
/* /*
* Emulate the floating point instruction at address PC. Returns 0 if * Emulate the floating point instruction at address PC. Returns -1 if the
* emulation fails. Notice that the kernel does not and cannot use FP * instruction to be emulated is illegal (such as with the opDEC trap), else
* regs. This is good because it means that instead of * the SI_CODE for a SIGFPE signal, else 0 if everything's ok.
* saving/restoring all fp regs, we simply stick the result of the *
* operation into the appropriate register. * 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 long
alpha_fp_emul (unsigned long pc) alpha_fp_emul (unsigned long pc)
...@@ -102,6 +104,7 @@ 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 fa, fb, fc, func, mode, src;
unsigned long res, va, vb, vc, swcr, fpcr; unsigned long res, va, vb, vc, swcr, fpcr;
__u32 insn; __u32 insn;
long si_code;
MOD_INC_USE_COUNT; MOD_INC_USE_COUNT;
...@@ -306,10 +309,19 @@ alpha_fp_emul (unsigned long pc) ...@@ -306,10 +309,19 @@ alpha_fp_emul (unsigned long pc)
wrfpcr(fpcr); wrfpcr(fpcr);
/* Do we generate a signal? */ /* Do we generate a signal? */
if (_fex & swcr & IEEE_TRAP_ENABLE_MASK) { _fex = _fex & swcr & IEEE_TRAP_ENABLE_MASK;
MOD_DEC_USE_COUNT; si_code = 0;
return 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 /* We used to write the destination register here, but DEC FORTRAN
...@@ -317,20 +329,20 @@ alpha_fp_emul (unsigned long pc) ...@@ -317,20 +329,20 @@ alpha_fp_emul (unsigned long pc)
immediately after the operations above. */ immediately after the operations above. */
MOD_DEC_USE_COUNT; MOD_DEC_USE_COUNT;
return 1; return 0;
bad_insn: bad_insn:
printk(KERN_ERR "alpha_fp_emul: Invalid FP insn %#x at %#lx\n", printk(KERN_ERR "alpha_fp_emul: Invalid FP insn %#x at %#lx\n",
insn, pc); insn, pc);
MOD_DEC_USE_COUNT; MOD_DEC_USE_COUNT;
return 0; return -1;
} }
long long
alpha_fp_emul_imprecise (struct pt_regs *regs, unsigned long write_mask) alpha_fp_emul_imprecise (struct pt_regs *regs, unsigned long write_mask)
{ {
unsigned long trigger_pc = regs->pc - 4; 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; MOD_INC_USE_COUNT;
...@@ -384,7 +396,7 @@ alpha_fp_emul_imprecise (struct pt_regs *regs, unsigned long write_mask) ...@@ -384,7 +396,7 @@ alpha_fp_emul_imprecise (struct pt_regs *regs, unsigned long write_mask)
if (!write_mask) { if (!write_mask) {
/* Re-execute insns in the trap-shadow. */ /* Re-execute insns in the trap-shadow. */
regs->pc = trigger_pc + 4; regs->pc = trigger_pc + 4;
no_signal = alpha_fp_emul(trigger_pc); si_code = alpha_fp_emul(trigger_pc);
goto egress; goto egress;
} }
trigger_pc -= 4; trigger_pc -= 4;
...@@ -392,5 +404,5 @@ alpha_fp_emul_imprecise (struct pt_regs *regs, unsigned long write_mask) ...@@ -392,5 +404,5 @@ alpha_fp_emul_imprecise (struct pt_regs *regs, unsigned long write_mask)
egress: egress:
MOD_DEC_USE_COUNT; MOD_DEC_USE_COUNT;
return no_signal; return si_code;
} }
...@@ -89,7 +89,8 @@ do_page_fault(unsigned long address, unsigned long mmcsr, ...@@ -89,7 +89,8 @@ do_page_fault(unsigned long address, unsigned long mmcsr,
struct vm_area_struct * vma; struct vm_area_struct * vma;
struct mm_struct *mm = current->mm; struct mm_struct *mm = current->mm;
unsigned int fixup; 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 /* 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 (or is suppressed by the PALcode). Support that for older CPUs
...@@ -129,6 +130,7 @@ do_page_fault(unsigned long address, unsigned long mmcsr, ...@@ -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 /* Ok, we have a good vm_area for this memory access, so
we can handle it. */ we can handle it. */
good_area: good_area:
si_code = SEGV_ACCERR;
if (cause < 0) { if (cause < 0) {
if (!(vma->vm_flags & VM_EXEC)) if (!(vma->vm_flags & VM_EXEC))
goto bad_area; goto bad_area;
...@@ -148,10 +150,20 @@ do_page_fault(unsigned long address, unsigned long mmcsr, ...@@ -148,10 +150,20 @@ do_page_fault(unsigned long address, unsigned long mmcsr,
fault = handle_mm_fault(mm, vma, address, cause > 0); fault = handle_mm_fault(mm, vma, address, cause > 0);
up_read(&mm->mmap_sem); up_read(&mm->mmap_sem);
if (fault < 0) switch (fault) {
goto out_of_memory; case VM_FAULT_MINOR:
if (fault == 0) current->min_flt++;
break;
case VM_FAULT_MAJOR:
current->maj_flt++;
break;
case VM_FAULT_SIGBUS:
goto do_sigbus; goto do_sigbus;
case VM_FAULT_OOM:
goto out_of_memory;
default:
BUG();
}
return; return;
/* Something tried to access memory that isn't in our memory map. /* 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, ...@@ -159,20 +171,14 @@ do_page_fault(unsigned long address, unsigned long mmcsr,
bad_area: bad_area:
up_read(&mm->mmap_sem); up_read(&mm->mmap_sem);
if (user_mode(regs)) { if (user_mode(regs))
force_sig(SIGSEGV, current); goto do_sigsegv;
return;
}
no_context: no_context:
/* Are we prepared to handle this fault as an exception? */ /* Are we prepared to handle this fault as an exception? */
if ((fixup = search_exception_table(regs->pc, regs->gp)) != 0) { if ((fixup = search_exception_table(regs->pc, regs->gp)) != 0) {
unsigned long newpc; unsigned long newpc;
newpc = fixup_exception(dpf_reg, fixup, regs->pc); 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; regs->pc = newpc;
return; return;
} }
...@@ -201,17 +207,28 @@ do_page_fault(unsigned long address, unsigned long mmcsr, ...@@ -201,17 +207,28 @@ do_page_fault(unsigned long address, unsigned long mmcsr,
do_sigbus: do_sigbus:
/* Send a sigbus, regardless of whether we were in kernel /* Send a sigbus, regardless of whether we were in kernel
or user mode. */ 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)) if (!user_mode(regs))
goto no_context; goto no_context;
return; 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 #ifdef CONFIG_ALPHA_LARGE_VMALLOC
vmalloc_fault: vmalloc_fault:
if (user_mode(regs)) { if (user_mode(regs))
force_sig(SIGSEGV, current); goto do_sigsegv;
return; else {
} else {
/* Synchronize this task's top level page-table /* Synchronize this task's top level page-table
with the "reference" page table from init. */ with the "reference" page table from init. */
long offset = __pgd_offset(address); long offset = __pgd_offset(address);
......
#ifndef _ALPHA_SIGINFO_H #ifndef _ALPHA_SIGINFO_H
#define _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 SIGEV_PAD_SIZE ((SIGEV_MAX_SIZE/sizeof(int)) - 4)
#define HAVE_ARCH_COPY_SIGINFO
#include <asm-generic/siginfo.h> #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 #endif
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