source: rtems/c/src/exec/score/cpu/powerpc/other_cpu/cpu.c @ ba46ffa6

4.104.114.84.95
Last change on this file since ba46ffa6 was ba46ffa6, checked in by Joel Sherrill <joel.sherrill@…>, on 06/14/99 at 16:51:13

This is a large patch from Eric Valette <valette@…> that was
described in the message following this paragraph. This patch also includes
a mcp750 BSP.

From valette@… Mon Jun 14 10:03:08 1999
Date: Tue, 18 May 1999 01:30:14 +0200 (CEST)
From: VALETTE Eric <valette@…>
To: joel@…
Cc: raguet@…, rtems-snapshots@…, valette@…
Subject: Questions/Suggestion? regarding RTEMS PowerPC code (long)

Dear knowledgeable RTEMS powerpc users,

As some of you may know, I'm currently finalizing a port
of RTEMS on a MCP750 Motorola board. I have done most
of it but have some questions to ask before submitting
the port.

In order to understand some of the changes I have made
or would like to make, maybe it is worth describing the
MCP750 Motorola board.

the MCP750 is a COMPACT PCI powerpc board with :

1) a MPC750 233 MHz processor,
2) a raven bus bridge/PCI controller that
implement an OPENPIC compliant interrupt controller,
3) a VIA 82C586 PCI/ISA bridge that offers a PC
compliant IO for keyboard, serial line, IDE, and
the well known PC 8259 cascaded PIC interrupt
architecture model,
4) a DEC 21140 Ethernet controller,
5) the PPCBUG Motorola firmware in flash,
6) A DEC PCI bridge,

This architecture is common to most Motorola 60x/7xx
board except that :

1) on VME board, the DEC PCI bridge is replaced by
a VME chipset,
2) the VIA 82C586 PCI/ISA bridge is replaced by
another bridge that is almost fully compatible
with the via bridge...

So the port should be a rather close basis for many
60x/7xx motorola board...

On this board, I already have ported Linux 2.2.3 and
use it both as a development and target board.

Now the questions/suggestions I have :

1) EXCEPTION CODE


As far as I know exceptions on PPC are handled like
interrupts. I dislike this very much as :

a) Except for the decrementer exception (and
maybe some other on mpc8xx), exceptions are
not recoverable and the handler just need to print
the full context and go to the firmware or debugger...
b) The interrupt switch is only necessary for the
decrementer and external interrupt (at least on
6xx,7xx).
c) The full context for exception is never saved and
thus cannot be used by debugger... I do understand
the most important for interrupts low level code
is to save the minimal context enabling to call C
code for performance reasons. On non recoverable
exception on the other hand, the most important is
to save the maximum information concerning proc status
in order to analyze the reason of the fault. At
least we will need this in order to implement the
port of RGDB on PPC

==> I wrote an API for connecting raw exceptions (and thus
raw interrupts) for mpc750. It should be valid for most
powerpc processors... I hope to find a way to make this coexist
with actual code layout. The code is actually located
in lib/libcpu/powerpc/mpc750 and is thus optional
(provided I write my own version of exec/score/cpu/powerpc/cpu.c ...)

See remark about files/directory layout organization in 4)

2) Current Implementation of ISR low level code


I do not understand why the MSR EE flags is cleared
again in exec/score/cpu/powerpc/irq_stubs.S

#if (PPC_USE_SPRG)

mfmsr r5
mfspr r6, sprg2

#else

lwz r6,msr_initial(r11)
lis r5,~PPC_MSR_DISABLE_MASK@ha
ori r5,r5,~PPC_MSR_DISABLE_MASK@l
and r6,r6,r5
mfmsr r5

#endif

Reading the doc, when a decrementer interrupt or an
external interrupt is active, the MSR EE flag is already
cleared. BTW if exception/interrupt could occur, it would
trash SRR0 and SRR1. In fact the code may be useful to set
MSR[RI] that re-enables exception processing. BTW I will need
to set other value in MSR to handle interrupts :

