This is the mail archive of the ecos-discuss@sources.redhat.com mailing list for the eCos project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Virtual Vectors Primer



As promised (uh, some weeks back) here's some documentation on virtual
vectors and control of debug/console output. All the relevant changes
have been checked in and should be available in the sources.redhat.com
CVS repository RSN.

The below will eventually be added to the eCos documentation in a
slightly modified form.

Note that not all targets support virtual vectors (yet) and thus do
not respect (or even enable) the new configuration options. If you
think the below sounds good, you may want to help convert the
remaining targets to use virtual vectors :)

Cheers,
Jesper




Virtual Vectors Primer
======================

What are virtual vectors, what do they do, and why are they needed? 

"Virtual vectors" is the name of a table located at a static location
in the target address space. This table contains 64 vectors that point
to _service_ functions or data.

The fact that the vectors are always placed at the same location in
the address space means that both ROM and RAM startup configurations
can access these and thus the services pointed to.

The primary goal is to allow services to be provided by ROM
configurations (ROM monitors in particular) with _clients_ in RAM
configurations being able to use these services.

Without the table of pointers this would be impossible since the ROM
and RAM applications would be linked separately - in effect having
separate name spaces - preventing direct references from one to the
other.

This decoupling of service from client is needed by RedBoot, allowing
among other things debugging of applications which do not contain
debugging client code (stubs).


Initialization (or Mechanism vs. Policy)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Virtual vectors are a _mechanism_ for decoupling services from clients
in the address space. 

The mechanism allows services to be implemented by ROM monitor, RAM
application, to be switched out at run-time, to be disabled by
installing pointers to dummy functions, etc.

The appropriate use of the mechanism is specified loosely by a
_policy_. The general policy dictates that the vectors are initialized
in whole by ROM monitors (built for ROM or RAM), or by stand-alone
applications.

For configurations relying on a ROM monitor environment, the policy is
to allow initialization on a service by service basis. The default is
to initialize all services, except COMMS services since these are
presumed to already be carrying a communication session to the
debugger / console which was used for launching the application.  This
means that the bulk of the code gets tested in normal builds, and not
just once in a blue moon when building new stubs or a ROM
configuration.

The configuration options are written to comply with this policy by
default, but can be overridden by the user if desired. Defaults are:

 o For application development: the ROM monitor provides debugging and
   diagnostic IO services, the RAM application relies on these by
   default.

 o For production systems: the application contains all the necessary
   services.


Pros and Cons of Virtual Vectors
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

There are pros and cons associated with the use of virtual vectors. We
do believe that the pros generally outweigh the cons by a great
margin, but there may be situations where the opposite is true.

The use of the services are implemented by way of macros, meaning that
it is possible to circumvent the virtual vectors if desired. There is
(as yet) no implementation for doing this, but it is possible.

Here is a list of pros and cons:

 Pro: Allows debugging without including stubs

      Comments: This is the primary reason for using virtual
                vectors. It allows the ROM monitor to provide most of
                the debugging infrastructure, requiring only the
                application to provide hooks for asynchronous debugger
                interrupts and for accessing kernel thread
                information.

 Pro: Allows debugging to be initiated from arbitrary channel

      Comments: While this is only true where the application does not
                actively override the debugging channel setup, it is a
                very nice feature during development. In particular it
                makes it possible to launch (and/or debug)
                applications via Ethernet even though the application
                configuration does not contain networking support.

 Pro: Image smaller due to services being provided by ROM monitor

      Comments: All service functions except HAL IO are included in
                the default configuration. But if these are all
                disabled the image for download will be a little
                smaller. Probably doesn't matter much for regular
                development, but it is a worthwhile saving for the
                20000 daily tests run in the Red Hat eCos test farm.

 Con: The vectors add a layer of indirection, increasing application
      size and reducing performance.

      Comments: The size increase is a fraction of what is required to
                implement the services. So for RAM configurations
                there is a net saving, while for ROM configurations
                there is a small overhead.

                The performance loss means little for most of the
                services (of which the most commonly used is
                diagnostic IO which happens via polled routines
                anyway).

 Con: The layer of indirection is another point of failure.

      Comments: The concern primarily being that of vectors being
                trashed by rogue writes from bad code, causing a
                complete loss of the service and possibly a crash.
                But this does not differ much from a rogue write to
                anywhere else in the address space which could cause
                the same amount of mayhem. But it is arguably an
                additional point of failure for the service in
                question.

 Con: All the indirection stuff makes it harder to bring a HAL up

      Comments: This is a valid concern. However, seeing as most of
                the code in question is shared between all HALs and
                should remain unchanged over time, the risk of it
                being broken when a new HAL is being worked on should
                be minimal.

                When starting a new port, be sure to implement
                the HAL IO drivers according to the scheme used in
                other drivers, and there should be no problem.

                However, it is still possible to circumvent the
                vectors if they are suspect of causing problems:
                simply change the HAL_DIAG_INIT and
                HAL_DIAG_WRITE_CHAR macros to use the raw IO
                functions.


Available services
~~~~~~~~~~~~~~~~~~

The hal_if.h file in the common HAL defines the complete list of
available services. A few worth mentioning in particular:

 o COMMS services. All HAL IO happens via the communication channels.
 o uS delay. Fine granularity (busy wait) delay function.
 o Reset. Allows a software initiated reset of the board.


