Source to osfmk/ppc/alignment.c
/*
* Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* The contents of this file constitute Original Code as defined in and
* are subject to the Apple Public Source License Version 1.1 (the
* "License"). You may not use this file except in compliance with the
* License. Please obtain a copy of the License at
* http://www.apple.com/publicsource and read it before using this file.
*
* This Original Code and all software distributed under the License are
* distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
* License for the specific language governing rights and limitations
* under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*
* Copyright 1996 1995 by Open Software Foundation, Inc. 1997 1996 1995 1994 1993 1992 1991
* All Rights Reserved
*
* Permission to use, copy, modify, and distribute this software and
* its documentation for any purpose and without fee is hereby granted,
* provided that the above copyright notice appears in all copies and
* that both the copyright notice and this permission notice appear in
* supporting documentation.
*
* OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE.
*
* IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
* NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
/*
* Copyright 1996 1995 by Apple Computer, Inc. 1997 1996 1995 1994 1993 1992 1991
* All Rights Reserved
*
* Permission to use, copy, modify, and distribute this software and
* its documentation for any purpose and without fee is hereby granted,
* provided that the above copyright notice appears in all copies and
* that both the copyright notice and this permission notice appear in
* supporting documentation.
*
* APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE.
*
* IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
* NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <debug.h>
#include <kern/thread_act.h>
#include <mach/thread_status.h>
#include <mach/boolean.h>
#include <kern/misc_protos.h>
#include <kern/simple_lock.h>
#include <ppc/proc_reg.h>
#include <ppc/fpu_protos.h>
#include <ppc/misc_protos.h>
#include <ppc/exception.h>
#if DEBUG
/* These variable may be used to keep track of alignment exceptions */
int alignment_exception_count_user;
int alignment_exception_count_kernel;
#endif
#define _AINST(x) boolean_t align_##x##(unsigned long dsisr,\
struct ppc_saved_state *ssp, \
struct ppc_float_state *fsp, \
unsigned long *align_buffer, \
unsigned long dar)
#define _AFENTRY(name, r, b) { #name, align_##name##, r, b, TRUE }
#define _AENTRY(name, r, b) { #name, align_##name##, r, b, FALSE }
#define _ANIL { (void *) 0, (void *) 0, 0, 0 }
_AINST(lwz);
_AINST(stw);
_AINST(lhz);
_AINST(lha);
_AINST(sth);
_AINST(lmw);
_AINST(lfs);
_AINST(lfd);
_AINST(stfs);
_AINST(stfd);
_AINST(lwzu);
_AINST(stwu);
_AINST(lhzu);
_AINST(lhau);
_AINST(sthu);
_AINST(lfsu);
_AINST(lfdu);
_AINST(stfsu);
_AINST(stfdu);
_AINST(lswx);
_AINST(lswi);
_AINST(lwbrx);
_AINST(stwbrx);
_AINST(lhbrx);
_AINST(sthbrx);
_AINST(dcbz);
_AINST(lwzx);
_AINST(stwx);
_AINST(lhzx);
_AINST(lhax);
_AINST(sthx);
_AINST(lfsx);
_AINST(lfdx);
_AINST(stfsx);
_AINST(stfdx);
_AINST(lwzux);
_AINST(stwux);
_AINST(lhzux);
_AINST(lhaux);
_AINST(sthux);
_AINST(stmw);
_AINST(lfsux);
_AINST(lfdux);
_AINST(stfsux);
_AINST(stfdux);
/*
* Routines to set and get FPU registers.
*/
void GET_FPU_REG(struct ppc_float_state *fsp,
unsigned long reg,
unsigned long *value);
void SET_FPU_REG(struct ppc_float_state *fsp,
unsigned long reg,
unsigned long *value);
__inline__ void GET_FPU_REG(struct ppc_float_state *fsp,
unsigned long reg,
unsigned long *value)
{
value[0] = ((unsigned long *) &fsp->fpregs[reg])[0];
value[1] = ((unsigned long *) &fsp->fpregs[reg])[1];
}
__inline__ void SET_FPU_REG(struct ppc_float_state *fsp,
unsigned long reg, unsigned long *value)
{
((unsigned long *) &fsp->fpregs[reg])[0] = value[0];
((unsigned long *) &fsp->fpregs[reg])[1] = value[1];
}
/*
* Macros to load and set registers according to
* a given cast type.
*/
#define GET_REG(p, reg, value, cast) \
{ *((cast *) value) = *((cast *) (&p->r0+reg)); }
#define SET_REG(p, reg, value, cast) \
{ *((cast *) (&p->r0+reg)) = *((cast *) value); }
/*
* Macros to help decode the DSISR.
*/
#define DSISR_BITS_15_16(bits) ((bits>>15) & 0x3)
#define DSISR_BITS_17_21(bits) ((bits>>10) & 0x1f)
#define DSISR_BITS_REG(bits) ((bits>>5) & 0x1f)
#define DSISR_BITS_RA(bits) (bits & 0x1f)
struct ppc_align_instruction {
char *name;
boolean_t (*a_instruct)(unsigned long,
struct ppc_saved_state *,
struct ppc_float_state *,
unsigned long *,
unsigned long );
int a_readbytes;
int a_writebytes;
boolean_t a_is_float;
} align_table00[] = {
_AENTRY(lwz, 4, 0), /* 00 0 0000 */
_ANIL, /* 00 0 0001 */
_AENTRY(stw, 0, 4), /* 00 0 0010 */
_ANIL, /* 00 0 0011 */
_AENTRY(lhz, 2, 0), /* 00 0 0100 */
_AENTRY(lha, 2, 0), /* 00 0 0101 */
_AENTRY(sth, 0, 2), /* 00 0 0110 */
_AENTRY(lmw, 32*4,0), /* 00 0 0111 */
_AFENTRY(lfs, 4, 0), /* 00 0 1000 */
_AFENTRY(lfd, 8, 0), /* 00 0 1001 */
_AFENTRY(stfs, 0, 4), /* 00 0 1010 */
_AFENTRY(stfd, 0, 8), /* 00 0 1011 */
_ANIL, /* 00 0 1100 ?*/
_ANIL, /* 00 0 1101 - lwa */
_ANIL, /* 00 0 1110 ?*/
_ANIL, /* 00 0 1111 - std */
_AENTRY(lwzu, 4, 0), /* 00 1 0000 */
_ANIL, /* 00 1 0001 ?*/
_AENTRY(stwu, 0, 4), /* 00 1 0010 */
_ANIL, /* 00 1 0011 */
_AENTRY(lhzu, 2, 0), /* 00 1 0100 */
_AENTRY(lhau, 2, 0), /* 00 1 0101 */
_AENTRY(sthu, 0, 2), /* 00 1 0110 */
_AENTRY(stmw, 0, 0), /* 00 1 0111 */
_AFENTRY(lfsu, 4, 0), /* 00 1 1000 */
_AFENTRY(lfdu, 8, 0), /* 00 1 1001 - lfdu */
_AFENTRY(stfsu, 0, 4), /* 00 1 1010 */
_AFENTRY(stfdu, 0, 8), /* 00 1 1011 - stfdu */
};
struct ppc_align_instruction align_table01[] = {
_ANIL, /* 01 0 0000 - ldx */
_ANIL, /* 01 0 0001 ?*/
_ANIL, /* 01 0 0010 - stdx */
_ANIL, /* 01 0 0011 ?*/
_ANIL, /* 01 0 0100 ?*/
_ANIL, /* 01 0 0101 - lwax */
_ANIL, /* 01 0 0110 ?*/
_ANIL, /* 01 0 0111 ?*/
_AENTRY(lswx,32, 0), /* 01 0 1000 - lswx */
_AENTRY(lswi,32, 0), /* 01 0 1001 - lswi */
_ANIL, /* 01 0 1010 - stswx */
_ANIL, /* 01 0 1011 - stswi */
_ANIL, /* 01 0 1100 ?*/
_ANIL, /* 01 0 1101 ?*/
_ANIL, /* 01 0 1110 ?*/
_ANIL, /* 01 0 1111 ?*/
_ANIL, /* 01 1 0000 - ldux */
_ANIL, /* 01 1 0001 ?*/
_ANIL, /* 01 1 0010 - stdux */
_ANIL, /* 01 1 0011 ?*/
_ANIL, /* 01 1 0100 ?*/
_ANIL, /* 01 1 0101 - lwaux */
};
struct ppc_align_instruction align_table10[] = {
_ANIL, /* 10 0 0000 ?*/
_ANIL, /* 10 0 0001 ?*/
_ANIL, /* 10 0 0010 - stwcx. */
_ANIL, /* 10 0 0011 - stdcx.*/
_ANIL, /* 10 0 0100 ?*/
_ANIL, /* 10 0 0101 ?*/
_ANIL, /* 10 0 0110 ?*/
_ANIL, /* 10 0 0111 ?*/
_AENTRY(lwbrx, 2, 0), /* 10 0 1000 */
_ANIL, /* 10 0 1001 ?*/
_AENTRY(stwbrx, 0, 4), /* 10 0 1010 */
_ANIL, /* 10 0 1011 */
_AENTRY(lhbrx, 2, 0), /* 10 0 1110 */
_ANIL, /* 10 0 1101 ?*/
_AENTRY(sthbrx, 0, 2), /* 10 0 1110 */
_ANIL, /* 10 0 1111 ?*/
_ANIL, /* 10 1 0000 ?*/
_ANIL, /* 10 1 0001 ?*/
_ANIL, /* 10 1 0010 ?*/
_ANIL, /* 10 1 0011 ?*/
_ANIL, /* 10 1 0100 - eciwx */
_ANIL, /* 10 1 0101 ?*/
_ANIL, /* 10 1 0110 - ecowx */
_ANIL, /* 10 1 0111 ?*/
_ANIL, /* 10 1 1000 ?*/
_ANIL, /* 10 1 1001 ?*/
_ANIL, /* 10 1 1010 ?*/
_ANIL, /* 10 1 1011 ?*/
_ANIL, /* 10 1 1100 ?*/
_ANIL, /* 10 1 1101 ?*/
_ANIL, /* 10 1 1110 ?*/
_AENTRY(dcbz, 0, 0), /* 10 1 1111 */
};
struct ppc_align_instruction align_table11[] = {
_AENTRY(lwzx, 4, 0), /* 11 0 0000 */
_ANIL, /* 11 0 0001 ?*/
_AENTRY(stwx, 0, 4), /* 11 0 0010 */
_ANIL, /* 11 0 0011 */
_AENTRY(lhzx, 2, 0), /* 11 0 0100 */
_AENTRY(lhax, 2, 0), /* 11 0 0101 */
_AENTRY(sthx, 0, 2), /* 11 0 0110 */
_ANIL, /* 11 0 0111?*/
_AFENTRY(lfsx, 4, 0), /* 11 0 1000 */
_AFENTRY(lfdx, 8, 0), /* 11 0 1001 */
_AFENTRY(stfsx, 0, 4), /* 11 0 1010 */
_AFENTRY(stfdx, 0, 8), /* 11 0 1011 */
_ANIL, /* 11 0 1100 ?*/
_ANIL, /* 11 0 1101 ?*/
_ANIL, /* 11 0 1110 ?*/
_ANIL, /* 11 0 1111 - stfiwx */
_AENTRY(lwzux, 4, 0), /* 11 1 0000 */
_ANIL, /* 11 1 0001 ?*/
_AENTRY(stwux, 0, 4), /* 11 1 0010 */
_ANIL, /* 11 1 0011 */
_AENTRY(lhzux, 4, 0), /* 11 1 0100 */
_AENTRY(lhaux, 4, 0), /* 11 1 0101 */
_AENTRY(sthux, 0, 4), /* 11 1 0110 */
_ANIL, /* 11 1 0111 ?*/
_AFENTRY(lfsux, 4, 0), /* 11 1 1000 */
_AFENTRY(lfdux, 0, 8), /* 11 1 1001 */
_AFENTRY(stfsux, 0, 4), /* 11 1 1010 */
_AFENTRY(stfdux, 0, 8), /* 11 1 1011 */
};
struct ppc_align_instruction_table {
struct ppc_align_instruction *table;
int size;
} align_tables[4] = {
align_table00, sizeof(align_table00)/
sizeof(struct ppc_align_instruction),
align_table01, sizeof(align_table01)/
sizeof(struct ppc_align_instruction),
align_table10, sizeof(align_table10)/
sizeof(struct ppc_align_instruction),
align_table11, sizeof(align_table11)/
sizeof(struct ppc_align_instruction)
};
extern int real_ncpus; /* Number of actual CPUs */
/*
* Alignment Exception Handler
*
*
* This handler is called when the chip attempts
* to execute an instruction which causes page
* boundaries to be crossed. Typically, this will
* happen on stfd* and lfd* instructions.
* (A request has been made for GNU C compiler
* NOT to make use of these instructions to
* load and store 8 bytes at a time.)
*
* This is a *SLOW* handler. There is room for vast
* improvement. However, it is expected that alignment
* exceptions will be very infrequent.
*
* Not all of the 64 instructions (as listed in
* PowerPC Microprocessor Family book under the Alignment
* Exception section) are handled yet.
* Only the most common ones which are expected to
* happen.
*
* -- Michael Burg, Apple Computer, Inc. 1996
*
* TODO NMGS finish handler
*/
boolean_t
alignment(unsigned long dsisr, unsigned long dar,
struct ppc_saved_state *ssp)
{
struct ppc_align_instruction_table *table;
struct ppc_align_instruction *entry;
struct ppc_float_state *fpc;
unsigned long align_buffer[32];
boolean_t success = FALSE;
thread_act_t act;
spl_t s;
int i;
#if DEBUG
if (USER_MODE(ssp->srr1)) (void)hw_atomic_add(&alignment_exception_count_user, 1);
else (void)hw_atomic_add(&alignment_exception_count_kernel, 1);
#endif
table = &align_tables[DSISR_BITS_15_16(dsisr)];
if (table == (void *) 0
|| table->size < DSISR_BITS_17_21(dsisr)) {
#if DEBUG
printf("EXCEPTION NOT HANDLED: Out of range.\n");
printf("dsisr=%X, dar=%X\n",dsisr, dar);
printf("table=%X\n",DSISR_BITS_15_16(dsisr));
printf("table->size=%X\n", table->size);
printf("entry=%X\n",DSISR_BITS_17_21(dsisr));
#endif
goto out;
}
entry = &table->table[DSISR_BITS_17_21(dsisr)];
if (entry->a_instruct == (void *) 0) {
#if DEBUG
printf("EXCEPTION NOT HANDLED: Inst out of table range.\n");
printf("table=%X\n",DSISR_BITS_15_16(dsisr));
printf("entry=%X\n",DSISR_BITS_17_21(dsisr));
#endif
goto out;
}
/*
* Check to see if the instruction is a
* floating point operation. Save off
* the FPU register set ...
*/
if (entry->a_is_float)
fpu_save();
/*
* Pull in any bytes which are going to be
* read.
*/
if (entry->a_readbytes) {
if (USER_MODE(ssp->srr1)) {
if (copyin((char *) dar,
(char *) align_buffer,
entry->a_readbytes)) {
return TRUE;
}
} else {
bcopy((char *) dar,
(char *) align_buffer,
entry->a_readbytes);
}
}
#if 0 && DEBUG
printf("Alignment exception: %s %d,0x%x (r%d/w%d) (tmp %x/%x)\n",
entry->name, DSISR_BITS_REG(dsisr),
dar, entry->a_readbytes, entry->a_writebytes,
align_buffer[0], align_buffer[1]);
printf(" pc=(0x%08X), msr=(0x%X)",ssp->srr0, ssp->srr1);
#endif
act = current_act(); /* Get the current activation */
success = entry->a_instruct(dsisr,
ssp,
find_user_fpu(act), /* Find this user's FPU state. NULL if none */
/* NULL should never happen */
align_buffer,
dar);
if (success) {
if (entry->a_writebytes) {
if (USER_MODE(ssp->srr1)) {
if (copyout((char *) align_buffer,
(char *) dar,
entry->a_writebytes)) {
return TRUE;
}
} else {
bcopy((char *) align_buffer,
(char *) dar,
entry->a_writebytes);
}
}
else {
for(i=0; i < real_ncpus; i++) { /* Cycle through processors */
(void)hw_compare_and_store((unsigned int)act, 0, &per_proc_info[i].FPU_thread); /* Clear if ours */
}
if (USER_MODE(ssp->srr1)) {
if (copyout((char *) align_buffer,
(char *) dar,
entry->a_writebytes)) {
return TRUE;
}
} else {
bcopy((char *) align_buffer,
(char *) dar,
entry->a_writebytes);
}
}
ssp->srr0 += 4; /* Skip the instruction .. */
}
return !success;
out:
#if 0 && DEBUG
printf("ALIGNMENT EXCEPTION: (dsisr 0x%x) table %d 0x%x\n",
dsisr, DSISR_BITS_15_16(dsisr), DSISR_BITS_17_21(dsisr));
#endif
return TRUE;
}
_AINST(lwz)
{
SET_REG(ssp, DSISR_BITS_REG(dsisr), align_buffer, unsigned long);
return TRUE;
}
_AINST(stw)
{
GET_REG(ssp, DSISR_BITS_REG(dsisr), align_buffer, unsigned long);
return TRUE;
}
_AINST(lhz)
{
unsigned long value = *((unsigned short *) align_buffer);
SET_REG(ssp, DSISR_BITS_REG(dsisr), &value, unsigned long);
return TRUE;
}
_AINST(lha)
{
long value = *((short *) align_buffer);
SET_REG(ssp, DSISR_BITS_REG(dsisr), &value, unsigned long);
return TRUE;
}
_AINST(sth)
{
GET_REG(ssp, DSISR_BITS_REG(dsisr), align_buffer, unsigned short);
return TRUE;
}
_AINST(lmw)
{
int i;
for (i = 0; i < (32-DSISR_BITS_REG(dsisr)); i++)
{
SET_REG(ssp, DSISR_BITS_REG(dsisr)+i, &align_buffer[i], unsigned long);
}
return TRUE;
}
struct fpsp {
unsigned long s :1; /* Sign bit */
unsigned long exp :8; /* exponent + bias */
unsigned long fraction:23; /* fraction */
};
typedef struct fpsp fpsp_t, *fpspPtr;
struct fpdp {
unsigned long s :1; /* Sign bit */
unsigned long exp :11; /* exponent + bias */
unsigned long fraction:20; /* fraction */
unsigned long fraction1; /* fraction */
};
typedef struct fpdp fpdp_t, *fpdpPtr;
_AINST(lfs)
{
unsigned long lalign_buf[2];
lfs (align_buffer, lalign_buf);
SET_FPU_REG(fsp, DSISR_BITS_REG(dsisr), lalign_buf);
return TRUE;
}
_AINST(lfd)
{
SET_FPU_REG(fsp, DSISR_BITS_REG(dsisr), align_buffer);
return TRUE;
}
_AINST(stfs)
{
unsigned long lalign_buf[2];
GET_FPU_REG(fsp, DSISR_BITS_REG(dsisr), lalign_buf);
stfs(lalign_buf, align_buffer);
return TRUE;
}
_AINST(stfd)
{
GET_FPU_REG(fsp, DSISR_BITS_REG(dsisr), align_buffer);
return TRUE;
}
_AINST(lwzu)
{
SET_REG(ssp, DSISR_BITS_REG(dsisr), align_buffer, unsigned long)
SET_REG(ssp, DSISR_BITS_RA(dsisr), &dar, unsigned long);
return TRUE;
}
_AINST(stwu)
{
GET_REG(ssp, DSISR_BITS_REG(dsisr), align_buffer, unsigned long)
SET_REG(ssp, DSISR_BITS_RA(dsisr), &dar, unsigned long);
return TRUE;
}
_AINST(lhzu)
{
SET_REG(ssp, DSISR_BITS_REG(dsisr), align_buffer, unsigned short)
SET_REG(ssp, DSISR_BITS_RA(dsisr), &dar, unsigned long);
return TRUE;
}
_AINST(lhau)
{
unsigned long value = *((short *) align_buffer);
SET_REG(ssp, DSISR_BITS_REG(dsisr), &value, unsigned long);
SET_REG(ssp, DSISR_BITS_RA(dsisr), &dar, unsigned long);
return TRUE;
}
_AINST(sthu)
{
GET_REG(ssp, DSISR_BITS_REG(dsisr), align_buffer, unsigned short)
SET_REG(ssp, DSISR_BITS_RA(dsisr), &dar, unsigned long);
return TRUE;
}
_AINST(stmw)
{
int i, rS = DSISR_BITS_REG(dsisr);
int numRegs = 32 - rS;
int numBytes = numRegs * 4;
int retval;
for (i = 0; i < numRegs; i++)
{
#if 0
printf(" align_buffer[%d] == 0x%x\n",i,align_buffer[i]);
#endif
GET_REG(ssp, rS+i, &align_buffer[i], unsigned long);
#if 0
printf(" now align_buffer[%d] == 0x%x\n",i,align_buffer[i]);
#endif
}
if (USER_MODE(ssp->srr1)) {
if ((retval=copyout((char *)align_buffer,(char *)dar,numBytes)) != 0) {
return FALSE;
}
#if 0
printf(" copyout(%X, %X, %X) succeeded\n",align_buffer,dar,numBytes);
#endif
}
else {
bcopy((char *) align_buffer, (char *) dar, numBytes);
}
return TRUE;
}
_AINST(lfsu)
{
unsigned long lalign_buf[2];
lfs (align_buffer, lalign_buf);
SET_FPU_REG(fsp, DSISR_BITS_REG(dsisr), lalign_buf);
SET_REG(ssp, DSISR_BITS_RA(dsisr), &dar, unsigned long);
return TRUE;
}
_AINST(lfdu)
{
SET_FPU_REG(fsp, DSISR_BITS_REG(dsisr), align_buffer);
SET_REG(ssp, DSISR_BITS_RA(dsisr), &dar, unsigned long);
return TRUE;
}
_AINST(stfsu)
{
unsigned long lalign_buf[2];
GET_FPU_REG(fsp, DSISR_BITS_REG(dsisr), lalign_buf);
stfs(lalign_buf, align_buffer);
SET_REG(ssp, DSISR_BITS_RA(dsisr), &dar, unsigned long);
return TRUE;
}
_AINST(stfdu)
{
GET_FPU_REG(fsp, DSISR_BITS_REG(dsisr), align_buffer);
SET_REG(ssp, DSISR_BITS_RA(dsisr), &dar, unsigned long);
return TRUE;
}
_AINST(lswx)
{
int i, nb, nr, inst, zero = 0;
/* check for invalid form of instruction */
if (DSISR_BITS_RA(dsisr) >= DSISR_BITS_REG(dsisr) )
return FALSE;
if (USER_MODE(ssp->srr1)) {
if (copyin((char *) ssp->srr0, (char *) &inst, 4 )) {
return FALSE;
}
} else {
bcopy((char *) ssp->srr0, (char *) &inst, 4 );
}
nb = (inst >> 11) & 0x1F; /* get the number of bytes in the instr */
nr = (nb + sizeof(long)-1) / sizeof(long);/* get the number of regs to copy */
if ((nr + DSISR_BITS_REG(dsisr)) > 31)
return FALSE; /* not supported yet */
for (i = 0; i < nr; i++)
{
SET_REG(ssp, DSISR_BITS_REG(dsisr)+i, &zero, unsigned long);
}
/* copy the string into the save state */
bcopy((char *) align_buffer, (char *) ssp->r0+DSISR_BITS_REG(dsisr), nb );
return TRUE;
}
_AINST(lswi)
{
int i, nb, nr, inst, zero = 0;
/* check for invalid form of instruction */
if (DSISR_BITS_RA(dsisr) >= DSISR_BITS_REG(dsisr) )
return FALSE;
if (USER_MODE(ssp->srr1)) {
if (copyin((char *) ssp->srr0, (char *) &inst, 4 )) {
return FALSE;
}
} else {
bcopy((char *) ssp->srr0, (char *) &inst, 4 );
}
nb = (inst >> 11) & 0x1F; /* get the number of bytes in the instr */
nr = (nb + sizeof(long)-1) / sizeof(long);/* get the number of regs to copy */
if ((nr + DSISR_BITS_REG(dsisr)) > 31)
return FALSE; /* not supported yet */
for (i = 0; i < nr; i++)
{
SET_REG(ssp, DSISR_BITS_REG(dsisr)+i, &zero, unsigned long);
}
/* copy the string into the save state */
bcopy((char *) align_buffer, (char *) ssp->r0+DSISR_BITS_REG(dsisr), nb );
return TRUE;
}
_AINST(stswx)
{
return FALSE;
}
_AINST(stswi)
{
return FALSE;
}
_AINST(stwcx)
{
return FALSE;
}
_AINST(stdcx)
{
return FALSE;
}
_AINST(lwbrx)
{
unsigned long new_value;
__asm__ volatile("lwbrx %0,0,%1" : : "b" (new_value),
"b" (&align_buffer[0]));
SET_REG(ssp, DSISR_BITS_REG(dsisr), &new_value, unsigned long);
return TRUE;
}
_AINST(stwbrx)
{
unsigned long value;
GET_REG(ssp, DSISR_BITS_REG(dsisr), &value, unsigned long);
__asm__ volatile("stwbrx %0,0,%1" : : "b" (value), "b" (&align_buffer[0]));
return TRUE;
}
_AINST(lhbrx)
{
unsigned short value;
__asm__ volatile("lhbrx %0,0,%1" : : "b" (value), "b" (&align_buffer[0]));
SET_REG(ssp, DSISR_BITS_REG(dsisr), &value, unsigned short);
return TRUE;
}
_AINST(sthbrx)
{
unsigned short value;
GET_REG(ssp, DSISR_BITS_REG(dsisr), &value, unsigned short);
__asm__ volatile("sthbrx %0,0,%1" : : "b" (value), "b" (&align_buffer[0]));
return TRUE;
}
_AINST(eciwx)
{
return FALSE;
}
_AINST(ecowx)
{
return FALSE;
}
_AINST(dcbz)
{
long *alignedDAR = (long *)((long)dar & ~(CACHE_LINE_SIZE-1));
if (USER_MODE(ssp->srr1)) {
align_buffer[0] = 0;
align_buffer[1] = 0;
align_buffer[2] = 0;
align_buffer[3] = 0;
align_buffer[4] = 0;
align_buffer[5] = 0;
align_buffer[6] = 0;
align_buffer[7] = 0;
if (copyout((char *)align_buffer,(char *)alignedDAR,CACHE_LINE_SIZE) != 0)
return FALSE;
} else {
/* Cannot use bcopy here just in case it caused the exception */
alignedDAR[0] = 0;
alignedDAR[1] = 0;
alignedDAR[2] = 0;
alignedDAR[3] = 0;
alignedDAR[4] = 0;
alignedDAR[5] = 0;
alignedDAR[6] = 0;
alignedDAR[7] = 0;
}
return TRUE;
}
_AINST(lwzx)
{
SET_REG(ssp, DSISR_BITS_REG(dsisr), &align_buffer[0], unsigned long);
return TRUE;
}
_AINST(stwx)
{
GET_REG(ssp, DSISR_BITS_REG(dsisr), &align_buffer[0], unsigned long);
return TRUE;
}
_AINST(lhzx)
{
SET_REG(ssp, DSISR_BITS_REG(dsisr), &align_buffer[0], unsigned short);
return TRUE;
}
_AINST(lhax)
{
unsigned long value = *((short *) &align_buffer[0]);
SET_REG(ssp, DSISR_BITS_REG(dsisr), &value, unsigned long);
return TRUE;
}
_AINST(sthx)
{
GET_REG(ssp, DSISR_BITS_REG(dsisr), &align_buffer[0], unsigned short);
return TRUE;
}
_AINST(lfsx)
{
long lalign_buf[2];
lfs (align_buffer, lalign_buf);
SET_FPU_REG(fsp, DSISR_BITS_REG(dsisr), lalign_buf);
return TRUE;
}
_AINST(lfdx)
{
SET_FPU_REG(fsp, DSISR_BITS_REG(dsisr), align_buffer);
return TRUE;
}
_AINST(stfsx)
{
long lalign_buf[2];
GET_FPU_REG(fsp, DSISR_BITS_REG(dsisr), lalign_buf);
stfs(lalign_buf, align_buffer);
return TRUE;
}
_AINST(stfdx)
{
GET_FPU_REG(fsp, DSISR_BITS_REG(dsisr), align_buffer);
return TRUE;
}
_AINST(lwzux)
{
SET_REG(ssp, DSISR_BITS_REG(dsisr), &align_buffer[0], unsigned long);
SET_REG(ssp, DSISR_BITS_RA(dsisr), &dar, unsigned long);
return TRUE;
}
_AINST(stwux)
{
GET_REG(ssp, DSISR_BITS_REG(dsisr), &align_buffer[0], unsigned long);
SET_REG(ssp, DSISR_BITS_RA(dsisr), &dar, unsigned long);
return TRUE;
}
_AINST(lhzux)
{
unsigned long value = *((unsigned short *)&align_buffer[0]);
SET_REG(ssp, DSISR_BITS_REG(dsisr), &value, unsigned long);
SET_REG(ssp, DSISR_BITS_RA(dsisr), &dar, unsigned long);
return TRUE;
}
_AINST(lhaux)
{
long value = *((short *) &align_buffer[0]);
SET_REG(ssp, DSISR_BITS_REG(dsisr), &value, unsigned long);
SET_REG(ssp, DSISR_BITS_RA(dsisr), &dar, unsigned long);
return TRUE;
}
_AINST(sthux)
{
GET_REG(ssp, DSISR_BITS_REG(dsisr), &align_buffer[0], unsigned short);
SET_REG(ssp, DSISR_BITS_RA(dsisr), &dar, unsigned long);
return TRUE;
}
_AINST(lfsux)
{
long lalign_buf[2];
lfs (align_buffer, lalign_buf);
SET_FPU_REG(fsp, DSISR_BITS_REG(dsisr), lalign_buf);
SET_REG(ssp, DSISR_BITS_RA(dsisr), &dar, unsigned long);
return TRUE;
}
_AINST(lfdux)
{
SET_FPU_REG(fsp, DSISR_BITS_REG(dsisr), &align_buffer[0]);
SET_REG(ssp, DSISR_BITS_RA(dsisr), &dar, unsigned long);
return TRUE;
}
_AINST(stfsux)
{
long lalign_buf[2];
GET_FPU_REG(fsp, DSISR_BITS_REG(dsisr), lalign_buf);
stfs(lalign_buf, align_buffer);
SET_REG(ssp, DSISR_BITS_RA(dsisr), &dar, unsigned long);
return TRUE;
}
_AINST(stfdux)
{
GET_FPU_REG(fsp, DSISR_BITS_REG(dsisr), &align_buffer[0]);
SET_REG(ssp, DSISR_BITS_RA(dsisr), &dar, unsigned long);
return TRUE;
}