a) I want the MSR[IR] and MSR[DR] to be set for
performance reasons and also because I need DBAT
support to have access to PCI memory space as the
interrupt controller is in the PCI space.

Reading the code, I see others have the same kind of request :

/* SCE 980217

*

  • We need address translation ON when we call our ISR routine

mtmsr r5

*/

This is just another prof that even the lowest level
IRQ code is fundamentally board dependent and
not simply processor dependent especially when
the processor use external interrupt controller
because it has a single interrupt request line...

Note that if you look at the PPC code high level interrupt
handling code, as the "set_vector" routine that really connects
the interrupt is in the BSP/startup/genpvec.c,
the fact that IRQ handling is BSP specific is DE-FACTO
acknowledged.

I know I have already expressed this and understand that this
would require some heavy change in the code but believe
me you will reach a point where you will not be able
to find a compatible while optimum implementation for low level
interrupt handling code...) In my case this is already true...

So please consider removing low level IRQ handling from
exec/score/cpu/* and only let there exception handling code...
Exceptions are usually only processor dependent and do
not depend on external hardware mechanism to be masked or
acknowledged or re-enabled (there are probably exception but ...)

I have already done this for pc386 bsp but need to make it again.
This time I will even propose an API.

3) R2/R13 manipulation for EABI implementation


I do not understand the handling of r2 and r13 in the
EABI case. The specification for r2 says pointer to sdata2,
sbss2 section => constant. However I do not see -ffixed-r2
passed to any compilation system in make/custom/*
(for info linux does this on PPC).

So either this is a default compiler option when choosing
powerpc-rtems and thus we do not need to do anything with
this register as all the code is compiled with this compiler
and linked together OR this register may be used by rtems code
and then we do not need any special initialization or
handling.

The specification for r13 says pointer to the small data
area. r13 argumentation is the same except that as far
as I know the usage of the small data area requires
specific compiler support so that access to variables is
compiled via loading the LSB in a register and then
using r13 to get full address... It is like a small
memory model and it was present in IBM C compilers.

=> I propose to suppress any specific code for r2 and
r13 in the EABI case.

4) Code layout organization (yes again :-))


I think there are a number of design flaws in the way
the code is for ppc organized and I will try to point them out.
I have been beaten by this again on this new port, and
was beaten last year while modifying code for pc386.

a) exec/score/cpu/* vs lib/libcpu/cpu/*.

I think that too many things are put in exec/score/cpu that
have nothing to do with RTEMS internals but are rather
related to CPU feature.

This include at least :

a) registers access routine (e.g GET_MSR_Value),
b) interrupt masking/unmasking routines,
c) cache_mngt_routine,
d) mmu_mngt_routine,
e) Routines to connect the raw_exception, raw_interrupt
handler,

b) lib/libcpu/cpu/powerpc/*

With a processor family as exuberant as the powerpc family,
and their well known subtle differences (604 vs 750) or
unfortunately majors (8xx vs 60x) the directory structure
is fine (except maybe the names that are not homogeneous)

powerpc

ppc421 mpc821 ...

I only needed to add mpc750. But the fact that libcpu.a was not
produced was a pain and the fact that this organization may
duplicates code is also problematic.

So, except if the support of automake provides a better solution
I would like to propose something like this :

powerpc

mpc421 mpc821 ... mpc750 shared wrapup

with the following rules :

a) "shared" would act as a source container for sources that may
be shared among processors. Needed files would be compiled inside
the processor specific directory using the vpath Makefile
mechanism. "shared" may also contain compilation code
for routine that are really shared and not worth to inline...
(did not found many things so far as registers access routine
ARE WORTH INLINING)... In the case something is compiled there,
it should create libcpushared.a

b) layout under processor specific directory is free provided
that

1)the result of the compilation process exports :

libcpu/powerpc/"PROC"/*.h in $(PROJECT_INCLUDE)/libcpu

2) each processor specific directory creates
a library called libcpuspecific.a

Note that this organization enables to have a file that
is nearly the same than in shared but that must differ
because of processor differences...

c) "wrapup" should create libcpu.a using libcpushared.a
libcpuspecific.a and export it $(PROJECT_INCLUDE)/libcpu

The only thing I have no ideal solution is the way to put shared
definitions in "shared" and only processor specific definition
in "proc". To give a concrete example, most MSR bit definition
are shared among PPC processors and only some differs. if we create
a single msr.h in shared it will have ifdef. If in msr.h we
include libcpu/msr_c.h we will need to have it in each prowerpc
specific directory (even empty). Opinions are welcomed ...

Note that a similar mechanism exist in libbsp/i386 that also
contains a shared directory that is used by several bsp
like pc386 and i386ex and a similar wrapup mechanism...

NB: I have done this for mpc750 and other processors could just use
similar Makefiles...

c) The exec/score/cpu/powerpc directory layout.

I think the directory layout should be the same than the
libcpu/powerpc. As it is not, there are a lot of ifdefs
inside the code... And of course low level interrupt handling
code should be removed...

Besides that I do not understand why

1) things are compiled in the wrap directory,
2) some includes are moved to rtems/score,

I think the "preinstall" mechanism enables to put
everything in the current directory (or better in a per processor
directory),

5) Interrupt handling API


Again :-). But I think that using all the features the PIC
offers is a MUST for RT system. I already explained in the
prologue of this (long and probably boring) mail that the MCP750
boards offers an OPENPIC compliant architecture and that
the VIA 82586 PCI/ISA bridge offers a PC compatible IO and
PIC mapping. Here is a logical view of the RAVEN/VIA 82586
interrupt mapping :


| OPEN | <-----|8259|
| PIC | | | 2 ------
|(RAVEN)| | | <-----|8259|
| | | | | | 11
| | | | | | <----
| | | | | |
| | | | | |


------
| VIA PCI/ISA bridge
| x
-------- PCI interrupts

OPENPIC offers interrupt priorities among PCI interrupts
and interrupt selective masking. The 8259 offers the same kind
of feature. With actual powerpc interrupt code :

1) there is no way to specify priorities among
interrupts handler. This is REALLY a bad thing.
For me it is as importnat as having priorities
for threads...
2) for my implementation, each ISR should
contain the code that acknowledge the RAVEN
and 8259 cascade, modify interrupt mask on both
chips, and reenable interrupt at processor level,
..., restore then on interrupt return,.... This code
is actually similar to code located in some
genpvec.c powerpc files,
3) I must update _ISR_Nesting_level because
irq.inl use it...
4) the libchip code connects the ISR via set_vector
but the libchip handler code does not contain any code to
manipulate external interrupt controller hardware
in order to acknoledge the interrupt or re-enable
them (except for the target hardware of course)
So this code is broken unless set_vector adds an
additionnal prologue/epilogue before calling/returning
from in order to acknoledge/mask the raven and the
8259 PICS... => Anyway already EACH BSP MUST REWRITE
PART OF INTERRUPT HANDLING CODE TO CORRECTLY IMPLEMENT
SET_VECTOR.

I would rather offer an API similar to the one provided
in libbsp/i386/shared/irq/irq.h so that :

1) Once the driver supplied methods is called the
only things the ISR has to do is to worry about the
external hardware that triggered the interrupt.
Everything on openpic/VIA/processor would have been
done by the low levels (same things as set-vector)
2) The caller will need to supply the on/off/isOn
routine that are fundamental to correctly implements
debuggers/performance monitoring is a portable way
3) A globally configurable interrupt priorities
mechanism...

I have nothing against providing a compatible
set_vector just to make libchip happy but
as I have already explained in other
mails (months ago), I really think that the ISR
connection should be handled by the BSP and that no
code containing irq connection should exist the
rtems generic layers... Thus I really dislike
libchip on this aspect because in a long term
it will force to adopt the less reach API
for interrupt handling that exists (set_vector).

Additional note : I think the _ISR_Is_in_progress()
inline routine should be :

1) Put in a processor specific section,
2) Should not rely on a global variable,

As :

a) on symmetric MP, there is one interrupt level
per CPU,
b) On processor that have an ISP (e,g 68040),
this variable is useless (MSR bit testing could
be used)
c) On PPC, instead of using the address of the
variable via CPU_IRQ_info.Nest_level a dedicated
SPR could be used.

NOTE: most of this is also true for _Thread_Dispatch_disable_level

END NOTE


Please do not take what I said in the mail as a criticism for
anyone who submitted ppc code. Any code present helped me
a lot understanding PPC behavior. I just wanted by this
mail to :

1) try to better understand the actual code,
2) propose concrete ways of enhancing current code
by providing an alternative implementation for MCP750. I
will make my best effort to try to brake nothing but this
is actually hard due to the file layout organisation.
3) make understandable some changes I will probably make
if joel let me do them :-)

Any comments/objections are welcomed as usual.

--


/ ` Eric Valette

/-- o _. Canon CRF

(_, / (_(_( Rue de la touche lambert

35517 Cesson-Sevigne Cedex
FRANCE

Tel: +33 (0)2 99 87 68 91 Fax: +33 (0)2 99 84 11 30
E-mail: valette@…

  • Property mode set to 100644
File size: 20.2 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
408#if defined(mpc860) || defined(mpc821)
409const CPU_Trap_table_entry _CPU_Trap_slot_template_m860 = {
410  0x7c0803ac,           /* mtlr  %r0                            */
411  0x81210028,           /* lwz   %r9, IP_9(%r1)                 */
412  0x38000000,           /* li    %r0, PPC_IRQ                   */
413  0x48000002            /* b     PROC (_ISR_Handler)            */
414};
415#endif /* mpc860 */
416
417unsigned32  ppc_exception_vector_addr(
418  unsigned32 vector
419);
420
421
422/*PAGE
423 *
424 *  _CPU_ISR_install_raw_handler
425 *
426 *  This routine installs the specified handler as a "raw" non-executive
427 *  supported trap handler (a.k.a. interrupt service routine).
428 *
429 *  Input Parameters:
430 *    vector      - trap table entry number plus synchronous
431 *                    vs. asynchronous information
432 *    new_handler - address of the handler to be installed
433 *    old_handler - pointer to an address of the handler previously installed
434 *
435 *  Output Parameters: NONE
436 *    *new_handler - address of the handler previously installed
437 *
438 *  NOTE:
439 *
440 *  This routine is based on the SPARC routine _CPU_ISR_install_raw_handler.
441 *  Install a software trap handler as an executive interrupt handler
442 *  (which is desirable since RTEMS takes care of window and register issues),
443 *  then the executive needs to know that the return address is to the trap
444 *  rather than the instruction following the trap.
445 *
446 */
447 
448void _CPU_ISR_install_raw_handler(
449  unsigned32  vector,
450  proc_ptr    new_handler,
451  proc_ptr   *old_handler
452)
453{
454  unsigned32             real_vector;
455  CPU_Trap_table_entry  *slot;
456  unsigned32             u32_handler=0;
457
458  /*
459   *  Get the "real" trap number for this vector ignoring the synchronous
460   *  versus asynchronous indicator included with our vector numbers.
461   */
462
463  real_vector = vector;
464
465  /*
466   *  Get the current base address of the trap table and calculate a pointer
467   *  to the slot we are interested in.
468   */
469  slot = (CPU_Trap_table_entry  *)ppc_exception_vector_addr( real_vector );
470
471  /*
472   *  Get the address of the old_handler from the trap table.
473   *
474   *  NOTE: The old_handler returned will be bogus if it does not follow
475   *        the RTEMS model.
476   */
477
478#define HIGH_BITS_MASK   0xFFFFFC00
479#define HIGH_BITS_SHIFT  10
480#define LOW_BITS_MASK    0x000003FF
481
482  if (slot->stwu_r1 == _CPU_Trap_slot_template.stwu_r1) {
483    /*
484     * Set u32_handler = to target address 
485     */
486    u32_handler = slot->b_Handler & 0x03fffffc;
487
488    /* IMD FIX: sign extend address fragment... */
489    if (u32_handler & 0x02000000) {
490      u32_handler  |= 0xfc000000;
491    }
492
493    *old_handler =  (proc_ptr) u32_handler;
494  } else
495/* There are two kinds of handlers for the MPC860. One is the 'standard'
496 *  one like above. The other is for the cascaded interrupts from the SIU
497 *  and CPM. Therefore we must check for the alternate one if the standard
498 *  one is not present
499 */
500#if defined(mpc860) || defined(mpc821)
501  if (slot->stwu_r1 == _CPU_Trap_slot_template_m860.stwu_r1) {
502    /*
503     * Set u32_handler = to target address 
504     */
505    u32_handler = slot->b_Handler & 0x03fffffc;
506    *old_handler =  (proc_ptr) u32_handler;
507  } else
508#endif /* mpc860 */
509
510    *old_handler = 0;
511
512  /*
513   *  Copy the template to the slot and then fix it.
514   */
515#if defined(mpc860) || defined(mpc821)
516  if (vector >= PPC_IRQ_IRQ0)
517    *slot = _CPU_Trap_slot_template_m860;
518  else
519#endif /* mpc860 */
520  *slot = _CPU_Trap_slot_template;
521
522  u32_handler = (unsigned32) new_handler;
523
524  /*
525   * IMD FIX: insert address fragment only (bits 6..29)
526   *          therefore check for proper address range
527   *          and remove unwanted bits
528   */
529  if ((u32_handler & 0xfc000000) == 0xfc000000) {
530    u32_handler  &= ~0xfc000000;
531  }
532  else if ((u32_handler & 0xfc000000) != 0x00000000) {
533    _Internal_error_Occurred(INTERNAL_ERROR_CORE,
534                             TRUE,
535                             u32_handler);
536  }
537
538  slot->b_Handler |= u32_handler;
539
540  slot->li_r0_IRQ  |= vector;
541
542  _CPU_Data_Cache_Block_Flush( slot );
543}
544
545unsigned32  ppc_exception_vector_addr(
546  unsigned32 vector
547)
548{
549#if (!PPC_HAS_EVPR)
550  unsigned32 Msr;
551#endif
552  unsigned32 Top = 0;
553  unsigned32 Offset = 0x000;
554
555#if (PPC_HAS_EXCEPTION_PREFIX)
556  _CPU_MSR_Value ( Msr );
557  if ( ( Msr & PPC_MSR_EP) != 0 ) /* Vectors at FFFx_xxxx */
558    Top = 0xfff00000;
559#elif (PPC_HAS_EVPR)
560  asm volatile( "mfspr %0,0x3d6" : "=r" (Top)); /* EVPR */
561  Top = Top & 0xffff0000;
562#endif
563
564  switch ( vector ) {
565    case PPC_IRQ_SYSTEM_RESET:   /* on 40x aka PPC_IRQ_CRIT */
566      Offset = 0x00100;
567      break;
568    case PPC_IRQ_MCHECK:
569      Offset = 0x00200;
570      break;
571    case PPC_IRQ_PROTECT:
572      Offset = 0x00300;
573      break;
574    case PPC_IRQ_ISI:
575      Offset = 0x00400;
576      break;
577    case PPC_IRQ_EXTERNAL:
578      Offset = 0x00500;
579      break;
580    case PPC_IRQ_ALIGNMENT:
581      Offset = 0x00600;
582      break;
583    case PPC_IRQ_PROGRAM:
584      Offset = 0x00700;
585      break;
586    case PPC_IRQ_NOFP:
587      Offset = 0x00800;
588      break;
589    case PPC_IRQ_DECREMENTER:
590      Offset = 0x00900;
591      break;
592    case PPC_IRQ_RESERVED_A:
593      Offset = 0x00a00;
594      break;
595    case PPC_IRQ_RESERVED_B:
596      Offset = 0x00b00;
597      break;
598    case PPC_IRQ_SCALL:
599      Offset = 0x00c00;
600      break;
601    case PPC_IRQ_TRACE:
602      Offset = 0x00d00;
603      break;
604    case PPC_IRQ_FP_ASST:
605      Offset = 0x00e00;
606      break;
607
608#if defined(ppc403)
609                                 
610/*  PPC_IRQ_CRIT is the same vector as PPC_IRQ_RESET
611    case PPC_IRQ_CRIT:
612      Offset = 0x00100;
613      break;
614*/
615    case PPC_IRQ_PIT:
616      Offset = 0x01000;
617      break;
618    case PPC_IRQ_FIT:
619      Offset = 0x01010;
620      break;
621    case PPC_IRQ_WATCHDOG:
622      Offset = 0x01020;
623      break;
624    case PPC_IRQ_DEBUG:
625      Offset = 0x02000;
626      break;
627
628#elif defined(ppc601)
629    case PPC_IRQ_TRACE:
630      Offset = 0x02000;
631      break;
632
633#elif defined(ppc603)
634    case PPC_IRQ_TRANS_MISS:
635      Offset = 0x1000;
636      break;
637    case PPC_IRQ_DATA_LOAD:
638      Offset = 0x1100;
639      break;
640    case PPC_IRQ_DATA_STORE:
641      Offset = 0x1200;
642      break;
643    case PPC_IRQ_ADDR_BRK:
644      Offset = 0x1300;
645      break;
646    case PPC_IRQ_SYS_MGT:
647      Offset = 0x1400;
648      break;
649
650#elif defined(ppc603e)
651    case PPC_TLB_INST_MISS:
652      Offset = 0x1000;
653      break;
654    case PPC_TLB_LOAD_MISS:
655      Offset = 0x1100;
656      break;
657    case PPC_TLB_STORE_MISS:
658      Offset = 0x1200;
659      break;
660    case PPC_IRQ_ADDRBRK:
661      Offset = 0x1300;
662      break;
663    case PPC_IRQ_SYS_MGT:
664      Offset = 0x1400;
665      break;
666
667#elif defined(ppc604)
668    case PPC_IRQ_ADDR_BRK:
669      Offset = 0x1300;
670      break;
671    case PPC_IRQ_SYS_MGT:
672      Offset = 0x1400;
673      break;
674
675#elif defined(mpc860) || defined(mpc821)
676    case PPC_IRQ_EMULATE:
677      Offset = 0x1000;
678      break;
679    case PPC_IRQ_INST_MISS:
680      Offset = 0x1100;
681      break;
682    case PPC_IRQ_DATA_MISS:
683      Offset = 0x1200;
684      break;
685    case PPC_IRQ_INST_ERR:
686      Offset = 0x1300;
687      break;
688    case PPC_IRQ_DATA_ERR:
689      Offset = 0x1400;
690      break;
691    case PPC_IRQ_DATA_BPNT:
692      Offset = 0x1c00;
693      break;
694    case PPC_IRQ_INST_BPNT:
695      Offset = 0x1d00;
696      break;
697    case PPC_IRQ_IO_BPNT:
698      Offset = 0x1e00;
699      break;
700    case PPC_IRQ_DEV_PORT:
701      Offset = 0x1f00;
702      break;
703    case PPC_IRQ_IRQ0:
704      Offset = 0x2000;
705      break;
706    case PPC_IRQ_LVL0:
707      Offset = 0x2040;
708      break;
709    case PPC_IRQ_IRQ1:
710      Offset = 0x2080;
711      break;
712    case PPC_IRQ_LVL1:
713      Offset = 0x20c0;
714      break;
715    case PPC_IRQ_IRQ2:
716      Offset = 0x2100;
717      break;
718    case PPC_IRQ_LVL2:
719      Offset = 0x2140;
720      break;
721    case PPC_IRQ_IRQ3:
722      Offset = 0x2180;
723      break;
724    case PPC_IRQ_LVL3:
725      Offset = 0x21c0;
726      break;
727    case PPC_IRQ_IRQ4:
728      Offset = 0x2200;
729      break;
730    case PPC_IRQ_LVL4:
731      Offset = 0x2240;
732      break;
733    case PPC_IRQ_IRQ5:
734      Offset = 0x2280;
735      break;
736    case PPC_IRQ_LVL5:
737      Offset = 0x22c0;
738      break;
739    case PPC_IRQ_IRQ6:
740      Offset = 0x2300;
741      break;
742    case PPC_IRQ_LVL6:
743      Offset = 0x2340;
744      break;
745    case PPC_IRQ_IRQ7:
746      Offset = 0x2380;
747      break;
748    case PPC_IRQ_LVL7:
749      Offset = 0x23c0;
750      break;
751    case PPC_IRQ_CPM_RESERVED_0:
752      Offset = 0x2400;
753      break;
754    case PPC_IRQ_CPM_PC4:
755      Offset = 0x2410;
756      break;
757    case PPC_IRQ_CPM_PC5:
758      Offset = 0x2420;
759      break;
760    case PPC_IRQ_CPM_SMC2:
761      Offset = 0x2430;
762      break;
763    case PPC_IRQ_CPM_SMC1:
764      Offset = 0x2440;
765      break;
766    case PPC_IRQ_CPM_SPI:
767      Offset = 0x2450;
768      break;
769    case PPC_IRQ_CPM_PC6:
770      Offset = 0x2460;
771      break;
772    case PPC_IRQ_CPM_TIMER4:
773      Offset = 0x2470;
774      break;
775    case PPC_IRQ_CPM_RESERVED_8:
776      Offset = 0x2480;
777      break;
778    case PPC_IRQ_CPM_PC7:
779      Offset = 0x2490;
780      break;
781    case PPC_IRQ_CPM_PC8:
782      Offset = 0x24a0;
783      break;
784    case PPC_IRQ_CPM_PC9:
785      Offset = 0x24b0;
786      break;
787    case PPC_IRQ_CPM_TIMER3:
788      Offset = 0x24c0;
789      break;
790    case PPC_IRQ_CPM_RESERVED_D:
791      Offset = 0x24d0;
792      break;
793    case PPC_IRQ_CPM_PC10:
794      Offset = 0x24e0;
795      break;
796    case PPC_IRQ_CPM_PC11:
797      Offset = 0x24f0;
798      break;
799    case PPC_IRQ_CPM_I2C:
800      Offset = 0x2500;
801      break;
802    case PPC_IRQ_CPM_RISC_TIMER:
803      Offset = 0x2510;
804      break;
805    case PPC_IRQ_CPM_TIMER2:
806      Offset = 0x2520;
807      break;
808    case PPC_IRQ_CPM_RESERVED_13:
809      Offset = 0x2530;
810      break;
811    case PPC_IRQ_CPM_IDMA2:
812      Offset = 0x2540;
813      break;
814    case PPC_IRQ_CPM_IDMA1:
815      Offset = 0x2550;
816      break;
817    case PPC_IRQ_CPM_SDMA_ERROR:
818      Offset = 0x2560;
819      break;
820    case PPC_IRQ_CPM_PC12:
821      Offset = 0x2570;
822      break;
823    case PPC_IRQ_CPM_PC13:
824      Offset = 0x2580;
825      break;
826    case PPC_IRQ_CPM_TIMER1:
827      Offset = 0x2590;
828      break;
829    case PPC_IRQ_CPM_PC14:
830      Offset = 0x25a0;
831      break;
832    case PPC_IRQ_CPM_SCC4:
833      Offset = 0x25b0;
834      break;
835    case PPC_IRQ_CPM_SCC3:
836      Offset = 0x25c0;
837      break;
838    case PPC_IRQ_CPM_SCC2:
839      Offset = 0x25d0;
840      break;
841    case PPC_IRQ_CPM_SCC1:
842      Offset = 0x25e0;
843      break;
844    case PPC_IRQ_CPM_PC15:
845      Offset = 0x25f0;
846      break;
847#endif
848
849  }
850  Top += Offset;
851  return Top;
852}
853
Note: See TracBrowser for help on using the repository browser.