eCosTM Reference Manual
Prev | Chapter 7. The eCos Hardware Abstraction Layer (HAL) | Next

# Kernel porting notes

This section briefly describes the issues involved in porting eCos to a new target platform and/or architecture.

## Porting overview

The effort required to port eCos to a new target varies. Adding support for a new platform/board may require almost no effort, while adding support for a new architecture is more demanding. Additionally, new device drivers may have to be written if there is no existing support for the target’s devices.

Given that there are usually more target platforms using the same microprocessor or microcontroller, adding eCos support for a new target would often be a question of adding support for the new target platform. The architectures supported by eCos include the following: ARM7, MIPS (TX39), MN10300, PowerPC (MPC8xx), and SPARClite.

Adding a new architecture support is a bigger job and also requires tool support (GCC, GDB and binutils) which is a big undertaking in itself.

### Platform support

Adding support for a new platform requires (a subset of):

1. Adding eCos configuration information.

2. Memory layout description.

3. Memory controller initialization.

4. Interrupt controller handling.

5. Minimal serial device driver for GDB interaction and simple diagnostics output.

   System timer initialization and control.

   Wallclock driver.

   A wallclock emulation based on the system timer is provided with the standard eCos distribution. For those hardware platforms where a battery backed-up clock device or other means of determining actual wallclock time exists, a wallclock driver may be implemented more fully.

If the architecture in question is a microcontroller (as opposed to a microprocessor), the job of porting may be as simple as adding configuration information and defining a new memory layout (items one and two). Currently eCos supports the following microcontrollers: MN10300, MPC8xx, and TX39.

### Architectural support

Adding support for a new architecture requires:

1. Adding eCos configuration information.

2. Writing a HAL for the CPU core"s register model, interrupt and exception model, cache model, and possibly simple handling for the MMU model.

3. For microcontrollers the HAL should also support the memory controller, interrupt controller and a possible on-MCP serial controller for GDB interaction and simple diagnostics output, system timer initialization and control, and a wallclock driver.

If there is already support for a member of the same architecture family, the porting job may just consist of adding extra feature support to the existing HAL. Or if the new target architecture only defines a subset of the architecture family, the HAL may need additional configuration control, allowing parts of the existing HAL code to be disabled.

## Adding configuration information

