source: rtems/c/src/exec/score/cpu/powerpc/cpu.c @ 086836e1

4.104.114.84.95
Last change on this file since 086836e1 was 086836e1, checked in by Joel Sherrill <joel.sherrill@…>, on 10/01/98 at 18:50:43

Patch from Thomas Doerfler <td@…> to improve 403 support.

  • c/src/exec/score/cpu/powerpc/ppc.h: some small changes (added ppc403 characteristics like a exception vector prefix register, some special register definitions). I am quite sure, they are compatible with the existing sources, although I did not check
  • c/src/exec/score/cpu/powerpc/cpu.c: There is one severe limitation in the exception entries: Due to the current code arrangement, the "branch absolute" to the ISR handler may only jump to the first 128MByte or the last 128MByte of the 4GByte address range. When the ppc403 is running out of ROM, the ROM functions are located in the last 128MByte (0xFFF00000 and up). These addresses were not handled correctly (sign reduced) in "install_raw_handler". The change I added should work on existing ppc BSPs aswell...
  • Property mode set to 100644
File size: 15.6 KB
Line 
1/*
2 *  PowerPC CPU Dependent Source
3 *
4 *  Author:     Andrew Bray <andy@i-cubed.co.uk>
5 *
6 *  COPYRIGHT (c) 1995 by i-cubed ltd.
7 *
8 *  To anyone who acknowledges that this file is provided "AS IS"
9 *  without any express or implied warranty:
10 *      permission to use, copy, modify, and distribute this file
11 *      for any purpose is hereby granted without fee, provided that
12 *      the above copyright notice and this notice appears in all
13 *      copies, and that the name of i-cubed limited not be used in
14 *      advertising or publicity pertaining to distribution of the
15 *      software without specific, written prior permission.
16 *      i-cubed limited makes no representations about the suitability
17 *      of this software for any purpose.
18 *
19 *  Derived from c/src/exec/cpu/no_cpu/cpu.c:
20 *
21 *  COPYRIGHT (c) 1989-1997.
22 *  On-Line Applications Research Corporation (OAR).
23 *  Copyright assigned to U.S. Government, 1994.
24 *
25 *  The license and distribution terms for this file may be found in
26 *  the file LICENSE in this distribution or at
27 *  http://www.OARcorp.com/rtems/license.html.
28 *
29 *  $Id$
30 */
31
32#include <rtems/system.h>
33#include <rtems/score/isr.h>
34#include <rtems/score/context.h>
35#include <rtems/score/thread.h>
36#include <rtems/score/interr.h>
37
38/*
39 *  These are for testing purposes.
40 */
41
42/*  _CPU_Initialize
43 *
44 *  This routine performs processor dependent initialization.
45 *
46 *  INPUT PARAMETERS:
47 *    cpu_table       - CPU table to initialize
48 *    thread_dispatch - address of disptaching routine
49 */
50
51static void ppc_spurious(int, CPU_Interrupt_frame *);
52
53void _CPU_Initialize(
54  rtems_cpu_table  *cpu_table,
55  void      (*thread_dispatch)      /* ignored on this CPU */
56)
57{
58  proc_ptr handler = (proc_ptr)ppc_spurious;
59  int i;
60#if (PPC_ABI != PPC_ABI_POWEROPEN)
61  register unsigned32 r2 = 0;
62#if (PPC_ABI != PPC_ABI_GCC27)
63  register unsigned32 r13 = 0;
64
65  asm ("mr %0,13" : "=r" ((r13)) : "0" ((r13)));
66  _CPU_IRQ_info.Default_r13 = r13;
67#endif
68
69  asm ("mr %0,2" : "=r" ((r2)) : "0" ((r2)));
70  _CPU_IRQ_info.Default_r2 = r2;
71#endif
72
73  _CPU_IRQ_info.Nest_level = &_ISR_Nest_level;
74  _CPU_IRQ_info.Disable_level = &_Thread_Dispatch_disable_level;
75  _CPU_IRQ_info.Vector_table = _ISR_Vector_table;
76#if (PPC_ABI == PPC_ABI_POWEROPEN)
77  _CPU_IRQ_info.Dispatch_r2 = ((unsigned32 *)_Thread_Dispatch)[1];
78#endif
79  _CPU_IRQ_info.Switch_necessary = &_Context_Switch_necessary;
80  _CPU_IRQ_info.Signal = &_ISR_Signals_to_thread_executing;
81
82#if (PPC_USE_SPRG)
83  i = (int)&_CPU_IRQ_info;
84  asm volatile("mtspr 0x113, %0" : "=r" (i) : "0" (i)); /* SPRG 3 */
85#endif
86
87  /*
88   * Store Msr Value in the IRQ info structure.
89   */
90   _CPU_MSR_Value(_CPU_IRQ_info.msr_initial);
91 
92#if (PPC_USE_SPRG)
93  i = _CPU_IRQ_info.msr_initial;
94  asm volatile("mtspr 0x112, %0" : "=r" (i) : "0" (i)); /* SPRG 2 */
95#endif
96
97  if ( cpu_table->spurious_handler )
98    handler = (proc_ptr)cpu_table->spurious_handler;
99
100  for (i = 0; i < PPC_INTERRUPT_MAX;  i++)
101    _ISR_Vector_table[i] = handler;
102
103  _CPU_Table = *cpu_table;
104}
105
106/*PAGE
107 *
108 *  _CPU_ISR_Calculate_level
109 *
110 *  The PowerPC puts its interrupt enable status in the MSR register
111 *  which also contains things like endianness control.  To be more
112 *  awkward, the layout varies from processor to processor.  This
113 *  is why it was necessary to adopt a scheme which allowed the user
114 *  to specify specifically which interrupt sources were enabled.
115 */
116 
117unsigned32 _CPU_ISR_Calculate_level(
118  unsigned32 new_level
119)
120{
121  register unsigned32 new_msr = 0;
122
123  /*
124   *  Set the critical interrupt enable bit
125   */
126
127#if (PPC_HAS_RFCI)
128  if ( !(new_level & PPC_INTERRUPT_LEVEL_CE) )
129    new_msr |= PPC_MSR_CE;
130#endif
131
132  if ( !(new_level & PPC_INTERRUPT_LEVEL_ME) )
133    new_msr |= PPC_MSR_ME;
134
135  if ( !(new_level & PPC_INTERRUPT_LEVEL_EE) )
136    new_msr |= PPC_MSR_EE;
137
138  return new_msr;
139}
140
141/*PAGE
142 *
143 *  _CPU_ISR_Set_level
144 *
145 *  This routine sets the requested level in the MSR.
146 */
147
148void _CPU_ISR_Set_level(
149  unsigned32 new_level
150)
151{
152  register unsigned32 tmp = 0;
153  register unsigned32 new_msr;
154
155  new_msr = _CPU_ISR_Calculate_level( new_level );
156
157  asm volatile (
158    "mfmsr %0; andc %0,%0,%1; and %2, %2, %1; or %0, %0, %2; mtmsr %0" :
159    "=&r" ((tmp)) :
160    "r" ((PPC_MSR_DISABLE_MASK)), "r" ((new_msr)), "0" ((tmp))
161  );
162}
163
164/*PAGE
165 *
166 *  _CPU_ISR_Get_level
167 *
168 *  This routine gets the current interrupt level from the MSR and
169 *  converts it to an RTEMS interrupt level.
170 */
171
172unsigned32 _CPU_ISR_Get_level( void )
173{
174  unsigned32 level = 0;
175  unsigned32 msr;
176 
177  asm volatile("mfmsr %0" : "=r" ((msr)));
178 
179  msr &= PPC_MSR_DISABLE_MASK;
180
181  /*
182   *  Set the critical interrupt enable bit
183   */
184
185#if (PPC_HAS_RFCI)
186  if ( !(msr & PPC_MSR_CE) )
187    level |= PPC_INTERRUPT_LEVEL_CE;
188#endif
189
190  if ( !(msr & PPC_MSR_ME) )
191    level |= PPC_INTERRUPT_LEVEL_ME;
192
193  if ( !(msr & PPC_MSR_EE) )
194    level |= PPC_INTERRUPT_LEVEL_EE;
195
196  return level;
197}
198
199/*PAGE
200 *
201 *  _CPU_Context_Initialize
202 */
203
204#if (PPC_ABI == PPC_ABI_POWEROPEN)
205#define CPU_MINIMUM_STACK_FRAME_SIZE 56
206#else /* PPC_ABI_SVR4 or PPC_ABI_EABI */
207#define CPU_MINIMUM_STACK_FRAME_SIZE 8
208#endif
209
210void _CPU_Context_Initialize(
211  Context_Control  *the_context,
212  unsigned32       *stack_base,
213  unsigned32        size,
214  unsigned32        new_level,
215  void             *entry_point,
216  boolean           is_fp
217)
218{
219  unsigned32 msr_value;
220  unsigned32 sp;
221
222  sp = (unsigned32)stack_base + size - CPU_MINIMUM_STACK_FRAME_SIZE;
223  *((unsigned32 *)sp) = 0;
224  the_context->gpr1 = sp;
225   
226  the_context->msr = _CPU_ISR_Calculate_level( new_level );
227
228  /*
229   *  The FP bit of the MSR should only be enabled if this is a floating
230   *  point task.  Unfortunately, the vfprintf_r routine in newlib
231   *  ends up pushing a floating point register regardless of whether or
232   *  not a floating point number is being printed.  Serious restructuring
233   *  of vfprintf.c will be required to avoid this behavior.  At this
234   *  time (7 July 1997), this restructuring is not being done.
235   */
236
237  /*if ( is_fp ) */
238    the_context->msr |= PPC_MSR_FP;
239
240  /*
241   *  Calculate the task's MSR value:
242   *
243   *     + Set the exception prefix bit to point to the exception table
244   *     + Force the RI bit
245   *     + Use the DR and IR bits
246   */
247  _CPU_MSR_Value( msr_value );
248  the_context->msr |= (msr_value & PPC_MSR_EP);
249  the_context->msr |= PPC_MSR_RI;
250  the_context->msr |= msr_value & (PPC_MSR_DR|PPC_MSR_IR);
251
252#if (PPC_ABI == PPC_ABI_POWEROPEN)
253  { unsigned32 *desc = (unsigned32 *)entry_point;
254
255    the_context->pc = desc[0];
256    the_context->gpr2 = desc[1];
257  }
258#endif
259
260#if (PPC_ABI == PPC_ABI_SVR4)
261  { unsigned    r13 = 0;
262    asm volatile ("mr %0, 13" : "=r" ((r13)));
263   
264    the_context->pc = (unsigned32)entry_point;
265    the_context->gpr13 = r13;
266  }
267#endif
268
269#if (PPC_ABI == PPC_ABI_EABI)
270  { unsigned32  r2 = 0;
271    unsigned    r13 = 0;
272    asm volatile ("mr %0,2; mr %1,13" : "=r" ((r2)), "=r" ((r13)));
273 
274    the_context->pc = (unsigned32)entry_point;
275    the_context->gpr2 = r2;
276    the_context->gpr13 = r13;
277  }
278#endif
279}
280
281
282/*  _CPU_ISR_install_vector
283 *
284 *  This kernel routine installs the RTEMS handler for the
285 *  specified vector.
286 *
287 *  Input parameters:
288 *    vector      - interrupt vector number
289 *    old_handler - former ISR for this vector number
290 *    new_handler - replacement ISR for this vector number
291 *
292 *  Output parameters:  NONE
293 *
294 */
295
296void _CPU_ISR_install_vector(
297  unsigned32  vector,
298  proc_ptr    new_handler,
299  proc_ptr   *old_handler
300)
301{
302   proc_ptr   ignored;
303   *old_handler = _ISR_Vector_table[ vector ];
304
305   /*
306    *  If the interrupt vector table is a table of pointer to isr entry
307    *  points, then we need to install the appropriate RTEMS interrupt
308    *  handler for this vector number.
309    */
310
311   /*
312    * Install the wrapper so this ISR can be invoked properly.
313    */
314   if (_CPU_Table.exceptions_in_RAM)
315      _CPU_ISR_install_raw_handler( vector, _ISR_Handler, &ignored );
316
317   /*
318    *  We put the actual user ISR address in '_ISR_vector_table'.  This will
319    *  be used by the _ISR_Handler so the user gets control.
320    */
321
322    _ISR_Vector_table[ vector ] = new_handler ? (ISR_Handler_entry)new_handler :
323       _CPU_Table.spurious_handler ?
324          (ISR_Handler_entry)_CPU_Table.spurious_handler :
325          (ISR_Handler_entry)ppc_spurious;
326}
327
328/*PAGE
329 *
330 *  _CPU_Install_interrupt_stack
331 */
332
333void _CPU_Install_interrupt_stack( void )
334{
335#if (PPC_ABI == PPC_ABI_POWEROPEN || PPC_ABI == PPC_ABI_GCC27)
336  _CPU_IRQ_info.Stack = _CPU_Interrupt_stack_high - 56;
337#else
338  _CPU_IRQ_info.Stack = _CPU_Interrupt_stack_high - 8;
339#endif
340}
341
342/* Handle a spurious interrupt */
343static void ppc_spurious(int v, CPU_Interrupt_frame *i)
344{
345#if 0
346    printf("Spurious interrupt on vector %d from %08.8x\n",
347           v, i->pc);
348#endif
349#ifdef ppc403
350    if (v == PPC_IRQ_EXTERNAL)
351        {
352            register int r = 0;
353
354            asm volatile("mtdcr 0x42, %0" :
355                "=&r" ((r)) : "0" ((r))); /* EXIER */
356        }
357    else if (v == PPC_IRQ_PIT)
358        {
359            register int r = 0x08000000;
360
361            asm volatile("mtspr 0x3d8, %0" :
362                "=&r" ((r)) : "0" ((r))); /* TSR */
363        }
364    else if (v == PPC_IRQ_FIT)
365        {
366            register int r = 0x04000000;
367
368            asm volatile("mtspr 0x3d8, %0" :
369                "=&r" ((r)) : "0" ((r))); /* TSR */
370        }
371#endif
372}
373
374void _CPU_Fatal_error(unsigned32 _error)
375{
376  asm volatile ("mr 3, %0" : : "r" ((_error)));
377  asm volatile ("tweq 5,5");
378  asm volatile ("li 0,0; mtmsr 0");
379  while (1) ;
380}
381
382#define PPC_SYNCHRONOUS_TRAP_BIT_MASK    0x100
383#define PPC_ASYNCHRONOUS_TRAP( _trap ) (_trap)
384#define PPC_SYNCHRONOUS_TRAP ( _trap ) ((_trap)+PPC_SYNCHRONOUS_TRAP_BIT_MASK)
385#define PPC_REAL_TRAP_NUMBER ( _trap ) ((_trap)%PPC_SYNCHRONOUS_TRAP_BIT_MASK)
386
387
388const CPU_Trap_table_entry _CPU_Trap_slot_template = {
389
390#if (PPC_ABI == PPC_ABI_POWEROPEN || PPC_ABI == PPC_ABI_GCC27)
391#error " Vector install not tested."
392#if (PPC_HAS_FPU)
393#error " Vector install not tested."
394  0x9421feb0,           /* stwu r1, -(20*4 + 18*8 + IP_END)(r1) */
395#else
396#error " Vector install not tested."
397  0x9421ff40,           /* stwu    r1, -(20*4 + IP_END)(r1)     */
398#endif
399#else
400  0x9421ff90,           /* stwu    r1, -(IP_END)(r1)            */
401#endif
402
403  0x90010008,           /* stw   %r0, IP_0(%r1)                 */
404  0x38000000,           /* li    %r0, PPC_IRQ                   */
405  0x48000002            /* ba    PROC (_ISR_Handler)            */
406};
407
408unsigned32  ppc_exception_vector_addr(
409  unsigned32 vector
410);
411
412
413/*PAGE
414 *
415 *  _CPU_ISR_install_raw_handler
416 *
417 *  This routine installs the specified handler as a "raw" non-executive
418 *  supported trap handler (a.k.a. interrupt service routine).
419 *
420 *  Input Parameters:
421 *    vector      - trap table entry number plus synchronous
422 *                    vs. asynchronous information
423 *    new_handler - address of the handler to be installed
424 *    old_handler - pointer to an address of the handler previously installed
425 *
426 *  Output Parameters: NONE
427 *    *new_handler - address of the handler previously installed
428 *
429 *  NOTE:
430 *
431 *  This routine is based on the SPARC routine _CPU_ISR_install_raw_handler.
432 *  Install a software trap handler as an executive interrupt handler
433 *  (which is desirable since RTEMS takes care of window and register issues),
434 *  then the executive needs to know that the return address is to the trap
435 *  rather than the instruction following the trap.
436 *
437 */
438 
439void _CPU_ISR_install_raw_handler(
440  unsigned32  vector,
441  proc_ptr    new_handler,
442  proc_ptr   *old_handler
443)
444{
445  unsigned32             real_vector;
446  CPU_Trap_table_entry  *slot;
447  unsigned32             u32_handler=0;
448
449  /*
450   *  Get the "real" trap number for this vector ignoring the synchronous
451   *  versus asynchronous indicator included with our vector numbers.
452   */
453
454  real_vector = vector;
455
456  /*
457   *  Get the current base address of the trap table and calculate a pointer
458   *  to the slot we are interested in.
459   */
460  slot = (CPU_Trap_table_entry  *)ppc_exception_vector_addr( real_vector );
461
462  /*
463   *  Get the address of the old_handler from the trap table.
464   *
465   *  NOTE: The old_handler returned will be bogus if it does not follow
466   *        the RTEMS model.
467   */
468
469#define HIGH_BITS_MASK   0xFFFFFC00
470#define HIGH_BITS_SHIFT  10
471#define LOW_BITS_MASK    0x000003FF
472
473  if (slot->stwu_r1 == _CPU_Trap_slot_template.stwu_r1) {
474    /*
475     * Set u32_handler = to target address 
476     */
477    u32_handler = slot->b_Handler & 0x03fffffc;
478
479    /* IMD FIX: sign extend address fragment... */
480    if (u32_handler & 0x02000000) {
481      u32_handler  |= 0xfc000000;
482    }
483
484    *old_handler =  (proc_ptr) u32_handler;
485  } else
486    *old_handler = 0;
487
488  /*
489   *  Copy the template to the slot and then fix it.
490   */
491  *slot = _CPU_Trap_slot_template;
492
493  u32_handler = (unsigned32) new_handler;
494
495  /*
496   * IMD FIX: insert address fragment only (bits 6..29)
497   *          therefore check for proper address range
498   *          and remove unwanted bits
499   */
500  if ((u32_handler & 0xfc000000) == 0xfc000000) {
501    u32_handler  &= ~0xfc000000;
502  }
503  else if ((u32_handler & 0xfc000000) != 0x00000000) {
504    _Internal_error_Occurred(INTERNAL_ERROR_CORE,
505                             TRUE,
506                             u32_handler);
507  }
508
509  slot->b_Handler |= u32_handler;
510
511  slot->li_r0_IRQ  |= vector;
512
513  _CPU_Data_Cache_Block_Flush( slot );
514}
515
516unsigned32  ppc_exception_vector_addr(
517  unsigned32 vector
518)
519{
520#if (!PPC_HAS_EVPR)
521  unsigned32 Msr;
522#endif
523  unsigned32 Top = 0;
524  unsigned32 Offset = 0x000;
525
526#if (PPC_HAS_EXCEPTION_PREFIX)
527  _CPU_MSR_Value ( Msr );
528  if ( ( Msr & PPC_MSR_EP) != 0 ) /* Vectors at FFFx_xxxx */
529    Top = 0xfff00000;
530#elif (PPC_HAS_EVPR)
531  asm volatile( "mfspr %0,0x3d6" : "=r" (Top)); /* EVPR */
532  Top = Top & 0xffff0000;
533#endif
534
535  switch ( vector ) {
536    case PPC_IRQ_SYSTEM_RESET:   /* on 40x aka PPC_IRQ_CRIT */
537      Offset = 0x00100;
538      break;
539    case PPC_IRQ_MCHECK:
540      Offset = 0x00200;
541      break;
542    case PPC_IRQ_PROTECT:
543      Offset = 0x00300;
544      break;
545    case PPC_IRQ_ISI:
546      Offset = 0x00400;
547      break;
548    case PPC_IRQ_EXTERNAL:
549      Offset = 0x00500;
550      break;
551    case PPC_IRQ_ALIGNMENT:
552      Offset = 0x00600;
553      break;
554    case PPC_IRQ_PROGRAM:
555      Offset = 0x00700;
556      break;
557    case PPC_IRQ_NOFP:
558      Offset = 0x00800;
559      break;
560    case PPC_IRQ_DECREMENTER:
561      Offset = 0x00900;
562      break;
563    case PPC_IRQ_RESERVED_A:
564      Offset = 0x00a00;
565      break;
566    case PPC_IRQ_RESERVED_B:
567      Offset = 0x00b00;
568      break;
569    case PPC_IRQ_SCALL:
570      Offset = 0x00c00;
571      break;
572    case PPC_IRQ_TRACE:
573      Offset = 0x00d00;
574      break;
575    case PPC_IRQ_FP_ASST:
576      Offset = 0x00e00;
577      break;
578
579#if defined(ppc403)
580                                 
581/*  PPC_IRQ_CRIT is the same vector as PPC_IRQ_RESET
582    case PPC_IRQ_CRIT:
583      Offset = 0x00100;
584      break;
585*/
586    case PPC_IRQ_PIT:
587      Offset = 0x01000;
588      break;
589    case PPC_IRQ_FIT:
590      Offset = 0x01010;
591      break;
592    case PPC_IRQ_WATCHDOG:
593      Offset = 0x01020;
594      break;
595    case PPC_IRQ_DEBUG:
596      Offset = 0x02000;
597      break;
598
599#elif defined(ppc601)
600    case PPC_IRQ_TRACE:
601      Offset = 0x02000;
602      break;
603
604#elif defined(ppc603)
605    case PPC_IRQ_TRANS_MISS:
606      Offset = 0x1000;
607      break;
608    case PPC_IRQ_DATA_LOAD:
609      Offset = 0x1100;
610      break;
611    case PPC_IRQ_DATA_STORE:
612      Offset = 0x1200;
613      break;
614    case PPC_IRQ_ADDR_BRK:
615      Offset = 0x1300;
616      break;
617    case PPC_IRQ_SYS_MGT:
618      Offset = 0x1400;
619      break;
620
621#elif defined(ppc603e)
622    case PPC_TLB_INST_MISS:
623      Offset = 0x1000;
624      break;
625    case PPC_TLB_LOAD_MISS:
626      Offset = 0x1100;
627      break;
628    case PPC_TLB_STORE_MISS:
629      Offset = 0x1200;
630      break;
631    case PPC_IRQ_ADDRBRK:
632      Offset = 0x1300;
633      break;
634    case PPC_IRQ_SYS_MGT:
635      Offset = 0x1400;
636      break;
637
638#elif defined(ppc604)
639    case PPC_IRQ_ADDR_BRK:
640      Offset = 0x1300;
641      break;
642    case PPC_IRQ_SYS_MGT:
643      Offset = 0x1400;
644      break;
645#endif
646
647  }
648  Top += Offset;
649  return Top;
650}
651
Note: See TracBrowser for help on using the repository browser.