X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fppc64%2Fkernel%2Falign.c;h=853b3ae7435c94cd43b99a38b7f1ab91718f11eb;hb=9bf4aaab3e101692164d49b7ca357651eb691cb6;hp=dc455830dd3d3f686127a9a0fca1f7be69a8b825;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/arch/ppc64/kernel/align.c b/arch/ppc64/kernel/align.c index dc455830d..853b3ae74 100644 --- a/arch/ppc64/kernel/align.c +++ b/arch/ppc64/kernel/align.c @@ -22,8 +22,6 @@ #include #include -void disable_kernel_fp(void); /* asm function from head.S */ - struct aligninfo { unsigned char len; unsigned char flags; @@ -215,8 +213,9 @@ fix_alignment(struct pt_regs *regs) unsigned long i; int ret; unsigned dsisr; - unsigned char *addr, *p; - unsigned long *lp; + unsigned char __user *addr; + unsigned char __user *p; + unsigned long __user *lp; union { long ll; double dd; @@ -241,9 +240,9 @@ fix_alignment(struct pt_regs *regs) if (cur_cpu_spec->cpu_features & CPU_FTR_NODSISRALIGN) { unsigned int real_instr; - if (__get_user(real_instr, (unsigned int *)regs->nip)) + if (__get_user(real_instr, (unsigned int __user *)regs->nip)) return 0; - dsisr = make_dsisr(*((unsigned *)regs->nip)); + dsisr = make_dsisr(real_instr); } /* extract the operation and registers from the dsisr */ @@ -257,7 +256,7 @@ fix_alignment(struct pt_regs *regs) flags = aligninfo[instr].flags; /* DAR has the operand effective address */ - addr = (unsigned char *)regs->dar; + addr = (unsigned char __user *)regs->dar; /* A size of 0 indicates an instruction we don't support */ /* we also don't support the multiples (lmw, stmw, lmd, stmd) */ @@ -270,7 +269,7 @@ fix_alignment(struct pt_regs *regs) * storage */ if (instr == DCBZ) - addr = (unsigned char *) ((unsigned long)addr & -L1_CACHE_BYTES); + addr = (unsigned char __user *) ((unsigned long)addr & -L1_CACHE_BYTES); /* Verify the address of the operand */ if (user_mode(regs)) { @@ -279,8 +278,11 @@ fix_alignment(struct pt_regs *regs) } /* Force the fprs into the save area so we can reference them */ - if ((flags & F) && (regs->msr & MSR_FP)) - giveup_fpu(current); + if (flags & F) { + if (!user_mode(regs)) + return 0; + flush_fp_to_thread(current); + } /* If we are loading, get the data from user space */ if (flags & LD) { @@ -309,9 +311,11 @@ fix_alignment(struct pt_regs *regs) if (flags & F) { if (nb == 4) { /* Doing stfs, have to convert to single */ + preempt_disable(); enable_kernel_fp(); cvt_df(¤t->thread.fpr[reg], (float *)&data.v[4], ¤t->thread.fpscr); disable_kernel_fp(); + preempt_enable(); } else data.dd = current->thread.fpr[reg]; @@ -343,9 +347,11 @@ fix_alignment(struct pt_regs *regs) if (flags & F) { if (nb == 4) { /* Doing lfs, have to convert to double */ + preempt_disable(); enable_kernel_fp(); cvt_fd((float *)&data.v[4], ¤t->thread.fpr[reg], ¤t->thread.fpscr); disable_kernel_fp(); + preempt_enable(); } else current->thread.fpr[reg] = data.dd; @@ -360,7 +366,7 @@ fix_alignment(struct pt_regs *regs) p = addr; switch (nb) { case 128: /* Special case - must be dcbz */ - lp = (unsigned long *)p; + lp = (unsigned long __user *)p; for (i = 0; i < L1_CACHE_BYTES / sizeof(long); ++i) ret |= __put_user(0, lp++); break;