Architecture and platform configuration information resides in two top-level files `targets` and `packages` as well as in architecture and platform specific configuration files (`hal/<arch>/arch/current/include/pkgconf/hal_<arch>.h` and `hal/<arch>/<platform>/current/include/pkgconf/hal_<arch>_<platform>.h.` Furthermore, each platform must define memory layouts for each startup type.

### `targets`

Architecture and platform information must be added to the `targets` file.

    target powerpc {
        alias               { PowerPC powerpc-eabi }
        command_prefix      powerpc-eabi
        packages            { CYGPKG_HAL_POWERPC }
        hal                 hal/powerpc/arch

        cflags {
            ARCHFLAGS       "-mcpu=860 -D_SOFT_FLOAT"
            ERRFLAGS        "-Wall -Wpointer-arith -Wstrict-prototypes -Winline -Wundef"
            CXXERRFLAGS     "-Woverloaded-virtual"
            LANGFLAGS       "-ffunction-sections -fdata-sections"
            DBGFLAGS        "-g -O2"
            CXXLANGFLAGS    "-fno-rtti -fno-exceptions -fvtable-gc -finit-priority"
            LDLANGFLAGS     "-Wl,--gc-sections -Wl,-static"
        }

        platform cogent {
            alias           { "Cogent board" }
            startup         { ram rom stubs }
            packages        {
                CYGPKG_HAL_POWERPC_COGENT
                CYGPKG_DEVICES_WALLCLOCK
                CYGPKG_DEVICES_WATCHDOG
            }
        }
    }

pkgconf uses the entries in `targets` to create a build tree. The `--target` option matches target name (`powerpc`) or its aliases (`PowerPC` `powerpc-eabi`), just as the `--platform` option matches platform name (`cogent`) or its aliases (`Cogent board`). The same is true for the `--startup` option which matches on the list of valid startup types (`ram`, `rom` and `stubs`).

The `command_prefix` is the prefix on the cross compiler tools, usually the same target triplet used when configuring the tools (`powerpc-eabi`).

`packages` lists the hardware-related packages that should be enabled if this target is selected. Typically this will just be the appropriate architectural HAL package provided for this architecture (`CYGPKG_HAL_POWERPC`), while `hal` specifies the relative path of the source files.

`cflags` specifies the compiler and linker flags. The `-finit-priority` flag is required for proper initialization of eCos, while `-ffunction-sections`, `-fdata-sections`, and `-Wl,--gc-sections` are required to provide linker garbage collection which removes functions and initialized data that are not going to be used. The other `FLAGS` definitions can be set according to preference, taking care to ensure that `ARCHFLAGS` contains all necessary flags for the particular architecture.

The `platform` option is used to define a new target platform. There can be several of these for each architecture. The name and startup types are defined using `platform`, `alias`, and `startup` as described above. `packages` defines the set of packages supported by this particular platform. This set must include the platform HAL package (`CYGPKG_HAL_POWERPC_COGENT`), but can name other packages (`CYGPKG_DEVICES_WALLCLOCK` and `CYGPKG_DEVICES_WATCHDOG`) which will be enabled per default when selecting this architecture/platform configuration.

### `packages`

The individual packages must be defined in the `packages` file.

    package CYGPKG_HAL_POWERPC {
            alias           { "PowerPC common HAL" hal_powerpc powerpc_hal powerpc_arch_hal }
            directory       hal/powerpc/arch
            include_dir     cyg/hal
            hardware
    }

    package CYGPKG_HAL_POWERPC_COGENT {
            alias           { "PowerPC Cogent board support" hal_powerpc_cogent powerpc_cogent_hal }
            directory       hal/powerpc/cogent
            include_dir     cyg/hal
            hardware
    }

These are the definitions of the two packages named in the `targets` file. The aliases can be used with the `--disable-` and `--enable-` options of pkgconf.

`directory` specifies the relative path of the source files, `include_dir` where header files provided by the package should be copied to in the install directory, and `hardware` specifies that these packages is normally associated with specific hardware and should only be enabled for the appropriate hardware.

### Package-specific configuration

The package-specific configuration files provide presentation information used by the Configuration Tool, dependencies on other packages and of course additional fine-grained options that are architecture and/or target specific. See the two files `hal/powerpc/arch/current/include/pkgconf/hal_powerpc.h` and `hal/powerpc/cogent/current/include/pkgconf/hal_powerpc_cogent.h` for an example.

### Memory layout information

For each target platform must be defined the memory layout used for any given startup type. This information resides in two files `mlt_<arch>_<platform>_<startup>.ldi` and `mlt_<arch>_<platform>_<startup>.mlt` in the directory `hal/<arch>/<platform>/current/include/pkgconf/`. The former is a linker script fragment, the latter a file describing the layout for the eCos Configuration Tool.

Redefining the memory layout can be done in the Configuration Tool, which will create the linker script (the `.ldi` file). It is also possible to do by hand, in which case only the linker script should be created; when no `.mlt` file exists, the Configuration Tool will not overwrite the default linker script.

## Platform porting

Platform porting basically consists of making a copy of an existing platform directory and changing the code to match the new platform. The header and source files in the platform directory and their contents are described in the section called Architectural HAL files.

In particular the configuration information and memory layout need changing, as may the board initialization code and the minimal serial drivers used by `hal_diag.c` and `plf_stub.c`.

Another useful reference for porting to a new platform is the GNUPro documentation on gdb stubs, which can be found at http://www.cygnus.com/pubs/gnupro/3_GNUPro_Debugging_Tools/b_Debugging_with_GDB/gdbThe_GDB_remote_serial_protocol.html

## Architectural porting

The easiest way to make a new architectural port of eCos is to make a copy of an existing HAL and change the code to suit the new CPU. This guide will use the PowerPC Cogent board as an example. Wherever powerpc, ppc, or cogent is mentioned in this guide or in the source files, you should replace the strings with appropriate architecture and platform names. There are also a few files that need renaming.

If there is simulator support for the new CPU it is possible to test big parts of the HAL and the rest of the eCos kernel before a port to a specific platform is attempted. This is an advantage as doing a platform port can cause problems of it own, making it difficult to determine whether the architectural or platform parts of the port in progress are to blame when something is not working properly.

When no simulator support exists, the starting point of a port is to produce a minimal GDB stub for the target platform, which will allow code to be downloaded, executed and/or debugged on the board. This guide is based on a situation where no simulator exists as it would be the most likely scenario.

### Writing an eCos GDB stub

A GDB stub has both a architectural part (description of the CPUs registers, exception decoding, breakpoint and stepping model, etc.) and a platform part (board initialization and simple serial driver).

Writing a stub is a subset of the work required to a full architectural and platform port of the HAL (and thus eCos). The below sections will be a rough list of minimal requirements for a stub; remaining elements of the files can be fleshed out when extending the port to include full eCos functionality. The files and their contents are described in the section called Architectural HAL files.

> Tip: If the target board has an existing download stub (not necessarily GDB compliant), the GDB stub can be tested by changing it to run from RAM rather than ROM (using `ram` startup instead of `stubs` startup).

> After downloading the stub and starting it, it should be possible to connect GDB to the target. Note that trying to download another application may cause the memory of the stub to be overwritten, so some consideration is required when defining the memory layout.

> If the target board does not have an existing download stub and requires a new EPROM to be burned for each testing cycle, you may want to start with writing a minimal stub which can only be used for downloading data to the target board.

> For this purpose you can skip the exception support code in `vectors.S` and hack `hal/common/current/src/stubrom/stubrom.c` to jump directly to the stub code without using a breakpoint.

> Tip: While working on improving the stub code or other parts of the HAL you can use the simple diagnostics output functions (by way of diag_printf) as a crude way of providing debugging feedback until you get full GDB stub functionality in place.

> Tip: A good way of debugging the stub itself is to enable remote debugging in GDB (set remotedebug 1). This makes GDB display any communication between itself and the stub on the target. Consult the GDB file `remote.c` for details on the protocol.

#### Architecture files

`include/basetype.h`

  Implement in full. Little effort.

`include/hal_arch.h`

  The following macros are required for the stub: `HAL_SavedRegisters`, `HAL_BREAKPOINT`, `HAL_BREAKINST`, `HAL_BREAKINST_SIZE`, `HAL_GET_GDB_REGISTERS`, and `HAL_SET_GDB_REGISTERS`.

`include/hal_cache.h`

  The macros in this file can be left as empty if caches are kept disabled. This is definitely the best way to start porting, avoiding cache problems entirely. The cache is not of much use until eCos can be used with applications anyway.

`include/hal_intr.h`

  It is necessary to implement enough exception handling code to properly handle breakpoints.

  As the porting job progresses, asynchronous break points (CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT) may come in handy. These require a minimal interrupt system to be in place.

`include/hal_io.h`

  Should be fully implemented. Usually zero effort.

`include/<arch>_regs.h`

  Can be filled in piecemeal as the porting job progresses.

`include/<arch>_stub.h`

  Redefine `NUMREGS`, `REGSIZE`, and `regnames` using the same register layout as GDB. The register definitions can be found in the `config/<arch>/tm-<arch>.h` file in the GDB sources. The definitions for the PowerPC were found in `config/rs6000/tm-rs6000.h`.

  Discrepancies between what GDB expects and what is defined in the stub will show up when you use the info reg command in GDB (and know what the register contents on the target should be). Be careful to get the `REGSIZE` macro defined correctly.

`src/context.c`

  Nothing here required by the stub.

`src/hal_misc.c`

  The two functions `cyg_hal_invoke_constructors` and `cyg_hal_exception_handler` must be implemented. The former is the same on most architectures and the latter just needs to call `__handle_exception`.

`src/<arch>.ld`

  The linker script must be properly defined.

`src/<arch>_stub.c`

  This file must be fully implemented.

  `__computeSignal` can be defined to just return SIGTRAP as a minimal implementation. Proper signal decoding may help debugging though.

  Single-stepping can be implemented in one of two ways. Some architectures (such as the PowerPC) have hardware support to control single-stepping making it simple to implement. Other architectures require use of breakpoints to implement the functionality, which requires instruction decoding. Examples of the latter approach can be found in the ARM, MIPS, and MN10300 stubs. Implementing instruction decoding obviously requires more effort.

`src/vectors.S`

  This is the core file of the architecture HAL. It is hard to define what the minimal implementation requirements are for stubs to work. It may be worth and/or necessary to do a full implementation of this file to start with, but here are some pointers anyway.

  `_start` as defined for the PowerPC is about the minimum requirement, but you can ignore MMU and cache setup while working on the stub.

  `__default_exception_vsr` and `restore_state` must preserve enough state to allow breakpoints without trashing CPU state for the application code. If you need asynchronous GDB breakpoints `__default_interrupt_vsr` must also be defined well enough to allow interrupts without trashing the CPU state of the interrupted application code.

  Assorted tables also need to be defined, depending on how much of the exception and interrupt handlers is implemented.

#### Platform files

`include/hal_diag.h`

  Shouldn"t require any changes.

`include/plf_stub.h`

  This file provides the interface to the platform stub functions for the `generic-stub.c` code.

  The minimal stub (no asynchronous GDB breakpoints) only requires `HAL_STUB_PLATFORM_INIT_SERIAL`, `HAL_STUB_PLATFORM_GET_CHAR`, and `HAL_STUB_PLATFORM_PUT_CHAR` and the matching functions in `plf_stub.c` to be defined.

`src/<platform>.c`

  This file defines `hal_hardware_init` which takes care of initializing the board. For the Cogent board this includes watchdog initialization and memory controller setup. Other boards may have different requirements.

`src/hal_diag.c`

  This file defines three functions that provide simple diagnostics output; `hal_diag_init`, `hal_diag_write_char`, and `hal_diag_read_char`. Normally these would implement a very simple serial driver. They could also address an LCD or just some LEDs.

  The simple serial driver for the Cogent board is implemented in a separate file, `cma_ser.c`, which is shared with the `plf_stub.c` file.

`src/plf_stub.c`

  This file implements the serial driver needed by the GDB stub. The minimal stub only requires `init`, `putc`, and `getc` functions. A stub which supports asynchronous breakpoints also requires functions to handle serial interrupts. For example implementations see `cma_ser.c` or the `plf_stub.c` file for the MN10300 stdeval1 board.

### Building the stub

1. Prepare a build directory, configuring eCos for `stubs` startup.

2. Disable all packages except eCos common HAL, infrastructure, <arch> common HAL, and <arch> <platform> board support.

3. Disable the HAL common options `CYGFUN_HAL_COMMON_KERNEL_SUPPORT` and `CYGDBG_HAL_DEBUG_GDB_THREAD_SUPPORT`.

   Enable the HAL common option `CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS`.

4. Build libtarget.

5. Change to the directory `hal/common/current/src/stubrom` and type make. This should result in an eCos GDB stub image file called `stubrom`. This can be converted to SRECord or binary format (using objcopy) which can be used by EPROM burner or PROM emulator software.

### Filling in the blanks

When a GDB stub has been written and is working, finishing the HAL port is pretty much a question of completing the header files and writing the functions that were not needed for the stub.

Prev | Home | Next
Future developments | Up | eCos Interrupt Model