]> git.saurik.com Git - apple/xnu.git/blob - osfmk/ppc/alignment.c
e5ac61c0b9bd831f6f9dcb69d4192723db9e8838
[apple/xnu.git] / osfmk / ppc / alignment.c
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 */
77 int alignment_exception_count_user;
78 int 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
142 void GET_FPU_REG(struct ppc_float_state *fsp,
143 unsigned long reg,
144 unsigned long *value);
145 void 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
185 struct 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
226 struct 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
251 struct 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
286 struct 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
318 struct 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
335 extern 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
364 boolean_t
365 alignment(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
489 out:
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
548 struct fpsp {
549 unsigned long s :1; /* Sign bit */
550 unsigned long exp :8; /* exponent + bias */
551 unsigned long fraction:23; /* fraction */
552 };
553 typedef struct fpsp fpsp_t, *fpspPtr;
554
555 struct 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 };
561 typedef 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 }