source: rtems-docs/porting/task_context.rst @ 36def91

4.115
Last change on this file since 36def91 was 36def91, checked in by Joel Sherrill <joel@…>, on 10/28/16 at 00:47:07

rtems-docs: Fix many unnecessary back slashes

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