]> git.saurik.com Git - apple/xnu.git/blame - osfmk/ppc/alignment.c
xnu-124.13.tar.gz
[apple/xnu.git] / osfmk / ppc / alignment.c
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22/*
23 * Copyright 1996 1995 by Open Software Foundation, Inc. 1997 1996 1995 1994 1993 1992 1991
24 * All Rights Reserved
25 *
26 * Permission to use, copy, modify, and distribute this software and
27 * its documentation for any purpose and without fee is hereby granted,
28 * provided that the above copyright notice appears in all copies and
29 * that both the copyright notice and this permission notice appear in
30 * supporting documentation.
31 *
32 * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
33 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
34 * FOR A PARTICULAR PURPOSE.
35 *
36 * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
37 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
38 * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
39 * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
40 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
41 *
42 */
43/*
44 * Copyright 1996 1995 by Apple Computer, Inc. 1997 1996 1995 1994 1993 1992 1991
45 * All Rights Reserved
46 *
47 * Permission to use, copy, modify, and distribute this software and
48 * its documentation for any purpose and without fee is hereby granted,
49 * provided that the above copyright notice appears in all copies and
50 * that both the copyright notice and this permission notice appear in
51 * supporting documentation.
52 *
53 * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
54 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
55 * FOR A PARTICULAR PURPOSE.
56 *
57 * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
58 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
59 * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
60 * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
61 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
62 */
63
64#include <debug.h>
65#include <kern/thread_act.h>
66#include <mach/thread_status.h>
67#include <mach/boolean.h>
68#include <kern/misc_protos.h>
69#include <kern/simple_lock.h>
70#include <ppc/proc_reg.h>
71#include <ppc/fpu_protos.h>
72#include <ppc/misc_protos.h>
73#include <ppc/exception.h>
74
75#if DEBUG
76/* These variable may be used to keep track of alignment exceptions */
77int alignment_exception_count_user;
78int alignment_exception_count_kernel;
79#endif
80
81#define _AINST(x) boolean_t align_##x##(unsigned long dsisr,\
82 struct ppc_saved_state *ssp, \
83 struct ppc_float_state *fsp, \
84 unsigned long *align_buffer, \
85 unsigned long dar)
86
87
88#define _AFENTRY(name, r, b) { #name, align_##name##, r, b, TRUE }
89#define _AENTRY(name, r, b) { #name, align_##name##, r, b, FALSE }
90#define _ANIL { (void *) 0, (void *) 0, 0, 0 }
91
92_AINST(lwz);
93_AINST(stw);
94_AINST(lhz);
95_AINST(lha);
96_AINST(sth);
97_AINST(lmw);
98_AINST(lfs);
99_AINST(lfd);
100_AINST(stfs);
101_AINST(stfd);
102_AINST(lwzu);
103_AINST(stwu);
104_AINST(lhzu);
105_AINST(lhau);
106_AINST(sthu);
107_AINST(lfsu);
108_AINST(lfdu);
109_AINST(stfsu);
110_AINST(stfdu);
111_AINST(lswx);
112_AINST(lswi);
113_AINST(lwbrx);
114_AINST(stwbrx);
115_AINST(lhbrx);
116_AINST(sthbrx);
117_AINST(dcbz);
118_AINST(lwzx);
119_AINST(stwx);
120_AINST(lhzx);
121_AINST(lhax);
122_AINST(sthx);
123_AINST(lfsx);
124_AINST(lfdx);
125_AINST(stfsx);
126_AINST(stfdx);
127_AINST(lwzux);
128_AINST(stwux);
129_AINST(lhzux);
130_AINST(lhaux);
131_AINST(sthux);
132_AINST(stmw);
133_AINST(lfsux);
134_AINST(lfdux);
135_AINST(stfsux);
136_AINST(stfdux);
137
138/*
139 * Routines to set and get FPU registers.
140 */
141
142void GET_FPU_REG(struct ppc_float_state *fsp,
143 unsigned long reg,
144 unsigned long *value);
145void SET_FPU_REG(struct ppc_float_state *fsp,
146 unsigned long reg,
147 unsigned long *value);
148
149__inline__ void GET_FPU_REG(struct ppc_float_state *fsp,
150 unsigned long reg,
151 unsigned long *value)
152{
153 value[0] = ((unsigned long *) &fsp->fpregs[reg])[0];
154 value[1] = ((unsigned long *) &fsp->fpregs[reg])[1];
155}
156
157__inline__ void SET_FPU_REG(struct ppc_float_state *fsp,
158 unsigned long reg, unsigned long *value)
159{
160 ((unsigned long *) &fsp->fpregs[reg])[0] = value[0];
161 ((unsigned long *) &fsp->fpregs[reg])[1] = value[1];
162}
163
164
165/*
166 * Macros to load and set registers according to
167 * a given cast type.
168 */
169
170#define GET_REG(p, reg, value, cast) \
171 { *((cast *) value) = *((cast *) (&p->r0+reg)); }
172#define SET_REG(p, reg, value, cast) \
173 { *((cast *) (&p->r0+reg)) = *((cast *) value); }
174
175/*
176 * Macros to help decode the DSISR.
177 */
178
179#define DSISR_BITS_15_16(bits) ((bits>>15) & 0x3)
180#define DSISR_BITS_17_21(bits) ((bits>>10) & 0x1f)
181#define DSISR_BITS_REG(bits) ((bits>>5) & 0x1f)
182#define DSISR_BITS_RA(bits) (bits & 0x1f)
183
184
185struct ppc_align_instruction {
186 char *name;
187 boolean_t (*a_instruct)(unsigned long,
188 struct ppc_saved_state *,
189 struct ppc_float_state *,
190 unsigned long *,
191 unsigned long );
192 int a_readbytes;
193 int a_writebytes;
194 boolean_t a_is_float;
195} align_table00[] = {
196_AENTRY(lwz, 4, 0), /* 00 0 0000 */
197_ANIL, /* 00 0 0001 */
198_AENTRY(stw, 0, 4), /* 00 0 0010 */
199_ANIL, /* 00 0 0011 */
200_AENTRY(lhz, 2, 0), /* 00 0 0100 */
201_AENTRY(lha, 2, 0), /* 00 0 0101 */
202_AENTRY(sth, 0, 2), /* 00 0 0110 */
203_AENTRY(lmw, 32*4,0), /* 00 0 0111 */
204_AFENTRY(lfs, 4, 0), /* 00 0 1000 */
205_AFENTRY(lfd, 8, 0), /* 00 0 1001 */
206_AFENTRY(stfs, 0, 4), /* 00 0 1010 */
207_AFENTRY(stfd, 0, 8), /* 00 0 1011 */
208_ANIL, /* 00 0 1100 ?*/
209_ANIL, /* 00 0 1101 - lwa */
210_ANIL, /* 00 0 1110 ?*/
211_ANIL, /* 00 0 1111 - std */
212_AENTRY(lwzu, 4, 0), /* 00 1 0000 */
213_ANIL, /* 00 1 0001 ?*/
214_AENTRY(stwu, 0, 4), /* 00 1 0010 */
215_ANIL, /* 00 1 0011 */
216_AENTRY(lhzu, 2, 0), /* 00 1 0100 */
217_AENTRY(lhau, 2, 0), /* 00 1 0101 */
218_AENTRY(sthu, 0, 2), /* 00 1 0110 */
219_AENTRY(stmw, 0, 0), /* 00 1 0111 */
220_AFENTRY(lfsu, 4, 0), /* 00 1 1000 */
221_AFENTRY(lfdu, 8, 0), /* 00 1 1001 - lfdu */
222_AFENTRY(stfsu, 0, 4), /* 00 1 1010 */
223_AFENTRY(stfdu, 0, 8), /* 00 1 1011 - stfdu */
224};
225
226struct ppc_align_instruction align_table01[] = {
227_ANIL, /* 01 0 0000 - ldx */
228_ANIL, /* 01 0 0001 ?*/
229_ANIL, /* 01 0 0010 - stdx */
230_ANIL, /* 01 0 0011 ?*/
231_ANIL, /* 01 0 0100 ?*/
232_ANIL, /* 01 0 0101 - lwax */
233_ANIL, /* 01 0 0110 ?*/
234_ANIL, /* 01 0 0111 ?*/
235_AENTRY(lswx,32, 0), /* 01 0 1000 - lswx */
236_AENTRY(lswi,32, 0), /* 01 0 1001 - lswi */
237_ANIL, /* 01 0 1010 - stswx */
238_ANIL, /* 01 0 1011 - stswi */
239_ANIL, /* 01 0 1100 ?*/
240_ANIL, /* 01 0 1101 ?*/
241_ANIL, /* 01 0 1110 ?*/
242_ANIL, /* 01 0 1111 ?*/
243_ANIL, /* 01 1 0000 - ldux */
244_ANIL, /* 01 1 0001 ?*/
245_ANIL, /* 01 1 0010 - stdux */
246_ANIL, /* 01 1 0011 ?*/
247_ANIL, /* 01 1 0100 ?*/
248_ANIL, /* 01 1 0101 - lwaux */
249};
250
251struct ppc_align_instruction align_table10[] = {
252_ANIL, /* 10 0 0000 ?*/
253_ANIL, /* 10 0 0001 ?*/
254_ANIL, /* 10 0 0010 - stwcx. */
255_ANIL, /* 10 0 0011 - stdcx.*/
256_ANIL, /* 10 0 0100 ?*/
257_ANIL, /* 10 0 0101 ?*/
258_ANIL, /* 10 0 0110 ?*/
259_ANIL, /* 10 0 0111 ?*/
260_AENTRY(lwbrx, 2, 0), /* 10 0 1000 */
261_ANIL, /* 10 0 1001 ?*/
262_AENTRY(stwbrx, 0, 4), /* 10 0 1010 */
263_ANIL, /* 10 0 1011 */
264_AENTRY(lhbrx, 2, 0), /* 10 0 1110 */
265_ANIL, /* 10 0 1101 ?*/
266_AENTRY(sthbrx, 0, 2), /* 10 0 1110 */
267_ANIL, /* 10 0 1111 ?*/
268_ANIL, /* 10 1 0000 ?*/
269_ANIL, /* 10 1 0001 ?*/
270_ANIL, /* 10 1 0010 ?*/
271_ANIL, /* 10 1 0011 ?*/
272_ANIL, /* 10 1 0100 - eciwx */
273_ANIL, /* 10 1 0101 ?*/
274_ANIL, /* 10 1 0110 - ecowx */
275_ANIL, /* 10 1 0111 ?*/
276_ANIL, /* 10 1 1000 ?*/
277_ANIL, /* 10 1 1001 ?*/
278_ANIL, /* 10 1 1010 ?*/
279_ANIL, /* 10 1 1011 ?*/
280_ANIL, /* 10 1 1100 ?*/
281_ANIL, /* 10 1 1101 ?*/
282_ANIL, /* 10 1 1110 ?*/
283_AENTRY(dcbz, 0, 0), /* 10 1 1111 */
284};
285
286struct ppc_align_instruction align_table11[] = {
287_AENTRY(lwzx, 4, 0), /* 11 0 0000 */
288_ANIL, /* 11 0 0001 ?*/
289_AENTRY(stwx, 0, 4), /* 11 0 0010 */
290_ANIL, /* 11 0 0011 */
291_AENTRY(lhzx, 2, 0), /* 11 0 0100 */
292_AENTRY(lhax, 2, 0), /* 11 0 0101 */
293_AENTRY(sthx, 0, 2), /* 11 0 0110 */
294_ANIL, /* 11 0 0111?*/
295_AFENTRY(lfsx, 4, 0), /* 11 0 1000 */
296_AFENTRY(lfdx, 8, 0), /* 11 0 1001 */
297_AFENTRY(stfsx, 0, 4), /* 11 0 1010 */
298_AFENTRY(stfdx, 0, 8), /* 11 0 1011 */
299_ANIL, /* 11 0 1100 ?*/
300_ANIL, /* 11 0 1101 ?*/
301_ANIL, /* 11 0 1110 ?*/
302_ANIL, /* 11 0 1111 - stfiwx */
303_AENTRY(lwzux, 4, 0), /* 11 1 0000 */
304_ANIL, /* 11 1 0001 ?*/
305_AENTRY(stwux, 0, 4), /* 11 1 0010 */
306_ANIL, /* 11 1 0011 */
307_AENTRY(lhzux, 4, 0), /* 11 1 0100 */
308_AENTRY(lhaux, 4, 0), /* 11 1 0101 */
309_AENTRY(sthux, 0, 4), /* 11 1 0110 */
310_ANIL, /* 11 1 0111 ?*/
311_AFENTRY(lfsux, 4, 0), /* 11 1 1000 */
312_AFENTRY(lfdux, 0, 8), /* 11 1 1001 */
313_AFENTRY(stfsux, 0, 4), /* 11 1 1010 */
314_AFENTRY(stfdux, 0, 8), /* 11 1 1011 */
315};
316
317
318struct ppc_align_instruction_table {
319 struct ppc_align_instruction *table;
320 int size;
321} align_tables[4] = {
322 align_table00, sizeof(align_table00)/
323 sizeof(struct ppc_align_instruction),
324
325 align_table01, sizeof(align_table01)/
326 sizeof(struct ppc_align_instruction),
327
328 align_table10, sizeof(align_table10)/
329 sizeof(struct ppc_align_instruction),
330
331 align_table11, sizeof(align_table11)/
332 sizeof(struct ppc_align_instruction)
333};
334
335extern int real_ncpus; /* Number of actual CPUs */
336
337/*
338 * Alignment Exception Handler
339 *
340 *
341 * This handler is called when the chip attempts
342 * to execute an instruction which causes page
343 * boundaries to be crossed. Typically, this will
344 * happen on stfd* and lfd* instructions.
345 * (A request has been made for GNU C compiler
346 * NOT to make use of these instructions to
347 * load and store 8 bytes at a time.)
348 *
349 * This is a *SLOW* handler. There is room for vast
350 * improvement. However, it is expected that alignment
351 * exceptions will be very infrequent.
352 *
353 * Not all of the 64 instructions (as listed in
354 * PowerPC Microprocessor Family book under the Alignment
355 * Exception section) are handled yet.
356 * Only the most common ones which are expected to
357 * happen.
358 *
359 * -- Michael Burg, Apple Computer, Inc. 1996
360 *
361 * TODO NMGS finish handler
362 */
363
364boolean_t
365alignment(unsigned long dsisr, unsigned long dar,
366 struct ppc_saved_state *ssp)
367{
368 struct ppc_align_instruction_table *table;
369 struct ppc_align_instruction *entry;
370 struct ppc_float_state *fpc;
371 unsigned long align_buffer[32];
372 boolean_t success = FALSE;
373 thread_act_t act;
374 spl_t s;
375 int i;
376
377#if DEBUG
378 if (USER_MODE(ssp->srr1)) (void)hw_atomic_add(&alignment_exception_count_user, 1);
379 else (void)hw_atomic_add(&alignment_exception_count_kernel, 1);
380#endif
381
382 table = &align_tables[DSISR_BITS_15_16(dsisr)];
383
384 if (table == (void *) 0
385 || table->size < DSISR_BITS_17_21(dsisr)) {
386#if DEBUG
387 printf("EXCEPTION NOT HANDLED: Out of range.\n");
388 printf("dsisr=%X, dar=%X\n",dsisr, dar);
389 printf("table=%X\n",DSISR_BITS_15_16(dsisr));
390 printf("table->size=%X\n", table->size);
391 printf("entry=%X\n",DSISR_BITS_17_21(dsisr));
392#endif
393 goto out;
394 }
395
396 entry = &table->table[DSISR_BITS_17_21(dsisr)];
397
398 if (entry->a_instruct == (void *) 0) {
399#if DEBUG
400 printf("EXCEPTION NOT HANDLED: Inst out of table range.\n");
401 printf("table=%X\n",DSISR_BITS_15_16(dsisr));
402 printf("entry=%X\n",DSISR_BITS_17_21(dsisr));
403#endif
404 goto out;
405 }
406
407 /*
408 * Check to see if the instruction is a
409 * floating point operation. Save off
410 * the FPU register set ...
411 */
412
413 if (entry->a_is_float)
414 fpu_save();
415
416 /*
417 * Pull in any bytes which are going to be
418 * read.
419 */
420
421 if (entry->a_readbytes) {
422 if (USER_MODE(ssp->srr1)) {
423 if (copyin((char *) dar,
424 (char *) align_buffer,
425 entry->a_readbytes)) {
426 return TRUE;
427 }
428 } else {
429 bcopy((char *) dar,
430 (char *) align_buffer,
431 entry->a_readbytes);
432 }
433 }
434
435#if 0 && DEBUG
436 printf("Alignment exception: %s %d,0x%x (r%d/w%d) (tmp %x/%x)\n",
437 entry->name, DSISR_BITS_REG(dsisr),
438 dar, entry->a_readbytes, entry->a_writebytes,
439 align_buffer[0], align_buffer[1]);
440 printf(" pc=(0x%08X), msr=(0x%X)",ssp->srr0, ssp->srr1);
441#endif
442
443 act = current_act(); /* Get the current activation */
444
445 success = entry->a_instruct(dsisr,
446 ssp,
447 find_user_fpu(act), /* Find this user's FPU state. NULL if none */
448 /* NULL should never happen */
449 align_buffer,
450 dar);
451
452 if (success) {
453 if (entry->a_writebytes) {
454 if (USER_MODE(ssp->srr1)) {
455 if (copyout((char *) align_buffer,
456 (char *) dar,
457 entry->a_writebytes)) {
458 return TRUE;
459 }
460 } else {
461 bcopy((char *) align_buffer,
462 (char *) dar,
463 entry->a_writebytes);
464 }
465 }
466 else {
467 for(i=0; i < real_ncpus; i++) { /* Cycle through processors */
468 (void)hw_compare_and_store((unsigned int)act, 0, &per_proc_info[i].FPU_thread); /* Clear if ours */
469 }
470
471 if (USER_MODE(ssp->srr1)) {
472 if (copyout((char *) align_buffer,
473 (char *) dar,
474 entry->a_writebytes)) {
475 return TRUE;
476 }
477 } else {
478 bcopy((char *) align_buffer,
479 (char *) dar,
480 entry->a_writebytes);
481 }
482 }
483
484 ssp->srr0 += 4; /* Skip the instruction .. */
485 }
486
487 return !success;
488
489out:
490#if 0 && DEBUG
491 printf("ALIGNMENT EXCEPTION: (dsisr 0x%x) table %d 0x%x\n",
492 dsisr, DSISR_BITS_15_16(dsisr), DSISR_BITS_17_21(dsisr));
493#endif
494
495 return TRUE;
496}
497
498_AINST(lwz)
499{
500 SET_REG(ssp, DSISR_BITS_REG(dsisr), align_buffer, unsigned long);
501
502 return TRUE;
503}
504
505_AINST(stw)
506{
507 GET_REG(ssp, DSISR_BITS_REG(dsisr), align_buffer, unsigned long);
508
509 return TRUE;
510}
511
512_AINST(lhz)
513{
514 unsigned long value = *((unsigned short *) align_buffer);
515
516 SET_REG(ssp, DSISR_BITS_REG(dsisr), &value, unsigned long);
517
518 return TRUE;
519}
520
521_AINST(lha)
522{
523 long value = *((short *) align_buffer);
524
525 SET_REG(ssp, DSISR_BITS_REG(dsisr), &value, unsigned long);
526
527 return TRUE;
528}
529
530_AINST(sth)
531{
532 GET_REG(ssp, DSISR_BITS_REG(dsisr), align_buffer, unsigned short);
533
534 return TRUE;
535}
536
537_AINST(lmw)
538{
539 int i;
540
541 for (i = 0; i < (32-DSISR_BITS_REG(dsisr)); i++)
542 {
543 SET_REG(ssp, DSISR_BITS_REG(dsisr)+i, &align_buffer[i], unsigned long);
544 }
545 return TRUE;
546}
547
548struct fpsp {
549 unsigned long s :1; /* Sign bit */
550 unsigned long exp :8; /* exponent + bias */
551 unsigned long fraction:23; /* fraction */
552};
553typedef struct fpsp fpsp_t, *fpspPtr;
554
555struct fpdp {
556 unsigned long s :1; /* Sign bit */
557 unsigned long exp :11; /* exponent + bias */
558 unsigned long fraction:20; /* fraction */
559 unsigned long fraction1; /* fraction */
560};
561typedef struct fpdp fpdp_t, *fpdpPtr;
562
563
564_AINST(lfs)
565{
566 unsigned long lalign_buf[2];
567
568
569 lfs (align_buffer, lalign_buf);
570 SET_FPU_REG(fsp, DSISR_BITS_REG(dsisr), lalign_buf);
571 return TRUE;
572}
573
574_AINST(lfd)
575{
576 SET_FPU_REG(fsp, DSISR_BITS_REG(dsisr), align_buffer);
577 return TRUE;
578}
579
580_AINST(stfs)
581{
582 unsigned long lalign_buf[2];
583
584
585 GET_FPU_REG(fsp, DSISR_BITS_REG(dsisr), lalign_buf);
586 stfs(lalign_buf, align_buffer);
587 return TRUE;
588}
589
590_AINST(stfd)
591{
592 GET_FPU_REG(fsp, DSISR_BITS_REG(dsisr), align_buffer);
593 return TRUE;
594}
595
596_AINST(lwzu)
597{
598 SET_REG(ssp, DSISR_BITS_REG(dsisr), align_buffer, unsigned long)
599 SET_REG(ssp, DSISR_BITS_RA(dsisr), &dar, unsigned long);
600 return TRUE;
601}
602
603_AINST(stwu)
604{
605 GET_REG(ssp, DSISR_BITS_REG(dsisr), align_buffer, unsigned long)
606 SET_REG(ssp, DSISR_BITS_RA(dsisr), &dar, unsigned long);
607 return TRUE;
608}
609
610
611_AINST(lhzu)
612{
613 SET_REG(ssp, DSISR_BITS_REG(dsisr), align_buffer, unsigned short)
614 SET_REG(ssp, DSISR_BITS_RA(dsisr), &dar, unsigned long);
615 return TRUE;
616}
617
618_AINST(lhau)
619{
620 unsigned long value = *((short *) align_buffer);
621
622 SET_REG(ssp, DSISR_BITS_REG(dsisr), &value, unsigned long);
623 SET_REG(ssp, DSISR_BITS_RA(dsisr), &dar, unsigned long);
624
625 return TRUE;
626}
627
628_AINST(sthu)
629{
630 GET_REG(ssp, DSISR_BITS_REG(dsisr), align_buffer, unsigned short)
631 SET_REG(ssp, DSISR_BITS_RA(dsisr), &dar, unsigned long);
632 return TRUE;
633}
634
635_AINST(stmw)
636{
637 int i, rS = DSISR_BITS_REG(dsisr);
638 int numRegs = 32 - rS;
639 int numBytes = numRegs * 4;
640 int retval;
641
642
643 for (i = 0; i < numRegs; i++)
644 {
645#if 0
646 printf(" align_buffer[%d] == 0x%x\n",i,align_buffer[i]);
647#endif
648 GET_REG(ssp, rS+i, &align_buffer[i], unsigned long);
649#if 0
650 printf(" now align_buffer[%d] == 0x%x\n",i,align_buffer[i]);
651#endif
652 }
653 if (USER_MODE(ssp->srr1)) {
654 if ((retval=copyout((char *)align_buffer,(char *)dar,numBytes)) != 0) {
655 return FALSE;
656 }
657#if 0
658 printf(" copyout(%X, %X, %X) succeeded\n",align_buffer,dar,numBytes);
659#endif
660 }
661 else {
662 bcopy((char *) align_buffer, (char *) dar, numBytes);
663 }
664 return TRUE;
665}
666
667_AINST(lfsu)
668{
669 unsigned long lalign_buf[2];
670
671
672 lfs (align_buffer, lalign_buf);
673 SET_FPU_REG(fsp, DSISR_BITS_REG(dsisr), lalign_buf);
674 SET_REG(ssp, DSISR_BITS_RA(dsisr), &dar, unsigned long);
675 return TRUE;
676}
677
678_AINST(lfdu)
679{
680 SET_FPU_REG(fsp, DSISR_BITS_REG(dsisr), align_buffer);
681 SET_REG(ssp, DSISR_BITS_RA(dsisr), &dar, unsigned long);
682
683 return TRUE;
684}
685
686_AINST(stfsu)
687{
688 unsigned long lalign_buf[2];
689
690
691 GET_FPU_REG(fsp, DSISR_BITS_REG(dsisr), lalign_buf);
692 stfs(lalign_buf, align_buffer);
693 SET_REG(ssp, DSISR_BITS_RA(dsisr), &dar, unsigned long);
694 return TRUE;
695}
696
697
698_AINST(stfdu)
699{
700 GET_FPU_REG(fsp, DSISR_BITS_REG(dsisr), align_buffer);
701 SET_REG(ssp, DSISR_BITS_RA(dsisr), &dar, unsigned long);
702
703 return TRUE;
704}
705
706_AINST(lswx)
707{
708 int i, nb, nr, inst, zero = 0;
709
710
711 /* check for invalid form of instruction */
712 if (DSISR_BITS_RA(dsisr) >= DSISR_BITS_REG(dsisr) )
713 return FALSE;
714
715 if (USER_MODE(ssp->srr1)) {
716 if (copyin((char *) ssp->srr0, (char *) &inst, 4 )) {
717 return FALSE;
718 }
719 } else {
720 bcopy((char *) ssp->srr0, (char *) &inst, 4 );
721 }
722
723 nb = (inst >> 11) & 0x1F; /* get the number of bytes in the instr */
724 nr = (nb + sizeof(long)-1) / sizeof(long);/* get the number of regs to copy */
725
726 if ((nr + DSISR_BITS_REG(dsisr)) > 31)
727 return FALSE; /* not supported yet */
728
729 for (i = 0; i < nr; i++)
730 {
731 SET_REG(ssp, DSISR_BITS_REG(dsisr)+i, &zero, unsigned long);
732 }
733 /* copy the string into the save state */
734 bcopy((char *) align_buffer, (char *) ssp->r0+DSISR_BITS_REG(dsisr), nb );
735 return TRUE;
736}
737
738_AINST(lswi)
739{
740 int i, nb, nr, inst, zero = 0;
741
742
743 /* check for invalid form of instruction */
744 if (DSISR_BITS_RA(dsisr) >= DSISR_BITS_REG(dsisr) )
745 return FALSE;
746
747 if (USER_MODE(ssp->srr1)) {
748 if (copyin((char *) ssp->srr0, (char *) &inst, 4 )) {
749 return FALSE;
750 }
751 } else {
752 bcopy((char *) ssp->srr0, (char *) &inst, 4 );
753 }
754
755 nb = (inst >> 11) & 0x1F; /* get the number of bytes in the instr */
756 nr = (nb + sizeof(long)-1) / sizeof(long);/* get the number of regs to copy */
757
758 if ((nr + DSISR_BITS_REG(dsisr)) > 31)
759 return FALSE; /* not supported yet */
760
761 for (i = 0; i < nr; i++)
762 {
763 SET_REG(ssp, DSISR_BITS_REG(dsisr)+i, &zero, unsigned long);
764 }
765 /* copy the string into the save state */
766 bcopy((char *) align_buffer, (char *) ssp->r0+DSISR_BITS_REG(dsisr), nb );
767 return TRUE;
768}
769
770_AINST(stswx)
771{
772 return FALSE;
773}
774
775_AINST(stswi)
776{
777 return FALSE;
778}
779
780
781
782
783
784
785
786_AINST(stwcx)
787{
788 return FALSE;
789}
790
791_AINST(stdcx)
792{
793 return FALSE;
794}
795
796_AINST(lwbrx)
797{
798 unsigned long new_value;
799
800 __asm__ volatile("lwbrx %0,0,%1" : : "b" (new_value),
801 "b" (&align_buffer[0]));
802
803 SET_REG(ssp, DSISR_BITS_REG(dsisr), &new_value, unsigned long);
804
805 return TRUE;
806}
807
808_AINST(stwbrx)
809{
810 unsigned long value;
811
812 GET_REG(ssp, DSISR_BITS_REG(dsisr), &value, unsigned long);
813 __asm__ volatile("stwbrx %0,0,%1" : : "b" (value), "b" (&align_buffer[0]));
814
815 return TRUE;
816}
817
818_AINST(lhbrx)
819{
820 unsigned short value;
821
822 __asm__ volatile("lhbrx %0,0,%1" : : "b" (value), "b" (&align_buffer[0]));
823
824 SET_REG(ssp, DSISR_BITS_REG(dsisr), &value, unsigned short);
825
826 return TRUE;
827}
828
829_AINST(sthbrx)
830{
831 unsigned short value;
832
833 GET_REG(ssp, DSISR_BITS_REG(dsisr), &value, unsigned short);
834 __asm__ volatile("sthbrx %0,0,%1" : : "b" (value), "b" (&align_buffer[0]));
835
836 return TRUE;
837}
838
839_AINST(eciwx)
840{
841 return FALSE;
842}
843
844_AINST(ecowx)
845{
846 return FALSE;
847}
848
849_AINST(dcbz)
850{
851 long *alignedDAR = (long *)((long)dar & ~(CACHE_LINE_SIZE-1));
852
853
854 if (USER_MODE(ssp->srr1)) {
855
856 align_buffer[0] = 0;
857 align_buffer[1] = 0;
858 align_buffer[2] = 0;
859 align_buffer[3] = 0;
860 align_buffer[4] = 0;
861 align_buffer[5] = 0;
862 align_buffer[6] = 0;
863 align_buffer[7] = 0;
864
865 if (copyout((char *)align_buffer,(char *)alignedDAR,CACHE_LINE_SIZE) != 0)
866 return FALSE;
867 } else {
868 /* Cannot use bcopy here just in case it caused the exception */
869 alignedDAR[0] = 0;
870 alignedDAR[1] = 0;
871 alignedDAR[2] = 0;
872 alignedDAR[3] = 0;
873 alignedDAR[4] = 0;
874 alignedDAR[5] = 0;
875 alignedDAR[6] = 0;
876 alignedDAR[7] = 0;
877 }
878 return TRUE;
879}
880
881
882
883
884
885
886
887_AINST(lwzx)
888{
889 SET_REG(ssp, DSISR_BITS_REG(dsisr), &align_buffer[0], unsigned long);
890
891 return TRUE;
892}
893
894_AINST(stwx)
895{
896 GET_REG(ssp, DSISR_BITS_REG(dsisr), &align_buffer[0], unsigned long);
897
898 return TRUE;
899}
900
901_AINST(lhzx)
902{
903 SET_REG(ssp, DSISR_BITS_REG(dsisr), &align_buffer[0], unsigned short);
904
905 return TRUE;
906}
907
908_AINST(lhax)
909{
910 unsigned long value = *((short *) &align_buffer[0]);
911
912 SET_REG(ssp, DSISR_BITS_REG(dsisr), &value, unsigned long);
913
914 return TRUE;
915}
916
917_AINST(sthx)
918{
919 GET_REG(ssp, DSISR_BITS_REG(dsisr), &align_buffer[0], unsigned short);
920
921 return TRUE;
922}
923
924_AINST(lfsx)
925{
926 long lalign_buf[2];
927
928
929 lfs (align_buffer, lalign_buf);
930 SET_FPU_REG(fsp, DSISR_BITS_REG(dsisr), lalign_buf);
931 return TRUE;
932}
933
934_AINST(lfdx)
935{
936 SET_FPU_REG(fsp, DSISR_BITS_REG(dsisr), align_buffer);
937
938 return TRUE;
939}
940
941_AINST(stfsx)
942{
943 long lalign_buf[2];
944
945
946 GET_FPU_REG(fsp, DSISR_BITS_REG(dsisr), lalign_buf);
947 stfs(lalign_buf, align_buffer);
948 return TRUE;
949}
950
951_AINST(stfdx)
952{
953 GET_FPU_REG(fsp, DSISR_BITS_REG(dsisr), align_buffer);
954
955 return TRUE;
956}
957
958_AINST(lwzux)
959{
960 SET_REG(ssp, DSISR_BITS_REG(dsisr), &align_buffer[0], unsigned long);
961 SET_REG(ssp, DSISR_BITS_RA(dsisr), &dar, unsigned long);
962
963 return TRUE;
964}
965
966_AINST(stwux)
967{
968 GET_REG(ssp, DSISR_BITS_REG(dsisr), &align_buffer[0], unsigned long);
969 SET_REG(ssp, DSISR_BITS_RA(dsisr), &dar, unsigned long);
970
971 return TRUE;
972}
973
974_AINST(lhzux)
975{
976 unsigned long value = *((unsigned short *)&align_buffer[0]);
977
978 SET_REG(ssp, DSISR_BITS_REG(dsisr), &value, unsigned long);
979 SET_REG(ssp, DSISR_BITS_RA(dsisr), &dar, unsigned long);
980
981 return TRUE;
982}
983
984_AINST(lhaux)
985{
986 long value = *((short *) &align_buffer[0]);
987
988 SET_REG(ssp, DSISR_BITS_REG(dsisr), &value, unsigned long);
989 SET_REG(ssp, DSISR_BITS_RA(dsisr), &dar, unsigned long);
990
991 return TRUE;
992}
993
994_AINST(sthux)
995{
996 GET_REG(ssp, DSISR_BITS_REG(dsisr), &align_buffer[0], unsigned short);
997 SET_REG(ssp, DSISR_BITS_RA(dsisr), &dar, unsigned long);
998
999 return TRUE;
1000}
1001
1002_AINST(lfsux)
1003{
1004 long lalign_buf[2];
1005
1006
1007 lfs (align_buffer, lalign_buf);
1008 SET_FPU_REG(fsp, DSISR_BITS_REG(dsisr), lalign_buf);
1009 SET_REG(ssp, DSISR_BITS_RA(dsisr), &dar, unsigned long);
1010 return TRUE;
1011}
1012
1013_AINST(lfdux)
1014{
1015 SET_FPU_REG(fsp, DSISR_BITS_REG(dsisr), &align_buffer[0]);
1016 SET_REG(ssp, DSISR_BITS_RA(dsisr), &dar, unsigned long);
1017
1018 return TRUE;
1019}
1020
1021
1022_AINST(stfsux)
1023{
1024 long lalign_buf[2];
1025
1026
1027 GET_FPU_REG(fsp, DSISR_BITS_REG(dsisr), lalign_buf);
1028 stfs(lalign_buf, align_buffer);
1029 SET_REG(ssp, DSISR_BITS_RA(dsisr), &dar, unsigned long);
1030 return TRUE;
1031}
1032
1033_AINST(stfdux)
1034{
1035 GET_FPU_REG(fsp, DSISR_BITS_REG(dsisr), &align_buffer[0]);
1036 SET_REG(ssp, DSISR_BITS_RA(dsisr), &dar, unsigned long);
1037
1038 return TRUE;
1039}