The COMMS channels
==================

As all HAL IO happens via the COMMS channels these deserve to be
described in a little more detail. In particular the controls of where
diagnostic output is routed and how it is treated to allow for display
in debuggers.


Console and Debugging Channels
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

There are two COMMS channels - one for console IO and one for
debugging IO. They can be individually configured to use any of the
actual IO ports (serial or Ethernet) available on the platform.

The console channel is used for any IO initiated by calling the
diag_() functions. Note that these should only be used during
development for debugging, assertion and possibly tracing
messages. All proper IO should happen via proper devices. This means
it should be possible to remove the HAL device drivers from production
configurations where assertions are disabled.

The debugging channel is used for communication between the debugger
and the stub which remotely controls the target for the debugger (the
stub runs on the target). This usually happens via some protocol,
encoding commands and replies in some suitable form.

Having two separate channels allows, e.g., for simple logging without
conflicts with the debugger or interactive IO which some debuggers do
not allow.


Mangling
~~~~~~~~

As debuggers usually have a protocol using specialized commands when
communicating with the stub on the target, sending out text as raw
ASCII from the target on the same channel will either result in
protocol errors (with loss of control over the target) or the text may
just be ignored as junk by the debugger.

To get around this, some debuggers have a special command for text
output. Mangling is the process of encoding diagnostic ASCII text
output in the form specified by the debugger protocol.

When it is necessary to use mangling, i.e. when writing console output
to the same port used for debugging, a mangler function is installed
on the console channel which mangles the text and passes it on to the
debugger channel.


What's the problem with the old code
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

This is what it did: on initialization it would check if the CDL
configured console channel differed from the active debug channel -
and if so, set the console channel, thereby disabling mangling.

The idea was that whatever channel was configured to be used for
console (i.e., diagnostic output) in the application was what should
be used. Also, it meant that if debug and console channels were
normally the same, a changed console channel would imply a request for
unmangled output.

But this prevented at least two things:

 o It was impossible to inherit the existing connection by which the
   application was launched (either by RedBoot commands via telnet, or
   by via a debugger).

   This was mostly a problem on targets supporting Ethernet access
   since the diagnostic output would not be returned via the Ethernet
   connection, but on the configured serial port.

   The problem also occurred on any targets with multiple serial ports
   where the ROM monitor was configured to use a different port than
   the CDL defaults.

 o Proper control of when to mangle or just write out raw ASCII text.

   Sometimes it's desirable to disable mangling, even if the channel
   specified is the same as that used for debugging. This usually
   happens if GDB is used to download the application, but direct
   interaction with the application on the same channel is desired
   (GDB protocol only allows output from the target, no input).


So what does the new code do
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Console output configuration is either inherited from the ROM monitor
launching the application, or it is specified by the application. This
is controlled by the new option
CYGSEM_HAL_VIRTUAL_VECTOR_INHERIT_CONSOLE which defaults to enabled
when the configuration is set to use a ROM monitor.

If the user wants to specify the console configuration in the
application image, there are two new options that are used for this.

Defaults are to direct diagnostic output via a mangler to the
debugging channel (CYGDBG_HAL_DIAG_TO_DEBUG_CHAN enabled). The mangler
type is controlled by the option CYGSEM_HAL_DIAG_MANGLER. At present
there are only two mangler types:

 o GDB

   This causes a mangler appropriate for debugging with GDB to be
   installed on the console channel.

 o None

   This causes a NULL mangler to be installed on the console channel.
   It will redirect the IO to/from the debug channel without mangling
   of the data. This option differs from setting the console channel
   to the same IO port as the debugging channel in that it will keep
   redirecting data to the debugging channel even if that is changed
   to some other port.

Finally, by disabling CYGDBG_HAL_DIAG_TO_DEBUG_CHAN, the diagnostic
output is directed in raw form to the specified console IO port.


In summary this results in the following common configuration
scenarios for RAM startup configurations:

 - For regular debugging with diagnostic output appearing in the
   debugger, mangling is enabled and stubs disabled.

   Diagnostic output appears via the debugging channel as initiated by
   the ROM monitor, allowing for correct behavior whether the
   application was launched via serial or Ethernet, from the RedBoot
   command line or from a debugger.

 - For debugging with raw diagnostic output, mangling is
   disabled. 

   Debugging session continues as initiated by the ROM monitor,
   whether the application was launched via serial or
   Ethernet. Diagnostic output is directed at the IO port configured
   in the application configuration.

 Note: There is one caveat to be aware of. If the application uses
       proper devices (be it serial or Ethernet) on the same ports as
       those used by the ROM monitor, the connections initiated by the
       ROM monitor will be terminated.

And for ROM startup configurations:

 - Production configuration with raw output and no debugging features
   (configured for RAM or ROM), mangling is disabled, no stubs are
   included.

   Diagnostic output appears (in unmangled form) on the specified IO
   port.

 - RedBoot configuration, includes debugging features and necessary
   mangling.

   Diagnostic and debugging output port is auto-selected by the first
   connection to any of the supported IO ports. Can change from
   interactive mode to debugging mode when a debugger is detected -
   when this happens a mangler will be installed as required.

 - GDB stubs configuration (obsoleted by RedBoot configuration),
   includes debugging features, mangling is hardwired to GDB protocol.

   Diagnostic and debugging output is hardwired to configured IO
   ports, mangling is hardwired.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]