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