Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 67214
b: refs/heads/master
c: c6d4267
h: refs/heads/master
v: v3
  • Loading branch information
Paul Mackerras committed Aug 17, 2007
1 parent 14e2b4b commit 74b61c5
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 9 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 09a54101e15f43607722dee55f33d1962653c6cb
refs/heads/master: c6d4267eced79775399f256fbb4adb671e9b597e
57 changes: 49 additions & 8 deletions trunk/arch/powerpc/kernel/align.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ struct aligninfo {
/* Bits in the flags field */
#define LD 0 /* load */
#define ST 1 /* store */
#define SE 2 /* sign-extend value */
#define SE 2 /* sign-extend value, or FP ld/st as word */
#define F 4 /* to/from fp regs */
#define U 8 /* update index register */
#define M 0x10 /* multiple load/store */
Expand Down Expand Up @@ -87,9 +87,9 @@ static struct aligninfo aligninfo[128] = {
{ 8, LD+F+U }, /* 00 1 1001: lfdu */
{ 4, ST+F+S+U }, /* 00 1 1010: stfsu */
{ 8, ST+F+U }, /* 00 1 1011: stfdu */
INVALID, /* 00 1 1100 */
{ 16, LD+F }, /* 00 1 1100: lfdp */
INVALID, /* 00 1 1101 */
INVALID, /* 00 1 1110 */
{ 16, ST+F }, /* 00 1 1110: stfdp */
INVALID, /* 00 1 1111 */
{ 8, LD }, /* 01 0 0000: ldx */
INVALID, /* 01 0 0001 */
Expand Down Expand Up @@ -167,10 +167,10 @@ static struct aligninfo aligninfo[128] = {
{ 8, LD+F }, /* 11 0 1001: lfdx */
{ 4, ST+F+S }, /* 11 0 1010: stfsx */
{ 8, ST+F }, /* 11 0 1011: stfdx */
INVALID, /* 11 0 1100 */
{ 8, LD+M }, /* 11 0 1101: lmd */
INVALID, /* 11 0 1110 */
{ 8, ST+M }, /* 11 0 1111: stmd */
{ 16, LD+F }, /* 11 0 1100: lfdpx */
{ 4, LD+F+SE }, /* 11 0 1101: lfiwax */
{ 16, ST+F }, /* 11 0 1110: stfdpx */
{ 4, ST+F }, /* 11 0 1111: stfiwx */
{ 4, LD+U }, /* 11 1 0000: lwzux */
INVALID, /* 11 1 0001 */
{ 4, ST+U }, /* 11 1 0010: stwux */
Expand Down Expand Up @@ -356,6 +356,42 @@ static int emulate_multiple(struct pt_regs *regs, unsigned char __user *addr,
return 1;
}

/*
* Emulate floating-point pair loads and stores.
* Only POWER6 has these instructions, and it does true little-endian,
* so we don't need the address swizzling.
*/
static int emulate_fp_pair(struct pt_regs *regs, unsigned char __user *addr,
unsigned int reg, unsigned int flags)
{
char *ptr = (char *) &current->thread.fpr[reg];
int i, ret;

if (!(flags & F))
return 0;
if (reg & 1)
return 0; /* invalid form: FRS/FRT must be even */
if (!(flags & SW)) {
/* not byte-swapped - easy */
if (!(flags & ST))
ret = __copy_from_user(ptr, addr, 16);
else
ret = __copy_to_user(addr, ptr, 16);
} else {
/* each FPR value is byte-swapped separately */
ret = 0;
for (i = 0; i < 16; ++i) {
if (!(flags & ST))
ret |= __get_user(ptr[i^7], addr + i);
else
ret |= __put_user(ptr[i^7], addr + i);
}
}
if (ret)
return -EFAULT;
return 1; /* exception handled and fixed up */
}


/*
* Called on alignment exception. Attempts to fixup
Expand Down Expand Up @@ -471,6 +507,10 @@ int fix_alignment(struct pt_regs *regs)
flush_fp_to_thread(current);
}

/* Special case for 16-byte FP loads and stores */
if (nb == 16)
return emulate_fp_pair(regs, addr, reg, flags);

/* If we are loading, get the data from user space, else
* get it from register values
*/
Expand Down Expand Up @@ -531,7 +571,8 @@ int fix_alignment(struct pt_regs *regs)
* or floating point single precision conversion
*/
switch (flags & ~(U|SW)) {
case LD+SE: /* sign extend */
case LD+SE: /* sign extending integer loads */
case LD+F+SE: /* sign extend for lfiwax */
if ( nb == 2 )
data.ll = data.x16.low16;
else /* nb must be 4 */
Expand Down

0 comments on commit 74b61c5

Please sign in to comment.