xref: /netbsd-src/external/gpl3/gdb/dist/sim/ppc/interrupts.c (revision a5847cc334d9a7029f6352b847e9e8d71a0f9e0c)
1 /*  This file is part of the program psim.
2 
3     Copyright 1994, 1995, 1996, 1997, 2003 Andrew Cagney
4 
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9 
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14 
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 
19     */
20 
21 
22 #ifndef _INTERRUPTS_C_
23 #define _INTERRUPTS_C_
24 
25 #include <signal.h>
26 
27 #include "cpu.h"
28 #include "idecode.h"
29 #include "os_emul.h"
30 
31 
32 /* Operating environment support code
33 
34    Unlike the VEA, the OEA must fully model the effect an interrupt
35    has on the processors state.
36 
37    Each function below return updated values for registers effected by
38    interrupts */
39 
40 
41 STATIC_INLINE_INTERRUPTS\
42 (msreg)
43 interrupt_msr(msreg old_msr,
44 	      msreg msr_clear,
45 	      msreg msr_set)
46 {
47   msreg msr_set_to_0 = (msr_branch_trace_enable
48 			| msr_data_relocate
49 			| msr_external_interrupt_enable
50 			| msr_floating_point_exception_mode_0
51 			| msr_floating_point_exception_mode_1
52 			| msr_floating_point_available
53 			| msr_instruction_relocate
54 			| msr_power_management_enable
55 			| msr_problem_state
56 			| msr_recoverable_interrupt
57 			| msr_single_step_trace_enable);
58   /* remember, in 32bit mode msr_64bit_mode is zero */
59   msreg new_msr = ((((old_msr & ~msr_set_to_0)
60 		     | msr_64bit_mode)
61 		    & ~msr_clear)
62 		   | msr_set);
63   return new_msr;
64 }
65 
66 
67 STATIC_INLINE_INTERRUPTS\
68 (msreg)
69 interrupt_srr1(msreg old_msr,
70 	       msreg srr1_clear,
71 	       msreg srr1_set)
72 {
73   spreg srr1_mask = (MASK(0,32)
74 		     | MASK(37, 41)
75 		     | MASK(48, 63));
76   spreg srr1 = (old_msr & srr1_mask & ~srr1_clear) | srr1_set;
77   return srr1;
78 }
79 
80 
81 STATIC_INLINE_INTERRUPTS\
82 (unsigned_word)
83 interrupt_base_ea(msreg msr)
84 {
85   if (msr & msr_interrupt_prefix)
86     return MASK(0, 43);
87   else
88     return 0;
89 }
90 
91 
92 /* finish off an interrupt for the OEA model, updating all registers
93    and forcing a restart of the processor */
94 
95 STATIC_INLINE_INTERRUPTS\
96 (unsigned_word)
97 perform_oea_interrupt(cpu *processor,
98 		      unsigned_word cia,
99 		      unsigned_word vector_offset,
100 		      msreg msr_clear,
101 		      msreg msr_set,
102 		      msreg srr1_clear,
103 		      msreg srr1_set)
104 {
105   msreg old_msr = MSR;
106   msreg new_msr = interrupt_msr(old_msr, msr_clear, msr_set);
107   unsigned_word nia;
108   if (!(old_msr & msr_recoverable_interrupt)) {
109     cpu_error(processor, cia,
110 	      "double interrupt - MSR[RI] bit clear when attempting to deliver interrupt, cia=0x%lx, msr=0x%lx; srr0=0x%lx(cia), srr1=0x%lx(msr); trap-vector=0x%lx, trap-msr=0x%lx",
111 	      (unsigned long)cia,
112 	      (unsigned long)old_msr,
113 	      (unsigned long)SRR0,
114 	      (unsigned long)SRR1,
115 	      (unsigned long)vector_offset,
116 	      (unsigned long)new_msr);
117   }
118   SRR0 = (spreg)(cia);
119   SRR1 = interrupt_srr1(old_msr, srr1_clear, srr1_set);
120   MSR = new_msr;
121   nia = interrupt_base_ea(new_msr) + vector_offset;
122   cpu_synchronize_context(processor, cia);
123   return nia;
124 }
125 
126 
127 INLINE_INTERRUPTS\
128 (void)
129 machine_check_interrupt(cpu *processor,
130 			unsigned_word cia)
131 {
132   switch (CURRENT_ENVIRONMENT) {
133 
134   case USER_ENVIRONMENT:
135   case VIRTUAL_ENVIRONMENT:
136     cpu_error(processor, cia, "machine-check interrupt");
137 
138   case OPERATING_ENVIRONMENT:
139     TRACE(trace_interrupts, ("machine-check interrupt - cia=0x%lx\n",
140 			     (unsigned long)cia));
141     cia = perform_oea_interrupt(processor, cia, 0x00200, 0, 0, 0, 0);
142     cpu_restart(processor, cia);
143 
144   default:
145     error("internal error - machine_check_interrupt - bad switch");
146 
147   }
148 }
149 
150 
151 INLINE_INTERRUPTS\
152 (void)
153 data_storage_interrupt(cpu *processor,
154 		       unsigned_word cia,
155 		       unsigned_word ea,
156 		       storage_interrupt_reasons reason,
157 		       int is_store)
158 {
159   switch (CURRENT_ENVIRONMENT) {
160 
161   case USER_ENVIRONMENT:
162   case VIRTUAL_ENVIRONMENT:
163     error("internal error - data_storage_interrupt - should not be called in VEA mode");
164     break;
165 
166   case OPERATING_ENVIRONMENT:
167     {
168       spreg direction = (is_store ? dsisr_store_operation : 0);
169       switch (reason) {
170       case direct_store_storage_interrupt:
171 	DSISR = dsisr_direct_store_error_exception | direction;
172 	break;
173       case hash_table_miss_storage_interrupt:
174 	DSISR = dsisr_hash_table_or_dbat_miss | direction;
175 	break;
176       case protection_violation_storage_interrupt:
177 	DSISR = dsisr_protection_violation | direction;
178 	break;
179       case earwax_violation_storage_interrupt:
180 	DSISR = dsisr_earwax_violation | direction;
181 	break;
182       case segment_table_miss_storage_interrupt:
183 	DSISR = dsisr_segment_table_miss | direction;
184 	break;
185       case earwax_disabled_storage_interrupt:
186 	DSISR = dsisr_earwax_disabled | direction;
187 	break;
188       default:
189 	error("internal error - data_storage_interrupt - reason %d not implemented", reason);
190 	break;
191       }
192       DAR = (spreg)ea;
193       TRACE(trace_interrupts, ("data storage interrupt - cia=0x%lx DAR=0x%lx DSISR=0x%lx\n",
194 			       (unsigned long)cia,
195 			       (unsigned long)DAR,
196 			       (unsigned long)DSISR));
197       cia = perform_oea_interrupt(processor, cia, 0x00300, 0, 0, 0, 0);
198       cpu_restart(processor, cia);
199     }
200 
201   default:
202     error("internal error - data_storage_interrupt - bad switch");
203 
204   }
205 }
206 
207 
208 INLINE_INTERRUPTS\
209 (void)
210 instruction_storage_interrupt(cpu *processor,
211 			      unsigned_word cia,
212 			      storage_interrupt_reasons reason)
213 {
214   switch (CURRENT_ENVIRONMENT) {
215 
216   case USER_ENVIRONMENT:
217   case VIRTUAL_ENVIRONMENT:
218     error("internal error - instruction_storage_interrupt - should not be called in VEA mode");
219 
220   case OPERATING_ENVIRONMENT:
221     {
222       msreg srr1_set;
223       switch(reason) {
224       case hash_table_miss_storage_interrupt:
225 	srr1_set = srr1_hash_table_or_ibat_miss;
226 	break;
227       case direct_store_storage_interrupt:
228 	srr1_set = srr1_direct_store_error_exception;
229 	break;
230       case protection_violation_storage_interrupt:
231 	srr1_set = srr1_protection_violation;
232 	break;
233       case segment_table_miss_storage_interrupt:
234 	srr1_set = srr1_segment_table_miss;
235 	break;
236       default:
237 	srr1_set = 0;
238 	error("internal error - instruction_storage_interrupt - reason %d not implemented");
239 	break;
240       }
241       TRACE(trace_interrupts, ("instruction storage interrupt - cia=0x%lx SRR1|=0x%lx\n",
242 			       (unsigned long)cia,
243 			       (unsigned long)srr1_set));
244       cia = perform_oea_interrupt(processor, cia, 0x00400, 0, 0, 0, srr1_set);
245       cpu_restart(processor, cia);
246     }
247 
248   default:
249     error("internal error - instruction_storage_interrupt - bad switch");
250 
251   }
252 }
253 
254 
255 
256 INLINE_INTERRUPTS\
257 (void)
258 alignment_interrupt(cpu *processor,
259 		    unsigned_word cia,
260 		    unsigned_word ra)
261 {
262   switch (CURRENT_ENVIRONMENT) {
263 
264   case USER_ENVIRONMENT:
265   case VIRTUAL_ENVIRONMENT:
266     cpu_error(processor, cia, "alignment interrupt - ra=0x%lx", ra);
267 
268   case OPERATING_ENVIRONMENT:
269     DAR = (spreg)ra;
270     DSISR = 0; /* FIXME */
271     TRACE(trace_interrupts, ("alignment interrupt - cia=0x%lx DAR=0x%lx DSISR=0x%lx\n",
272 			     (unsigned long)cia,
273 			     (unsigned long)DAR,
274 			     (unsigned long)DSISR));
275     cia = perform_oea_interrupt(processor, cia, 0x00600, 0, 0, 0, 0);
276     cpu_restart(processor, cia);
277 
278   default:
279     error("internal error - alignment_interrupt - bad switch");
280 
281   }
282 }
283 
284 
285 
286 
287 INLINE_INTERRUPTS\
288 (void)
289 program_interrupt(cpu *processor,
290 		  unsigned_word cia,
291 		  program_interrupt_reasons reason)
292 {
293   switch (CURRENT_ENVIRONMENT) {
294 
295   case USER_ENVIRONMENT:
296   case VIRTUAL_ENVIRONMENT:
297     switch (reason) {
298     case floating_point_enabled_program_interrupt:
299       cpu_error(processor, cia, "program interrupt - %s",
300 		"floating point enabled");
301       break;
302     case illegal_instruction_program_interrupt:
303       cpu_error(processor, cia, "program interrupt - %s",
304 		"illegal instruction");
305       break;
306     case privileged_instruction_program_interrupt:
307       cpu_error(processor, cia, "program interrupt - %s",
308 		"privileged instruction");
309       break;
310     case trap_program_interrupt:
311       cpu_error(processor, cia, "program interrupt - %s",
312 		"trap");
313       break;
314     case optional_instruction_program_interrupt:
315       cpu_error(processor, cia, "program interrupt - %s",
316 		"illegal instruction (optional instruction not supported)");
317       break;
318     case mpc860c0_instruction_program_interrupt:
319       cpu_error(processor, cia, "program interrupt - %s",
320         	"problematic branch detected, see MPC860 C0 errata");
321       break;
322     default:
323       error("internal error - program_interrupt - reason %d not implemented", reason);
324     }
325 
326   case OPERATING_ENVIRONMENT:
327     {
328       msreg srr1_set;
329       switch (reason) {
330       case floating_point_enabled_program_interrupt:
331 	srr1_set = srr1_floating_point_enabled;
332 	break;
333       case optional_instruction_program_interrupt:
334       case illegal_instruction_program_interrupt:
335 	srr1_set = srr1_illegal_instruction;
336 	break;
337       case privileged_instruction_program_interrupt:
338 	srr1_set = srr1_priviliged_instruction;
339 	break;
340       case trap_program_interrupt:
341 	srr1_set = srr1_trap;
342 	break;
343       case mpc860c0_instruction_program_interrupt:
344         srr1_set = 0;
345         cpu_error(processor, cia, "program interrupt - %s",
346               "problematic branch detected, see MPC860 C0 errata");
347         break;
348       default:
349 	srr1_set = 0;
350 	error("internal error - program_interrupt - reason %d not implemented", reason);
351 	break;
352       }
353       TRACE(trace_interrupts, ("program interrupt - cia=0x%lx SRR1|=0x%lx\n",
354 			       (unsigned long)cia,
355 			       (unsigned long)srr1_set));
356       cia = perform_oea_interrupt(processor, cia, 0x00700, 0, 0, 0, srr1_set);
357       cpu_restart(processor, cia);
358     }
359 
360   default:
361     error("internal error - program_interrupt - bad switch");
362 
363   }
364 }
365 
366 
367 INLINE_INTERRUPTS\
368 (void)
369 floating_point_unavailable_interrupt(cpu *processor,
370 				     unsigned_word cia)
371 {
372   switch (CURRENT_ENVIRONMENT) {
373 
374   case USER_ENVIRONMENT:
375   case VIRTUAL_ENVIRONMENT:
376     cpu_error(processor, cia, "floating-point unavailable interrupt");
377 
378   case OPERATING_ENVIRONMENT:
379     TRACE(trace_interrupts, ("floating-point unavailable interrupt - cia=0x%lx\n",
380 			     (unsigned long)cia));
381     cia = perform_oea_interrupt(processor, cia, 0x00800, 0, 0, 0, 0);
382     cpu_restart(processor, cia);
383 
384   default:
385     error("internal error - floating_point_unavailable_interrupt - bad switch");
386 
387   }
388 }
389 
390 
391 INLINE_INTERRUPTS\
392 (void)
393 system_call_interrupt(cpu *processor,
394 		      unsigned_word cia)
395 {
396   TRACE(trace_interrupts, ("system-call interrupt - cia=0x%lx\n", (unsigned long)cia));
397 
398   switch (CURRENT_ENVIRONMENT) {
399 
400   case USER_ENVIRONMENT:
401   case VIRTUAL_ENVIRONMENT:
402     os_emul_system_call(processor, cia);
403     cpu_restart(processor, cia+4);
404 
405   case OPERATING_ENVIRONMENT:
406     cia = perform_oea_interrupt(processor, cia+4, 0x00c00, 0, 0, 0, 0);
407     cpu_restart(processor, cia);
408 
409   default:
410     error("internal error - system_call_interrupt - bad switch");
411 
412   }
413 }
414 
415 INLINE_INTERRUPTS\
416 (void)
417 floating_point_assist_interrupt(cpu *processor,
418 				unsigned_word cia)
419 {
420   switch (CURRENT_ENVIRONMENT) {
421 
422   case USER_ENVIRONMENT:
423   case VIRTUAL_ENVIRONMENT:
424     cpu_error(processor, cia, "floating-point assist interrupt");
425 
426   case OPERATING_ENVIRONMENT:
427     TRACE(trace_interrupts, ("floating-point assist interrupt - cia=0x%lx\n", (unsigned long)cia));
428     cia = perform_oea_interrupt(processor, cia, 0x00e00, 0, 0, 0, 0);
429     cpu_restart(processor, cia);
430 
431   default:
432     error("internal error - floating_point_assist_interrupt - bad switch");
433 
434   }
435 }
436 
437 
438 
439 /* handle an externally generated event or an interrupt that has just
440    been enabled through changes to the MSR. */
441 
442 STATIC_INLINE_INTERRUPTS\
443 (void)
444 deliver_hardware_interrupt(void *data)
445 {
446   cpu *processor = (cpu*)data;
447   interrupts *ints = cpu_interrupts(processor);
448   ints->delivery_scheduled = NULL;
449   if ((cpu_registers(processor)->msr & (msr_floating_point_exception_mode_0
450 					| msr_floating_point_exception_mode_1))
451       && cpu_registers(processor)->fpscr & fpscr_fex) {
452     msreg srr1_set = srr1_floating_point_enabled | srr1_subsequent_instruction;
453     unsigned_word cia = cpu_get_program_counter(processor);
454     unsigned_word nia = perform_oea_interrupt(processor,
455 					      cia, 0x00700, 0, 0, 0, srr1_set);
456     cpu_set_program_counter(processor, nia);
457   }
458   else if (cpu_registers(processor)->msr & msr_external_interrupt_enable) {
459     /* external interrupts have a high priority and remain pending */
460     if (ints->pending_interrupts & external_interrupt_pending) {
461       unsigned_word cia = cpu_get_program_counter(processor);
462       unsigned_word nia = perform_oea_interrupt(processor,
463 						cia, 0x00500, 0, 0, 0, 0);
464       TRACE(trace_interrupts, ("external interrupt - cia=0x%lx\n", (unsigned long)cia));
465       cpu_set_program_counter(processor, nia);
466     }
467     /* decrementer interrupts have a lower priority and are once only */
468     else if (ints->pending_interrupts & decrementer_interrupt_pending) {
469       unsigned_word cia = cpu_get_program_counter(processor);
470       unsigned_word nia = perform_oea_interrupt(processor,
471 						cia, 0x00900, 0, 0, 0, 0);
472       TRACE(trace_interrupts, ("decrementer interrupt - cia 0x%lx, time %ld\n",
473 			       (unsigned long)cia,
474 			       (unsigned long)event_queue_time(psim_event_queue(cpu_system(processor)))
475 			       ));
476       cpu_set_program_counter(processor, nia);
477       ints->pending_interrupts &= ~decrementer_interrupt_pending;
478     }
479   }
480 }
481 
482 STATIC_INLINE_INTERRUPTS\
483 (void)
484 schedule_hardware_interrupt_delivery(cpu *processor)
485 {
486   interrupts *ints = cpu_interrupts(processor);
487   if (ints->delivery_scheduled == NULL) {
488     ints->delivery_scheduled =
489       event_queue_schedule(psim_event_queue(cpu_system(processor)),
490 			   0, deliver_hardware_interrupt, processor);
491   }
492 }
493 
494 
495 INLINE_INTERRUPTS\
496 (void)
497 check_masked_interrupts(cpu *processor)
498 {
499   if (((cpu_registers(processor)->msr & (msr_floating_point_exception_mode_0
500 					 | msr_floating_point_exception_mode_1))
501        && cpu_registers(processor)->fpscr & fpscr_fex)
502       || ((cpu_registers(processor)->msr & msr_external_interrupt_enable)
503 	  && (cpu_interrupts(processor)->pending_interrupts)))
504     schedule_hardware_interrupt_delivery(processor);
505 }
506 
507 INLINE_INTERRUPTS\
508 (void)
509 decrementer_interrupt(cpu *processor)
510 {
511   interrupts *ints = cpu_interrupts(processor);
512   ints->pending_interrupts |= decrementer_interrupt_pending;
513   if (cpu_registers(processor)->msr & msr_external_interrupt_enable) {
514     schedule_hardware_interrupt_delivery(processor);
515   }
516 }
517 
518 INLINE_INTERRUPTS\
519 (void)
520 external_interrupt(cpu *processor,
521 		   int is_asserted)
522 {
523   interrupts *ints = cpu_interrupts(processor);
524   if (is_asserted) {
525     if (!(ints->pending_interrupts & external_interrupt_pending)) {
526       ints->pending_interrupts |= external_interrupt_pending;
527       if (cpu_registers(processor)->msr & msr_external_interrupt_enable)
528 	schedule_hardware_interrupt_delivery(processor);
529     }
530     else {
531       /* check that we haven't missed out on a chance to deliver an
532          interrupt */
533       ASSERT(!(cpu_registers(processor)->msr & msr_external_interrupt_enable));
534     }
535   }
536   else {
537     ints->pending_interrupts &= ~external_interrupt_pending;
538   }
539 }
540 
541 #endif /* _INTERRUPTS_C_ */
542