Commit 2550d7f1 authored by Paul Mackerras's avatar Paul Mackerras

Merge samba.org:/home/paulus/kernel/linux-2.5

into samba.org:/home/paulus/kernel/for-linus-ppc
parents 7c2dd86b f8c1260f
......@@ -21,11 +21,11 @@ struct aligninfo {
unsigned char flags;
};
#if defined(CONFIG_4xx)
#if defined(CONFIG_4xx) || defined(CONFIG_POWER4)
#define OPCD(inst) (((inst) & 0xFC000000) >> 26)
#define RS(inst) (((inst) & 0x03E00000) >> 21)
#define RA(inst) (((inst) & 0x001F0000) >> 16)
#define IS_DFORM(code) ((code) >= 32 && (code) <= 55)
#define IS_XFORM(code) ((code) == 31)
#endif
#define INVALID { 0, 0 }
......@@ -61,9 +61,9 @@ static struct aligninfo aligninfo[128] = {
{ 4, ST+F+S }, /* 00 0 1010: stfs */
{ 8, ST+F }, /* 00 0 1011: stfd */
INVALID, /* 00 0 1100 */
INVALID, /* 00 0 1101 */
INVALID, /* 00 0 1101: ld/ldu/lwa */
INVALID, /* 00 0 1110 */
INVALID, /* 00 0 1111 */
INVALID, /* 00 0 1111: std/stdu */
{ 4, LD+U }, /* 00 1 0000: lwzu */
INVALID, /* 00 1 0001 */
{ 4, ST+U }, /* 00 1 0010: stwu */
......@@ -80,12 +80,12 @@ static struct aligninfo aligninfo[128] = {
INVALID, /* 00 1 1101 */
INVALID, /* 00 1 1110 */
INVALID, /* 00 1 1111 */
INVALID, /* 01 0 0000 */
INVALID, /* 01 0 0000: ldx */
INVALID, /* 01 0 0001 */
INVALID, /* 01 0 0010 */
INVALID, /* 01 0 0010: stdx */
INVALID, /* 01 0 0011 */
INVALID, /* 01 0 0100 */
INVALID, /* 01 0 0101: lwax?? */
INVALID, /* 01 0 0101: lwax */
INVALID, /* 01 0 0110 */
INVALID, /* 01 0 0111 */
{ 0, LD+HARD }, /* 01 0 1000: lswx */
......@@ -96,12 +96,12 @@ static struct aligninfo aligninfo[128] = {
INVALID, /* 01 0 1101 */
INVALID, /* 01 0 1110 */
INVALID, /* 01 0 1111 */
INVALID, /* 01 1 0000 */
INVALID, /* 01 1 0000: ldux */
INVALID, /* 01 1 0001 */
INVALID, /* 01 1 0010 */
INVALID, /* 01 1 0010: stdux */
INVALID, /* 01 1 0011 */
INVALID, /* 01 1 0100 */
INVALID, /* 01 1 0101: lwaux?? */
INVALID, /* 01 1 0101: lwaux */
INVALID, /* 01 1 0110 */
INVALID, /* 01 1 0111 */
INVALID, /* 01 1 1000 */
......@@ -157,9 +157,9 @@ static struct aligninfo aligninfo[128] = {
{ 4, ST+F+S }, /* 11 0 1010: stfsx */
{ 8, ST+F }, /* 11 0 1011: stfdx */
INVALID, /* 11 0 1100 */
INVALID, /* 11 0 1101 */
INVALID, /* 11 0 1101: lmd */
INVALID, /* 11 0 1110 */
INVALID, /* 11 0 1111 */
INVALID, /* 11 0 1111: stmd */
{ 4, LD+U }, /* 11 1 0000: lwzux */
INVALID, /* 11 1 0001 */
{ 4, ST+U }, /* 11 1 0010: stwux */
......@@ -184,7 +184,7 @@ int
fix_alignment(struct pt_regs *regs)
{
int instr, nb, flags;
#if defined(CONFIG_4xx)
#if defined(CONFIG_4xx) || defined(CONFIG_POWER4)
int opcode, f1, f2, f3;
#endif
int i, t;
......@@ -199,9 +199,11 @@ fix_alignment(struct pt_regs *regs)
CHECK_FULL_REGS(regs);
#if defined(CONFIG_4xx)
#if defined(CONFIG_4xx) || defined(CONFIG_POWER4)
/* The 4xx-family processors have no DSISR register,
* so we emulate it.
* The POWER4 has a DSISR register but doesn't set it on
* an alignment fault. -- paulus
*/
instr = *((unsigned int *)regs->nip);
......@@ -209,7 +211,7 @@ fix_alignment(struct pt_regs *regs)
reg = RS(instr);
areg = RA(instr);
if (IS_DFORM(opcode)) {
if (!IS_XFORM(opcode)) {
f1 = 0;
f2 = (instr & 0x04000000) >> 26;
f3 = (instr & 0x78000000) >> 27;
......
......@@ -52,6 +52,7 @@ main(void)
DEFINE(THREAD_VR0, offsetof(struct thread_struct, vr[0]));
DEFINE(THREAD_VRSAVE, offsetof(struct thread_struct, vrsave));
DEFINE(THREAD_VSCR, offsetof(struct thread_struct, vscr));
DEFINE(THREAD_USED_VR, offsetof(struct thread_struct, used_vr));
#endif /* CONFIG_ALTIVEC */
/* Interrupt register frame */
DEFINE(STACK_FRAME_OVERHEAD, STACK_FRAME_OVERHEAD);
......@@ -101,7 +102,7 @@ main(void)
DEFINE(_XER, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, xer));
DEFINE(_DAR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dar));
DEFINE(_DSISR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dsisr));
/* The PowerPC 400-class processors have neither the DAR nor the DSISR
/* The PowerPC 400-class & Book-E processors have neither the DAR nor the DSISR
* SPRs. Hence, we overload them to hold the similar DEAR and ESR SPRs
* for such processors. For critical interrupts we use them to
* hold SRR0 and SRR1.
......
......@@ -915,7 +915,9 @@ load_up_altivec:
/* enable use of AltiVec after return */
oris r9,r9,MSR_VEC@h
mfspr r5,SPRG3 /* current task's THREAD (phys) */
li r4,1
li r10,THREAD_VSCR
stw r4,THREAD_USED_VR(r5)
lvx vr0,r10,r5
mtvscr vr0
REST_32VR(0,r10,r5)
......
......@@ -1379,7 +1379,7 @@ _GLOBAL(sys_call_table)
.long sys_clock_gettime
.long sys_clock_getres
.long sys_clock_nanosleep
.long sys_ni_syscall /* reserved for swapcontext */
.long sys_swapcontext
.long sys_tgkill /* 250 */
.long sys_utimes
.long sys_statfs64
......
......@@ -415,6 +415,7 @@ void start_thread(struct pt_regs *regs, unsigned long nip, unsigned long sp)
memset(current->thread.vr, 0, sizeof(current->thread.vr));
memset(&current->thread.vscr, 0, sizeof(current->thread.vscr));
current->thread.vrsave = 0;
current->thread.used_vr = 0;
#endif /* CONFIG_ALTIVEC */
}
......
This diff is collapsed.
......@@ -95,14 +95,19 @@ void die(const char * str, struct pt_regs * fp, long err)
}
void
_exception(int signr, struct pt_regs *regs)
_exception(int signr, struct pt_regs *regs, int code, unsigned long addr)
{
if (!user_mode(regs))
{
siginfo_t info;
if (!user_mode(regs)) {
debugger(regs);
die("Exception in kernel mode", regs, signr);
}
force_sig(signr, current);
info.si_signo = signr;
info.si_errno = 0;
info.si_code = code;
info.si_addr = (void *) addr;
force_sig_info(signr, &info, current);
}
/*
......@@ -154,12 +159,40 @@ static inline int check_io_access(struct pt_regs *regs)
return 0;
}
#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
/* On 4xx, the reason for the machine check or program exception
is in the ESR. */
#define get_reason(regs) ((regs)->dsisr)
#define REASON_FP 0
#define REASON_ILLEGAL ESR_PIL
#define REASON_PRIVILEGED ESR_PPR
#define REASON_TRAP ESR_PTR
/* single-step stuff */
#define single_stepping(regs) (current->thread.dbcr0 & DBCR0_IC)
#define clear_single_step(regs) (current->thread.dbcr0 &= ~DBCR0_IC)
#else
/* On non-4xx, the reason for the machine check or program
exception is in the MSR. */
#define get_reason(regs) ((regs)->msr)
#define REASON_FP 0x100000
#define REASON_ILLEGAL 0x80000
#define REASON_PRIVILEGED 0x40000
#define REASON_TRAP 0x20000
#define single_stepping(regs) ((regs)->msr & MSR_SE)
#define clear_single_step(regs) ((regs)->msr &= ~MSR_SE)
#endif
void
MachineCheckException(struct pt_regs *regs)
{
unsigned long reason = get_reason(regs);
if (user_mode(regs)) {
regs->msr |= MSR_RI;
_exception(SIGSEGV, regs);
_exception(SIGBUS, regs, BUS_ADRERR, regs->nip);
return;
}
......@@ -178,10 +211,18 @@ MachineCheckException(struct pt_regs *regs)
if (check_io_access(regs))
return;
#ifndef CONFIG_4xx
printk(KERN_CRIT "Machine check in kernel mode.\n");
printk(KERN_CRIT "Caused by (from SRR1=%lx): ", regs->msr);
switch (regs->msr & 0x601F0000) {
#ifdef CONFIG_4xx
if (reason & ESR_IMCP) {
printk("Instruction");
mtspr(SPRN_ESR, reason & ~ESR_IMCP);
} else
printk("Data");
printk(" machine check in kernel mode.\n");
#else /* !CONFIG_4xx */
printk("Machine check in kernel mode.\n");
printk("Caused by (from SRR1=%lx): ", reason);
switch (reason & 0x601F0000) {
case 0x80000:
printk("Machine check signal\n");
break;
......@@ -208,15 +249,6 @@ MachineCheckException(struct pt_regs *regs)
default:
printk("Unknown values in msr\n");
}
#else /* CONFIG_4xx */
/* Note that the ESR gets stored in regs->dsisr on 4xx. */
if (regs->dsisr & ESR_MCI) {
printk(KERN_CRIT "Instruction");
mtspr(SPRN_ESR, regs->dsisr & ~ESR_MCI);
} else
printk(KERN_CRIT "Data");
printk(" machine check in kernel mode.\n");
#endif /* CONFIG_4xx */
debugger(regs);
......@@ -238,7 +270,7 @@ UnknownException(struct pt_regs *regs)
{
printk("Bad trap at PC: %lx, MSR: %lx, vector=%lx %s\n",
regs->nip, regs->msr, regs->trap, print_tainted());
_exception(SIGTRAP, regs);
_exception(SIGTRAP, regs, 0, 0);
}
void
......@@ -246,13 +278,13 @@ InstructionBreakpoint(struct pt_regs *regs)
{
if (debugger_iabr_match(regs))
return;
_exception(SIGTRAP, regs);
_exception(SIGTRAP, regs, TRAP_BRKPT, 0);
}
void
RunModeException(struct pt_regs *regs)
{
_exception(SIGTRAP, regs);
_exception(SIGTRAP, regs, 0, 0);
}
/* Illegal instruction emulation support. Originally written to
......@@ -271,17 +303,17 @@ RunModeException(struct pt_regs *regs)
static int
emulate_instruction(struct pt_regs *regs)
{
uint instword;
uint rd;
uint retval;
u32 instword;
u32 rd;
int retval;
retval = EINVAL;
retval = -EINVAL;
if (!user_mode(regs))
return retval;
CHECK_FULL_REGS(regs);
if (get_user(instword, (uint __user *)(regs->nip)))
if (get_user(instword, (u32 __user *)(regs->nip)))
return -EFAULT;
/* Emulate the mfspr rD, PVR.
......@@ -290,10 +322,23 @@ emulate_instruction(struct pt_regs *regs)
rd = (instword >> 21) & 0x1f;
regs->gpr[rd] = mfspr(PVR);
retval = 0;
}
if (retval == 0)
regs->nip += 4;
return(retval);
}
return retval;
}
/*
* After we have successfully emulated an instruction, we have to
* check if the instruction was being single-stepped, and if so,
* pretend we got a single-step exception. This was pointed out
* by Kumar Gala. -- paulus
*/
static void emulate_single_step(struct pt_regs *regs)
{
if (single_stepping(regs)) {
clear_single_step(regs);
_exception(SIGTRAP, regs, TRAP_TRACE, 0);
}
}
/*
......@@ -349,29 +394,47 @@ check_bug_trap(struct pt_regs *regs)
void
ProgramCheckException(struct pt_regs *regs)
{
int errcode;
#if defined(CONFIG_4xx)
unsigned int esr = regs->dsisr;
int isbpt = esr & ESR_PTR;
unsigned int reason = get_reason(regs);
extern int do_mathemu(struct pt_regs *regs);
#ifdef CONFIG_MATH_EMULATION
if (!isbpt && do_mathemu(regs) == 0)
/* (reason & REASON_ILLEGAL) would be the obvious thing here,
* but there seems to be a hardware bug on the 405GP (RevD)
* that means ESR is sometimes set incorrectly - either to
* ESR_DST (!?) or 0. In the process of chasing this with the
* hardware people - not sure if it can happen on any illegal
* instruction or only on FP instructions, whether there is a
* pattern to occurences etc. -dgibson 31/Mar/2003 */
if (!(reason & REASON_TRAP) && do_mathemu(regs) == 0) {
emulate_single_step(regs);
return;
}
#endif /* CONFIG_MATH_EMULATION */
#else /* ! CONFIG_4xx */
int isbpt = regs->msr & 0x20000;
if (regs->msr & 0x100000) {
if (reason & REASON_FP) {
/* IEEE FP exception */
_exception(SIGFPE, regs);
int code = 0;
u32 fpscr;
if (regs->msr & MSR_FP)
giveup_fpu(current);
fpscr = current->thread.fpscr;
fpscr &= fpscr << 22; /* mask summary bits with enables */
if (fpscr & FPSCR_VX)
code = FPE_FLTINV;
else if (fpscr & FPSCR_OX)
code = FPE_FLTOVF;
else if (fpscr & FPSCR_UX)
code = FPE_FLTUND;
else if (fpscr & FPSCR_ZX)
code = FPE_FLTDIV;
else if (fpscr & FPSCR_XX)
code = FPE_FLTRES;
_exception(SIGFPE, regs, code, regs->nip);
return;
}
#endif /* ! CONFIG_4xx */
if (isbpt) {
if (reason & REASON_TRAP) {
/* trap exception */
if (debugger_bpt(regs))
return;
......@@ -379,17 +442,21 @@ ProgramCheckException(struct pt_regs *regs)
regs->nip += 4;
return;
}
_exception(SIGTRAP, regs);
_exception(SIGTRAP, regs, TRAP_BRKPT, 0);
return;
}
if (reason & REASON_PRIVILEGED) {
/* Try to emulate it if we should. */
if ((errcode = emulate_instruction(regs))) {
if (errcode == -EFAULT)
_exception(SIGBUS, regs);
else
_exception(SIGILL, regs);
if (emulate_instruction(regs) == 0) {
emulate_single_step(regs);
return;
}
_exception(SIGILL, regs, ILL_PRVOPC, regs->nip);
return;
}
_exception(SIGILL, regs, ILL_ILLOPC, regs->nip);
}
void
......@@ -398,7 +465,7 @@ SingleStepException(struct pt_regs *regs)
regs->msr &= ~MSR_SE; /* Turn off 'trace' bit */
if (debugger_sstep(regs))
return;
_exception(SIGTRAP, regs);
_exception(SIGTRAP, regs, TRAP_TRACE, 0);
}
void
......@@ -414,12 +481,12 @@ AlignmentException(struct pt_regs *regs)
if (fixed == -EFAULT) {
/* fixed == -EFAULT means the operand address was bad */
if (user_mode(regs))
force_sig(SIGSEGV, current);
_exception(SIGSEGV, regs, SEGV_ACCERR, regs->dar);
else
bad_page_fault(regs, regs->dar, SIGSEGV);
return;
}
_exception(SIGBUS, regs);
_exception(SIGBUS, regs, BUS_ADRALN, regs->dar);
}
void
......@@ -470,16 +537,17 @@ SoftwareEmulation(struct pt_regs *regs)
#endif
if (errcode) {
if (errcode > 0)
_exception(SIGFPE, regs);
_exception(SIGFPE, regs, 0, 0);
else if (errcode == -EFAULT)
_exception(SIGSEGV, regs);
_exception(SIGSEGV, regs, 0, 0);
else
_exception(SIGILL, regs);
}
_exception(SIGILL, regs, ILL_ILLOPC, regs->nip);
} else
emulate_single_step(regs);
}
#endif /* CONFIG_8xx */
#if defined(CONFIG_4xx)
#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
void DebugException(struct pt_regs *regs, unsigned long debug_status)
{
......@@ -487,7 +555,7 @@ void DebugException(struct pt_regs *regs, unsigned long debug_status)
if (debug_status & DBSR_TIE) { /* trap instruction*/
if (!user_mode(regs) && debugger_bpt(regs))
return;
_exception(SIGTRAP, regs);
_exception(SIGTRAP, regs, 0, 0);
}
#endif
......@@ -495,10 +563,10 @@ void DebugException(struct pt_regs *regs, unsigned long debug_status)
if (!user_mode(regs) && debugger_sstep(regs))
return;
current->thread.dbcr0 &= ~DBCR0_IC;
_exception(SIGTRAP, regs);
_exception(SIGTRAP, regs, TRAP_TRACE, 0);
}
}
#endif /* CONFIG_4xx */
#endif /* CONFIG_4xx || CONFIG_BOOKE */
#if !defined(CONFIG_TAU_INT)
void
......
......@@ -276,7 +276,7 @@ static __inline__ int fls(unsigned int x)
* Find the first bit set in a 140-bit bitmap.
* The first 100 bits are unlikely to be set.
*/
static inline int sched_find_first_bit(unsigned long *b)
static inline int sched_find_first_bit(const unsigned long *b)
{
if (unlikely(b[0]))
return __ffs(b[0]);
......@@ -295,7 +295,7 @@ static inline int sched_find_first_bit(unsigned long *b)
* @offset: The bitnumber to start searching at
* @size: The maximum size to search
*/
static __inline__ unsigned long find_next_bit(unsigned long *addr,
static __inline__ unsigned long find_next_bit(const unsigned long *addr,
unsigned long size, unsigned long offset)
{
unsigned int *p = ((unsigned int *) addr) + (offset >> 5);
......@@ -352,7 +352,7 @@ static __inline__ unsigned long find_next_bit(unsigned long *addr,
#define find_first_zero_bit(addr, size) \
find_next_zero_bit((addr), (size), 0)
static __inline__ unsigned long find_next_zero_bit(unsigned long * addr,
static __inline__ unsigned long find_next_zero_bit(const unsigned long *addr,
unsigned long size, unsigned long offset)
{
unsigned int * p = ((unsigned int *) addr) + (offset >> 5);
......@@ -411,7 +411,7 @@ static __inline__ int ext2_test_bit(int nr, __const__ void * addr)
#define ext2_find_first_zero_bit(addr, size) \
ext2_find_next_zero_bit((addr), (size), 0)
static __inline__ unsigned long ext2_find_next_zero_bit(void *addr,
static __inline__ unsigned long ext2_find_next_zero_bit(const void *addr,
unsigned long size, unsigned long offset)
{
unsigned int *p = ((unsigned int *) addr) + (offset >> 5);
......
......@@ -26,6 +26,7 @@
#include <linux/interrupt.h>
#include <asm/kmap_types.h>
#include <asm/tlbflush.h>
#include <asm/page.h>
/* undef for production */
#define HIGHMEM_DEBUG 1
......@@ -42,7 +43,7 @@ extern void kmap_init(void) __init;
* chunk of RAM.
*/
#define PKMAP_BASE CONFIG_HIGHMEM_START
#define LAST_PKMAP 1024
#define LAST_PKMAP (1 << PTE_SHIFT)
#define LAST_PKMAP_MASK (LAST_PKMAP-1)
#define PKMAP_NR(virt) ((virt-PKMAP_BASE) >> PAGE_SHIFT)
#define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT))
......
......@@ -848,6 +848,7 @@ struct thread_struct {
/* AltiVec status */
vector128 vscr __attribute((aligned(16)));
unsigned long vrsave;
int used_vr; /* set if process has used altivec */
#endif /* CONFIG_ALTIVEC */
};
......
#ifndef _ASMPPC_UCONTEXT_H
#define _ASMPPC_UCONTEXT_H
/* Copied from i386. */
#include <asm/elf.h>
#include <asm/signal.h>
struct mcontext {
elf_gregset_t mc_gregs;
elf_fpregset_t mc_fregs;
unsigned long mc_pad[2];
elf_vrregset_t mc_vregs __attribute__((__aligned__(16)));
};
struct ucontext {
unsigned long uc_flags;
struct ucontext *uc_link;
stack_t uc_stack;
struct sigcontext uc_mcontext;
sigset_t uc_sigmask; /* mask last for extensibility */
int uc_pad[7];
struct mcontext *uc_regs; /* backward compat */
sigset_t uc_oldsigmask; /* backward compat */
int uc_pad2;
sigset_t uc_sigmask;
/* glibc has 1024-bit signal masks, ours are 64-bit */
int uc_maskext[30];
struct mcontext uc_mcontext;
};
#endif /* !_ASMPPC_UCONTEXT_H */
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