From 72a62ad88f82fe1ffee50024db4dd0f3fa5806f7 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Thu, 3 Nov 2016 16:58:08 +1100 Subject: Rename all manuals with an _ to have a -. It helps released naming of files. --- bsp-howto/ada95_interrupt.rst | 75 +++++ bsp-howto/analog.rst | 165 ++++++++++ bsp-howto/ata.rst | 181 +++++++++++ bsp-howto/clock.rst | 297 ++++++++++++++++++ bsp-howto/command.rst | 9 + bsp-howto/conf.py | 13 + bsp-howto/console.rst | 579 +++++++++++++++++++++++++++++++++++ bsp-howto/discrete.rst | 190 ++++++++++++ bsp-howto/frame_buffer.rst | 256 ++++++++++++++++ bsp-howto/ide_controller.rst | 156 ++++++++++ bsp-howto/index.rst | 63 ++++ bsp-howto/initilization_code.rst | 382 +++++++++++++++++++++++ bsp-howto/linker_script.rst | 361 ++++++++++++++++++++++ bsp-howto/makefiles.rst | 190 ++++++++++++ bsp-howto/miscellanous_support.rst | 364 ++++++++++++++++++++++ bsp-howto/networking.rst | 310 +++++++++++++++++++ bsp-howto/non_volatile_memory.rst | 217 +++++++++++++ bsp-howto/preface.rst | 58 ++++ bsp-howto/real_time_clock.rst | 211 +++++++++++++ bsp-howto/shared_memory_support.rst | 242 +++++++++++++++ bsp-howto/target_dependant_files.rst | 229 ++++++++++++++ bsp-howto/timer.rst | 102 ++++++ bsp-howto/wscript | 6 + 23 files changed, 4656 insertions(+) create mode 100644 bsp-howto/ada95_interrupt.rst create mode 100644 bsp-howto/analog.rst create mode 100644 bsp-howto/ata.rst create mode 100644 bsp-howto/clock.rst create mode 100644 bsp-howto/command.rst create mode 100644 bsp-howto/conf.py create mode 100644 bsp-howto/console.rst create mode 100644 bsp-howto/discrete.rst create mode 100644 bsp-howto/frame_buffer.rst create mode 100644 bsp-howto/ide_controller.rst create mode 100644 bsp-howto/index.rst create mode 100644 bsp-howto/initilization_code.rst create mode 100644 bsp-howto/linker_script.rst create mode 100644 bsp-howto/makefiles.rst create mode 100644 bsp-howto/miscellanous_support.rst create mode 100644 bsp-howto/networking.rst create mode 100644 bsp-howto/non_volatile_memory.rst create mode 100644 bsp-howto/preface.rst create mode 100644 bsp-howto/real_time_clock.rst create mode 100644 bsp-howto/shared_memory_support.rst create mode 100644 bsp-howto/target_dependant_files.rst create mode 100644 bsp-howto/timer.rst create mode 100644 bsp-howto/wscript (limited to 'bsp-howto') diff --git a/bsp-howto/ada95_interrupt.rst b/bsp-howto/ada95_interrupt.rst new file mode 100644 index 0000000..f6fc0fc --- /dev/null +++ b/bsp-howto/ada95_interrupt.rst @@ -0,0 +1,75 @@ +.. comment SPDX-License-Identifier: CC-BY-SA-4.0 + +.. COMMENT: COPYRIGHT (c) 1988-2008. +.. COMMENT: On-Line Applications Research Corporation (OAR). +.. COMMENT: All rights reserved. + +Ada95 Interrupt Support +####################### + +Introduction +============ + +This chapter describes what is required to enable Ada interrupt and error +exception handling when using GNAT over RTEMS. + +The GNAT Ada95 interrupt support RTEMS was developed by Jiri Gaisler + who also wrote this chapter. + +Mapping Interrupts to POSIX Signals +=================================== + +In Ada95, interrupts can be attached with the interrupt_attach pragma. For +most systems, the gnat run-time will use POSIX signal to implement the +interrupt handling, mapping one signal per interrupt. For interrupts to be +propagated to the attached Ada handler, the corresponding signal must be raised +when the interrupt occurs. + +The same mechanism is used to generate Ada error exceptions. Three error +exceptions are defined: program, constraint and storage error. These are +generated by raising the predefined signals: SIGILL, SIGFPE and SIGSEGV. These +signals should be raised when a spurious or erroneous trap occurs. + +To enable gnat interrupt and error exception support for a particular BSP, the +following has to be done: + +- Write an interrupt/trap handler that will raise the corresponding signal + depending on the interrupt/trap number. + +- Install the interrupt handler for all interrupts/traps that will be handled + by gnat (including spurious). + +- At startup, gnat calls ``__gnat_install_handler()``. The BSP must provide + this function which installs the interrupt/trap handlers. + +Which CPU-interrupt will generate which signal is implementation defined. There +are 32 POSIX signals (1 - 32), and all except the three error signals (SIGILL, +SIGFPE and SIGSEGV) can be used. I would suggest to use the upper 16 (17 - 32) +which do not have an assigned POSIX name. + +Note that the pragma interrupt_attach will only bind a signal to a particular +Ada handler - it will not unmask the interrupt or do any other things to enable +it. This have to be done separately, typically by writing various device +register. + +Example Ada95 Interrupt Program +=============================== + +An example program (``irq_test``) is included in the Ada examples package to +show how interrupts can be handled in Ada95. Note that generation of the test +interrupt (``irqforce.c``) is BSP specific and must be edited. + +.. note:: + + The ``irq_test`` example was written for the SPARC/ERC32 BSP. + +Version Requirements +==================== + +With RTEMS 4.0, a patch was required to psignal.c in RTEMS sources (to correct +a bug associated to the default action of signals 15-32). The SPARC/ERC32 +RTEMS BSP includes the``gnatsupp`` subdirectory that can be used as an example +for other BSPs. + +With GNAT 3.11p, a patch is required for ``a-init.c`` to invoke the BSP +specific routine that installs the exception handlers. diff --git a/bsp-howto/analog.rst b/bsp-howto/analog.rst new file mode 100644 index 0000000..ac8ddb0 --- /dev/null +++ b/bsp-howto/analog.rst @@ -0,0 +1,165 @@ +.. comment SPDX-License-Identifier: CC-BY-SA-4.0 + +.. COMMENT: COPYRIGHT (c) 1988-2002. +.. COMMENT: On-Line Applications Research Corporation (OAR). +.. COMMENT: All rights reserved. + +Analog Driver +############# + +The Analog driver is responsible for providing an interface to Digital to +Analog Converters (DACs) and Analog to Digital Converters (ADCs). The +capabilities provided by this class of device driver are: + +- Initialize an Analog Board + +- Open a Particular Analog + +- Close a Particular Analog + +- Read from a Particular Analog + +- Write to a Particular Analog + +- Reset DACs + +- Reinitialize DACS + +Most analog devices are found on I/O cards that support multiple DACs or ADCs +on a single card. + +There are currently no analog device drivers included in the RTEMS source tree. +The information provided in this chapter is based on drivers developed for +applications using RTEMS. It is hoped that this driver model information can +form the basis for a standard analog driver model that can be supported in +future RTEMS distribution. + +Major and Minor Numbers +======================= + +The ``major`` number of a device driver is its index in the RTEMS Device +Address Table. + +A ``minor`` number is associated with each device instance managed by a +particular device driver. An RTEMS minor number is an ``unsigned32`` entity. +Convention calls for dividing the bits in the minor number down into categories +like the following: + +- ``board`` - indicates the board a particular device is located on + +- ``port`` - indicates the particular device on a board. + +From the above, it should be clear that a single device driver can support +multiple copies of the same board in a single system. The minor number is used +to distinguish the devices. + +Analog Driver Configuration +=========================== + +There is not a standard analog driver configuration table but some fields are +common across different drivers. The analog driver configuration table is +typically an array of structures with each structure containing the information +for a particular board. The following is a list of the type of information +normally required to configure an analog board: + +``board_offset`` + is the base address of a board. + +``DAC_initial_values`` + is an array of the voltages that should be written to each DAC during + initialization. This allows the driver to start the board in a known + state. + +Initialize an Analog Board +========================== + +At system initialization, the analog driver's initialization entry point will +be invoked. As part of initialization, the driver will perform whatever board +initialization is required and then set all outputs to their configured initial +state. + +The analog driver may register a device name for each DAC and ADC in the +system. + +Open a Particular Analog +======================== + +This is the driver open call. Usually this call does nothing other than +validate the minor number. + +With some drivers, it may be necessary to allocate memory when a particular +device is opened. If that is the case, then this is often the place to do this +operation. + +Close a Particular Analog +========================= + +This is the driver close call. Usually this call does nothing. + +With some drivers, it may be necessary to allocate memory when a particular +device is opened. If that is the case, then this is the place where that +memory should be deallocated. + +Read from a Particular Analog +============================= + +This corresponds to the driver read call. After validating the minor number +and arguments, this call reads the indicated device. Most analog devices store +the last value written to a DAC. Since DACs are output only devices, saving +the last written value gives the appearance that DACs can be read from also. +If the device is an ADC, then it is sampled. + +.. note:: + + Many boards have multiple analog inputs but only one ADC. On these boards, + it will be necessary to provide some type of mutual exclusion during reads. + On these boards, there is a MUX which must be switched before sampling the + ADC. After the MUX is switched, the driver must delay some short period of + time (usually microseconds) before the signal is stable and can be sampled. + To make matters worse, some ADCs cannot respond to wide voltage swings in a + single sample. On these ADCs, one must do two samples when the voltage + swing is too large. On a practical basis, this means that the driver + usually ends up double sampling the ADC on these systems. + +The value returned is a single precision floating point number representing the +voltage read. This value is stored in the ``argument_block`` passed in to the +call. By returning the voltage, the caller is freed from having to know the +number of bits in the analog and board dependent conversion algorithm. + +Write to a Particular Analog +============================ + +This corresponds to the driver write call. After validating the minor number +and arguments, this call writes the indicated device. If the specified device +is an ADC, then an error is usually returned. + +The value written is a single precision floating point number representing the +voltage to be written to the specified DAC. This value is stored in the +``argument_block`` passed in to the call. By passing the voltage to the device +driver, the caller is freed from having to know the number of bits in the +analog and board dependent conversion algorithm. + +Reset DACs +========== + +This is one of the IOCTL functions supported by the I/O control device driver +entry point. When this IOCTL function is invoked, all of the DACs are written +to 0.0 volts. + +Reinitialize DACS +================= + +This is one of the IOCTL functions supported by the I/O control device driver +entry point. When this IOCTL function is invoked, all of the DACs are written +with the initial value configured for this device. + +Get Last Written Values +======================= + +This is one of the IOCTL functions supported by the I/O control device driver +entry point. When this IOCTL function is invoked, the following information is +returned to the caller: + +- last value written to the specified DAC + +- timestamp of when the last write was performed diff --git a/bsp-howto/ata.rst b/bsp-howto/ata.rst new file mode 100644 index 0000000..1d3546d --- /dev/null +++ b/bsp-howto/ata.rst @@ -0,0 +1,181 @@ +.. comment SPDX-License-Identifier: CC-BY-SA-4.0 + +.. COMMENT: COPYRIGHT (c) 1988-2002. +.. COMMENT: On-Line Applications Research Corporation (OAR). +.. COMMENT: All rights reserved. + +ATA Driver +########## + +Terms +===== + +ATA device - physical device attached to an IDE controller + +Introduction +============ + +ATA driver provides generic interface to an ATA device. ATA driver is hardware +independent implementation of ATA standard defined in working draft "AT +Attachment Interface with Extensions (ATA-2)" X3T10/0948D revision 4c, March +18, 1996. ATA Driver based on IDE Controller Driver and may be used for +computer systems with single IDE controller and with multiple as well. Although +current implementation has several restrictions detailed below ATA driver +architecture allows easily extend the driver. Current restrictions are: + +- Only mandatory (see draft p.29) and two optional (READ/WRITE MULTIPLE) + commands are implemented + +- Only PIO mode is supported but both poll and interrupt driven + +The reference implementation for ATA driver can be found in +``cpukit/libblock/src/ata.c``. + +Initialization +============== + +The ``ata_initialize`` routine is responsible for ATA driver +initialization. The main goal of the initialization is to detect and register +in the system all ATA devices attached to IDE controllers successfully +initialized by the IDE Controller driver. + +In the implementation of the driver, the following actions are performed: + +.. code-block:: c + + rtems_device_driver ata_initialize( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg + ) + { + initialize internal ATA driver data structure + + for each IDE controller successfully initialized by the IDE Controller driver + if the controller is interrupt driven + set up interrupt handler + + obtain information about ATA devices attached to the controller + with help of EXECUTE DEVICE DIAGNOSTIC command + + for each ATA device detected on the controller + obtain device parameters with help of DEVICE IDENTIFY command + + register new ATA device as new block device in the system + } + +Special processing of ATA commands is required because of absence of +multitasking environment during the driver initialization. + +Detected ATA devices are registered in the system as physical block devices +(see libblock library description). Device names are formed based on IDE +controller minor number device is attached to and device number on the +controller (0 - Master, 1 - Slave). In current implementation 64 minor numbers +are reserved for each ATA device which allows to support up to 63 logical +partitions per device. + +================ ============= =========== ================ +controller minor device number device name ata device minor +================ ============= =========== ================ +0 0 hda 0 +0 1 hdb 64 +1 0 hdc 128 +1 1 hdd 172 +... ... ... ... +================ ============= =========== ================ + +ATA Driver Architecture +======================= + +ATA Driver Main Internal Data Structures +---------------------------------------- + +ATA driver works with ATA requests. ATA request is described by the following +structure: + +.. code-block:: c + + /* ATA request */ + typedef struct ata_req_s { + Chain_Node link; /* link in requests chain */ + char type; /* request type */ + ata_registers_t regs; /* ATA command */ + uint32_t cnt; /* Number of sectors to be exchanged */ + uint32_t cbuf; /* number of current buffer from breq in use */ + uint32_t pos; /* current position in 'cbuf' */ + blkdev_request *breq; /* blkdev_request which corresponds to the ata request */ + rtems_id sema; /* semaphore which is used if synchronous + * processing of the ata request is required */ + rtems_status_code status; /* status of ata request processing */ + int error; /* error code */ + } ata_req_t; + +ATA driver supports separate ATA requests queues for each IDE controller (one +queue per controller). The following structure contains information about +controller's queue and devices attached to the controller: + +.. code-block:: c + + /* + * This structure describes controller state, devices configuration on the + * controller and chain of ATA requests to the controller. + */ + typedef struct ata_ide_ctrl_s { + bool present; /* controller state */ + ata_dev_t device[2]; /* ata devices description */ + Chain_Control reqs; /* requests chain */ + } ata_ide_ctrl_t; + +Driver uses array of the structures indexed by the controllers minor number. + +The following structure allows to map an ATA device to the pair (IDE controller +minor number device is attached to, device number on the controller): + +.. code-block:: c + + /* + * Mapping of RTEMS ATA devices to the following pairs: + * (IDE controller number served the device, device number on the controller) + */ + typedef struct ata_ide_dev_s { + int ctrl_minor;/* minor number of IDE controller serves RTEMS ATA device */ + int device; /* device number on IDE controller (0 or 1) */ + } ata_ide_dev_t; + +Driver uses array of the structures indexed by the ATA devices minor number. + +ATA driver defines the following internal events: + +.. code-block:: c + + /* ATA driver events */ + typedef enum ata_msg_type_s { + ATA_MSG_GEN_EVT = 1, /* general event */ + ATA_MSG_SUCCESS_EVT, /* success event */ + ATA_MSG_ERROR_EVT, /* error event */ + ATA_MSG_PROCESS_NEXT_EVT /* process next ata request event */ + } ata_msg_type_t; + +Brief ATA Driver Core Overview +------------------------------ + +All ATA driver functionality is available via ATA driver ioctl. Current +implementation supports only two ioctls: ``BLKIO_REQUEST`` and +``ATAIO_SET_MULTIPLE_MODE``. Each ATA driver ``ioctl()`` call generates an ATA +request which is appended to the appropriate controller queue depending on ATA +device the request belongs to. If appended request is single request in the +controller's queue then ATA driver event is generated. + +ATA driver task which manages queue of ATA driver events is core of ATA +driver. In current driver version queue of ATA driver events implemented as +RTEMS message queue. Each message contains event type, IDE controller minor +number on which event happened and error if an error occurred. Events may be +generated either by ATA driver ioctl call or by ATA driver task itself. Each +time ATA driver task receives an event it gets controller minor number from +event, takes first ATA request from controller queue and processes it depending +on request and event types. An ATA request processing may also includes sending +of several events. If ATA request processing is finished the ATA request is +removed from the controller queue. Note, that in current implementation maximum +one event per controller may be queued at any moment of the time. + +(This part seems not very clear, hope I rewrite it soon) diff --git a/bsp-howto/clock.rst b/bsp-howto/clock.rst new file mode 100644 index 0000000..38b6d62 --- /dev/null +++ b/bsp-howto/clock.rst @@ -0,0 +1,297 @@ +.. comment SPDX-License-Identifier: CC-BY-SA-4.0 + +.. COMMENT: COPYRIGHT (c) 1988-2002. +.. COMMENT: On-Line Applications Research Corporation (OAR). +.. COMMENT: All rights reserved. + +Clock Driver +############ + +Introduction +============ + +The purpose of the clock driver is to provide two services for the operating +system. + +- A steady time basis to the kernel, so that the RTEMS primitives that need a + clock tick work properly. See the *Clock Manager* chapter of the *RTEMS + Application C User's Guide* for more details. + +- An optional time counter to generate timestamps of the uptime and wall clock + time. + +The clock driver is usually located in the :file:`clock` directory of the BSP. +Clock drivers should use the :dfn:`Clock Driver Shell` available via the +:file:`clockdrv_shell.h` include file. + +Clock Driver Shell +================== + +The :dfn:`Clock Driver Shell` include file defines the clock driver functions +declared in ``#include `` which are used by RTEMS +configuration file ``#include ``. In case the application +configuration defines ``#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER``, +then the clock driver is registered and should provide its services to the +operating system. A hardware specific clock driver must provide some +functions, defines and macros for the :dfn:`Clock Driver Shell` which are +explained here step by step. A clock driver file looks in general like this. + +.. code-block:: c + + /* + * A section with functions, defines and macros to provide hardware specific + * functions for the Clock Driver Shell. + */ + #include "../../../shared/clockdrv_shell.h" + +Initialization +-------------- + +Depending on the hardware capabilities one out of three clock driver variants +must be selected. + +- The most basic clock driver provides only a periodic interrupt service + routine which calls ``rtems_clock_tick()``. The interval is determined by + the application configuration via ``#define CONFIGURE_MICROSECONDS_PER_TICK`` + and can be obtained via ``rtems_configuration_get_microseconds_per_tick()``. + The timestamp resolution is limited to the clock tick interval. + +- In case the hardware lacks support for a free running counter, then the + module used for the clock tick may provide support for timestamps with a + resolution below the clock tick interval. For this so called simple + timecounters can be used. + +- The desired variant uses a free running counter to provide accurate + timestamps. This variant is mandatory on SMP configurations. + +Clock Tick Only Variant +~~~~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: c + + static void some_support_initialize_hardware( void ) + { + /* Initialize hardware */ + } + + #define Clock_driver_support_initialize_hardware() \ + some_support_initialize_hardware() + + /* Indicate that this clock driver lacks a proper timecounter in hardware */ + + #define CLOCK_DRIVER_USE_DUMMY_TIMECOUNTER + + #include "../../../shared/clockdrv_shell.h" + +Simple Timecounter Variant +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: c + + #include + + static rtems_timecounter_simple some_tc; + + static uint32_t some_tc_get( rtems_timecounter_simple *tc ) + { + return some.counter; + } + + static bool some_tc_is_pending( rtems_timecounter_simple *tc ) + { + return some.is_pending; + } + + static uint32_t some_tc_get_timecount( struct timecounter *tc ) + { + return rtems_timecounter_simple_downcounter_get( + tc, + some_tc_get, + some_tc_is_pending + ); + } + + static void some_tc_tick( void ) + { + rtems_timecounter_simple_downcounter_tick( &some_tc, some_tc_get ); + } + + static void some_support_initialize_hardware( void ) + { + uint32_t frequency = 123456; + uint64_t us_per_tick = rtems_configuration_get_microseconds_per_tick(); + uint32_t timecounter_ticks_per_clock_tick = + ( frequency * us_per_tick ) / 1000000; + + /* Initialize hardware */ + rtems_timecounter_simple_install( + &some_tc, + frequency, + timecounter_ticks_per_clock_tick, + some_tc_get_timecount + ); + } + + #define Clock_driver_support_initialize_hardware() \ + some_support_initialize_hardware() + #define Clock_driver_timecounter_tick() \ + some_tc_tick() + + #include "../../../shared/clockdrv_shell.h" + +Timecounter Variant +~~~~~~~~~~~~~~~~~~~ + +This variant is preferred since it is the most efficient and yields the most +accurate timestamps. It is also mandatory on SMP configurations to obtain +valid timestamps. The hardware must provide a periodic interrupt to service +the clock tick and a free running counter for the timecounter. The free +running counter must have a power of two period. The ``tc_counter_mask`` must +be initialized to the free running counter period minus one, e.g. for a 32-bit +counter this is 0xffffffff. The ``tc_get_timecount`` function must return the +current counter value (the counter values must increase, so if the counter +counts down, a conversion is necessary). Use +``RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER`` for the ``tc_quality``. Set +``tc_frequency`` to the frequency of the free running counter in Hz. All other +fields of the ``struct timecounter`` must be zero initialized. Install the +initialized timecounter via ``rtems_timecounter_install()``. + +.. code-block:: c + + #include + + static struct timecounter some_tc; + + static uint32_t some_tc_get_timecount( struct timecounter *tc ) + { + some.free_running_counter; + } + + static void some_support_initialize_hardware( void ) + { + uint64_t us_per_tick = rtems_configuration_get_microseconds_per_tick(); + uint32_t frequency = 123456; + + /* + * The multiplication must be done in 64-bit arithmetic to avoid an integer + * overflow on targets with a high enough counter frequency. + */ + uint32_t interval = (uint32_t) ( ( frequency * us_per_tick ) / 1000000 ); + + /* + * Initialize hardware and set up a periodic interrupt for the configuration + * based interval. + */ + some_tc.tc_get_timecount = some_tc_get_timecount; + some_tc.tc_counter_mask = 0xffffffff; + some_tc.tc_frequency = frequency; + some_tc.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER; + rtems_timecounter_install( &some_tc ); + } + + #define Clock_driver_support_initialize_hardware() \ + some_support_initialize_hardware() + + #include "../../../shared/clockdrv_shell.h" + +Install Clock Tick Interrupt Service Routine +-------------------------------------------- + +The clock driver must provide a function to install the clock tick interrupt +service routine via ``Clock_driver_support_install_isr()``. + +.. code-block:: c + + #include + #include + + static void some_support_install_isr( rtems_interrupt_handler isr ) + { + rtems_status_code sc; + sc = rtems_interrupt_handler_install( + SOME_IRQ, + "Clock", + RTEMS_INTERRUPT_UNIQUE, + isr, + NULL + ); + if ( sc != RTEMS_SUCCESSFUL ) { + bsp_fatal( SOME_FATAL_IRQ_INSTALL ); + } + } + + #define Clock_driver_support_install_isr( isr, old ) \ + some_support_install_isr( isr ) + + #include "../../../shared/clockdrv_shell.h" + +Support At Tick +--------------- + +The hardware specific support at tick is specified by +``Clock_driver_support_at_tick()``. + +.. code-block:: c + + static void some_support_at_tick( void ) + { + /* Clear interrupt */ + } + + #define Clock_driver_support_at_tick() \ + some_support_at_tick() + + #include "../../../shared/clockdrv_shell.h" + +System Shutdown Support +----------------------- + +The :dfn:`Clock Driver Shell` provides the routine ``Clock_exit()`` that is +scheduled to be run during system shutdown via the ``atexit()`` routine. The +hardware specific shutdown support is specified by +``Clock_driver_support_shutdown_hardware()`` which is used by ``Clock_exit()``. +It should disable the clock tick source if it was enabled. This can be used to +prevent clock ticks after the system is shutdown. + +.. code-block:: c + + static void some_support_shutdown_hardware( void ) + { + /* Shutdown hardware */ + } + + #define Clock_driver_support_shutdown_hardware() \ + some_support_shutdown_hardware() + + #include "../../../shared/clockdrv_shell.h" + +Multiple Clock Driver Ticks Per Clock Tick +------------------------------------------ + +In case the hardware needs more than one clock driver tick per clock tick (e.g. +due to a limited range of the hardware timer), then this can be specified with +the optional ``#define CLOCK_DRIVER_ISRS_PER_TICK`` and ``#define +CLOCK_DRIVER_ISRS_PER_TICK_VALUE`` defines. This is currently used only for +x86 and it hopefully remains that way. + +.. code-block:: c + + /* Enable multiple clock driver ticks per clock tick */ + #define CLOCK_DRIVER_ISRS_PER_TICK 1 + + /* Specifiy the clock driver ticks per clock tick value */ + #define CLOCK_DRIVER_ISRS_PER_TICK_VALUE 123 + + #include "../../../shared/clockdrv_shell.h" + +Clock Driver Ticks Counter +-------------------------- + +The :dfn:`Clock Driver Shell` provide a global variable that is simply a count +of the number of clock driver interrupt service routines that have occurred. +This information is valuable when debugging a system. This variable is +declared as follows: + +.. code-block:: c + + volatile uint32_t Clock_driver_ticks; diff --git a/bsp-howto/command.rst b/bsp-howto/command.rst new file mode 100644 index 0000000..46bd174 --- /dev/null +++ b/bsp-howto/command.rst @@ -0,0 +1,9 @@ +.. comment SPDX-License-Identifier: CC-BY-SA-4.0 + +Command and Variable Index +########################## + +There are currently no Command and Variable Index entries. + +.. COMMENT: @printindex fn + diff --git a/bsp-howto/conf.py b/bsp-howto/conf.py new file mode 100644 index 0000000..2fa48ba --- /dev/null +++ b/bsp-howto/conf.py @@ -0,0 +1,13 @@ +import sys, os +sys.path.append(os.path.abspath('../common/')) + +from conf import * + +version = '4.11.0' +release = '4.11.0' + +project = "RTEMS BSP and Device Driver Development Guide" + +latex_documents = [ + ('index', 'bsp-howto.tex', u'RTEMS BSP and Device Driver Development Guide', u'RTEMS Documentation Project', 'manual'), +] diff --git a/bsp-howto/console.rst b/bsp-howto/console.rst new file mode 100644 index 0000000..bcca519 --- /dev/null +++ b/bsp-howto/console.rst @@ -0,0 +1,579 @@ +.. comment SPDX-License-Identifier: CC-BY-SA-4.0 + +.. COMMENT: COPYRIGHT (c) 1988-2002. +.. COMMENT: On-Line Applications Research Corporation (OAR). +.. COMMENT: All rights reserved. + +Console Driver +############## + +Introduction +============ + +This chapter describes the operation of a console driver using the RTEMS POSIX +Termios support. Traditionally RTEMS has referred to all serial device drivers +as console device drivers. A console driver can be used to do raw data +processing in addition to the "normal" standard input and output device +functions required of a console. + +The serial driver may be called as the consequence of a C Library call such as +``printf`` or ``scanf`` or directly via the``read`` or ``write`` system calls. +There are two main functioning modes: + +- console: formatted input/output, with special characters (end of line, + tabulations, etc.) recognition and processing, + +- raw: permits raw data processing. + +One may think that two serial drivers are needed to handle these two types of +data, but Termios permits having only one driver. + +Termios +======= + +Termios is a standard for terminal management, included in the POSIX 1003.1b +standard. As part of the POSIX and Open Group Single UNIX Specification, is +commonly provided on UNIX implementations. The Open Group has the termios +portion of the POSIX standard online at +http://opengroup.org/onlinepubs/007908775/xbd/termios.html. The requirements +for the ```` file are also provided and are at +http://opengroup.org/onlinepubs/007908775/xsh/termios.h.html. + +Having RTEMS support for Termios is beneficial because: + +- from the user's side because it provides standard primitive operations to + access the terminal and change configuration settings. These operations are + the same under UNIX and RTEMS. + +- from the BSP developer's side because it frees the developer from dealing + with buffer states and mutual exclusions on them. Early RTEMS console device + drivers also did their own special character processing. + +- it is part of an internationally recognized standard. + +- it makes porting code from other environments easier. + +Termios support includes: + +- raw and console handling, + +- blocking or non-blocking characters receive, with or without Timeout. + +At this time, RTEMS documentation does not include a thorough discussion of the +Termios functionality. For more information on Termios, type ``man termios`` +on a Unix box or point a web browser athttp://www.freebsd.org/cgi/man.cgi. + +Driver Functioning Modes +======================== + +There are generally three main functioning modes for an UART (Universal +Asynchronous Receiver-Transmitter, i.e. the serial chip): + +- polled mode + +- interrupt driven mode + +- task driven mode + +In polled mode, the processor blocks on sending/receiving characters. This +mode is not the most efficient way to utilize the UART. But polled mode is +usually necessary when one wants to print an error message in the event of a +fatal error such as a fatal error in the BSP. This is also the simplest mode +to program. Polled mode is generally preferred if the serial port is to be +used primarily as a debug console. In a simple polled driver, the software +will continuously check the status of the UART when it is reading or writing to +the UART. Termios improves on this by delaying the caller for 1 clock tick +between successive checks of the UART on a read operation. + +In interrupt driven mode, the processor does not block on sending/receiving +characters. Data is buffered between the interrupt service routine and +application code. Two buffers are used to insulate the application from the +relative slowness of the serial device. One of the buffers is used for +incoming characters, while the other is used for outgoing characters. + +An interrupt is raised when a character is received by the UART. The interrupt +subroutine places the incoming character at the end of the input buffer. When +an application asks for input, the characters at the front of the buffer are +returned. + +When the application prints to the serial device, the outgoing characters are +placed at the end of the output buffer. The driver will place one or more +characters in the UART (the exact number depends on the UART) An interrupt will +be raised when all the characters have been transmitted. The interrupt service +routine has to send the characters remaining in the output buffer the same way. +When the transmitting side of the UART is idle, it is typically necessary to +prime the transmitter before the first interrupt will occur. + +The task driven mode is similar to interrupt driven mode, but the actual data +processing is done in dedicated tasks instead of interrupt routines. + +Serial Driver Functioning Overview +================================== + +The following Figure shows how a Termios driven serial driver works: Figure not +included in ASCII version + +The following list describes the basic flow. + +- the application programmer uses standard C library call (printf, scanf, read, + write, etc.), + +- C library (ctx.g. RedHat (formerly Cygnus) Newlib) calls the RTEMS system + call interface. This code can be found in the:file:`cpukit/libcsupport/src` + directory. + +- Glue code calls the serial driver entry routines. + +Basics +------ + +The low-level driver API changed between RTEMS 4.10 and RTEMS 4.11. The legacy +callback API is still supported, but its use is discouraged. The following +functions are deprecated: + +- ``rtems_termios_open()`` - use ``rtems_termios_device_open()`` in combination + with ``rtems_termios_device_install()`` instead. + +- ``rtems_termios_close()`` - use ``rtems_termios_device_close()`` instead. + +This manual describes the new API. A new console driver should consist of +three parts. + +- The basic console driver functions using the Termios support. Add this the + BSPs Makefile.am: + +.. code-block:: makefile + + [...] + libbsp_a_SOURCES += ../../shared/console-termios.c + [...] + +- A general serial module specific low-level driver providing the handler table + for the Termios ``rtems_termios_device_install()`` function. This low-level + driver could be used for more than one BSP. + +- A BSP specific initialization routine ``console_initialize()``, that calls + ``rtems_termios_device_install()`` providing a low-level driver context for + each installed device. + +You need to provide a device handler structure for the Termios device +interface. The functions are described later in this chapter. The first open +and set attributes handler return a boolean status to indicate success (true) +or failure (false). The polled read function returns an unsigned character in +case one is available or minus one otherwise. + +If you want to use polled IO it should look like the following. Termios must +be told the addresses of the handler that are to be used for simple character +IO, i.e. pointers to the ``my_driver_poll_read()`` and +``my_driver_poll_write()`` functions described later in `Termios and Polled +IO`_. + +.. code-block:: c + + const rtems_termios_handler my_driver_handler_polled = { + .first_open = my_driver_first_open, + .last_close = my_driver_last_close, + .poll_read = my_driver_poll_read, + .write = my_driver_poll_write, + .set_attributes = my_driver_set_attributes, + .stop_remote_tx = NULL, + .start_remote_tx = NULL, + .mode = TERMIOS_POLLED + } + +For an interrupt driven implementation you need the following. The driver +functioning is quite different in this mode. There is no device driver read +handler to be passed to Termios. Indeed a ``console_read()`` call returns the +contents of Termios input buffer. This buffer is filled in the driver +interrupt subroutine, see also `Termios and Interrupt Driven IO`_. The driver +is responsible for providing a pointer to the``my_driver_interrupt_write()`` +function. + +.. code-block:: c + + const rtems_termios_handler my_driver_handler_interrupt = { + .first_open = my_driver_first_open, + .last_close = my_driver_last_close, + .poll_read = NULL, + .write = my_driver_interrupt_write, + .set_attributes = my_driver_set_attributes, + .stopRemoteTx = NULL, + .stop_remote_tx = NULL, + .start_remote_tx = NULL, + .mode = TERMIOS_IRQ_DRIVEN + }; + +You can also provide hander for remote transmission control. This is not +covered in this manual, so they are set to ``NULL`` in the above examples. + +The low-level driver should provide a data structure for its device context. +The initialization routine must provide a context for each installed device via +``rtems_termios_device_install()``. For simplicity of the console +initialization example the device name is also present. Here is an example +header file. + +.. code-block:: c + + #ifndef MY_DRIVER_H + #define MY_DRIVER_H + + #include + #include + + /* Low-level driver specific data structure */ + typedef struct { + rtems_termios_device_context base; + const char *device_name; + volatile module_register_block *regs; + /* More stuff */ + } my_driver_context; + + extern const rtems_termios_handler my_driver_handler_polled; + extern const rtems_termios_handler my_driver_handler_interrupt; + + #endif /* MY_DRIVER_H */ + +Termios and Polled IO +--------------------- + +The following handler are provided by the low-level driver and invoked by +Termios for simple character IO. + +The ``my_driver_poll_write()`` routine is responsible for writing ``n`` +characters from ``buf`` to the serial device specified by ``tty``. + +.. code-block:: c + + static void my_driver_poll_write( + rtems_termios_device_context *base, + const char *buf, + size_t n + ) + { + my_driver_context *ctx = (my_driver_context *) base; + size_t i; + /* Write */ + for (i = 0; i < n; ++i) { + my_driver_write_char(ctx, buf[i]); + } + } + +The ``my_driver_poll_read`` routine is responsible for reading a single +character from the serial device specified by ``tty``. If no character is +available, then the routine should return minus one. + +.. code-block:: c + + static int my_driver_poll_read(rtems_termios_device_context *base) + { + my_driver_context *ctx = (my_driver_context *) base; + /* Check if a character is available */ + if (my_driver_can_read_char(ctx)) { + /* Return the character */ + return my_driver_read_char(ctx); + } else { + /* Return an error status */ + return -1; + } + } + +Termios and Interrupt Driven IO +------------------------------- + +The UART generally generates interrupts when it is ready to accept or to emit a +number of characters. In this mode, the interrupt subroutine is the core of +the driver. + +The ``my_driver_interrupt_handler()`` is responsible for processing +asynchronous interrupts from the UART. There may be multiple interrupt +handlers for a single UART. Some UARTs can generate a unique interrupt vector +for each interrupt source such as a character has been received or the +transmitter is ready for another character. + +In the simplest case, the ``my_driver_interrupt_handler()`` will have to check +the status of the UART and determine what caused the interrupt. The following +describes the operation of an ``my_driver_interrupt_handler`` which has to do +this: + +.. code-block:: c + + static void my_driver_interrupt_handler( + rtems_vector_number vector, + void *arg + ) + { + rtems_termios_tty *tty = arg; + my_driver_context *ctx = rtems_termios_get_device_context(tty); + char buf[N]; + size_t n; + + /* + * Check if we have received something. The function reads the + * received characters from the device and stores them in the + * buffer. It returns the number of read characters. + */ + n = my_driver_read_received_chars(ctx, buf, N); + if (n > 0) { + /* Hand the data over to the Termios infrastructure */ + rtems_termios_enqueue_raw_characters(tty, buf, n); + } + + /* + * Check if we have something transmitted. The functions returns + * the number of transmitted characters since the last write to the + * device. + */ + n = my_driver_transmitted_chars(ctx); + if (n > 0) { + /* + * Notify Termios that we have transmitted some characters. It + * will call now the interrupt write function if more characters + * are ready for transmission. + */ + rtems_termios_dequeue_characters(tty, n); + } + } + +The ``my_driver_interrupt_write()`` function is responsible for telling the +device that the ``n`` characters at ``buf`` are to be transmitted. It the +value ``n`` is zero to indicate that no more characters are to send. The +driver can disable the transmit interrupts now. This routine is invoked either +from task context with disabled interrupts to start a new transmission process +with exactly one character in case of an idle output state or from the +interrupt handler to refill the transmitter. If the routine is invoked to +start the transmit process the output state will become busy and Termios starts +to fill the output buffer. If the transmit interrupt arises before Termios was +able to fill the transmit buffer you will end up with one interrupt per +character. + +.. code-block:: c + + static void my_driver_interrupt_write( + rtems_termios_device_context *base, + const char *buf, + size_t n + ) + { + my_driver_context *ctx = (my_driver_context *) base; + + /* + * Tell the device to transmit some characters from buf (less than + * or equal to n). When the device is finished it should raise an + * interrupt. The interrupt handler will notify Termios that these + * characters have been transmitted and this may trigger this write + * function again. You may have to store the number of outstanding + * characters in the device data structure. + */ + /* + * Termios will set n to zero to indicate that the transmitter is + * now inactive. The output buffer is empty in this case. The + * driver may disable the transmit interrupts now. + */ + } + +Initialization +-------------- + +The BSP specific driver initialization is called once during the RTEMS +initialization process. + +The ``console_initialize()`` function may look like this: + +.. code-block:: c + + #include + #include + #include + #include + + static my_driver_context driver_context_table[M] = { /* Some values */ }; + + rtems_device_driver console_initialize( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg + ) + { + rtems_status_code sc; + #ifdef SOME_BSP_USE_INTERRUPTS + const rtems_termios_handler *handler = &my_driver_handler_interrupt; + #else + const rtems_termios_handler *handler = &my_driver_handler_polled; + #endif + + /* + * Initialize the Termios infrastructure. If Termios has already + * been initialized by another device driver, then this call will + * have no effect. + */ + rtems_termios_initialize(); + + /* Initialize each device */ + for ( + minor = 0; + minor < RTEMS_ARRAY_SIZE(driver_context_table); + ++minor + ) { + my_driver_context *ctx = &driver_context_table[minor]; + + /* + * Install this device in the file system and Termios. In order + * to use the console (i.e. being able to do printf, scanf etc. + * on stdin, stdout and stderr), one device must be registered as + * "/dev/console" (CONSOLE_DEVICE_NAME). + */ + sc = rtems_termios_device_install( + ctx->device_name, + major, + minor, + handler, + NULL, + ctx + ); + if (sc != RTEMS_SUCCESSFUL) { + bsp_fatal(SOME_BSP_FATAL_CONSOLE_DEVICE_INSTALL); + } + } + + return RTEMS_SUCCESSFUL; + } + +Opening a serial device +----------------------- + +The ``console_open()`` function provided by :file:`console-termios.c` is called +whenever a serial device is opened. The device registered as +``"/dev/console"`` (``CONSOLE_DEVICE_NAME``) is opened automatically during +RTEMS initialization. For instance, if UART channel 2 is registered as +``"/dev/tty1"``, the ``console_open()`` entry point will be called as the +result of an ``fopen("/dev/tty1", mode)`` in the application. + +During the first open of the device Termios will call the +``my_driver_first_open()`` handler. + +.. code-block:: c + + static bool my_driver_first_open( + rtems_termios_tty *tty, + rtems_termios_device_context *base, + struct termios *term, + rtems_libio_open_close_args_t *args + ) + { + my_driver_context *ctx = (my_driver_context *) base; + rtems_status_code sc; + bool ok; + + /* + * You may add some initialization code here. + */ + + /* + * Sets the initial baud rate. This should be set to the value of + * the boot loader. This function accepts only exact Termios baud + * values. + */ + sc = rtems_termios_set_initial_baud(tty, MY_DRIVER_BAUD_RATE); + if (sc != RTEMS_SUCCESSFUL) { + /* Not a valid Termios baud */ + } + + /* + * Alternatively you can set the best baud. + */ + rtems_termios_set_best_baud(term, MY_DRIVER_BAUD_RATE); + + /* + * To propagate the initial Termios attributes to the device use + * this. + */ + ok = my_driver_set_attributes(base, term); + if (!ok) { + /* This is bad */ + } + + /* + * Return true to indicate a successful set attributes, and false + * otherwise. + */ + return true; + } + +Closing a Serial Device +----------------------- + +The ``console_close()`` provided by :file:`console-termios.c` is invoked when +the serial device is to be closed. This entry point corresponds to the device +driver close entry point. + +Termios will call the ``my_driver_last_close()`` handler if the last close +happens on the device. + +.. code-block:: c + + static void my_driver_last_close( + rtems_termios_tty *tty, + rtems_termios_device_context *base, + rtems_libio_open_close_args_t *args + ) + { + my_driver_context *ctx = (my_driver_context *) base; + + /* + * The driver may do some cleanup here. + */ + } + +Reading Characters from a Serial Device +--------------------------------------- + +The ``console_read()`` provided by :file:`console-termios.c` is invoked when +the serial device is to be read from. This entry point corresponds to the +device driver read entry point. + +Writing Characters to a Serial Device +------------------------------------- + +The ``console_write()`` provided by :file:`console-termios.c` is invoked when +the serial device is to be written to. This entry point corresponds to the +device driver write entry point. + +Changing Serial Line Parameters +------------------------------- + +The ``console_control()`` provided by :file:`console-termios.c` is invoked when +the line parameters for a particular serial device are to be changed. This +entry point corresponds to the device driver IO control entry point. + +The application writer is able to control the serial line configuration with +Termios calls (such as the ``ioctl()`` command, see the Termios documentation +for more details). If the driver is to support dynamic configuration, then it +must have the ``console_control()`` piece of code. Basically ``ioctl()`` +commands call ``console_control()`` with the serial line configuration in a +Termios defined data structure. + +The driver is responsible for reinitializing the device with the correct +settings. For this purpose Termios calls the ``my_driver_set_attributes()`` +handler. + +.. code-block:: c + + static bool my_driver_set_attributes( + rtems_termios_device_context *base, + const struct termios *term + ) + { + my_driver_context *ctx = (my_driver_context *) base; + + /* + * Inspect the termios data structure and configure the device + * appropriately. The driver should only be concerned with the + * parts of the structure that specify hardware setting for the + * communications channel such as baud, character size, etc. + */ + /* + * Return true to indicate a successful set attributes, and false + * otherwise. + */ + return true; + } diff --git a/bsp-howto/discrete.rst b/bsp-howto/discrete.rst new file mode 100644 index 0000000..6fbc51e --- /dev/null +++ b/bsp-howto/discrete.rst @@ -0,0 +1,190 @@ +.. comment SPDX-License-Identifier: CC-BY-SA-4.0 + +Discrete Driver +############### + +The Discrete driver is responsible for providing an interface to Discrete +Input/Outputs. The capabilities provided by this class of device driver are: + +- Initialize a Discrete I/O Board + +- Open a Particular Discrete Bitfield + +- Close a Particular Discrete Bitfield + +- Read from a Particular Discrete Bitfield + +- Write to a Particular Discrete Bitfield + +- Reset DACs + +- Reinitialize DACS + +Most discrete I/O devices are found on I/O cards that support many bits of +discrete I/O on a single card. This driver model is centered on the notion of +reading bitfields from the card. + +There are currently no discrete I/O device drivers included in the RTEMS source +tree. The information provided in this chapter is based on drivers developed +for applications using RTEMS. It is hoped that this driver model information +can form the discrete I/O driver model that can be supported in future RTEMS +distribution. + +Major and Minor Numbers +======================= + +The ``major`` number of a device driver is its index in the RTEMS Device +Address Table. + +A ``minor`` number is associated with each device instance managed by a +particular device driver. An RTEMS minor number is an ``unsigned32`` entity. +Convention calls for dividing the bits in the minor number down into categories +that specify a particular bitfield. This results in categories like the +following: + +- ``board`` - indicates the board a particular bitfield is located on + +- ``word`` - indicates the particular word of discrete bits the bitfield is + located within + +- ``start`` - indicates the starting bit of the bitfield + +- ``width`` - indicates the width of the bitfield + +From the above, it should be clear that a single device driver can support +multiple copies of the same board in a single system. The minor number is used +to distinguish the devices. + +By providing a way to easily access a particular bitfield from the device +driver, the application is insulated with knowing how to mask fields in and out +of a discrete I/O. + +Discrete I/O Driver Configuration +================================= + +There is not a standard discrete I/O driver configuration table but some fields +are common across different drivers. The discrete I/O driver configuration +table is typically an array of structures with each structure containing the +information for a particular board. The following is a list of the type of +information normally required to configure an discrete I/O board: + +``board_offset`` + is the base address of a board. + +``relay_initial_values`` + is an array of the values that should be written to each output word on the + board during initialization. This allows the driver to start with the + board's output in a known state. + +Initialize a Discrete I/O Board +=============================== + +At system initialization, the discrete I/O driver's initialization entry point +will be invoked. As part of initialization, the driver will perform whatever +board initializatin is required and then set all outputs to their configured +initial state. + +The discrete I/O driver may register a device name for bitfields of particular +interest to the system. Normally this will be restricted to the names of each +word and, if the driver supports it, an "all words". + +Open a Particular Discrete Bitfield +=================================== + +This is the driver open call. Usually this call does nothing other than +validate the minor number. + +With some drivers, it may be necessary to allocate memory when a particular +device is opened. If that is the case, then this is often the place to do this +operation. + +Close a Particular Discrete Bitfield +==================================== + +This is the driver close call. Usually this call does nothing. + +With some drivers, it may be necessary to allocate memory when a particular +device is opened. If that is the case, then this is the place where that +memory should be deallocated. + +Read from a Particular Discrete Bitfield +======================================== + +This corresponds to the driver read call. After validating the minor number +and arguments, this call reads the indicated bitfield. A discrete I/O devices +may have to store the last value written to a discrete output. If the bitfield +is output only, saving the last written value gives the appearance that it can +be read from also. If the bitfield is input, then it is sampled. + +.. note:: + + Many discrete inputs have a tendency to bounce. The application may have to + take account for bounces. + +The value returned is an ``unsigned32`` number representing the bitfield read. +This value is stored in the ``argument_block`` passed in to the call. + +.. note:: + + Some discrete I/O drivers have a special minor number used to access all + discrete I/O bits on the board. If this special minor is used, then the + area pointed to by ``argument_block`` must be the correct size. + +Write to a Particular Discrete Bitfield +======================================= + +This corresponds to the driver write call. After validating the minor number +and arguments, this call writes the indicated device. If the specified device +is an ADC, then an error is usually returned. + +The value written is an ``unsigned32`` number representing the value to be +written to the specified bitfield. This value is stored in the +``argument_block`` passed in to the call. + +.. note:: + + Some discrete I/O drivers have a special minor number used to access all + discrete I/O bits on the board. If this special minor is used, then the + area pointed to by ``argument_block`` must be the correct size. + +Disable Discrete Outputs +======================== + +This is one of the IOCTL functions supported by the I/O control device driver +entry point. When this IOCTL function is invoked, the discrete outputs are +disabled. + +.. note:: + + It may not be possible to disable/enable discrete output on all discrete I/O + boards. + +Enable Discrete Outputs +======================= + +This is one of the IOCTL functions supported by the I/O control device driver +entry point. When this IOCTL function is invoked, the discrete outputs are +enabled. + +.. note:: + + It may not be possible to disable/enable discrete output on all discrete + I/O boards. + +Reinitialize Outputs +==================== + +This is one of the IOCTL functions supported by the I/O control device driver +entry point. When this IOCTL function is invoked, the discrete outputs are +rewritten with the configured initial output values. + +Get Last Written Values +======================= + +This is one of the IOCTL functions supported by the I/O control device driver +entry point. When this IOCTL function is invoked, the following information is +returned to the caller: + +- last value written to the specified output word + +- timestamp of when the last write was performed diff --git a/bsp-howto/frame_buffer.rst b/bsp-howto/frame_buffer.rst new file mode 100644 index 0000000..006191c --- /dev/null +++ b/bsp-howto/frame_buffer.rst @@ -0,0 +1,256 @@ +.. comment SPDX-License-Identifier: CC-BY-SA-4.0 + +.. COMMENT: COPYRIGHT (c) 1988-2002. +.. COMMENT: On-Line Applications Research Corporation (OAR). +.. COMMENT: All rights reserved. + +Frame Buffer Driver +################### + +In this chapter, we present the basic functionality implemented by a frame +buffer driver: + +- ``frame_buffer_initialize()`` +- ``frame_buffer_open()`` +- ``frame_buffer_close()`` +- ``frame_buffer_read()`` +- ``frame_buffer_write()`` +- ``frame_buffer_control()`` + +Introduction +============ + +The purpose of the frame buffer driver is to provide an abstraction for +graphics hardware. By using the frame buffer interface, an application can +display graphics without knowing anything about the low-level details of +interfacing to a particular graphics adapter. The parameters governing the +mapping of memory to displayed pixels (planar or linear, bit depth, etc) is +still implementation-specific, but device-independent methods are provided to +determine and potentially modify these parameters. + +The frame buffer driver is commonly located in the ``console`` directory of the +BSP and registered by the name :file:`/dev/fb0`. Additional frame buffers (if +available) are named :file:`/dev/fb1*,*/dev/fb2`, etc. + +To work with the frame buffer, the following operation sequence is +used:``open()``, ``ioctls()`` to get the frame buffer info, ``read()`` +and/or ``write()``, and ``close()``. + +Driver Function Overview +======================== + +Initialization +-------------- + +The driver initialization is called once during the RTEMS initialization +process and returns ``RTEMS_SUCCESSFUL`` when the device driver is successfully +initialized. During the initialization, a name is assigned to the frame buffer +device. If the graphics hardware supports console text output, as is the case +with the pc386 VGA hardware, initialization into graphics mode may be deferred +until the device is ``open()`` ed. + +The ``frame_buffer_initialize()`` function may look like this: + +.. code-block:: c + + rtems_device_driver frame_buffer_initialize( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg) + { + rtems_status_code status; + + printk( "frame buffer driver initializing..\n" ); + + /* + * Register the device + */ + status = rtems_io_register_name("/dev/fb0", major, 0); + if (status != RTEMS_SUCCESSFUL) + { + printk("Error registering frame buffer device!\n"); + rtems_fatal_error_occurred( status ); + } + + /* + * graphics hardware initialization goes here for non-console + * devices + */ + + return RTEMS_SUCCESSFUL; + } + +Opening the Frame Buffer Device +------------------------------- + +The ``frame_buffer_open()`` function is called whenever a frame buffer device +is opened. If the frame buffer is registered as :file:`/dev/fb0`, the +``frame_buffer_open`` entry point will be called as the result of an +``open("/dev/fb0", mode)`` in the application. + +Thread safety of the frame buffer driver is implementation-dependent. The VGA +driver shown below uses a mutex to prevent multiple open() operations of the +frame buffer device. + +The ``frame_buffer_open()`` function returns ``RTEMS_SUCCESSFUL`` when the +device driver is successfully opened, and ``RTEMS_UNSATISFIED`` if the device +is already open: + +.. code-block:: c + + rtems_device_driver frame_buffer_close( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg + ) + { + if (pthread_mutex_unlock(&mutex) == 0) { + /* restore previous state. for VGA this means return to text mode. + * leave out if graphics hardware has been initialized in + * frame_buffer_initialize() + */ + ega_hwterm(); + printk( "FBVGA close called.\n" ); + return RTEMS_SUCCESSFUL; + } + return RTEMS_UNSATISFIED; + } + +In the previous example, the function ``ega_hwinit()`` takes care of +hardware-specific initialization. + +Closing the Frame Buffer Device +------------------------------- + +The ``frame_buffer_close()`` is invoked when the frame buffer device is closed. +It frees up any resources allocated in ``frame_buffer_open()``, and should +restore previous hardware state. The entry point corresponds to the device +driver close entry point. + +Returns ``RTEMS_SUCCESSFUL`` when the device driver is successfully closed: + +.. code-block:: c + + rtems_device_driver frame_buffer_close( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg) + { + pthread_mutex_unlock(&mutex); + + /* TODO check mutex return value, RTEMS_UNSATISFIED if it failed. we + * don't want to unconditionally call ega_hwterm()... */ + /* restore previous state. for VGA this means return to text mode. + * leave out if graphics hardware has been initialized in + * frame_buffer_initialize() */ + ega_hwterm(); + printk( "frame buffer close called.\n" ); + return RTEMS_SUCCESSFUL; + } + +Reading from the Frame Buffer Device +------------------------------------ + +The ``frame_buffer_read()`` is invoked from a ``read()`` operation on the frame +buffer device. Read functions should allow normal and partial reading at the +end of frame buffer memory. This method returns ``RTEMS_SUCCESSFUL`` when the +device is successfully read from: + +.. code-block:: c + + rtems_device_driver frame_buffer_read( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg + ) + { + rtems_libio_rw_args_t *rw_args = (rtems_libio_rw_args_t *)arg; + rw_args->bytes_moved = ((rw_args->offset + rw_args->count) > fb_fix.smem_len ) ? + (fb_fix.smem_len - rw_args->offset) : rw_args->count; + memcpy(rw_args->buffer, + (const void *) (fb_fix.smem_start + rw_args->offset), + rw_args->bytes_moved); + return RTEMS_SUCCESSFUL; + } + +Writing to the Frame Buffer Device +---------------------------------- + +The ``frame_buffer_write()`` is invoked from a ``write()`` operation on the +frame buffer device. The frame buffer write function is similar to the read +function, and should handle similar cases involving partial writes. + +This method returns ``RTEMS_SUCCESSFUL`` when the device is successfully +written to: + +.. code-block:: c + + rtems_device_driver frame_buffer_write( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg + ) + { + rtems_libio_rw_args_t *rw_args = (rtems_libio_rw_args_t *)arg; + rw_args->bytes_moved = ((rw_args->offset + rw_args->count) > fb_fix.smem_len ) ? + (fb_fix.smem_len - rw_args->offset) : rw_args->count; + memcpy((void *) (fb_fix.smem_start + rw_args->offset), + rw_args->buffer, + rw_args->bytes_moved); + return RTEMS_SUCCESSFUL; + } + +Frame Buffer IO Control +----------------------- + +The frame buffer driver allows several ioctls, partially compatible with the +Linux kernel, to obtain information about the hardware. + +All ``ioctl()`` operations on the frame buffer device invoke +``frame_buffer_control()``. + +Ioctls supported: + +- ioctls to get the frame buffer screen info (fixed and variable). + +- ioctl to set and get palette. + +.. code-block:: c + + rtems_device_driver frame_buffer_control( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg + ) + { + rtems_libio_ioctl_args_t *args = arg; + + printk( "FBVGA ioctl called, cmd=%x\n", args->command ); + + switch( args->command ) { + case FBIOGET_FSCREENINFO: + args->ioctl_return = get_fix_screen_info( ( struct fb_fix_screeninfo * ) args->buffer ); + break; + case FBIOGET_VSCREENINFO: + args->ioctl_return = get_var_screen_info( ( struct fb_var_screeninfo * ) args->buffer ); + break; + case FBIOPUT_VSCREENINFO: + /* not implemented yet*/ + args->ioctl_return = -1; + return RTEMS_UNSATISFIED; + case FBIOGETCMAP: + args->ioctl_return = get_palette( ( struct fb_cmap * ) args->buffer ); + break; + case FBIOPUTCMAP: + args->ioctl_return = set_palette( ( struct fb_cmap * ) args->buffer ); + break; + default: + args->ioctl_return = 0; + break; + } + + return RTEMS_SUCCESSFUL; + } + +See ``rtems/fb.h`` for more information on the list of ioctls and data +structures they work with. diff --git a/bsp-howto/ide_controller.rst b/bsp-howto/ide_controller.rst new file mode 100644 index 0000000..82961da --- /dev/null +++ b/bsp-howto/ide_controller.rst @@ -0,0 +1,156 @@ +.. comment SPDX-License-Identifier: CC-BY-SA-4.0 + +.. COMMENT: COPYRIGHT (c) 1988-2002. +.. COMMENT: On-Line Applications Research Corporation (OAR). +.. COMMENT: All rights reserved. + +IDE Controller Driver +##################### + +Introduction +============ + +The IDE Controller driver is responsible for providing an interface to an IDE +Controller. The capabilities provided by this driver are: + +- Read IDE Controller register + +- Write IDE Controller register + +- Read data block through IDE Controller Data Register + +- Write data block through IDE Controller Data Register + +The reference implementation for an IDE Controller driver can be found in +``$RTEMS_SRC_ROOT/c/src/libchip/ide``. This driver is based on the libchip +concept and allows to work with any of the IDE Controller chips simply by +appropriate configuration of BSP. Drivers for a particular IDE Controller chips +locate in the following directories: drivers for well-known IDE Controller +chips locate into ``$RTEMS_SRC_ROOT/c/src/libchip/ide``, drivers for IDE +Controller chips integrated with CPU locate into +``$RTEMS_SRC_ROOT/c/src/lib/libcpu/myCPU`` and drivers for custom IDE +Controller chips (for example, implemented on FPGA) locate into +``$RTEMS_SRC_ROOT/c/src/lib/libbsp/myBSP``. There is a README file in these +directories for each supported IDE Controller chip. Each of these README +explains how to configure a BSP for that particular IDE Controller chip. + +Initialization +============== + +IDE Controller chips used by a BSP are statically configured into +``IDE_Controller_Table``. The ``ide_controller_initialize`` routine is +responsible for initialization of all configured IDE controller chips. +Initialization order of the chips based on the order the chips are defined in +the ``IDE_Controller_Table``. + +The following actions are performed by the IDE Controller driver initialization +routine: + +.. code-block:: c + + rtems_device_driver ide_controller_initialize( + rtems_device_major_number major, + rtems_device_minor_number minor_arg, + void *arg + ) + { + for each IDE Controller chip configured in IDE_Controller_Table + if (BSP dependent probe(if exists) AND device probe for this IDE chip + indicates it is present) + perform initialization of the particular chip + register device with configured name for this chip + } + +Read IDE Controller Register +============================ + +The ``ide_controller_read_register`` routine reads the content of the IDE +Controller chip register. IDE Controller chip is selected via the minor +number. This routine is not allowed to be called from an application. + +.. code-block:: c + + void ide_controller_read_register( + rtems_device_minor_number minor, + unsigned32 reg, + unsigned32 *value + ) + { + get IDE Controller chip configuration information from + IDE_Controller_Table by minor number + + invoke read register routine for the chip + } + +Write IDE Controller Register +============================= + +The ``ide_controller_write_register`` routine writes IDE Controller chip +register with specified value. IDE Controller chip is selected via the minor +number. This routine is not allowed to be called from an application. + +.. code-block:: c + + void ide_controller_write_register( + rtems_device_minor_number minor, + unsigned32 reg, + unsigned32 value + ) + { + get IDE Controller chip configuration information from + IDE_Controller_Table by minor number + + invoke write register routine for the chip + } + +Read Data Block Through IDE Controller Data Register +==================================================== + +The ``ide_controller_read_data_block`` provides multiple consequent read of the +IDE Controller Data Register. IDE Controller chip is selected via the minor +number. The same functionality may be achieved via separate multiple calls of +``ide_controller_read_register`` routine but ``ide_controller_read_data_block`` +allows to escape functions call overhead. This routine is not allowed to be +called from an application. + +.. code-block:: c + + void ide_controller_read_data_block( + rtems_device_minor_number minor, + unsigned16 block_size, + blkdev_sg_buffer *bufs, + uint32_t *cbuf, + uint32_t *pos + ) + { + get IDE Controller chip configuration information from + IDE_Controller_Table by minor number + + invoke read data block routine for the chip + } + +Write Data Block Through IDE Controller Data Register +===================================================== + +The ``ide_controller_write_data_block`` provides multiple consequent write into +the IDE Controller Data Register. IDE Controller chip is selected via the minor +number. The same functionality may be achieved via separate multiple calls of +``ide_controller_write_register`` routine but +``ide_controller_write_data_block`` allows to escape functions call +overhead. This routine is not allowed to be called from an application. + +.. code-block:: c + + void ide_controller_write_data_block( + rtems_device_minor_number minor, + unsigned16 block_size, + blkdev_sg_buffer *bufs, + uint32_t *cbuf, + uint32_t *pos + ) + { + get IDE Controller chip configuration information from + IDE_Controller_Table by minor number + + invoke write data block routine for the chip + } diff --git a/bsp-howto/index.rst b/bsp-howto/index.rst new file mode 100644 index 0000000..395067e --- /dev/null +++ b/bsp-howto/index.rst @@ -0,0 +1,63 @@ +.. comment SPDX-License-Identifier: CC-BY-SA-4.0 + +======================================= +BSP and Device Driver Development Guide +======================================= + +BSP and Device Driver Development Guide +--------------------------------------- + + | COPYRIGHT (c) 1988 - 2015. + | On-Line Applications Research Corporation (OAR). + +The authors have used their best efforts in preparing this material. These +efforts include the development, research, and testing of the theories and +programs to determine their effectiveness. No warranty of any kind, expressed +or implied, with regard to the software or the material contained in this +document is provided. No liability arising out of the application or use of +any product described in this document is assumed. The authors reserve the +right to revise this material and to make changes from time to time in the +content hereof without obligation to notify anyone of such revision or changes. + +The RTEMS Project is hosted at http://www.rtems.org. Any inquiries concerning +RTEMS, its related support components, or its documentation should be directed +to the Community Project hosted at http://www.rtems.org. + +.. topic:: RTEMS Online Resources + + ================ ============================= + Home https://www.rtems.org/ + Developers https://devel.rtems.org/ + Documentation https://docs.rtems.org/ + Bug Reporting https://devel.rtems.org/query + Mailing Lists https://lists.rtems.org/ + Git Repositories https://git.rtems.org/ + ================ ============================= + +.. toctree:: + :maxdepth: 3 + :numbered: + + preface + target_dependant_files + makefiles + linker_script + miscellanous_support + ada95_interrupt + initilization_code + console + clock + timer + real_time_clock + ata + ide_controller + non_volatile_memory + networking + shared_memory_support + frame_buffer + analog + discrete + command + +* :ref:`genindex` +* :ref:`search` diff --git a/bsp-howto/initilization_code.rst b/bsp-howto/initilization_code.rst new file mode 100644 index 0000000..a69731e --- /dev/null +++ b/bsp-howto/initilization_code.rst @@ -0,0 +1,382 @@ +.. comment SPDX-License-Identifier: CC-BY-SA-4.0 + +.. COMMENT: COPYRIGHT (c) 1988-2008. +.. COMMENT: On-Line Applications Research Corporation (OAR). +.. COMMENT: All rights reserved. + +Initialization Code +################### + +Introduction +============ + +The initialization code is the first piece of code executed when there's a +reset/reboot. Its purpose is to initialize the board for the application. This +chapter contains a narrative description of the initialization process followed +by a description of each of the files and routines commonly found in the BSP +related to initialization. The remainder of this chapter covers special issues +which require attention such as interrupt vector table and chip select +initialization. + +Most of the examples in this chapter will be based on the SPARC/ERC32 and +m68k/gen68340 BSP initialization code. Like most BSPs, the initialization for +these BSP is divided into two subdirectories under the BSP source directory. +The BSP source code for these BSPs is in the following directories: + +.. code-block:: shell + + c/src/lib/libbsp/m68k/gen68340 + c/src/lib/libbsp/sparc/erc32 + +Both BSPs contain startup code written in assembly language and C. The +gen68340 BSP has its early initialization start code in the ``start340`` +subdirectory and its C startup code in the ``startup`` directory. In the +``start340`` directory are two source files. The file ``startfor340only.s`` is +the simpler of these files as it only has initialization code for a MC68340 +board. The file ``start340.s`` contains initialization for a 68349 based board +as well. + +Similarly, the ERC32 BSP has startup code written in assembly language and C. +However, this BSP shares this code with other SPARC BSPs. Thus the +``Makefile.am`` explicitly references the following files for this +functionality. + +.. code-block:: shell + + ../../sparc/shared/start.S + +.. note:: + + In most BSPs, the directory named ``start340`` in the gen68340 BSP would be + simply named ``start`` or start followed by a BSP designation. + +Required Global Variables +========================= + +Although not strictly part of initialization, there are a few global variables +assumed to exist by reusable device drivers. These global variables should +only defined by the BSP when using one of these device drivers. + +The BSP author probably should be aware of the ``Configuration`` Table +structure generated by ```` during debug but should not +explicitly reference it in the source code. There are helper routines provided +by RTEMS to access individual fields. + +In older RTEMS versions, the BSP included a number of required global +variables. We have made every attempt to eliminate these in the interest of +simplicity. + +Board Initialization +==================== + +This section describes the steps an application goes through from the time the +first BSP code is executed until the first application task executes. + +The initialization flows from assembly language start code to the shared +``bootcard.c`` framework then through the C Library, RTEMS, device driver +initialization phases, and the context switch to the first application task. +After this, the application executes until it calls ``exit``, +``rtems_shutdown_executive``, or some other normal termination initiating +routine and a fatal system state is reached. The optional +``bsp_fatal_extension`` initial extension can perform BSP specific system +termination. + +The routines invoked during this will be discussed and their location in the +RTEMS source tree pointed out as we discuss each. + +Start Code - Assembly Language Initialization +--------------------------------------------- + +The assembly language code in the directory ``start`` is the first part of the +application to execute. It is responsible for initializing the processor and +board enough to execute the rest of the BSP. This includes: + +- initializing the stack + +- zeroing out the uninitialized data section ``.bss`` + +- disabling external interrupts + +- copy the initialized data from ROM to RAM + +The general rule of thumb is that the start code in assembly should do the +minimum necessary to allow C code to execute to complete the initialization +sequence. + +The initial assembly language start code completes its execution by invoking +the shared routine ``boot_card()``. + +The label (symbolic name) associated with the starting address of the program +is typically called ``start``. The start object file is the first object file +linked into the program image so it is ensured that the start code is at offset +0 in the ``.text`` section. It is the responsibility of the linker script in +conjunction with the compiler specifications file to put the start code in the +correct location in the application image. + +boot_card() - Boot the Card +--------------------------- + +The ``boot_card()`` is the first C code invoked. This file is the core +component in the RTEMS BSP Initialization Framework and provides the proper +sequencing of initialization steps for the BSP, RTEMS and device drivers. All +BSPs use the same shared version of ``boot_card()`` which is located in the +following file: + +.. code-block:: shell + + c/src/lib/libbsp/shared/bootcard.c + +The ``boot_card()`` routine performs the following functions: + +- It disables processor interrupts. + +- It sets the command line argument variables + for later use by the application. + +- It invokes the BSP specific routine ``bsp_work_area_initialize()`` which is + supposed to initialize the RTEMS Workspace and the C Program Heap. Usually + the default implementation in ``c/src/lib/libbsp/shared/bspgetworkarea.c`` + should be sufficient. Custom implementations can use + ``bsp_work_area_initialize_default()`` or + ``bsp_work_area_initialize_with_table()`` available as inline functions + from``#include ``. + +- It invokes the BSP specific routine ``bsp_start()`` which is written in C and + thus able to perform more advanced initialization. Often MMU, bus and + interrupt controller initialization occurs here. Since the RTEMS Workspace + and the C Program Heap was already initialized by + ``bsp_work_area_initialize()``, this routine may use ``malloc()``, etc. + +- It invokes the RTEMS directive ``rtems_initialize_data_structures()`` to + initialize the RTEMS executive to a state where objects can be created but + tasking is not enabled. + +- It invokes the BSP specific routine ``bsp_libc_init()`` to initialize the C + Library. Usually the default implementation in + ``c/src/lib/libbsp/shared/bsplibc.c`` should be sufficient. + +- It invokes the RTEMS directive ``rtems_initialize_before_drivers()`` to + initialize the MPCI Server thread in a multiprocessor configuration and + execute API specific extensions. + +- It invokes the BSP specific routine ``bsp_predriver_hook``. For most BSPs, + the implementation of this routine does nothing. + +- It invokes the RTEMS directive ``rtems_initialize_device_drivers()`` to + initialize the statically configured set of device drivers in the order they + were specified in the Configuration Table. + +- It invokes the BSP specific routine ``bsp_postdriver_hook``. For + most BSPs, the implementation of this routine does nothing. However, some + BSPs use this hook and perform some initialization which must be done at + this point in the initialization sequence. This is the last opportunity + for the BSP to insert BSP specific code into the initialization sequence. + +- It invokes the RTEMS directive ``rtems_initialize_start_multitasking()`` + which initiates multitasking and performs a context switch to the first user + application task and may enable interrupts as a side-effect of that context + switch. The context switch saves the executing context. The application + runs now. The directive ``rtems_shutdown_executive()`` will return to the + saved context. The ``exit()`` function will use this directive. After a + return to the saved context a fatal system state is reached. The fatal + source is ``RTEMS_FATAL_SOURCE_EXIT`` with a fatal code set to the value + passed to rtems_shutdown_executive(). The enabling of interrupts during the + first context switch is often the source for fatal errors during BSP + development because the BSP did not clear and/or disable all interrupt + sources and a spurious interrupt will occur. When in the context of the + first task but before its body has been entered, any C++ Global Constructors + will be invoked. + +That's it. We just went through the entire sequence. + +bsp_work_area_initialize() - BSP Specific Work Area Initialization +------------------------------------------------------------------ + +This is the first BSP specific C routine to execute during system +initialization. It must initialize the support for allocating memory from the +C Program Heap and RTEMS Workspace commonly referred to as the work areas. +Many BSPs place the work areas at the end of RAM although this is certainly not +a requirement. Usually the default implementation +in:file:`c/src/lib/libbsp/shared/bspgetworkarea.c` should be sufficient. +Custom implementations can use ``bsp_work_area_initialize_default()`` +or``bsp_work_area_initialize_with_table()`` available as inline functions from +``#include ``. + +bsp_start() - BSP Specific Initialization +----------------------------------------- + +This is the second BSP specific C routine to execute during system +initialization. It is called right after ``bsp_work_area_initialize()``. The +``bsp_start()`` routine often performs required fundamental hardware +initialization such as setting bus controller registers that do not have a +direct impact on whether or not C code can execute. The interrupt controllers +are usually initialized here. The source code for this routine is usually +found in the file :file:`c/src/lib/libbsp/${CPU}/${BSP}/startup/bspstart.c`. +It is not allowed to create any operating system objects, e.g. RTEMS +semaphores. + +After completing execution, this routine returns to the ``boot_card()`` +routine. In case of errors, the initialization should be terminated via +``bsp_fatal()``. + +bsp_predriver_hook() - BSP Specific Predriver Hook +-------------------------------------------------- + +The ``bsp_predriver_hook()`` method is the BSP specific routine that is invoked +immediately before the the device drivers are initialized. RTEMS initialization +is complete but interrupts and tasking are disabled. + +The BSP may use the shared version of this routine which is empty. Most BSPs +do not provide a specific implementation of this callback. + +Device Driver Initialization +---------------------------- + +At this point in the initialization sequence, the initialization routines for +all of the device drivers specified in the Device Driver Table are invoked. +The initialization routines are invoked in the order they appear in the Device +Driver Table. + +The Driver Address Table is part of the RTEMS Configuration Table. It defines +device drivers entry points (initialization, open, close, read, write, and +control). For more information about this table, please refer to the +*Configuring a System* chapter in the *RTEMS Application C User's Guide*. + +The RTEMS initialization procedure calls the initialization function for every +driver defined in the RTEMS Configuration Table (this allows one to include +only the drivers needed by the application). + +All these primitives have a major and a minor number as arguments: + +- the major number refers to the driver type, + +- the minor number is used to control two peripherals with the same driver (for + instance, we define only one major number for the serial driver, but two + minor numbers for channel A and B if there are two channels in the UART). + +RTEMS Postdriver Callback +------------------------- + +The ``bsp_postdriver_hook()`` BSP specific routine is invoked immediately after +the the device drivers and MPCI are initialized. Interrupts and tasking are +disabled. + +Most BSPs use the shared implementation of this routine which is responsible +for opening the device ``/dev/console`` for standard input, output and error if +the application has configured the Console Device Driver. This file is located +at: + +.. code-block:: shell + + c/src/lib/libbsp/shared/bsppost.c + +The Interrupt Vector Table +========================== + +The Interrupt Vector Table is called different things on different processor +families but the basic functionality is the same. Each entry in the Table +corresponds to the handler routine for a particular interrupt source. When an +interrupt from that source occurs, the specified handler routine is invoked. +Some context information is saved by the processor automatically when this +happens. RTEMS saves enough context information so that an interrupt service +routine can be implemented in a high level language. + +On some processors, the Interrupt Vector Table is at a fixed address. If this +address is in RAM, then usually the BSP only has to initialize it to contain +pointers to default handlers. If the table is in ROM, then the application +developer will have to take special steps to fill in the table. + +If the base address of the Interrupt Vector Table can be dynamically changed to +an arbitrary address, then the RTEMS port to that processor family will usually +allocate its own table and install it. For example, on some members of the +Motorola MC68xxx family, the Vector Base Register (``vbr``) contains this base +address. + +Interrupt Vector Table on the gen68340 BSP +------------------------------------------ + +The gen68340 BSP provides a default Interrupt Vector Table in the file +``$BSP_ROOT/start340/start340.s``. After the ``entry`` label is the definition +of space reserved for the table of interrupts vectors. This space is assigned +the symbolic name of ``__uhoh`` in the ``gen68340`` BSP. + +At ``__uhoh`` label is the default interrupt handler routine. This routine is +only called when an unexpected interrupts is raised. One can add their own +routine there (in that case there's a call to a routine - +$BSP_ROOT/startup/dumpanic.c - that prints which address caused the interrupt +and the contents of the registers, stack, etc.), but this should not return. + +Chip Select Initialization +========================== + +When the microprocessor accesses a memory area, address decoding is handled by +an address decoder, so that the microprocessor knows which memory chip(s) to +access. The following figure illustrates this: + +.. code-block:: c + + +-------------------+ + ------------| | + ------------| |------------ + ------------| Address |------------ + ------------| Decoder |------------ + ------------| |------------ + ------------| | + +-------------------+ + CPU Bus Chip Select + +The Chip Select registers must be programmed such that they match the +``linkcmds`` settings. In the gen68340 BSP, ROM and RAM addresses can be found +in both the ``linkcmds`` and initialization code, but this is not a great way +to do this. It is better to define addresses in the linker script. + +Integrated Processor Registers Initialization +============================================= + +The CPUs used in many embedded systems are highly complex devices with multiple +peripherals on the CPU itself. For these devices, there are always some +specific integrated processor registers that must be initialized. Refer to the +processors' manuals for details on these registers and be VERY careful +programming them. + +Data Section Recopy +=================== + +The next initialization part can be found in +``$BSP340_ROOT/start340/init68340.c``. First the Interrupt Vector Table is +copied into RAM, then the data section recopy is initiated +(``_CopyDataClearBSSAndStart`` in ``$BSP340_ROOT/start340/startfor340only.s``). + +This code performs the following actions: + +- copies the .data section from ROM to its location reserved in RAM (see + :ref:`Initialized Data` for more details about this copy), + +- clear ``.bss`` section (all the non-initialized data will take value 0). + +The RTEMS Configuration Table +============================= + +The RTEMS configuration table contains the maximum number of objects RTEMS can +handle during the application (e.g. maximum number of tasks, semaphores, +etc.). It's used to allocate the size for the RTEMS inner data structures. + +The RTEMS configuration table is application dependent, which means that one +has to provide one per application. It is usually defined by defining macros +and including the header file ````. In simple applications +such as the tests provided with RTEMS, it is commonly found in the main module +of the application. For more complex applications, it may be in a file by +itself. + +The header file ```` defines a constant table named +``Configuration``. With RTEMS 4.8 and older, it was accepted practice for the +BSP to copy this table into a modifiable copy named ``BSP_Configuration``. +This copy of the table was modified to define the base address of the RTEMS +Executive Workspace as well as to reflect any BSP and device driver +requirements not automatically handled by the application. In 4.9 and newer, +we have eliminated the BSP copies of the configuration tables and are making +efforts to make the configuration information generated by +```` constant and read only. + +For more information on the RTEMS Configuration Table, refer to the *RTEMS +Application C User's Guide*. diff --git a/bsp-howto/linker_script.rst b/bsp-howto/linker_script.rst new file mode 100644 index 0000000..9fe046b --- /dev/null +++ b/bsp-howto/linker_script.rst @@ -0,0 +1,361 @@ +.. comment SPDX-License-Identifier: CC-BY-SA-4.0 + + +.. COMMENT: COPYRIGHT (c) 1988-2011. +.. COMMENT: On-Line Applications Research Corporation (OAR). +.. COMMENT: All rights reserved. + +Linker Script +############# + +What is a "linkcmds" file? +========================== + +The ``linkcmds`` file is a script which is passed to the linker at linking +time. This file describes the memory configuration of the board as needed to +link the program. Specifically it specifies where the code and data for the +application will reside in memory. + +The format of the linker script is defined by the GNU Loader ``ld`` which is +included as a component of the GNU Binary Utilities. If you are using +GNU/Linux, then you probably have the documentation installed already and are +using these same tools configured for *native* use. Please visit the Binutils +project http://sourceware.org/binutils/ if you need more information. + +Program Sections +================ + +An embedded systems programmer must be much more aware of the placement of +their executable image in memory than the average applications programmer. A +program destined to be embedded as well as the target system have some specific +properties that must be taken into account. Embedded machines often mean +average performances and small memory usage. It is the memory usage that +concerns us when examining the linker command file. + +Two types of memories have to be distinguished: + +- RAM - volatile offering read and write access + +- ROM - non-volatile but read only + +Even though RAM and ROM can be found in every personal computer, one generally +doesn't care about them. In a personal computer, a program is nearly always +stored on disk and executed in RAM. Things are a bit different for embedded +targets: the target will execute the program each time it is rebooted or +switched on. The application program is stored in non-volatile memory such as +ROM, PROM, EEPROM, or Flash. On the other hand, data processing occurs in RAM. + +This leads us to the structure of an embedded program. In rough terms, an +embedded program is made of sections. It is the responsibility of the +application programmer to place these sections in the appropriate place in +target memory. To make this clearer, if using the COFF object file format on +the Motorola m68k family of microprocessors, the following sections will be +present: + +- code (``.text``) section: + is the program's code and it should not be modified. This section may be + placed in ROM. + +- non-initialized data (``.bss``) section: + holds uninitialized variables of the program. It can stay in RAM. + +- initialized data (``.data``) section: + holds the initialized program data which may be modified during the program's + life. This means they have to be in RAM. On the other hand, these variables + must be set to predefined values, and those predefined values have to be + stored in ROM. + +.. note:: + + Many programs and support libraries unknowingly assume that the ``.bss`` + section and, possibly, the application heap are initialized to zero at + program start. This is not required by the ISO/ANSI C Standard but is such + a common requirement that most BSPs do this. + +That brings us up to the notion of the image of an executable: it consists of +the set of the sections that together constitute the application. + +Image of an Executable +====================== + +As a program executable has many sections (note that the user can define their +own, and that compilers define theirs without any notice), one has to specify +the placement of each section as well as the type of memory (RAM or ROM) the +sections will be placed into. For instance, a program compiled for a Personal +Computer will see all the sections to go to RAM, while a program destined to be +embedded will see some of his sections going into the ROM. + +The connection between a section and where that section is loaded into memory +is made at link time. One has to let the linker know where the different +sections are to be placed once they are in memory. + +The following example shows a simple layout of program sections. With some +object formats, there are many more sections but the basic layout is +conceptually similar. + +============ ============= +.text RAM or ROM +.data RAM +.bss RAM +============ ============= + +Example Linker Command Script +============================= + +The GNU linker has a command language to specify the image format. This +command language can be quite complicated but most of what is required can be +learned by careful examination of a well-documented example. The following is +a heavily commented version of the linker script used with the the ``gen68340`` +BSP This file can be found at $BSP340_ROOT/startup/linkcmds. + +.. code-block:: c + + /* + * Specify that the output is to be coff-m68k regardless of what the + * native object format is. + */ + OUTPUT_FORMAT(coff-m68k) + /* + * Set the amount of RAM on the target board. + * + * NOTE: The default may be overridden by passing an argument to ld. + */ + RamSize = DEFINED(RamSize) ? RamSize : 4M; + /* + * Set the amount of RAM to be used for the application heap. Objects + * allocated using malloc() come from this area. Having a tight heap + * size is somewhat difficult and multiple attempts to squeeze it may + * be needed reducing memory usage is important. If all objects are + * allocated from the heap at system initialization time, this eases + * the sizing of the application heap. + * + * NOTE 1: The default may be overridden by passing an argument to ld. + * + * NOTE 2: The TCP/IP stack requires additional memory in the Heap. + * + * NOTE 3: The GNAT/RTEMS run-time requires additional memory in + * the Heap. + */ + HeapSize = DEFINED(HeapSize) ? HeapSize : 0x10000; + /* + * Set the size of the starting stack used during BSP initialization + * until first task switch. After that point, task stacks allocated + * by RTEMS are used. + * + * NOTE: The default may be overridden by passing an argument to ld. + */ + StackSize = DEFINED(StackSize) ? StackSize : 0x1000; + /* + * Starting addresses and length of RAM and ROM. + * + * The addresses must be valid addresses on the board. The + * Chip Selects should be initialized such that the code addresses + * are valid. + */ + MEMORY { + ram : ORIGIN = 0x10000000, LENGTH = 4M + rom : ORIGIN = 0x01000000, LENGTH = 4M + } + /* + * This is for the network driver. See the Networking documentation + * for more details. + */ + ETHERNET_ADDRESS = + DEFINED(ETHERNET_ADDRESS) ? ETHERNET_ADDRESS : 0xDEAD12; + /* + * The following defines the order in which the sections should go. + * It also defines a number of variables which can be used by the + * application program. + * + * NOTE: Each variable appears with 1 or 2 leading underscores to + * ensure that the variable is accessible from C code with a + * single underscore. Some object formats automatically add + * a leading underscore to all C global symbols. + */ + SECTIONS { + /* + * Make the RomBase variable available to the application. + */ + _RamSize = RamSize; + __RamSize = RamSize; + /* + * Boot PROM - Set the RomBase variable to the start of the ROM. + */ + rom : { + _RomBase = .; + __RomBase = .; + } >rom + /* + * Dynamic RAM - set the RamBase variable to the start of the RAM. + */ + ram : { + _RamBase = .; + __RamBase = .; + } >ram + /* + * Text (code) goes into ROM + */ + .text : { + /* + * Create a symbol for each object (.o). + */ + CREATE_OBJECT_SYMBOLS + /* + * Put all the object files code sections here. + */ + *(.text) + . = ALIGN (16); /* go to a 16-byte boundary */ + /* + * C++ constructors and destructors + * + * NOTE: See the CROSSGCC mailing-list FAQ for + * more details about the "\[......]". + */ + __CTOR_LIST__ = .; + [......] + __DTOR_END__ = .; + /* + * Declares where the .text section ends. + */ + etext = .; + _etext = .; + } >rom + /* + * Exception Handler Frame section + */ + .eh_fram : { + . = ALIGN (16); + *(.eh_fram) + } >ram + /* + * GCC Exception section + */ + .gcc_exc : { + . = ALIGN (16); + *(.gcc_exc) + } >ram + /* + * Special variable to let application get to the dual-ported + * memory. + */ + dpram : { + m340 = .; + _m340 = .; + . += (8 * 1024); + } >ram + /* + * Initialized Data section goes in RAM + */ + .data : { + copy_start = .; + *(.data) + . = ALIGN (16); + _edata = .; + copy_end = .; + } >ram + /* + * Uninitialized Data section goes in ROM + */ + .bss : { + /* + * M68K specific: Reserve some room for the Vector Table + * (256 vectors of 4 bytes). + */ + M68Kvec = .; + _M68Kvec = .; + . += (256 * 4); + /* + * Start of memory to zero out at initialization time. + */ + clear_start = .; + /* + * Put all the object files uninitialized data sections + * here. + */ + *(.bss) + *(COMMON) + . = ALIGN (16); + _end = .; + /* + * Start of the Application Heap + */ + _HeapStart = .; + __HeapStart = .; + . += HeapSize; + /* + * The Starting Stack goes after the Application Heap. + * M68K stack grows down so start at high address. + */ + . += StackSize; + . = ALIGN (16); + stack_init = .; + clear_end = .; + /* + * The RTEMS Executive Workspace goes here. RTEMS + * allocates tasks, stacks, semaphores, etc. from this + * memory. + */ + _WorkspaceBase = .; + __WorkspaceBase = .; + } >ram + +.. _Initialized Data: + +Initialized Data +================ + +Now there's a problem with the initialized data: the ``.data`` section has to +be in RAM as this data may be modified during the program execution. But how +will the values be initialized at boot time? + +One approach is to place the entire program image in RAM and reload the image +in its entirety each time the program is run. This is fine for use in a debug +environment where a high-speed connection is available between the development +host computer and the target. But even in this environment, it is cumbersome. + +The solution is to place a copy of the initialized data in a separate area of +memory and copy it into the proper location each time the program is started. +It is common practice to place a copy of the initialized ``.data`` section at +the end of the code (``.text``) section in ROM when building a PROM image. The +GNU tool ``objcopy`` can be used for this purpose. + +The following figure illustrates the steps a linked program goes through +to become a downloadable image. + ++--------------+------+--------------------------+--------------------+ +| .data (RAM) | | .data (RAM) | | ++--------------+ +--------------------------+ | +| .bss (RAM) | | .bss (RAM) | | ++--------------+ +--------------------------+--------------------+ +| .text (ROM) | | .text (ROM) | .text | ++--------------+------+---------+----------+-----+--------------------+ +| copy of .data (ROM) | | copy of .data | | ++---------------------+---------+----------------+--------------------+ +| Step 1 | Step 2 | Step 3 | ++---------------------+--------------------------+--------------------+ + + +In Step 1, the program is linked together using the BSP linker script. + +In Step 2, a copy is made of the ``.data`` section and placed after the +``.text`` section so it can be placed in PROM. This step is done after the +linking time. There is an example of doing this in the file +$RTEMS_ROOT/make/custom/gen68340.cfg: + +.. code-block:: shell + + # make a PROM image using objcopy + m68k-rtems-objcopy --adjust-section-vma \ + .data=`m68k-rtems-objdump --section-headers $(basename $@).exe | awk '[...]'` \ + $(basename $@).exe + +.. note:: + + The address of the "copy of ``.data`` section" is created by extracting the + last address in the ``.text`` section with an ``awk`` script. The details + of how this is done are not relevant. + +Step 3 shows the final executable image as it logically appears in the target's +non-volatile program memory. The board initialization code will copy the +""copy of ``.data`` section" (which are stored in ROM) to their reserved +location in RAM. diff --git a/bsp-howto/makefiles.rst b/bsp-howto/makefiles.rst new file mode 100644 index 0000000..b79437b --- /dev/null +++ b/bsp-howto/makefiles.rst @@ -0,0 +1,190 @@ +.. comment SPDX-License-Identifier: CC-BY-SA-4.0 + +.. COMMENT: COPYRIGHT (c) 1988-2002. +.. COMMENT: On-Line Applications Research Corporation (OAR). +.. COMMENT: All rights reserved. + +.. _Makefiles: + +Makefiles +######### + +This chapter discusses the Makefiles associated with a BSP. It does not +describe the process of configuring, building, and installing RTEMS. This +chapter will not provide detailed information about this process. Nonetheless, +it is important to remember that the general process consists of four phases as +shown here: + +- ``bootstrap`` + +- ``configure`` + +- ``build`` + +- ``install`` + +During the bootstrap phase, you are using the ``configure.ac`` and +``Makefile.am`` files as input to GNU autoconf and automake to generate a +variety of files. This is done by running the ``bootstrap`` script found at +the top of the RTEMS source tree. + +During the configure phase, a number of files are generated. These generated +files are tailored for the specific host/target combination by the configure +script. This set of files includes the Makefiles used to actually compile and +install RTEMS. + +During the build phase, the source files are compiled into object files and +libraries are built. + +During the install phase, the libraries, header files, and other support files +are copied to the BSP specific installation point. After installation is +successfully completed, the files generated by the configure and build phases +may be removed. + +Makefiles Used During The BSP Building Process +============================================== + +RTEMS uses the *GNU automake* and *GNU autoconf* automatic configuration +package. Consequently, there are a number of automatically generated files in +each directory in the RTEMS source tree. The ``bootstrap`` script found in the +top level directory of the RTEMS source tree is executed to produce the +automatically generated files. That script must be run from a directory with a +``configure.ac`` file in it. The ``bootstrap`` command is usually invoked in +one of the following manners: + +- ``bootstrap`` to regenerate all files that are generated by autoconf and + automake. + +- ``bootstrap -c`` to remove all files generated by autoconf and automake. + +- ``bootstrap -p`` to regenerate ``preinstall.am`` files. + +There is a file named ``Makefile.am`` in each directory of a BSP. This file is +used by *automake* to produce the file named ``Makefile.in`` which is also +found in each directory of a BSP. When modifying a ``Makefile.am``, you can +probably find examples of anything you need to do in one of the BSPs. + +The configure process specializes the ``Makefile.in`` files at the time that +RTEMS is configured for a specific development host and target. Makefiles are +automatically generated from the ``Makefile.in`` files. It is necessary for +the BSP developer to provide the ``Makefile.am`` files and generate the +``Makefile.in`` files. Most of the time, it is possible to copy the +``Makefile.am`` from another similar directory and edit it. + +The ``Makefile`` files generated are processed when configuring and building +RTEMS for a given BSP. + +The BSP developer is responsible for generating ``Makefile.am`` files which +properly build all the files associated with their BSP. Most BSPs will only +have a single ``Makefile.am`` which details the set of source files to build to +compose the BSP support library along with the set of include files that are to +be installed. + +This single ``Makefile.am`` at the top of the BSP tree specifies the set of +header files to install. This fragment from the SPARC/ERC32 BSP results in +four header files being installed. + +.. code-block:: makefile + + include_HEADERS = include/bsp.h + include_HEADERS += include/tm27.h + include_HEADERS += include/erc32.h + include_HEADERS += include/coverhd.h + +When adding new include files, you will be adding to the set of +``include_HEADERS``. When you finish editing the ``Makefile.am`` file, do not +forget to run ``bootstrap -p`` to regenerate the ``preinstall.am``. + +The ``Makefile.am`` also specifies which source files to build. By convention, +logical components within the BSP each assign their source files to a unique +variable. These variables which define the source files are collected into a +single variable which instructs the GNU autotools that we are building +``libbsp.a``. This fragment from the SPARC/ERC32 BSP shows how the startup +related, miscellaneous support code, and the console device driver source is +managed in the ``Makefile.am``. + +.. code-block:: makefile + + startup_SOURCES = ../../sparc/shared/bspclean.c ../../shared/bsplibc.c \ + ../../shared/bsppredriverhook.c \ + ../../shared/bsppost.c ../../sparc/shared/bspstart.c \ + ../../shared/bootcard.c ../../shared/sbrk.c startup/setvec.c \ + startup/spurious.c startup/erc32mec.c startup/boardinit.S + clock_SOURCES = clock/ckinit.c + ... + noinst_LIBRARIES = libbsp.a + libbsp_a_SOURCES = $(startup_SOURCES) $(console_SOURCES) ... + +When adding new files to an existing directory, do not forget to add the new +files to the list of files to be built in the corresponding ``XXX_SOURCES`` +variable in the ``Makefile.am`` and run``bootstrap``. + +Some BSPs use code that is built in ``libcpu``. If you BSP does this, then you +will need to make sure the objects are pulled into your BSP library. The +following from the SPARC/ERC32 BSP pulls in the cache, register window +management and system call support code from the directory corresponding to its +``RTEMS_CPU`` model. + +.. code-block:: makefile + + libbsp_a_LIBADD = ../../../libcpu/@RTEMS_CPU@/cache.rel \ + ../../../libcpu/@RTEMS_CPU@/reg_win.rel \ + ../../../libcpu/@RTEMS_CPU@/syscall.rel + +.. note: + +The ``Makefile.am`` files are ONLY processed by ``bootstrap`` and the resulting +``Makefile.in`` files are only processed during the configure process of a +RTEMS build. Therefore, when developing a BSP and adding a new file to a +``Makefile.am``, the already generated ``Makefile`` will not automatically +include the new references unless you configured RTEMS with the +``--enable-maintainer-mode`` option. Otherwise, the new file will not being be +taken into account! + +Creating a New BSP Make Customization File +========================================== + +When building a BSP or an application using that BSP, it is necessary to tailor +the compilation arguments to account for compiler flags, use custom linker +scripts, include the RTEMS libraries, etc.. The BSP must be built using this +information. Later, once the BSP is installed with the toolset, this same +information must be used when building the application. So a BSP must include +a build configuration file. The configuration file is ``make/custom/BSP.cfg``. + +The configuration file is taken into account when building one's application +using the RTEMS template Makefiles (``make/templates``). These application +template Makefiles have been included with the RTEMS source distribution since +the early 1990's. However there is a desire in the RTEMS user community to +move all provided examples to GNU autoconf. They are included in the 4.9 +release series and used for all examples provided with RTEMS. There is no +definite time table for obsoleting them. You are free to use these but be +warned they have fallen out of favor with many in the RTEMS community and may +disappear in the future. + +The following is a slightly shortened version of the make customization file +for the gen68340 BSP. The original source for this file can be found in the +``make/custom`` directory. + +.. code-block:: makefile + + # The RTEMS CPU Family and Model + RTEMS_CPU=m68k + RTEMS_CPU_MODEL=m68340 + include $(RTEMS_ROOT)/make/custom/default.cfg + # This is the actual bsp directory used during the build process. + RTEMS_BSP_FAMILY=gen68340 + # This contains the compiler options necessary to select the CPU model + # and (hopefully) optimize for it. + CPU_CFLAGS = -mcpu=cpu32 + # optimize flag: typically -O2 + CFLAGS_OPTIMIZE_V = -O2 -g -fomit-frame-pointer + +The make customization files have generally grown simpler and simpler with each +RTEMS release. Beginning in the 4.9 release series, the rules for linking an +RTEMS application are shared by all BSPs. Only BSPs which need to perform a +transformation from linked ELF file to a downloadable format have any +additional actions for program link time. In 4.8 and older, every BSP specified +the "make executable" or ``make-exe`` rule and duplicated the same actions. + +It is generally easier to copy a ``make/custom`` file from a BSP similar to the +one being developed. diff --git a/bsp-howto/miscellanous_support.rst b/bsp-howto/miscellanous_support.rst new file mode 100644 index 0000000..4a487ee --- /dev/null +++ b/bsp-howto/miscellanous_support.rst @@ -0,0 +1,364 @@ +.. comment SPDX-License-Identifier: CC-BY-SA-4.0 + + +.. COMMENT: COPYRIGHT (c) 1988-2002. +.. COMMENT: On-Line Applications Research Corporation (OAR). +.. COMMENT: All rights reserved. + +Miscellaneous Support Files +########################### + +GCC Compiler Specifications File +================================ + +The file ``bsp_specs`` defines the start files and libraries that are always +used with this BSP. The format of this file is admittedly cryptic and this +document will make no attempt to explain it completely. Below is the +``bsp_specs`` file from the PowerPC psim BSP: + +.. code-block:: c + + %rename endfile old_endfile + %rename startfile old_startfile + %rename link old_link + *startfile: + %{!qrtems: %(old_startfile)} \ + %{!nostdlib: %{qrtems: ecrti%O%s rtems_crti%O%s crtbegin.o%s start.o%s}} + *link: + %{!qrtems: %(old_link)} %{qrtems: -Qy -dp -Bstatic -e _start -u __vectors} + *endfile: + %{!qrtems: %(old_endfile)} %{qrtems: crtend.o%s ecrtn.o%s} + +The first section of this file renames the built-in definition of some +specification variables so they can be augmented without embedded their +original definition. The subsequent sections specify what behavior is expected +when the ``-qrtems`` option is specified. + +The ``*startfile`` section specifies that the BSP specific file ``start.o`` +will be used instead of ``crt0.o``. In addition, various EABI support files +(``ecrti.o`` etc.) will be linked in with the executable. + +The ``*link`` section adds some arguments to the linker when it is invoked by +GCC to link an application for this BSP. + +The format of this file is specific to the GNU Compiler Suite. The argument +used to override and extend the compiler built-in specifications is available +in all recent GCC versions. The ``-specs`` option is present in all ``egcs`` +distributions and ``gcc`` distributions starting with version 2.8.0. + +README Files +============ + +Most BSPs provide one or more ``README`` files. Generally, there is a +``README`` file at the top of the BSP source. This file describes the board +and its hardware configuration, provides vendor information, local +configuration information, information on downloading code to the board, +debugging, etc.. The intent of this file is to help someone begin to use the +BSP faster. + +A ``README`` file in a BSP subdirectory typically explains something about the +contents of that subdirectory in greater detail. For example, it may list the +documentation available for a particular peripheral controller and how to +obtain that documentation. It may also explain some particularly cryptic part +of the software in that directory or provide rationale on the implementation. + +times +===== + +This file contains the results of the RTEMS Timing Test Suite. It is in a +standard format so that results from one BSP can be easily compared with those +of another target board. + +If a BSP supports multiple variants, then there may be multiple ``times`` +files. Usually these are named ``times.VARIANTn``. + +Tools Subdirectory +================== + +Some BSPs provide additional tools that aid in using the target board. These +tools run on the development host and are built as part of building the BSP. +Most common is a script to automate running the RTEMS Test Suites on the BSP. +Examples of this include: + +- ``powerpc/psim`` includes scripts to ease use of the simulator + +- ``m68k/mvme162`` includes a utility to download across the VMEbus into target + memory if the host is a VMEbus board in the same chasis. + +bsp.h Include File +================== + +The file ``include/bsp.h`` contains prototypes and definitions specific to this +board. Every BSP is required to provide a ``bsp.h``. The best approach to +writing a ``bsp.h`` is copying an existing one as a starting point. + +Many ``bsp.h`` files provide prototypes of variables defined in the linker +script (``linkcmds``). + +tm27.h Include File +=================== + +The ``tm27`` test from the RTEMS Timing Test Suite is designed to measure the +length of time required to vector to and return from an interrupt handler. This +test requires some help from the BSP to know how to cause and manipulate the +interrupt source used for this measurement. The following is a list of these: + +- ``MUST_WAIT_FOR_INTERRUPT`` - modifies behavior of ``tm27``. + +- ``Install_tm27_vector`` - installs the interrupt service routine for the + Interrupt Benchmark Test (``tm27``). + +- ``Cause_tm27_intr`` - generates the interrupt source used in the Interrupt + Benchmark Test (``tm27``). + +- ``Clear_tm27_intr`` - clears the interrupt source used in the Interrupt + Benchmark Test (``tm27``). + +- ``Lower_tm27_intr`` - lowers the interrupt mask so the interrupt source used + in the Interrupt Benchmark Test (``tm27``) can generate a nested interrupt. + +All members of the Timing Test Suite are designed to run *WITHOUT* the Clock +Device Driver installed. This increases the predictability of the tests' +execution as well as avoids occassionally including the overhead of a clock +tick interrupt in the time reported. Because of this it is sometimes possible +to use the clock tick interrupt source as the source of this test interrupt. +On other architectures, it is possible to directly force an interrupt to occur. + +Calling Overhead File +===================== + +The file ``include/coverhd.h`` contains the overhead associated with invoking +each directive. This overhead consists of the execution time required to +package the parameters as well as to execute the "jump to subroutine" and +"return from subroutine" sequence. The intent of this file is to help separate +the calling overhead from the actual execution time of a directive. This file +is only used by the tests in the RTEMS Timing Test Suite. + +The numbers in this file are obtained by running the "Timer +Overhead"``tmoverhd`` test. The numbers in this file may be 0 and no overhead +is subtracted from the directive execution times reported by the Timing Suite. + +There is a shared implementation of ``coverhd.h`` which sets all of the +overhead constants to 0. On faster processors, this is usually the best +alternative for the BSP as the calling overhead is extremely small. This file +is located at: + +.. code-block:: c + + c/src/lib/libbsp/shared/include/coverhd.h + +sbrk() Implementation +===================== + +Although nearly all BSPs give all possible memory to the C Program Heap at +initialization, it is possible for a BSP to configure the initial size of the +heap small and let it grow on demand. If the BSP wants to dynamically extend +the heap used by the C Library memory allocation routines (i.e. ``malloc`` +family), then the``sbrk`` routine must be functional. The following is the +prototype for this routine: + +.. code-block:: c + + void * sbrk(size_t increment) + +The ``increment`` amount is based upon the ``sbrk_amount`` parameter passed to +the ``bsp_libc_init`` during system initialization. + +.. index:: CONFIGURE_MALLOC_BSP_SUPPORTS_SBRK + +If your BSP does not want to support dynamic heap extension, then you do not +have to do anything special. However, if you want to support ``sbrk``, you +must provide an implementation of this method and define +``CONFIGURE_MALLOC_BSP_SUPPORTS_SBRK`` in ``bsp.h``. This informs +``rtems/confdefs.h`` to configure the Malloc Family Extensions which support +``sbrk``. + +bsp_fatal_extension() - Cleanup the Hardware +============================================ + +The ``bsp_fatal_extension()`` is an optional BSP specific initial extension +invoked once a fatal system state is reached. Most of the BSPs use the same +shared version of ``bsp_fatal_extension()`` that does nothing or performs a +system reset. This implementation is located in the following file: + +.. code-block:: c + + c/src/lib/libbsp/shared/bspclean.c + +The ``bsp_fatal_extension()`` routine can be used to return to a ROM monitor, +insure that interrupt sources are disabled, etc.. This routine is the last +place to ensure a clean shutdown of the hardware. The fatal source, internal +error indicator, and the fatal code arguments are available to evaluate the +fatal condition. All of the non-fatal shutdown sequences ultimately pass their +exit status to ``rtems_shutdown_executive`` and this is what is passed to this +routine in case the fatal source is ``RTEMS_FATAL_SOURCE_EXIT``. + +On some BSPs, it prints a message indicating that the application completed +execution and waits for the user to press a key before resetting the board. +The PowerPC/gen83xx and PowerPC/gen5200 BSPs do this when they are built to +support the FreeScale evaluation boards. This is convenient when using the +boards in a development environment and may be disabled for production use. + +Configuration Macros +==================== + +Each BSP can define macros in bsp.h which alter some of the the default +configuration parameters in ``rtems/confdefs.h``. This section describes those +macros: + +.. index:: CONFIGURE_MALLOC_BSP_SUPPORTS_SBRK + +- ``CONFIGURE_MALLOC_BSP_SUPPORTS_SBRK`` must be defined if the BSP has proper + support for ``sbrk``. This is discussed in more detail in the previous + section. + +.. index:: BSP_IDLE_TASK_BODY + +- ``BSP_IDLE_TASK_BODY`` may be defined to the entry point of a BSP specific + IDLE thread implementation. This may be overridden if the application + provides its own IDLE task implementation. + +.. index:: BSP_IDLE_TASK_STACK_SIZE + +- ``BSP_IDLE_TASK_STACK_SIZE`` may be defined to the desired default stack size + for the IDLE task as recommended when using this BSP. + +.. index:: BSP_INTERRUPT_STACK_SIZE + +- ``BSP_INTERRUPT_STACK_SIZE`` may be defined to the desired default interrupt + stack size as recommended when using this BSP. This is sometimes required + when the BSP developer has knowledge of stack intensive interrupt handlers. + +.. index:: BSP_ZERO_WORKSPACE_AUTOMATICALLY + +- ``BSP_ZERO_WORKSPACE_AUTOMATICALLY`` is defined when the BSP requires that + RTEMS zero out the RTEMS C Program Heap at initialization. If the memory is + already zeroed out by a test sequence or boot ROM, then the boot time can be + reduced by not zeroing memory twice. + +.. index:: BSP_DEFAULT_UNIFIED_WORK_AREAS + +- ``BSP_DEFAULT_UNIFIED_WORK_AREAS`` is defined when the BSP recommends that + the unified work areas configuration should always be used. This is + desirable when the BSP is known to always have very little RAM and thus + saving memory by any means is desirable. + +set_vector() - Install an Interrupt Vector +========================================== + +On targets with Simple Vectored Interrupts, the BSP must provide an +implementation of the ``set_vector`` routine. This routine is responsible for +installing an interrupt vector. It invokes the support routines necessary to +install an interrupt handler as either a "raw" or an RTEMS interrupt handler. +Raw handlers bypass the RTEMS interrupt structure and are responsible for +saving and restoring all their own registers. Raw handlers are useful for +handling traps, debug vectors, etc. + +The ``set_vector`` routine is a central place to perform interrupt controller +manipulation and encapsulate that information. It is usually implemented as +follows: + +.. code-block:: c + + rtems_isr_entry set_vector( /* returns old vector */ + rtems_isr_entry handler, /* isr routine */ + rtems_vector_number vector, /* vector number */ + int type /* RTEMS or RAW intr */ + ) + { + if the type is RAW + install the raw vector + else + use rtems_interrupt_catch to install the vector + perform any interrupt controller necessary to unmask the interrupt source + return the previous handler + } + +.. note:: + + The i386, PowerPC and ARM ports use a Programmable Interrupt Controller + model which does not require the BSP to implement ``set_vector``. BSPs for + these architectures must provide a different set of support routines. + +Interrupt Delay Profiling +========================= + +The RTEMS profiling needs support by the BSP for the interrupt delay times. In +case profiling is enabled via the RTEMS build configuration option +``--enable-profiling`` (in this case the pre-processor symbol +``RTEMS_PROFILING`` is defined) a BSP may provide data for the interrupt delay +times. The BSP can feed interrupt delay times with the +``_Profiling_Update_max_interrupt_delay()`` function (``#include +``). For an example please have a look at +``c/src/lib/libbsp/sparc/leon3/clock/ckinit.c``. + +Programmable Interrupt Controller API +===================================== + +A BSP can use the PIC API to install Interrupt Service Routines through a set +of generic methods. In order to do so, the header files +libbsp/shared/include/irq-generic.h and ``libbsp/shared/include/irq-info.h`` +must be included by the bsp specific irq.h file present in the include/ +directory. The irq.h acts as a BSP interrupt support configuration file which +is used to define some important MACROS. It contains the declarations for any +required global functions like bsp_interrupt_dispatch(). Thus later on, every +call to the PIC interface requires including ```` + +The generic interrupt handler table is intitalized by invoking the +``bsp_interrupt_initialize()`` method from bsp_start() in the bspstart.c file +which sets up this table to store the ISR addresses, whose size is based on the +definition of macros, ``BSP_INTERRUPT_VECTOR_MIN`` and +``BSP_INTERRUPT_VECTOR_MAX`` in include/bsp.h + +For the generic handler table to properly function, some bsp specific code is +required, that should be present in ``irq/irq.c``. The bsp-specific functions +required to be writen by the BSP developer are : + +.. index:: bsp_interrupt_facility_initialize() + +- ``bsp_interrupt_facility_initialize()`` contains bsp specific interrupt + initialization code(Clear Pending interrupts by modifying registers, etc.). + This method is called from ``bsp_interrupt_initialize()`` internally while + setting up the table. + +.. index:: bsp_interrupt_handler_default() + +- ``bsp_interrupt_handler_default()`` acts as a fallback handler when no ISR + address has been provided corresponding to a vector in the table. + +.. index:: bsp_interrupt_dispatch() + +- ``bsp_interrupt_dispatch()`` service the ISR by handling any bsp specific + code & calling the generic method ``bsp_interrupt_handler_dispatch()`` which + in turn services the interrupt by running the ISR after looking it up in the + table. It acts as an entry to the interrupt switchboard, since the bsp + branches to this function at the time of occurrence of an interrupt. + +.. index:: bsp_interrupt_vector_enable() + +- ``bsp_interrupt_vector_enable()`` enables interrupts and is called in + irq-generic.c while setting up the table. + +.. index:: bsp_interrupt_vector_disable() + +- ``bsp_interrupt_vector_disable()`` disables interrupts and is called in + irq-generic.c while setting up the table & during other important parts. + +An interrupt handler is installed or removed with the help of the following functions : + +.. code-block:: c + + rtems_status_code rtems_interrupt_handler_install( /* returns status code */ + rtems_vector_number vector, /* interrupt vector */ + const char *info, /* custom identification text */ + rtems_option options, /* Type of Interrupt */ + rtems_interrupt_handler handler, /* interrupt handler */ + void *arg /* parameter to be passed + to handler at the time of + invocation */ + ) + rtems_status_code rtems_interrupt_handler_remove( /* returns status code */ + rtems_vector_number vector, /* interrupt vector */ + rtems_interrupt_handler handler, /* interrupt handler */ + void *arg /* parameter to be passed to handler */ + ) diff --git a/bsp-howto/networking.rst b/bsp-howto/networking.rst new file mode 100644 index 0000000..4bcbce2 --- /dev/null +++ b/bsp-howto/networking.rst @@ -0,0 +1,310 @@ +.. comment SPDX-License-Identifier: CC-BY-SA-4.0 + +.. COMMENT: COPYRIGHT (c) 1988-2002. +.. COMMENT: On-Line Applications Research Corporation (OAR). +.. COMMENT: All rights reserved. + +Networking Driver +################# + +Introduction +============ + +This chapter is intended to provide an introduction to the procedure for +writing RTEMS network device drivers. The example code is taken from the +'Generic 68360' network device driver. The source code for this driver is +located in the ``c/src/lib/libbsp/m68k/gen68360/network`` directory in the +RTEMS source code distribution. Having a copy of this driver at hand when +reading the following notes will help significantly. + +.. sidebar:: *Legacy Networking Stack* + + This docuemntation is for the legacy FreeBSD networking stack in the RTEMS + source tree. + +Learn about the network device +============================== + +Before starting to write the network driver become completely familiar with the +programmer's view of the device. The following points list some of the details +of the device that must be understood before a driver can be written. + +- Does the device use DMA to transfer packets to and from memory or does the + processor have to copy packets to and from memory on the device? + +- If the device uses DMA, is it capable of forming a single outgoing packet + from multiple fragments scattered in separate memory buffers? + +- If the device uses DMA, is it capable of chaining multiple outgoing packets, + or does each outgoing packet require intervention by the driver? + +- Does the device automatically pad short frames to the minimum 64 bytes or + does the driver have to supply the padding? + +- Does the device automatically retry a transmission on detection of a + collision? + +- If the device uses DMA, is it capable of buffering multiple packets to + memory, or does the receiver have to be restarted after the arrival of each + packet? + +- How are packets that are too short, too long, or received with CRC errors + handled? Does the device automatically continue reception or does the driver + have to intervene? + +- How is the device Ethernet address set? How is the device programmed to + accept or reject broadcast and multicast packets? + +- What interrupts does the device generate? Does it generate an interrupt for + each incoming packet, or only for packets received without error? Does it + generate an interrupt for each packet transmitted, or only when the transmit + queue is empty? What happens when a transmit error is detected? + +In addition, some controllers have specific questions regarding board specific +configuration. For example, the SONIC Ethernet controller has a very +configurable data bus interface. It can even be configured for sixteen and +thirty-two bit data buses. This type of information should be obtained from +the board vendor. + +Understand the network scheduling conventions +============================================= + +When writing code for the driver transmit and receive tasks, take care to +follow the network scheduling conventions. All tasks which are associated with +networking share various data structures and resources. To ensure the +consistency of these structures the tasks execute only when they hold the +network semaphore (``rtems_bsdnet_semaphore``). The transmit and receive tasks +must abide by this protocol. Be very careful to avoid 'deadly embraces' with +the other network tasks. A number of routines are provided to make it easier +for the network driver code to conform to the network task scheduling +conventions. + +- ``void rtems_bsdnet_semaphore_release(void)`` + This function releases the network semaphore. The network driver tasks must + call this function immediately before making any blocking RTEMS request. + +- ``void rtems_bsdnet_semaphore_obtain(void)`` + This function obtains the network semaphore. If a network driver task has + released the network semaphore to allow other network-related tasks to run + while the task blocks, then this function must be called to reobtain the + semaphore immediately after the return from the blocking RTEMS request. + +- ``rtems_bsdnet_event_receive(rtems_event_set, rtems_option, rtems_interval, + rtems_event_set *)`` + The network driver task should call this function when it wishes to wait for + an event. This function releases the network semaphore, calls + ``rtems_event_receive`` to wait for the specified event or events and + reobtains the semaphore. The value returned is the value returned by the + ``rtems_event_receive``. + +Network Driver Makefile +======================= + +Network drivers are considered part of the BSD network package and as such are +to be compiled with the appropriate flags. This can be accomplished by adding +``-D__INSIDE_RTEMS_BSD_TCPIP_STACK__`` to the ``command line``. If the driver +is inside the RTEMS source tree or is built using the RTEMS application +Makefiles, then adding the following line accomplishes this: + +.. code-block:: makefile + + DEFINES += -D__INSIDE_RTEMS_BSD_TCPIP_STACK__ + +This is equivalent to the following list of definitions. Early versions of the +RTEMS BSD network stack required that all of these be defined. + +.. code-block:: makefile + + -D_COMPILING_BSD_KERNEL_ -DKERNEL -DINET -DNFS -DDIAGNOSTIC -DBOOTP_COMPAT + +Defining these macros tells the network header files that the driver is to be +compiled with extended visibility into the network stack. This is in sharp +contrast to applications that simply use the network stack. Applications do +not require this level of visibility and should stick to the portable +application level API. + +As a direct result of being logically internal to the network stack, network +drivers use the BSD memory allocation routines This means, for example, that +malloc takes three arguments. See the SONIC device driver +(``c/src/lib/libchip/network/sonic.c``) for an example of this. Because of +this, network drivers should not include ````. Doing so will result +in conflicting definitions of ``malloc()``. + +*Application level* code including network servers such as the FTP daemon are +*not* part of the BSD kernel network code and should not be compiled with the +BSD network flags. They should include ```` and not define the +network stack visibility macros. + +Write the Driver Attach Function +================================ + +The driver attach function is responsible for configuring the driver and making +the connection between the network stack and the driver. + +Driver attach functions take a pointer to an ``rtems_bsdnet_ifconfig`` +structure as their only argument. and set the driver parameters based on the +values in this structure. If an entry in the configuration structure is zero +the attach function chooses an appropriate default value for that parameter. + +The driver should then set up several fields in the ifnet structure in the +device-dependent data structure supplied and maintained by the driver: + +``ifp->if_softc`` + Pointer to the device-dependent data. The first entry in the + device-dependent data structure must be an ``arpcom`` structure. + +``ifp->if_name`` + The name of the device. The network stack uses this string and the device + number for device name lookups. The device name should be obtained from + the ``name`` entry in the configuration structure. + +``ifp->if_unit`` + The device number. The network stack uses this number and the device name + for device name lookups. For example, if ``ifp->if_name`` is ``scc`` and + ``ifp->if_unit`` is ``1``, the full device name would be ``scc1``. The + unit number should be obtained from the ``name`` entry in the configuration + structure. + +``ifp->if_mtu`` + The maximum transmission unit for the device. For Ethernet devices this + value should almost always be 1500. + +``ifp->if_flags`` + The device flags. Ethernet devices should set the flags to + ``IFF_BROADCAST|IFF_SIMPLEX``, indicating that the device can broadcast + packets to multiple destinations and does not receive and transmit at the + same time. + +``ifp->if_snd.ifq_maxlen`` + The maximum length of the queue of packets waiting to be sent to the + driver. This is normally set to ``ifqmaxlen``. + +``ifp->if_init`` + The address of the driver initialization function. + +``ifp->if_start`` + The address of the driver start function. + +``ifp->if_ioctl`` + The address of the driver ioctl function. + +``ifp->if_output`` + The address of the output function. Ethernet devices should set this to + ``ether_output``. + +RTEMS provides a function to parse the driver name in the configuration +structure into a device name and unit number. + +.. code-block:: c + + int rtems_bsdnet_parse_driver_name ( + const struct rtems_bsdnet_ifconfig *config, + char **namep + ); + +The function takes two arguments; a pointer to the configuration structure and +a pointer to a pointer to a character. The function parses the configuration +name entry, allocates memory for the driver name, places the driver name in +this memory, sets the second argument to point to the name and returns the unit +number. On error, a message is printed and ``-1`` is returned. + +Once the attach function has set up the above entries it must link the driver +data structure onto the list of devices by calling ``if_attach``. Ethernet +devices should then call ``ether_ifattach``. Both functions take a pointer to +the device's ``ifnet`` structure as their only argument. + +The attach function should return a non-zero value to indicate that the driver +has been successfully configured and attached. + +Write the Driver Start Function. +================================ + +This function is called each time the network stack wants to start the +transmitter. This occures whenever the network stack adds a packet to a +device's send queue and the ``IFF_OACTIVE`` bit in the device's ``if_flags`` is +not set. + +For many devices this function need only set the ``IFF_OACTIVE`` bit in the +``if_flags`` and send an event to the transmit task indicating that a packet is +in the driver transmit queue. + +Write the Driver Initialization Function. +========================================= + +This function should initialize the device, attach to interrupt handler, and +start the driver transmit and receive tasks. The function: + +.. code-block:: c + + rtems_id rtems_bsdnet_newproc( + char *name, + int stacksize, + void (*entry)(void *), + void *arg + ); + +should be used to start the driver tasks. + +Note that the network stack may call the driver initialization function more +than once. Make sure multiple versions of the receive and transmit tasks are +not accidentally started. + +Write the Driver Transmit Task +============================== + +This task is reponsible for removing packets from the driver send queue and +sending them to the device. The task should block waiting for an event from +the driver start function indicating that packets are waiting to be +transmitted. When the transmit task has drained the driver send queue the task +should clear the ``IFF_OACTIVE`` bit in ``if_flags`` and block until another +outgoing packet is queued. + +Write the Driver Receive Task +============================= + +This task should block until a packet arrives from the device. If the device +is an Ethernet interface the function ``ether_input`` should be called to +forward the packet to the network stack. The arguments to ``ether_input`` are +a pointer to the interface data structure, a pointer to the ethernet header and +a pointer to an mbuf containing the packet itself. + +Write the Driver Interrupt Handler +================================== + +A typical interrupt handler will do nothing more than the hardware manipulation +required to acknowledge the interrupt and send an RTEMS event to wake up the +driver receive or transmit task waiting for the event. Network interface +interrupt handlers must not make any calls to other network routines. + +Write the Driver IOCTL Function +=============================== + +This function handles ioctl requests directed at the device. The ioctl +commands which must be handled are: + +``SIOCGIFADDR``, ``SIOCSIFADDR`` + If the device is an Ethernet interface these commands should be passed on + to ``ether_ioctl``. + +``SIOCSIFFLAGS`` + This command should be used to start or stop the device, depending on the + state of the interface ``IFF_UP`` and``IFF_RUNNING`` bits in ``if_flags``: + + ``IFF_RUNNING`` + Stop the device. + + ``IFF_UP`` + Start the device. + + ``IFF_UP|IFF_RUNNING`` + Stop then start the device. + + ``0`` + Do nothing. + +Write the Driver Statistic-Printing Function +============================================ + +This function should print the values of any statistic/diagnostic counters the +network driver may use. The driver ioctl function should call the +statistic-printing function when the ioctl command is ``SIO_RTEMS_SHOW_STATS``. diff --git a/bsp-howto/non_volatile_memory.rst b/bsp-howto/non_volatile_memory.rst new file mode 100644 index 0000000..7187dbf --- /dev/null +++ b/bsp-howto/non_volatile_memory.rst @@ -0,0 +1,217 @@ +.. comment SPDX-License-Identifier: CC-BY-SA-4.0 + +.. COMMENT: Written by Eric Norum +.. COMMENT: COPYRIGHT (c) 1988-2002. +.. COMMENT: On-Line Applications Research Corporation (OAR). +.. COMMENT: All rights reserved. + +Non-Volatile Memory Driver +########################## + +The Non-Volatile driver is responsible for providing an interface to various +types of non-volatile memory. These types of memory include, but are not +limited to, Flash, EEPROM, and battery backed RAM. The capabilities provided +by this class of device driver are: + +- Initialize the Non-Volatile Memory Driver + +- Optional Disable Read and Write Handlers + +- Open a Particular Memory Partition + +- Close a Particular Memory Partition + +- Read from a Particular Memory Partition + +- Write to a Particular Memory Partition + +- Erase the Non-Volatile Memory Area + +There is currently only one non-volatile device driver included in the RTEMS +source tree. The information provided in this chapter is based on drivers +developed for applications using RTEMS. It is hoped that this driver model +information can form the basis for a standard non-volatile memory driver model +that can be supported in future RTEMS distribution. + +Major and Minor Numbers +======================= + +The ``major`` number of a device driver is its index in the RTEMS Device +Address Table. + +A ``minor`` number is associated with each device instance managed by a +particular device driver. An RTEMS minor number is an ``unsigned32`` entity. +Convention calls dividing the bits in the minor number down into categories +that specify an area of non-volatile memory and a partition with that area. +This results in categories like the following: + +- ``area`` - indicates a block of non-volatile memory + +- ``partition`` - indicates a particular address range with an area + +From the above, it should be clear that a single device driver can support +multiple types of non-volatile memory in a single system. The minor number is +used to distinguish the types of memory and blocks of memory used for different +purposes. + +Non-Volatile Memory Driver Configuration +======================================== + +There is not a standard non-volatile driver configuration table but some fields +are common across different drivers. The non-volatile memory driver +configuration table is typically an array of structures with each structure +containing the information for a particular area of non-volatile memory. The +following is a list of the type of information normally required to configure +each area of non-volatile memory. + +``memory_type`` + is the type of memory device in this area. Choices are battery backed RAM, + EEPROM, Flash, or an optional user-supplied type. If the user-supplied + type is configured, then the user is responsible for providing a set of + routines to program the memory. + +``memory`` + is the base address of this memory area. + +``attributes`` + is a pointer to a memory type specific attribute block. Some of the fields + commonly contained in this memory type specific attribute structure area: + + ``use_protection_algorithm`` + is set to TRUE to indicate that the protection (i.e. locking) algorithm + should be used for this area of non-volatile memory. A particular type + of non-volatile memory may not have a protection algorithm. + + ``access`` + is an enumerated type to indicate the organization of the memory + devices in this memory area. The following is a list of the access + types supported by the current driver implementation: + + - simple unsigned8 + - simple unsigned16 + - simple unsigned32 + - simple unsigned64 + - single unsigned8 at offset 0 in an unsigned16 + - single unsigned8 at offset 1 in an unsigned16 + - single unsigned8 at offset 0 in an unsigned32 + - single unsigned8 at offset 1 in an unsigned32 + - single unsigned8 at offset 2 in an unsigned32 + - single unsigned8 at offset 3 in an unsigned32 + + ``depth`` + is the depth of the progamming FIFO on this particular chip. Some + chips, particularly EEPROMs, have the same programming algorithm but + vary in the depth of the amount of data that can be programmed in a + single block. + +``number_of_partitions`` + is the number of logical partitions within this area. + +``Partitions`` + is the address of the table that contains an entry to describe each + partition in this area. Fields within each element of this table are + defined as follows: + + ``offset`` + is the offset of this partition from the base address of this area. + + ``length`` + is the length of this partition. + +By dividing an area of memory into multiple partitions, it is possible to +easily divide the non-volatile memory for different purposes. + +Initialize the Non-Volatile Memory Driver +========================================= + +At system initialization, the non-volatile memory driver's initialization entry +point will be invoked. As part of initialization, the driver will perform +whatever initializatin is required on each non-volatile memory area. + +The discrete I/O driver may register device names for memory partitions of +particular interest to the system. Normally this will be restricted to the +device "/dev/nv_memory" to indicate the entire device driver. + +Disable Read and Write Handlers +=============================== + +Depending on the target's non-volatile memory configuration, it may be possible +to write to a status register and make the memory area completely inaccessible. +This is target dependent and beyond the standard capabilities of any memory +type. The user has the optional capability to provide handlers to disable and +enable access to a partiticular memory area. + +Open a Particular Memory Partition +================================== + +This is the driver open call. Usually this call does nothing other than +validate the minor number. + +With some drivers, it may be necessary to allocate memory when a particular +device is opened. If that is the case, then this is often the place to do this +operation. + +Close a Particular Memory Partition +=================================== + +This is the driver close call. Usually this call does nothing. + +With some drivers, it may be necessary to allocate memory when a particular +device is opened. If that is the case, then this is the place where that +memory should be deallocated. + +Read from a Particular Memory Partition +======================================= + +This corresponds to the driver read call. After validating the minor number +and arguments, this call enables reads from the specified memory area by +invoking the user supplied "enable reads handler" and then reads the indicated +memory area. When invoked the ``argument_block`` is actually a pointer to the +following structure type: + +.. code-block:: c + + typedef struct { + uint32_t offset; + void *buffer; + uint32_t length; + uint32_t status; + } Non_volatile_memory_Driver_arguments; + +The driver reads ``length`` bytes starting at ``offset`` into the partition and +places them at ``buffer``. The result is returned in ``status``. + +After the read operation is complete, the user supplied "disable reads handler" +is invoked to protect the memory area again. + +Write to a Particular Memory Partition +====================================== + +This corresponds to the driver write call. After validating the minor number +and arguments, this call enables writes to the specified memory area by +invoking the "enable writes handler", then unprotecting the memory area, and +finally actually writing to the indicated memory area. When invoked the +``argument_block`` is actually a pointer to the following structure type: + +.. code-block:: c + + typedef struct { + uint32_t offset; + void *buffer; + uint32_t length; + uint32_t status; + } Non_volatile_memory_Driver_arguments; + +The driver writes ``length`` bytes from ``buffer`` and writes them to the +non-volatile memory starting at ``offset`` into the partition. The result is +returned in ``status``. + +After the write operation is complete, the "disable writes handler" is invoked +to protect the memory area again. + +Erase the Non-Volatile Memory Area +================================== + +This is one of the IOCTL functions supported by the I/O control device driver +entry point. When this IOCTL function is invoked, the specified area of +non-volatile memory is erased. diff --git a/bsp-howto/preface.rst b/bsp-howto/preface.rst new file mode 100644 index 0000000..dc43075 --- /dev/null +++ b/bsp-howto/preface.rst @@ -0,0 +1,58 @@ +.. comment SPDX-License-Identifier: CC-BY-SA-4.0 + +.. COMMENT: COPYRIGHT (c) 1988-2002. +.. COMMENT: On-Line Applications Research Corporation (OAR). +.. COMMENT: All rights reserved. + +Introduction +############ + +Before reading this documentation, it is strongly advised to read the RTEMS +Development Environment Guide to get acquainted with the RTEMS directory +structure. This document describes how to do a RTEMS Board Support Package, +i.e. how to port RTEMS on a new target board. Discussions are provided for the +following topics: + +- RTEMS Board Support Package Organization + +- Makefiles and the Linker Command Script + +- Board Initialization Sequence + +- Device Drivers: + + - Console Driver + - Clock Driver + - Timer Driver + - Real-Time Clock Driver + - Non-Volatile Memory Driver + - Networking Driver + - Shared Memory Support Driver + - Analog Driver + - Discrete Driver + +The original version of this manual was written by Geoffroy Montel +. When he started development of the gen68340 +BSP, this manual did not exist. He wrote the initial version of +this manual as the result of his experiences. At that time, this +document was viewed internally as the most important "missing manual" +in the RTEMS documentation set. + +The gen68340 BSP is a good example of the life of an RTEMS BSP. It is +based upon a part not recommended for new designs and none of the core RTEMS +Project team members have one of these boards. Thus we are unlikely to +perform major updates on this BSP. So as long as it compiles and links all +tests, it will be available. + +The RTEMS Project team members are always trying to identify common +code across BSPs and refactoring the code into shared routines. +As part of this effort, the we will enhance the common BSP Framework. +Not surprisingly, not every BSP takes advantage of every feature in +the framework. The gen68340 does not take advantage of as many features +as the ERC32 BSP does. So in many ways, the ERC32 is a better example +BSP at this point. But even the ERC32 BSP does not include examples +of every driver template and framework available to the BSP author. +So in this guide we will try to point out good examples from other BSPs. + +Our goal is for you to be able to reuse as much code as possible and +write as little board specific code as possible. diff --git a/bsp-howto/real_time_clock.rst b/bsp-howto/real_time_clock.rst new file mode 100644 index 0000000..457c6e0 --- /dev/null +++ b/bsp-howto/real_time_clock.rst @@ -0,0 +1,211 @@ +.. comment SPDX-License-Identifier: CC-BY-SA-4.0 + +.. COMMENT: COPYRIGHT (c) 1988-2002. +.. COMMENT: On-Line Applications Research Corporation (OAR). +.. COMMENT: All rights reserved. + +Real-Time Clock Driver +###################### + +Introduction +============ + +The Real-Time Clock (*RTC*) driver is responsible for providing an interface to +an *RTC* device. The capabilities provided by this driver are: + +- Set the RTC TOD to RTEMS TOD + +- Set the RTEMS TOD to the RTC TOD + +- Get the RTC TOD + +- Set the RTC TOD to the Specified TOD + +- Get the Difference Between the RTEMS and RTC TOD + +.. note:: + + In this chapter, the abbreviation `TOD` is used for *Time of Day*. + +The reference implementation for a real-time clock driver can be found in +``c/src/lib/libbsp/shared/tod.c``. This driver is based on the libchip concept +and can be easily configured to work with any of the RTC chips supported by the +RTC chip drivers in the directory ``c/src/lib/lib/libchip/rtc``. There is a +README file in this directory for each supported RTC chip. Each of these +README explains how to configure the shared libchip implementation of the RTC +driver for that particular RTC chip. + +The DY-4 DMV177 BSP used the shared libchip implementation of the RTC driver. +There were no DMV177 specific configuration routines. A BSP could use +configuration routines to dynamically determine what type of real-time clock is +on a particular board. This would be useful for a BSP supporting multiple +board models. The relevant ports of the DMV177's ``RTC_Table`` configuration +table is below: + +.. code-block:: c + + #include + #include + #include + + bool dmv177_icm7170_probe(int minor); + + rtc_tbl RTC_Table[] = { + { "/dev/rtc0", /* sDeviceName */ + RTC_ICM7170, /* deviceType */ + &icm7170_fns, /* pDeviceFns */ + dmv177_icm7170_probe, /* deviceProbe */ + (void *) ICM7170_AT_1_MHZ, /* pDeviceParams */ + DMV170_RTC_ADDRESS, /* ulCtrlPort1 */ + 0, /* ulDataPort */ + icm7170_get_register_8, /* getRegister */ + icm7170_set_register_8, /* setRegister */ + } + }; + unsigned long RTC_Count = (sizeof(RTC_Table)/sizeof(rtc_tbl)); + rtems_device_minor_number RTC_Minor; + + bool dmv177_icm7170_probe(int minor) + { + volatile unsigned16 *card_resource_reg; + card_resource_reg = (volatile unsigned16 *) DMV170_CARD_RESORCE_REG; + if ( (*card_resource_reg & DMV170_RTC_INST_MASK) == DMV170_RTC_INSTALLED ) + return TRUE; + return FALSE; + } + +Initialization +============== + +The ``rtc_initialize`` routine is responsible for initializing the RTC chip so +it can be used. The shared libchip implementation of this driver supports +multiple RTCs and bases its initialization order on the order the chips are +defined in the ``RTC_Table``. Each chip defined in the table may or may not be +present on this particular board. It is the responsibility of the +``deviceProbe`` to indicate the presence of a particular RTC chip. The first +RTC found to be present is considered the preferred RTC. + +In the shared libchip based implementation of the driver, the following actions +are performed: + +.. code-block:: c + + rtems_device_driver rtc_initialize( + rtems_device_major_number major, + rtems_device_minor_number minor_arg, + void *arg + ) + { + for each RTC configured in RTC_Table + if the deviceProbe for this RTC indicates it is present + set RTC_Minor to this device + set RTC_Present to TRUE + break out of this loop + + if RTC_Present is not TRUE + return RTEMS_INVALID_NUMBER to indicate that no RTC is present + + register this minor number as the "/dev/rtc" + + perform the deviceInitialize routine for the preferred RTC chip + + for RTCs past this one in the RTC_Table + if the deviceProbe for this RTC indicates it is present + perform the deviceInitialize routine for this RTC chip + register the configured name for this RTC + } + +The ``deviceProbe`` routine returns TRUE if the device configured by this entry +in the ``RTC_Table`` is present. This configuration scheme allows one to +support multiple versions of the same board with a single BSP. For example, if +the first generation of a board had Vendor A's RTC chip and the second +generation had Vendor B's RTC chip, RTC_Table could contain information for +both. The ``deviceProbe`` configured for Vendor A's RTC chip would need to +return TRUE if the board was a first generation one. The ``deviceProbe`` +routines are very board dependent and must be provided by the BSP. + +setRealTimeToRTEMS +================== + +The ``setRealTimeToRTEMS`` routine sets the current RTEMS TOD to that +of the preferred RTC. + +.. code-block:: c + + void setRealTimeToRTEMS(void) + { + if no RTCs are present + return + + invoke the deviceGetTime routine for the preferred RTC + set the RTEMS TOD using rtems_clock_set + } + +setRealTimeFromRTEMS +==================== + +The ``setRealTimeFromRTEMS`` routine sets the preferred RTC TOD to the +current RTEMS TOD. + +.. code-block:: c + + void setRealTimeFromRTEMS(void) + { + if no RTCs are present + return + + obtain the RTEMS TOD using rtems_clock_get + invoke the deviceSetTime routine for the preferred RTC + } + +getRealTime +=========== + +The ``getRealTime`` returns the preferred RTC TOD to the caller. + +.. code-block:: c + + void getRealTime( rtems_time_of_day *tod ) + { + if no RTCs are present + return + + invoke the deviceGetTime routine for the preferred RTC + } + +setRealTime +=========== + +The ``setRealTime`` routine sets the preferred RTC TOD to the TOD specified by +the caller. + +.. code-block:: c + + void setRealTime( rtems_time_of_day *tod ) + { + if no RTCs are present + return + + invoke the deviceSetTime routine for the preferred RTC + } + +checkRealTime +============= + +The ``checkRealTime`` routine returns the number of seconds difference between +the RTC TOD and the current RTEMS TOD. + +.. code-block:: c + + int checkRealTime( void ) + { + if no RTCs are present + return -1 + + obtain the RTEMS TOD using rtems_clock_get + get the TOD from the preferred RTC using the deviceGetTime routine + convert the RTEMS TOD to seconds + convert the RTC TOD to seconds + + return the RTEMS TOD in seconds - RTC TOD in seconds + } diff --git a/bsp-howto/shared_memory_support.rst b/bsp-howto/shared_memory_support.rst new file mode 100644 index 0000000..f73588d --- /dev/null +++ b/bsp-howto/shared_memory_support.rst @@ -0,0 +1,242 @@ +.. comment SPDX-License-Identifier: CC-BY-SA-4.0 + +.. COMMENT: COPYRIGHT (c) 1988-2009. +.. COMMENT: On-Line Applications Research Corporation (OAR). +.. COMMENT: All rights reserved. + +Shared Memory Support Driver +############################ + +The Shared Memory Support Driver is responsible for providing glue routines and +configuration information required by the Shared Memory Multiprocessor +Communications Interface (MPCI). The Shared Memory Support Driver tailors the +portable Shared Memory Driver to a particular target platform. + +This driver is only required in shared memory multiprocessing systems that use +the RTEMS mulitprocessing support. For more information on RTEMS +multiprocessing capabilities and the MPCI, refer to the *Multiprocessing +Manager* chapter of the *RTEMS Application C User's Guide*. + +Shared Memory Configuration Table +================================= + +The Shared Memory Configuration Table is defined in the following structure: + +.. code-block:: c + + typedef volatile uint32_t vol_u32; + + typedef struct { + vol_u32 *address; /* write here for interrupt */ + vol_u32 value; /* this value causes interrupt */ + vol_u32 length; /* for this length (0,1,2,4) */ + } Shm_Interrupt_information; + + struct shm_config_info { + vol_u32 *base; /* base address of SHM */ + vol_u32 length; /* length (in bytes) of SHM */ + vol_u32 format; /* SHM is big or little endian */ + vol_u32 (*convert)(); /* neutral conversion routine */ + vol_u32 poll_intr; /* POLLED or INTR driven mode */ + void (*cause_intr)( uint32_t ); + Shm_Interrupt_information Intr; /* cause intr information */ + }; + + typedef struct shm_config_info shm_config_table; + +where the fields are defined as follows: + +``base`` + is the base address of the shared memory buffer used to pass messages + between the nodes in the system. + +``length`` + is the length (in bytes) of the shared memory buffer used to pass messages + between the nodes in the system. + +``format`` + is either ``SHM_BIG`` or ``SHM_LITTLE`` to indicate that the neutral format + of the shared memory area is big or little endian. The format of the + memory should be chosen to match most of the inter-node traffic. + +``convert`` + is the address of a routine which converts from native format to neutral + format. Ideally, the neutral format is the same as the native format so + this routine is quite simple. + +``poll_intr``, ``cause_intr`` + is either ``INTR_MODE`` or ``POLLED_MODE`` to indicate how the node will be + informed of incoming messages. + +``Intr`` + is the information required to cause an interrupt on a node. This + structure contains the following fields: + + ``address`` + is the address to write at to cause an interrupt on that node. For a + polled node, this should be NULL. + + ``value`` + is the value to write to cause an interrupt. + + ``length`` + is the length of the entity to write on the node to cause an interrupt. + This can be 0 to indicate polled operation, 1 to write a byte, 2 to + write a sixteen-bit entity, and 4 to write a thirty-two bit entity. + +Primitives +========== + +Convert Address +--------------- + +The ``Shm_Convert_address`` is responsible for converting an address of an +entity in the shared memory area into the address that should be used from this +node. Most targets will simply return the address passed to this routine. +However, some target boards will have a special window onto the shared memory. +For example, some VMEbus boards have special address windows to access +addresses that are normally reserved in the CPU's address space. + +.. code-block:: c + + void *Shm_Convert_address( void *address ) + { + return the local address version of this bus address + } + +Get Configuration +----------------- + +The ``Shm_Get_configuration`` routine is responsible for filling in the Shared +Memory Configuration Table passed to it. + +.. code-block:: c + + void Shm_Get_configuration( + uint32_t localnode, + shm_config_table **shmcfg + ) + { + fill in the Shared Memory Configuration Table + } + +Locking Primitives +------------------ + +This is a collection of routines that are invoked by the portable part of the +Shared Memory Driver to manage locks in the shared memory buffer area. +Accesses to the shared memory must be atomic. Two nodes in a multiprocessor +system must not be manipulating the shared data structures simultaneously. The +locking primitives are used to insure this. + +To avoid deadlock, local processor interrupts should be disabled the entire +time the locked queue is locked. + +The locking primitives operate on the lock ``field`` of the +``Shm_Locked_queue_Control`` data structure. This structure is defined as +follows: + +.. code-block:: c + + typedef struct { + vol_u32 lock; /* lock field for this queue */ + vol_u32 front; /* first envelope on queue */ + vol_u32 rear; /* last envelope on queue */ + vol_u32 owner; /* receiving (i.e. owning) node */ + } Shm_Locked_queue_Control; + +where each field is defined as follows: + +``lock`` + is the lock field. Every node in the system must agree on how this field + will be used. Many processor families provide an atomic "test and set" + instruction that is used to manage this field. + +``front`` + is the index of the first message on this locked queue. + +``rear`` + is the index of the last message on this locked queue. + +``owner`` + is the node number of the node that currently has this structure locked. + +Initializing a Shared Lock +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The ``Shm_Initialize_lock`` routine is responsible for initializing the lock +field. This routines usually is implemented as follows: + +.. code-block:: c + + void Shm_Initialize_lock( + Shm_Locked_queue_Control *lq_cb + ) + { + lq_cb->lock = LQ_UNLOCKED; + } + +Acquiring a Shared Lock +~~~~~~~~~~~~~~~~~~~~~~~ + +The ``Shm_Lock`` routine is responsible for acquiring the lock field. +Interrupts should be disabled while that lock is acquired. If the lock is +currently unavailble, then the locking routine should delay a few microseconds +to allow the other node to release the lock. Doing this reduces bus contention +for the lock. This routines usually is implemented as follows: + +.. code-block:: c + + void Shm_Lock( + Shm_Locked_queue_Control *lq_cb + ) + { + disable processor interrupts + set Shm_isrstat to previous interrupt disable level + + while ( TRUE ) { + atomically attempt to acquire the lock + if the lock was acquired + return + delay some small period of time + } + } + +Releasing a Shared Lock +~~~~~~~~~~~~~~~~~~~~~~~ + +The ``Shm_Unlock`` routine is responsible for releasing the lock field and +reenabling processor interrupts. This routines usually is implemented as +follows: + +.. code-block:: c + + void Shm_Unlock( + Shm_Locked_queue_Control *lq_cb + ) + { + set the lock to the unlocked value + reenable processor interrupts to their level prior + to the lock being acquired. This value was saved + in the global variable Shm_isrstat + } + +Installing the MPCI ISR +======================= + +The ``Shm_setvec`` is invoked by the portable portion of the shared memory to +install the interrupt service routine that is invoked when an incoming message +is announced. Some target boards support an interprocessor interrupt or +mailbox scheme and this is where the ISR for that interrupt would be installed. + +On an interrupt driven node, this routine would be implemented +as follows: + +.. code-block:: c + + void Shm_setvec( void ) + { + install the interprocessor communications ISR + } + +On a polled node, this routine would be empty. diff --git a/bsp-howto/target_dependant_files.rst b/bsp-howto/target_dependant_files.rst new file mode 100644 index 0000000..ecc9b3a --- /dev/null +++ b/bsp-howto/target_dependant_files.rst @@ -0,0 +1,229 @@ +.. comment SPDX-License-Identifier: CC-BY-SA-4.0 + +.. COMMENT: COPYRIGHT (c) 1988-2008. +.. COMMENT: On-Line Applications Research Corporation (OAR). +.. COMMENT: All rights reserved. + + +Target Dependent Files +###################### + +RTEMS has a multi-layered approach to portability. This is done to maximize the +amount of software that can be reused. Much of the RTEMS source code can be +reused on all RTEMS platforms. Other parts of the executive are specific to +hardware in some sense. RTEMS classifies target dependent code based upon its +dependencies into one of the following categories. + +- CPU dependent + +- Board dependent + +- Peripheral dependent + +CPU Dependent +============= + +This class of code includes the foundation routines for the executive proper +such as the context switch and the interrupt subroutine implementations. +Sources for the supported processor families can be found in +``cpukit/score/cpu``. A good starting point for a new family of processors is +the ``no_cpu`` directory, which holds both prototypes and descriptions of each +needed CPU dependent function. + +CPU dependent code is further subcategorized if the implementation is dependent +on a particular CPU model. For example, the MC68000 and MC68020 processors are +both members of the m68k CPU family but there are significant differences +between these CPU models which RTEMS must take into account. + +The source code found in the ``cpukit/score/cpu`` is required to only depend +upon the CPU model variations that GCC distinguishes for the purposes of +multilib'ing. Multilib is the term the GNU community uses to refer to building +a single library source multiple times with different compiler options so the +binary code generated is compatible. As an example, from GCC's perspective, +many PowerPC CPU models are just a PPC603e. Remember that GCC only cares about +the CPU code itself and need not be aware of any peripherals. In the embedded +community, we are exposed to thousands of CPU models which are all based upon +only a relative small number of CPU cores. + +Similarly for the SPARC/ERC32 BSP, the ``RTEMS_CPU`` is specified as ``erc32`` +which is the name of the CPU model and BSP for this SPARC V7 system on chip. +But the multilib variant used is actually ``v7`` which indicates the ERC32 CPU +core is a SPARC V7. + +Board Dependent +=============== + +This class of code provides the most specific glue between RTEMS and a +particular board. This code is represented by the Board Support Packages and +associated Device Drivers. Sources for the BSPs included in the RTEMS +distribution are located in the directory ``c/src/lib/libbsp``. The BSP source +directory is further subdivided based on the CPU family and BSP. + +Some BSPs may support multiple board models within a single board family. This +is necessary when the board supports multiple variants on a single base board. +For example, the Motorola MVME162 board family has a fairly large number of +variations based upon the particular CPU model and the peripherals actually +placed on the board. + +Peripheral Dependent +==================== + +This class of code provides a reusable library of peripheral device drivers +which can be tailored easily to a particular board. The libchip library is a +collection of reusable software objects that correspond to standard +controllers. Just as the hardware engineer chooses a standard controller when +designing a board, the goal of this library is to let the software engineer do +the same thing. + +The source code for the reusable peripheral driver library may be found in the +directory ``c/src/lib/libchip``. The source code is further divided based upon +the class of hardware. Example classes include serial communications +controllers, real-time clocks, non-volatile memory, and network controllers. + +Questions to Ask +================ + +When evaluating what is required to support RTEMS applications on a particular +target board, the following questions should be asked: + +- Does a BSP for this board exist? + +- Does a BSP for a similar board exists? + +- Is the board's CPU supported? + +If there is already a BSP for the board, then things may already be ready to +start developing application software. All that remains is to verify that the +existing BSP provides device drivers for all the peripherals on the board that +the application will be using. For example, the application in question may +require that the board's Ethernet controller be used and the existing BSP may +not support this. + +If the BSP does not exist and the board's CPU model is supported, then examine +the reusable chip library and existing BSPs for a close match. Other BSPs and +libchip provide starting points for the development of a new BSP. It is often +possible to copy existing components in the reusable chip library or device +drivers from BSPs from different CPU families as the starting point for a new +device driver. This will help reduce the development effort required. + +If the board's CPU family is supported but the particular CPU model on that +board is not, then the RTEMS port to that CPU family will have to be augmented. +After this is done, development of the new BSP can proceed. + +Otherwise both CPU dependent code and the BSP will have to be written. + +This type of development often requires specialized skills and there are people +in the community who provide those services. If you need help in making these +modifications to RTEMS try a search in a search engine with something like +"rtems support". The RTEMS Project encourages users to use support services +however we do not endorse any providers. + +CPU Dependent Executive Files +============================= + +The CPU dependent files in the RTEMS executive source code are found in the +following directory: + +.. code-block:: c + + cpukit/score/cpu/ + +where is replaced with the CPU family name. + +Within each CPU dependent directory inside the executive proper is a file named +``.h`` which contains information about each of the supported CPU models +within that family. + +CPU Dependent Support Files +=========================== + +The CPU dependent support files contain routines which aid in the development +of applications using that CPU family. For example, the support routines +may contain standard trap handlers for alignment or floating point exceptions +or device drivers for peripheral controllers found on the CPU itself. +This class of code may be found in the following directory: + +.. code-block:: c + + c/src/lib/libcpu/ + +CPU model dependent support code is found in the following directory: + +.. code-block:: c + + c/src/lib/libcpu// + + may be a specific CPU model name or a name indicating a CPU core or +a set of related CPU models. The file ``configure.ac`` in each +``c/src/lib/libcpu/`` directory contains the logic which enables the +appropriate subdirectories for the specific CPU model your BSP has. + +Board Support Package Structure +=============================== + +The BSPs are all under the ``c/src/lib/libbsp`` directory. Below this +directory, there is a subdirectory for each CPU family. Each BSP is found +under the subdirectory for the appropriate processor family (arm, powerpc, +sparc, etc.). In addition, there is source code available which may be shared +across all BSPs regardless of the CPU family or just across BSPs within a +single CPU family. This results in a BSP using the following directories: + +.. code-block:: c + + c/src/lib/libbsp/shared + c/src/lib/libbsp//shared + c/src/lib/libbsp// + +Under each BSP specific directory, there is a collection of subdirectories. +For commonly provided functionality, the BSPs follow a convention on +subdirectory naming. The following list describes the commonly found +subdirectories under each BSP. + +- ``console``: + is technically the serial driver for the BSP rather than just a console + driver, it deals with the board UARTs (i.e. serial devices). + +- ``clock``: + support for the clock tick - a regular time basis to the kernel. + +- ``timer``: + support of timer devices. + +- ``rtc`` or ``tod``: + support for the hardware real-time clock. + +- ``nvmem``: + support for non-volatile memory such as EEPROM or Flash. + +- ``network``: + the Ethernet driver. + +- ``shmsupp``: + support of shared memory driver MPCI layer in a multiprocessor system, + +- ``include``: + include files for this BSP. + +- ``gnatsupp``: + BSP specific support for the GNU Ada run-time. Each BSP that wishes to have + the possibility to map faults or exceptions into Ada language exceptions or + hardware interrupts into Ada interrupt tasks must provide this support. + +There may be other directories in the BSP tree and the name should be +indicative of the functionality of the code within that directory. + +The build order of the BSP is determined by the Makefile structure. This +structure is discussed in more detail in the :ref:`Makefiles` chapter. + +.. sidebar: + +This manual refers to the gen68340 BSP for numerous concrete examples. You +should have a copy of the gen68340 BSP available while reading this piece of +documentation. This BSP is located in the following directory: + +.. code-block:: c + + c/src/lib/libbsp/m68k/gen68340 + +Later in this document, the $BSP340_ROOT label will be used to refer to this +directory. diff --git a/bsp-howto/timer.rst b/bsp-howto/timer.rst new file mode 100644 index 0000000..ec1279f --- /dev/null +++ b/bsp-howto/timer.rst @@ -0,0 +1,102 @@ +.. comment SPDX-License-Identifier: CC-BY-SA-4.0 + +.. COMMENT: COPYRIGHT (c) 1988-2002. +.. COMMENT: On-Line Applications Research Corporation (OAR). +.. COMMENT: All rights reserved. + +Timer Driver +############ + +The timer driver is primarily used by the RTEMS Timing Tests. This driver +provides as accurate a benchmark timer as possible. It typically reports its +time in microseconds, CPU cycles, or bus cycles. This information can be very +useful for determining precisely what pieces of code require optimization and +to measure the impact of specific minor changes. + +The gen68340 BSP also uses the Timer Driver to support a high performance mode +of the on-CPU UART. + +Benchmark Timer +=============== + +The RTEMS Timing Test Suite requires a benchmark timer. The RTEMS Timing Test +Suite is very helpful for determining the performance of target hardware and +comparing its performance to that of other RTEMS targets. + +This section describes the routines which are assumed to exist by the RTEMS +Timing Test Suite. The names used are *EXACTLY* what is used in the RTEMS +Timing Test Suite so follow the naming convention. + +benchmark_timer_initialize +-------------------------- + +Initialize the timer source. + +.. code-block:: c + + void benchmark_timer_initialize(void) + { + initialize the benchmark timer + } + +Read_timer +---------- + +The ``benchmark_timer_read`` routine returns the number of benchmark time units +(typically microseconds) that have elapsed since the last call to +``benchmark_timer_initialize``. + +.. code-block:: c + + benchmark_timer_t benchmark_timer_read(void) + { + stop time = read the hardware timer + if the subtract overhead feature is enabled + subtract overhead from stop time + return the stop time + } + +Many implementations of this routine subtract the overhead required to +initialize and read the benchmark timer. This makes the times reported more +accurate. + +Some implementations report 0 if the harware timer value change is sufficiently +small. This is intended to indicate that the execution time is below the +resolution of the timer. + +benchmark_timer_disable_subtracting_average_overhead +---------------------------------------------------- + +This routine is invoked by the "Check Timer" (``tmck``) test in the RTEMS +Timing Test Suite. It makes the ``benchmark_timer_read`` routine NOT subtract +the overhead required to initialize and read the benchmark timer. This is used +by the ``tmoverhd`` test to determine the overhead required to initialize and +read the timer. + +.. code-block:: c + + void benchmark_timer_disable_subtracting_average_overhead(bool find_flag) + { + disable the subtract overhead feature + } + +The ``benchmark_timer_find_average_overhead`` variable is used to indicate the +state of the "subtract overhead feature". + +gen68340 UART FIFO Full Mode +============================ + +The gen68340 BSP is an example of the use of the timer to support the UART +input FIFO full mode (FIFO means First In First Out and roughly means +buffer). This mode consists in the UART raising an interrupt when n characters +have been received (*n* is the UART's FIFO length). It results in a lower +interrupt processing time, but the problem is that a scanf primitive will block +on a receipt of less than *n* characters. The solution is to set a timer that +will check whether there are some characters waiting in the UART's input +FIFO. The delay time has to be set carefully otherwise high rates will be +broken: + +- if no character was received last time the interrupt subroutine was entered, + set a long delay, + +- otherwise set the delay to the delay needed for ``n`` characters receipt. diff --git a/bsp-howto/wscript b/bsp-howto/wscript new file mode 100644 index 0000000..4a5f474 --- /dev/null +++ b/bsp-howto/wscript @@ -0,0 +1,6 @@ +from sys import path +from os.path import abspath +path.append(abspath('../common/')) + +from waf import cmd_configure as configure, cmd_build as build, spell, cmd_spell, cmd_options as options, linkcheck, cmd_linkcheck + -- cgit v1.2.3