source: rtems-docs/porting/task_context.rst @ 6733466

4.115
Last change on this file since 6733466 was 6733466, checked in by Amar Takhar <amar@…>, on 01/17/16 at 00:08:48

Split document into seperate files by section.

  • Property mode set to 100644
File size: 22.1 KB
Line 
1Task Context Management
2#######################
3
4Introduction
5============
6
7XXX
8
9Task Stacks
10===========
11
12XXX
13
14Direction of Stack Growth
15-------------------------
16
17The CPU_STACK_GROWS_UP macro is set based upon the answer to the following
18question: Does the stack grow up (toward higher addresses) or down (toward
19lower addresses)?  If the stack grows upward in memory, then this macro
20should be set to TRUE.  Otherwise, it should be set to FALSE to indicate
21that the stack grows downward toward smaller addresses.
22
23The following illustrates how the CPU_STACK_GROWS_UP macro is set:
24.. code:: c
25
26    #define CPU_STACK_GROWS_UP               TRUE
27
28Minimum Task Stack Size
29-----------------------
30
31The CPU_STACK_MINIMUM_SIZE macro should be set to the minimum size of each
32task stack.  This size is specified as the number of bytes.  This minimum
33stack size should be large enough to run all RTEMS tests.  The minimum
34stack size is chosen such that a "reasonable" small application should not
35have any problems.  Choosing a minimum stack size that is too small will
36result in the RTEMS tests "blowing" their stack and not executing
37properly.
38
39There are many reasons a task could require a stack size larger than the
40minimum.  For example, a task could have a very deep call path or declare
41large data structures on the stack.  Tasks which utilize C++ exceptions
42tend to require larger stacks as do Ada tasks.
43
44The following illustrates setting the minimum stack size to 4 kilobytes
45per task.
46.. code:: c
47
48    #define CPU_STACK_MINIMUM_SIZE          (1024*4)
49
50Stack Alignment Requirements
51----------------------------
52
53The CPU_STACK_ALIGNMENT macro is set to indicate the byte alignment
54requirement for the stack.  This alignment requirement may be stricter
55than that for the data types alignment specified by CPU_ALIGNMENT.  If the
56CPU_ALIGNMENT is strict enough for the stack, then this should be set to
570.
58
59The following illustrates how the CPU_STACK_ALIGNMENT macro should be set
60when there are no special requirements:
61.. code:: c
62
63    #define CPU_STACK_ALIGNMENT        0
64
65NOTE:  This must be a power of 2 either 0 or greater than CPU_ALIGNMENT. \[XXX is this true?]
66
67Task Context
68============
69
70Associated with each task is a context that distinguishes it from other
71tasks in the system and logically gives it its own scratch pad area for
72computations.  In addition, when an interrupt occurs some processor
73context information must be saved and restored.  This is managed in RTEMS
74as three items:
75
76- Basic task level context (e.g. the Context_Control structure)
77
78- Floating point task context (e.g. Context_Control_fp structure)
79
80- Interrupt level context (e.g.  the Context_Control_interrupt
81  structure)
82
83The integer and floating point context structures and the routines that
84manipulate them are discussed in detail in this section, while the
85interrupt level context structure is discussed in the XXX.
86
87Additionally, if the GNU debugger gdb is to be made aware of RTEMS tasks
88for this CPU, then care should be used in designing the context area.
89.. code:: c
90
91    typedef struct {
92    unsigned32 special_interrupt_register;
93    } CPU_Interrupt_frame;
94
95Basic Context Data Structure
96----------------------------
97
98The Context_Control data structure contains the basic integer context of a
99task.  In addition, this context area contains stack and frame pointers,
100processor status register(s), and any other registers that are normally
101altered by compiler generated code.  In addition, this context must
102contain the processor interrupt level since the processor interrupt level
103is maintained on a per-task basis.  This is necessary to support the
104interrupt level portion of the task mode as provided by the Classic RTEMS
105API.
106
107On some processors, it is cost-effective to save only the callee preserved
108registers during a task context switch.  This means that the ISR code
109needs to save those registers which do not persist across function calls.
110It is not mandatory to make this distinctions between the caller/callee
111saves registers for the purpose of minimizing context saved during task
112switch and on interrupts.  If the cost of saving extra registers is
113minimal, simplicity is the choice.  Save the same context on interrupt
114entry as for tasks in this case.
115
116The Context_Control data structure should be defined such that the order
117of elements results in the simplest, most efficient implementation of XXX.
118A typical implementation starts with a definition such as the following:
119.. code:: c
120
121    typedef struct {
122    unsigned32 some_integer_register;
123    unsigned32 another_integer_register;
124    unsigned32 some_system_register;
125    } Context_Control;
126
127Initializing a Context
128----------------------
129
130The _CPU_Context_Initialize routine initializes the context to a state
131suitable for starting a task after a context restore operation.
132Generally, this involves:
133
134- setting a starting address,
135
136- preparing the stack,
137
138- preparing the stack and frame pointers,
139
140- setting the proper interrupt level in the context, and
141
142- initializing the floating point context
143
144This routine generally does not set any unnecessary register in the
145context.  The state of the "general data" registers is undefined at task
146start time. The _CPU_Context_initialize routine is prototyped as follows:
147.. code:: c
148
149    void _CPU_Context_Initialize(
150    Context_Control \*_the_context,
151    void            \*_stack_base,
152    unsigned32       _size,
153    unsigned32       _isr,
154    void            \*_entry_point,
155    unsigned32       _is_fp
156    );
157
158The ``is_fp`` parameter is TRUE if the thread is to be a floating point
159thread.  This is typically only used on CPUs where the FPU may be easily
160disabled by software such as on the SPARC where the PSR contains an enable
161FPU bit.  The use of an FPU enable bit allows RTEMS to ensure that a
162non-floating point task is unable to access the FPU.  This guarantees that
163a deferred floating point context switch is safe.
164
165The ``_stack_base`` parameter is the base address of the memory area
166allocated for use as the task stack.  It is critical to understand that``_stack_base`` may not be the starting stack pointer for this task.
167On CPU families where the stack grows from high addresses to lower ones,
168(i.e. ``CPU_STACK_GROWS_UP`` is FALSE) the starting stack point
169will be near the end of the stack memory area or close to``_stack_base`` + ``_size``.  Even on CPU families where the stack
170grows from low to higher addresses, there may be some required
171outermost stack frame that must be put at the address ``_stack_base``.
172
173The ``_size`` parameter is the requested size in bytes of the stack for
174this task.  It is assumed that the memory area ``_stack_base``
175is of this size.
176
177XXX explain other parameters and check prototype
178
179Performing a Context Switch
180---------------------------
181
182The _CPU_Context_switch performs a normal non-FP context switch from the
183context of the current executing thread to the context of the heir thread.
184.. code:: c
185
186    void _CPU_Context_switch(
187    Context_Control  \*run,
188    Context_Control  \*heir
189    );
190
191This routine begins by saving the current state of the
192CPU (i.e. the context) in the context area at ``run``.
193Then the routine should load the CPU context pointed to
194by ``heir``.  Loading the new context will cause a
195branch to its task code, so the task that invoked``_CPU_Context_switch`` will not run for a while.
196When, eventually, a context switch is made to load
197context from ``*run`` again, this task will resume
198and ``_CPU_Context_switch`` will return to its caller.
199
200Care should be exercise when writing this routine.  All
201registers assumed to be preserved across subroutine calls
202must be preserved.  These registers may be saved in
203the task’s context area or on its stack.  However, the
204stack pointer and address to resume executing the task
205at must be included in the context (normally the subroutine
206return address to the caller of ``_Thread_Dispatch``.
207The decision of where to store the task’s context is based
208on numerous factors including the capabilities of
209the CPU architecture itself and simplicity as well
210as external considerations such as debuggers wishing
211to examine a task’s context.  In this case, it is
212often simpler to save all data in the context area.
213
214Also there may be special considerations
215when loading the stack pointers or interrupt level of the
216incoming task.  Independent of CPU specific considerations,
217if some context is saved on the task stack, then the porter
218must ensure that the stack pointer is adjusted *BEFORE*
219to make room for this context information before the
220information is written.  Otherwise, an interrupt could
221occur writing over the context data.  The following is
222an example of an *INCORRECT* sequence:
223.. code:: c
224
225    save part of context beyond current top of stack
226    interrupt pushes context -- overwriting written context
227    interrupt returns
228    adjust stack pointer
229
230Restoring a Context
231-------------------
232
233The _CPU_Context_restore routine is generally used only to restart the
234currently executing thread (i.e. self) in an efficient manner.  In many
235ports, it can simply be a label in _CPU_Context_switch. It may be
236unnecessary to reload some registers.
237.. code:: c
238
239    void _CPU_Context_restore(
240    Context_Control \*new_context
241    );
242
243Restarting the Currently Executing Task
244---------------------------------------
245
246The _CPU_Context_Restart_self is responsible for somehow restarting the
247currently executing task.  If you are lucky when porting RTEMS, then all
248that is necessary is restoring the context.  Otherwise, there will need to
249be a routine that does something special in this case.  Performing a
250_CPU_Context_Restore on the currently executing task after reinitializing
251that context should work on most ports.  It will not work if restarting
252self conflicts with the stack frame assumptions of restoring a context.
253
254The following is an implementation of _CPU_Context_Restart_self that can
255be used when no special handling is required for this case.
256.. code:: c
257
258    #define _CPU_Context_Restart_self( _the_context ) \\
259    _CPU_Context_restore( (_the_context) )
260
261XXX find a port which does not do it this way and include it here
262
263Floating Point Context
264======================
265
266CPU_HAS_FPU Macro Definition
267----------------------------
268
269The CPU_HAS_FPU macro is set based on the answer to the question: Does the
270CPU have hardware floating point?  If the CPU has an FPU, then this should
271be set to TRUE.  Otherwise, it should be set to FALSE.  The primary
272implication of setting this macro to TRUE is that it indicates that tasks
273may have floating point contexts.  In the Classic API, this means that the
274RTEMS_FLOATING_POINT task attribute specified as part of rtems_task_create
275is supported on this CPU.  If CPU_HAS_FPU is set to FALSE, then no tasks
276or threads may be floating point and the RTEMS_FLOATING_POINT task
277attribute is ignored.  On an API such as POSIX where all threads
278implicitly have a floating point context, then the setting of this macro
279determines whether every POSIX thread has a floating point context.
280
281The following example illustrates how the CPU_HARDWARE_FP (XXX macro name
282is varying) macro is set based on the CPU family dependent macro.
283.. code:: c
284
285    #if ( THIS_CPU_FAMILY_HAS_FPU == 1 ) /* where THIS_CPU_FAMILY \*/
286    /* might be M68K \*/
287    #define CPU_HARDWARE_FP     TRUE
288    #else
289    #define CPU_HARDWARE_FP     FALSE
290    #endif
291
292The macro name THIS_CPU_FAMILY_HAS_FPU should be made CPU specific.  It
293indicates whether or not this CPU model has FP support.  For example, the
294definition of the i386ex and i386sx CPU models would set I386_HAS_FPU to
295FALSE to indicate that these CPU models are i386’s without an i387 and
296wish to leave floating point support out of RTEMS when built for the
297i386_nofp processor model.  On a CPU with a built-in FPU like the i486,
298this would be defined as TRUE.
299
300On some processor families, the setting of the THIS_CPU_FAMILY_HAS_FPU
301macro may be derived from compiler predefinitions.  This can be used when
302the compiler distinguishes the individual CPU models for this CPU family
303as distinctly as RTEMS requires.  Often RTEMS needs to need more about the
304CPU model than the compiler because of differences at the system level
305such as caching, interrupt structure.
306
307CPU_ALL_TASKS_ARE_FP Macro Setting
308----------------------------------
309
310The CPU_ALL_TASKS_ARE_FP macro is set to TRUE or FALSE based upon the
311answer to the following question: Are all tasks RTEMS_FLOATING_POINT tasks
312implicitly?  If this macro is set TRUE, then all tasks and threads are
313assumed to have a floating point context.  In the Classic API, this is
314equivalent to setting the RTEMS_FLOATING_POINT task attribute on all
315rtems_task_create calls.  If the CPU_ALL_TASKS_ARE_FP macro is set to
316FALSE, then the RTEMS_FLOATING_POINT task attribute in the Classic API is
317honored.
318
319The rationale for this macro is that if a function that an application
320developer would not think utilize the FP unit DOES, then one can not
321easily predict which tasks will use the FP hardware. In this case, this
322option should be TRUE.  So far, the only CPU families for which this macro
323has been to TRUE are the HP PA-RISC and PowerPC.  For the HP PA-RISC, the
324HP C compiler and gcc both implicitly use the floating point registers to
325perform integer multiplies.  For the PowerPC, this feature macro is set to
326TRUE because the printf routine saves a floating point register whether or
327not a floating point number is actually printed.  If the newlib
328implementation of printf were restructured to avoid this, then the PowerPC
329port would not have to have this option set to TRUE.
330
331The following example illustrates how the CPU_ALL_TASKS_ARE_FP is set on
332the PowerPC.  On this CPU family, this macro is set to TRUE if the CPU
333model has hardware floating point.
334.. code:: c
335
336    #if (CPU_HARDWARE_FP == TRUE)
337    #define CPU_ALL_TASKS_ARE_FP     TRUE
338    #else
339    #define CPU_ALL_TASKS_ARE_FP     FALSE
340    #endif
341
342NOTE: If CPU_HARDWARE_FP is FALSE, then this should be FALSE as well.
343
344CPU_USE_DEFERRED_FP_SWITCH Macro Setting
345----------------------------------------
346
347The CPU_USE_DEFERRED_FP_SWITCH macro is set based upon the answer to the
348following question:  Should the saving of the floating point registers be
349deferred until a context switch is made to another different floating
350point task?  If the floating point context will not be stored until
351necessary, then this macro should be set to TRUE.  When set to TRUE, the
352floating point context of a task will remain in the floating point
353registers and not disturbed until another floating point task is switched
354to.
355
356If the CPU_USE_DEFERRED_FP_SWITCH is set to FALSE, then the floating point
357context is saved each time a floating point task is switched out and
358restored when the next floating point task is restored.  The state of the
359floating point registers between those two operations is not specified.
360
361There are a couple of known cases where the port should not defer saving
362the floating point context.  The first case is when the compiler generates
363instructions that use the FPU when floating point is not actually used.
364This occurs on the HP PA-RISC for example when an integer multiply is
365performed.  On the PowerPC, the printf routine includes a save of a
366floating point register to support printing floating point numbers even if
367the path that actually prints the floating point number is not invoked.
368In both of these cases, deferred floating point context switches can not
369be used.  If the floating point context has to be saved as part of
370interrupt dispatching, then it may also be necessary to disable deferred
371context switches.
372
373Setting this flag to TRUE results in using a different algorithm for
374deciding when to save and restore the floating point context.  The
375deferred FP switch algorithm minimizes the number of times the FP context
376is saved and restored.  The FP context is not saved until a context switch
377is made to another, different FP task.  Thus in a system with only one FP
378task, the FP context will never be saved or restored.
379
380The following illustrates setting the CPU_USE_DEFERRED_FP_SWITCH macro on
381a processor family such as the M68K or i386 which can use deferred
382floating point context switches.
383.. code:: c
384
385    #define CPU_USE_DEFERRED_FP_SWITCH       TRUE
386
387Note that currently, when in SMP configuration, deferred floating point
388context switching is unavailable.
389
390Floating Point Context Data Structure
391-------------------------------------
392
393The Context_Control_fp contains the per task information for the floating
394point unit.  The organization of this structure may be a list of floating
395point registers along with any floating point control and status registers
396or it simply consist of an array of a fixed number of bytes.  Defining the
397floating point context area as an array of bytes is done when the floating
398point context is dumped by a "FP save context" type instruction and the
399format is either not completely defined by the CPU documentation or the
400format is not critical for the implementation of the floating point
401context switch routines.  In this case, there is no need to figure out the
402exact format – only the size.  Of course, although this is enough
403information for RTEMS, it is probably not enough for a debugger such as
404gdb.  But that is another problem.
405.. code:: c
406
407    typedef struct {
408    double      some_float_register;
409    } Context_Control_fp;
410
411On some CPUs with hardware floating point support, the Context_Control_fp
412structure will not be used.
413
414Size of Floating Point Context Macro
415------------------------------------
416
417The CPU_CONTEXT_FP_SIZE macro is set to the size of the floating point
418context area. On some CPUs this will not be a "sizeof" because the format
419of the floating point area is not defined – only the size is.  This is
420usually on CPUs with a "floating point save context" instruction.  In
421general, though it is easier to define the structure as a "sizeof"
422operation and define the Context_Control_fp structure to be an area of
423bytes of the required size in this case.
424.. code:: c
425
426    #define CPU_CONTEXT_FP_SIZE sizeof( Context_Control_fp )
427
428Start of Floating Point Context Area Macro
429------------------------------------------
430
431The _CPU_Context_Fp_start macro is used in the XXX routine and allows the initial pointer into a  floating point context area (used to save the floating point context) to be at an arbitrary place in the floating point context area.  This is necessary because some FP units are designed to have their context saved as a stack which grows into lower addresses.  Other FP units can be saved by simply moving registers into offsets from the base of the context area.  Finally some FP units provide a "dump context" instruction which could fill in from high to low or low to high based on the whim of the CPU designers.  Regardless, the address at which that floating point context area pointer should start within the actual floating point context area varies between ports and this macro provides a clean way of addressing this.
432
433This is a common implementation of the _CPU_Context_Fp_start routine which
434is suitable for many processors.  In particular, RISC processors tend to
435use this implementation since the floating point context is saved as a
436sequence of store operations.
437.. code:: c
438
439    #define _CPU_Context_Fp_start( _base, _offset ) \\
440    ( (void \*) _Addresses_Add_offset( (_base), (_offset) ) )
441
442In contrast, the m68k treats the floating point context area as a stack
443which grows downward in memory.  Thus the following implementation of
444_CPU_Context_Fp_start is used in that port:
445
446.. code:: c
447
448    XXX insert m68k version here
449
450Initializing a Floating Point Context
451-------------------------------------
452
453The _CPU_Context_Initialize_fp routine initializes the floating point
454context area passed to it to. There are a few standard ways in which to
455initialize the floating point context.  The simplest, and least
456deterministic behaviorally, is to do nothing.  This leaves the FPU in a
457random state and is generally not a suitable way to implement this
458routine.  The second common implementation is to place a "null FP status
459word" into some status/control register in the FPU.  This mechanism is
460simple and works on many FPUs.  Another common way is to initialize the
461FPU to a known state during _CPU_Initialize and save the context (using
462_CPU_Context_save_fp_context) into the special floating point context
463_CPU_Null_fp_context.  Then all that is required to initialize a floating
464point context is to copy _CPU_Null_fp_context to the destination floating
465point context passed to it.  The following example implementation shows
466how to accomplish this:
467.. code:: c
468
469    #define _CPU_Context_Initialize_fp( _destination ) \\
470    { \\
471    \*((Context_Control_fp \*) \*((void \**) _destination)) = \\
472    _CPU_Null_fp_context; \\
473    }
474
475The _CPU_Null_fp_context is optional.  A port need only include this variable when it uses the above mechanism to initialize a floating point context.  This is typically done on CPUs where it is difficult to generate an "uninitialized" FP context.  If the port requires this variable, then it is declared as follows:
476.. code:: c
477
478    Context_Control_fp  _CPU_Null_fp_context;
479
480Saving a Floating Point Context
481-------------------------------
482
483The _CPU_Context_save_fp_context routine is responsible for saving the FP
484context at \*fp_context_ptr.  If the point to load the FP context from is
485changed then the pointer is modified by this routine.
486
487Sometimes a macro implementation of this is in cpu.h which dereferences
488the \** and a similarly named routine in this file is passed something like
489a (Context_Control_fp \*).  The general rule on making this decision is to
490avoid writing assembly language.
491.. code:: c
492
493    void _CPU_Context_save_fp(
494    void \**fp_context_ptr
495    )
496
497Restoring a Floating Point Context
498----------------------------------
499
500The _CPU_Context_restore_fp_context is responsible for restoring the FP
501context at \*fp_context_ptr.  If the point to load the FP context from is
502changed then the pointer is modified by this routine.
503
504Sometimes a macro implementation of this is in cpu.h which dereferences
505the \** and a similarly named routine in this file is passed something like
506a (Context_Control_fp \*).  The general rule on making this decision is to
507avoid writing assembly language.
508.. code:: c
509
510    void _CPU_Context_restore_fp(
511    void \**fp_context_ptr
512    );
513
514.. COMMENT: COPYRIGHT (c) 1988-2002.
515
516.. COMMENT: On-Line Applications Research Corporation (OAR).
517
518.. COMMENT: All rights reserved.
519
Note: See TracBrowser for help on using the repository browser.